Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to correctly retrieve modifier keys in a WPF KeyDown event?

I've seen a number of answers suggesting the use of Keyboard.Modifiers to determine whether a KeyDown event is for a key that had a modifier set. Unfortunately, because Keyboard.Modifiers returns the current state of the modifiers (instead of the state of the modifier when the key was pressed), this results in a really annoying intermittent bug for quick typists.

Specifically, imagine someone presses Ctrl+A, and releases Ctrl only a few milliseconds after pressing A. Now imagine that the system was under heavy load; the key handler started executing but was preempted for 50ms. By the time the key handler is executing again, the current state of Ctrl is "released". The key handler will now think that "A" was pressed without Ctrl, and this is bad.

Similarly, if a fast typist enters A, Ctrl+End and my application uses Keyboard.Modifiers, it could instead end up observing Ctrl+A...

In WinForms, the KeyDown event tells me the state of Ctrl exactly, even if it's already released by the time the event is being handled. How can I get this same behaviour in WPF?

Edit: it's possible that Keyboard.Modifiers doesn't actually retrieve the "current" modifier keys, but instead the modifier keys as related to the key down message currently being processed. In WinAPI, this was the distinction between "async" and non-async key state functions. Unfortunately, the documentation doesn't mention what exactly "current" means. If anyone knows, please say so.

like image 974
Roman Starkov Avatar asked Aug 25 '12 20:08

Roman Starkov


2 Answers

As there does not appear to be any modifier information in the event args you could keep track of the state yourself in some fields and handling both KeyUp and KeyDown to update them accordingly.

e.g.

private bool ctrl = false;
private void This_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.LeftCtrl) //or switch, also: `LeftCtrl` & `RightCtrl` are treated as separate keys
        ctrl = true;
    //etc..
}

private void This_KeyUp(object sender, KeyEventArgs e)
{
    if (e.Key == Key.LeftCtrl)
        ctrl = false;
    //etc..
}

Whether this is actually a good idea i cannot say...


If you want to handle key gestures i would suggest using dedicated methods like KeyBindings they should only fire when the gesture happened. For other input you may also want to have a look at TextInput which is more abstract and returns the text that the input is translated to.

like image 200
H.B. Avatar answered Oct 16 '22 22:10

H.B.


sorry for this destructive answer but...

after a little bit of research it becomes clear to me... the event is called "KeyDown" not "KeyCombinationDown" so it is totally independent of any Modifiers pressed BEFORE...

Actually there is a right way for achieve your goal: Using the Commanding-Pattern.

You define a COMMAND (see google for WPF-Commanding) and add a KeyBinding to your application, where you define the key or the keys/key-combination which will fire up the command...

See the example here: http://msdn.microsoft.com/en-us/library/system.windows.input.keybinding.aspx

IMHO, this is the only way and semantically more elegant, too.

(if this pattern will not be working for you in GENERAL, you maybe have to use native api with pinvoke).

cheers.

like image 42
TheHe Avatar answered Oct 16 '22 20:10

TheHe