I have C# app that monitors keystrokes via KeyDown and KeyPress events. Specifically, it watches for a VolumeMute keystroke (from a handheld device) to do some special processing. It works fine with one problem: Windows seems to intercept the VolumeMute keystroke and mutes the system volume (which I don't want to happen). I think Windows intercepts the keystroke before it is processed by my app because even when I signal the keystroke was handled (e.Handled = true), it mutes the system volume anyway. BTW, the same code works perfectly for other keystrokes I'm catching (ex Backspace, ect).
Is there a way to stop Windows from doing this volume mute?
System: WinXP SP3, .Net 4 Client Profile, Windows Forms app
Code snips
bool keyHandled = false;
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
if (keyHandled)
{
e.Handled = true;
}
}
// =====================================
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
keyHandled = false;
switch (e.KeyCode)
{
case Keys.VolumeMute:
DoSpecialProcessing();
keyHandled = true;
break;
default:
break;
}
e.Handled = keyHandled;
}
The button acts like a toggle, it will mute on the first press and "un-mute" on the next press. All you need is to simulate VolumeMute press again.
This answer explains how to do it.
Note: If you call this method from inside KeyDown handler then you probably need to use BeginInvoke or PostMessage to post a message to a message queue and return immediately in order to avoid race conditions.
Ok. I ended up using AutoHotKey to remap the VolumeMute to another key. Importantly, Windows never sees the VolumeMute keystroke before it gets remapped and doesn't mute the sound. So I can just start this AutoHotKey remap script when I need it. Beats messing with the Windows Registry. Thanks for the suggestions.
Related
EDIT 4: It seems this only happens when running the app through the debugger. So this is not a major problem.
I have a lot of custom keyboard controls, and a lot of it needs to fire regardless of what control has focus. So I'm using the following code in my MainPage constructor:
public MainPage()
{
Window.Current.CoreWindow.KeyDown += CoreWindow_KeyDown;
Window.Current.CoreWindow.KeyUp += CoreWindow_KeyUp;
}
public void public async void CoreWindow_KeyDown(CoreWindow sender, KeyEventArgs args)
{
// Handle here
}
But I'm having the worst kind of problem. Whenever things are happening on the UI thread it seems to be badly interfering with keyboard input. It's as if it stores some kind of backlog.
For example if I go to an AutoSuggestBox which does a lot of logic each keypress and populates the results with graphics loaded from a server and such, and I type 'abcd' it's quite often the 'd' won't register. Then when I type 'e' a few seconds later, the 'd' will go through but not the 'e'. It's not hardware related, it only does this in my UWP app I'm working on.
In the debugger I have confirmed that this unwanted behavior is all happening before the event is fired. args.VirtualKey is firing a 'd' when I type 'e'.
Also the keyup events only fire like 95% of the time. CoreWindow.PointerWheelChanged does not exhibit this problem. Gamepad input using the same handler as the keyboard does not have this problem either.
The more activity on the UI thread seems to increase the severity of the problem.
Does anyone know how to remedy this situation? Any kind of workaround or alternative solution, or at least an explanation of what might be happening?
EDIT:
I tried setting all 4 options for Window.Current.CoreWindow.Dispatcher.ProcessEvents(), no improvement.
EDIT 2:
It seems the fact that I'm capturing CoreWindow.Keydown for global events is a non-sequitur. The problem also happens with any regular KeyDown event on any focused control.
EDIT 3:
I believe I realize what's happening and I think it's a bug. My cursory understanding is that UWP keyboard input is sandboxed to prevent keylogger malware or something, so there's some lower-level translation between the raw key input and the VirtualKey that CoreWindow processes. That's fine, but it seems it doesn't work right under certain conditions.
When there is load on the UI thread during rapid keyboard input (like typing) it sometimes does not detect key releases. This is why KeyUp doesn't fire occasionally as I mentioned. This also messes up KeyDown because keys are in a lock state it thinks the key is being held down when in reality it is not. Then when the next key release does register, the CoreWindow dispatcher flushes its queue and the result is that it fires both an event for the previous key input as well as for the new one. So type 'abcd' and 'd doesn't fire. Wait 10 seconds and then press 'e'. Suddenly both 'd' and 'e' will appear. Or more likly press 'd' again because it didn't register the first time, and double 'dd' will display. Absolutely unacceptable behavior by any standard.
The best way you can try to reproduce it yourself is use an AutoSuggestBox that does something blocking like queries and loads image thumbnails in the results as you type. And keep in mind even a tiny bit of UI load seems to cause it. Even if I asynchronously preload the image as a stream or byte array, it still blocks the UI thread for 1-2ms when the BitmapImage source is set. 1-2ms less than a frame of video and thus visually imperceptible, but it seems it's enough to occasionally not detect when a keyboard key is released.
This could be something hardware specific. I've tested different keyboards but not a different computer.
You can try this:
public MainPage()
{
InitializeComponent();
Window.Current.CoreWindow.CharacterReceived += CoreWindow_CharacterReceived;
}
private async void CoreWindow_CharacterReceived(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.CharacterReceivedEventArgs args)
{
if (args.KeyCode == 27 ) //Escape
{
// your code here fore Escape key
}
if (args.KeyCode == 13) //Enter
{
// your code here fore Enter key
}
}
You can use key codes for other keyboard characters.
Activity on the UI thread during rapid keyboard input prevents CoreWindow from detecting a key release, at least on some hardware, targeting 1803 Spring Creators Update. Hopefully someone knows a better solution but for now here is a partial workaround solution:
public void CoreWindow_KeyDown(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.KeyEventArgs args)
{
CoreVirtualKeyStates keyState = sender.GetAsyncKeyState(args.VirtualKey);
if ((int)keyState == 3)
{
// KeyState is locked and pressed.
// Whenever this happens it means the event fired when I actaually pressed this key.
// Handle event.
}
else if ((int)keyState == 2)
{
// KeyState is locked but not pressed. How if it's not caps lock?
// When this happens it's an unwanted duplicate of the last keystroke.
// Do not handle event.
}
else if ((int)keyState == 0)
{
// Key state is None?!? How can a key that isn't currently down fire a KeyDown event?
// This is a phantom delayed rection of a missed event from two keystrokes ago.
// Do not handle event.
}
}
This will prevent the delayed reaction problem but there will still be missed keystrokes as a result. Not ideal but a vast improvement.
Here is the enum:
https://learn.microsoft.com/en-us/uwp/api/windows.ui.core.corevirtualkeystates
Oddly state 3 ("Pressed | Locked") that always represents a correct key input isn't in the documentation.
Also note that 'CoreVirtualKeyStates == 0' makes it clear this is a bug, at least with my hardware. How could a key with the 'None' state have fired a KeyDown event? Nobody's fingers are that fast. I think this is the CoreWindow dispatcher flushing its queue because it missed a KeyUp event.
I have some basic app on windows phone 8.1, and in that i have regular buttons, for navigate or exit application. I want to disable HardwareButton for back/exit, so if anyone press it, application will not exit.
Any help?
Btw, i tried:
Public void HardwareButtons_BackPressed(object sender, Windows.Phone.UI.Input.BackPressedEventArgs e)
{
e.Handled = false;
}
You have to rewrite the HardwareButtons_BackPressed method on App.xaml.cs file.
Also if you have handled the Event, you have to set e.Handled = true to tell the system you have already handled the event and dont push the event below in the queue.
For more and examples see MSDN.
here i'm trying to make a program that when i press the keyboard "F6", it would auto. move the cursor to a position and click. I tested my program on desktop, it works. But when I go into a game and press F6, it doesn't seem to be working. Some people work, some people does not. I was thinking is there any like keypreview priority that I can do?
private async void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
if (IsKeyPushedDown(Keys.F6))
{
if (auth == 0)
{
MessageBox.Show("请先登录");
timer1.Start();
return;
}
SendKeys.Send("{ESC}");
//Original
if (rdbtnoriginal.Checked == true)
{
await Task.Delay(5000);
hack();
}
}
timer1.Start();
}
Here I use a timer tick, I got the code from online, so when I'm not focusing on the form and press F6 it will trigger the event. But some people go into the game and press F6 it doesn't work
Winforms relies on the window being focused for key messages to register in the application (if the window isn't focused, the IsKeyPushedDown won't register any keys as the window hasn't recieved the keypressed message in the background. you may want to use the input features from DXInput or OpenGL, or have a look at this http://www.codeproject.com/Articles/18890/NET-Hookless-Key-logger-Advanced-Keystroke-Mining. there are probably other libraries/pieces of code. Google is your friend, Key logging is probably your best search term.
I'm running into a very peculiar issue. I noticed that occasionally while typing into my TextBox, I'll lose some keystrokes. I added a bunch of trace statements in events hooked by this TextBox, and I found that when I lost keystrokes, the KeyUp, KeyDown, and KeyPress events all correctly fired, but the TextChanged event never fired.
Does anybody have any idea why this would happen? I could write this off as a ".NET bug", but I'd rather figure out if there is a solution here.
In case there is a suggestion that I use the KeyUp/KeyDown events to determine if the text has changed, there is an issue there as well. KeyUp/KeyDown are called multiple times for each key press, so it would be very difficult to determine if someone was typing the same letter multiple times.
Hmmm....
This is going to be a shot, but, you did say you have the KeyUp, KeyDown and KeyPress event handlers right? Have you set the flag e.Handled to true in the event handlers, have a look here:
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
}
private void textBox1_KeyUp(object sender, KeyEventArgs e)
{
e.Handled = true;
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
Have a look here in the MSDN about this Handled property. (If you have MSDN 2008 SP 1 installed locally, the link is ms-help://MS.MSDNQTR.v90.en/fxref_system.windows.forms/html/dfc80b44-1d79-6315-cbea-1388a048c018.htm)
To quote:
Handled is implemented differently by different controls within Windows Forms.
For controls like TextBox which subclass native Win32 controls, it is
interpreted to mean that the key message should not be passed to the underlying
native control.
If you set Handled to true on a TextBox, that control will not pass the key
press events to the underlying Win32 text box control, but it will still
display the characters that the user typed.
Maybe it is not set i.e. e.Handled = false; thereby preventing the TextChanged Event from firing?
Can you check and confirm this?
Edit: After dreadprivateryan's response, I can suspect (due to lack of code posted), based on his response, e.Handled is true for when Enter key is pressed and false for everything else which in my mind, thinks that is the reason why no further keystrokes are being accepted as a result of this.
Are you trying to set focus to another control upon the Enter key being pressed? It could be that both KeyUp and KeyDown are conflicting...
Remove the keyboard hook and disable it...
My suggestion is to change the code completely in this manner as shown, take out either KeyDown or KeyUp Event Handler as they, simplistically put it, are the same, ok, technically, it is designated respectively for when a key is pressed down, and likewise when a key is released. Have a look at this link here. There was a similar question posted here on SO.
In the example below, I used the keyUp event handler to switch focus to the next available control upon enter key being pressed. In the KeyPress event handler, this simply filters the input and only allows numbers 0-9 respectively, anything else gets discarded. Included in that event handler, is the allowance for the backspace key to provide editing.
private void textBox1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter) SendKeys.Send("{TAB}");
}
private const string VALID_KEYS = "0123456789";
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (VALID_KEYS.IndexOf(char.ToUpper(e.KeyChar)) != -1 || e.KeyChar == (char)8)
e.Handled = false;
else
e.Handled = true;
}
Hope this helps,
Best regards,
Tom.
I don't actually know, but I have a random guess: You running in a VM?
One hack you could use is make a timer that reads the text and compares to the previously entered value. Call the event handler code when it isn't equal to the previously checked value. When you need to use the final entered value, do one additional check, in case the timer hasn't fired yet.
Do you mean the keypress is actually lost and never shows up in the box? Or do you mean you don't get a TextChanged event for every keypress?
I believe the TextChanged event is driven by the operating system's EN_CHANGE notification which is sent via a WM_COMMAND message. I know that certain kinds of messages in Windows are "coalesced" to avoid redundant notifications. For example this can happen with WM_MOUSEMOVE messages and is why you don't receive a mouse move event for every pixel that the mouse moves across the screen.
I can't say for sure but I suspect that the TextChanged event behaves this way as well. I can say though that alternate input methods have this side effect too. When using a Tablet PC input panel, the textbox will not get a TextChanged notification for every character.
The only keyboard hook supported for .NET managed code is a low-level keyboard hook (WH_KEYBOARD_LL).
See Using global keyboard hook (WH_KEYBOARD_LL) in WPF / C#
I have the above code working in my application at the moment so that when you swipe your card you will get a list of all the keystrokes. The problem is for typing delimiter characters such as "%" and ";" it will send me Alt+Numpad+? WPF Key objects corresponding to these symbols.
My question: Is there some way to make this behave more high-level, that is, to capture a string generated from all keyboard commands?
Cheers!
Not sure what's going on, but getting a character like % out of a keyboard hook is very untrivial. The hook only notifies you of virtual keys. But % is a typing key, produced by pressing Shift + 5 on my keyboard (a US layout). Windows normally produces these characters by processing the WM_KEYDOWN/UP messages, generating a WM_CHAR message for the typing key. That's not happening in your case. The low-level Windows function that does this is ToUnicodeEx().
I would guess if you are swiping the card, there's an input somewhere on the wpf form, like a textbox for example? Then I would be inclined to add an event, perhaps a KeyUp Event handler, (The keyboard wedge card scanner does send an end-of-processing signal such as ENTER to indicate the swipe was successful yes?), In the KeyUp Event Handler, build up a string using StringBuilder, and when the end-of-processing signal such as ENTER is caught, you can then remove the "%" and ";" from the StringBuilder instance and do whatever you have to do with it.
It might be easier to use a state system, when the KeyUp event handler receives a "%", then enter another state where the end expected state would be a ";"
static bool StartState = false;
StringBuilder sbInput = new StringBuilder();
private void textBox1_KeyUp(object sender, KeyEventArgs e)
{
if (!StartState){
if (e.KeyCode == Keys.D5) StartState = true;
sbInput.Append((char)e.KeyValue);
}else{
if (e.KeyCode == Keys.OemSemicolon){
StartState = false;
// sbInput will contain the data from the scanner,
// copy it somewhere else and reset sbInput
// sbInput.Remove(0, sbInput.Length);
}
sbInput.Append((char)e.KeyValue);
}
e.Handled = true;
}
Hope this helps,
Best regards,
Tom.