Skip to content

Fix #19128: webagg reports incorrect values for non-alphanumeric key events on non-qwerty keyboards #19146

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Feb 17, 2021
Merged

Fix #19128: webagg reports incorrect values for non-alphanumeric key events on non-qwerty keyboards #19146

merged 22 commits into from
Feb 17, 2021

Conversation

tonadev
Copy link
Contributor

@tonadev tonadev commented Dec 18, 2020

PR Summary

Fixes #19128. This PR improves webagg support for non-alphanumeric key events on non-qwerty keyboards.

KeyboardEvent.which got deprecated and Mozilla recommends to use KeyboardEvent.key instead.

KeyboardEvent.key works different:

If the pressed key has a printed representation, the returned value is a non-empty Unicode character string containing the printable representation of the key.

this allows us to handle correctly combinations of modifiers and keys, even on non-qwerty keyboards.

If the pressed key is a control or special character, the returned value is one of the pre-defined key values.

As I couldn't find a full list of all Matplotlib key names (however the class KeyEvent on backend_bases.py was a bit useful), I tried to keep support for all the keys supported before this changes (those on _LUT and _SHIFT_LUT) by using the same key names.

I also use the same code for reproduction of the bug reported on #19128 on the GTK3Agg backend as example of how key events should have been handled.

PR Checklist

  • Has pytest style unit tests (and pytest passes).
  • Is Flake 8 compliant (run flake8 on changed files to check).
  • New features are documented, with examples if plot related.
  • Documentation is sphinx and numpydoc compliant (the docs should build without error).
  • Conforms to Matplotlib style conventions (install flake8-docstrings and run flake8 --docstring-convention=all).
  • New features have an entry in doc/users/next_whats_new/ (follow instructions in README.rst there).
  • API changes documented in doc/api/next_api_changes/ (follow instructions in README.rst there).

Comment on lines 662 to 664
if (event.shiftKey && event.which !== 16) {
value += 'shift+';
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is shift never added now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not any more.

_handle_key(key) was the one that required the shift+ string on the key value. If shift+ was on a key value, then the function removed the shift+ of the string and depending on the remaining of the key code, it got the "correct" value (it was correct only if the user had a QWERTY keyboard and a US keyboard layout). e.g. "shift+2" was replaced with "@".

As KeyboardEvent.key handles that for us (even better, with support for non US keyboard layouts), we no longer need to specify the shift+ modifier on a key value.

@tacaswell tacaswell modified the milestones: v3.5.0, v3.4.0 Dec 18, 2020
@tacaswell
Copy link
Member

Does this correctly handle 'shift+f1'?

@tonadev
Copy link
Contributor Author

tonadev commented Dec 18, 2020

Does this correctly handle 'shift+f1'?

If you press Shift and F1. The behaviour is the same as the one when using GTK3Agg as backend when running:

python -c 'from pylab import *; plot(); gcf().canvas.mpl_connect("key_press_event", lambda e: print(e.key)); show()'

It prints:

shift
f1

but not shift+f1, is this behaviour correct?

@tacaswell
Copy link
Member

I get different behavior with qt and (on the default branch) webagg

sharon@13:23  ➤  python -c 'from pylab import *; plot(); gcf().canvas.mpl_connect("key_press_event", lambda e: print(e.key)); show()'
e%&shift
shift+f2
shift+f3
shift+f8
shift+f7
shift
shift+control
shift+ctrl+f2
shift+ctrl+f9
shift+ctrl+f10
q
(dd38) ✔  ~/source/p/matplotlib [master {origin/master}|… 1⚑ 7]
sharon@13:24  ➤  MPLBACKEND=webagg python -c 'from pylab import *; plot(); gcf().canvas.mpl_connect("key_press_event", lambda e: print(e.key)); show()'
Press Ctrl+C to stop WebAgg server
shift
shift+f1
shift+f2
shift+f5

@tonadev
Copy link
Contributor Author

tonadev commented Dec 18, 2020

I get the same behaviour on Gtk3Agg and TkAgg...

(matplotlib) galex@pop-os:~/Documentos/Desarrollo/Git/matplotlib$ MPLBACKEND=TkAgg python -c 'from pylab import *; plot(); gcf().canvas.mpl_connect("key_press_event", lambda e: print(e.key)); show()'
shift
f1
q
(matplotlib) galex@pop-os:~/Documentos/Desarrollo/Git/matplotlib$ MPLBACKEND=GTK3Agg python -c 'from pylab import *; plot(); gcf().canvas.mpl_connect("key_press_event", lambda e: print(e.key)); show()'
shift
!
shift
f1
q

@tacaswell
Copy link
Member

Ah, so we have identified an inconsistency between Qt and {tk, gtk}, that is exciting (in the wrong sort of ways)!

Both tk and qt seem to tack ctrl on the front of the f-keys.

jupiter@14:05MPLBACKEND=Qt5Agg python -c 'from pylab import *; plot(); gcf().canvas.mpl_connect("key_press_event", lambda e: print(e.key)); show()'
control
ctrl+f1
ctrl+f1
q
jupiter@14:09MPLBACKEND=TkAgg python -c 'from pylab import *; plot(); gcf().canvas.mpl_connect("key_press_event", lambda e: print(e.key)); show()'
control
ctrl+f1
ctrl+f1
ctrl+f1
control
ctrl+shift
shift
control
ctrl+f1
ctrl+f1
ctrl+f1

so I guess the question is if we should treat the shift key as a "modfier" key that we inform the user about when the key being shifted does not have a "natural" shift value (I guess we could return F1 vs f1? (that is a joke)). I think the way Qt is doing it (to treat shift as a sometimes mofidier key) is more correct, but am not sure of that.

Given that there is inconsistency between the backends already, my preference would be for webagg to "do what it did before", but would not block merging over that behavior being changed (as long as it is documented).

@tonadev Bonus points if you make all of the backends consistent in this PR, but if not can you please write up an issue with your thoughts / findings on the differences?

@tacaswell
Copy link
Member

Also, welcome to the project and congratulations on finding a can of worms on your first try ;)

@tonadev
Copy link
Contributor Author

tonadev commented Dec 19, 2020

@tonadev Bonus points if you make all of the backends consistent in this PR, but if not can you please write up an issue with your thoughts / findings on the differences?

I'll try to make all of the backends consistent in this PR. I have already started working on that.

This is what I have found so far. The following are the result of pressing some "random" key combinations on different backends using a non-US keyboard layout (that's why the correct value for "Shift+2" is ("), there is no need to test all the different Qt, Gtk, etc. backends as they share the same behaviour on keyboard events) on the master branch. A = a with Caps Lock on.

Key(s) Pressed WxAgg Qt5Agg WebAgg Gtk3Agg TkAgg
Shif+2 shift + Enter + 2 shift + Enter + " shift + Enter + @ shift + Enter + " shift + Enter + "
Shif+F1 shift + Enter + f1 shift + Enter + shift+f1 shift + Enter + shift+f1 shift + Enter + f1 shift + Enter + f1
Shif shift shift shift shift shift
Ctrl ctrl+control control control control control
Alt alt+alt alt alt alt alt
AltGr Nothing Nothing Nothing iso_level3_shift iso_level3_shift
CapsLock None Nothing caps caps_lock caps_lock
A a a a A A
a a a a a a
Shift+a shift+a shift + Enter + A shift + Enter + A shift + Enter + A shift + Enter + A
Shift+A shift+a shift + Enter + A shift + Enter + A shift + Enter + a shift + Enter + a
Ctrl+Shift+Alt ctrl+control + Enter + ctrl+shift + Enter + ctrl+alt control + Enter + ctrl+shift + Enter + shift+ctrl+super control + Enter + ctrl+shift + Enter + ctrl+alt control + Enter + ctrl+shift + Enter + ctrl+meta control + Enter + ctrl+shift + Enter + ctrl+meta
Ctrl+Shift+a ctrl+control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+a
Ctrl+Shift+A ctrl+control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+a control + Enter + ctrl+shift + Enter + ctrl+a
F1 f1 f1 f1 f1 f1
Ctrl+F1 ctrl+f1 control + Enter + ctrl+f1 control + Enter + ctrl+f1 control + Enter + ctrl+f1 control + Enter + ctrl+f1

@tonadev
Copy link
Contributor Author

tonadev commented Dec 19, 2020

so I guess the question is if we should treat the shift key as a "modfier" key that we inform the user about when the key being shifted does not have a "natural" shift value (I guess we could return F1 vs f1? (that is a joke)). I think the way Qt is doing it (to treat shift as a sometimes mofidier key) is more correct, but am not sure of that.

What do you mean with "a sometimes modifier key"?

Maybe, we should add "shift+" to a key value, only if shift is down and another special key is pressed. Keys that represent letters, numbers or some symbols (e.g. "{", "-", etc.) won't add that prefix, as shift will act actually as a modifier (maybe that's what you mean with a sometimes modifier). That might require us to keep track of, at least, the most essential special keys (I like Mozilla's list of special keys, again, only the essentials). Any other ideas or is this idea ok?

Wx backend key event handling is very poor, as noted on the table on my previous comment, it doesn't handle shift plus letter/number/symbol keys correctly. Must be improved.

Also, welcome to the project and congratulations on finding a can of worms on your first try ;)

Thanks!

@tonadev
Copy link
Contributor Author

tonadev commented Dec 20, 2020

As of my last changes, these are the results of pressing the same key combinations of one of my previous comments.

Key(s) Pressed WxAgg Qt5Agg WebAgg Gtk3Agg TkAgg
Shif+2 shift + Enter + shift+2 shift + Enter + " shift + Enter + " shift + Enter + " shift + Enter + "
Shif+F1 shift + Enter + shift+f1 shift + Enter + shift+f1 shift + Enter + shift+f1 shift + Enter + f1 shift + Enter + f1
Shif shift shift shift shift shift
Ctrl control control control control control
Alt alt alt alt alt alt
AltGr Nothing Nothing alt iso_level3_shift iso_level3_shift
CapsLock caps_lock Nothing caps_lock caps_lock caps_lock
A a a A A A
a a a a a a
Shift+a shift + Enter + A shift + Enter + A shift + Enter + A shift + Enter + A shift + Enter + A
Shift+A shift + Enter + A shift + Enter + A shift + Enter + a shift + Enter + a shift + Enter + a
Ctrl+Shift+Alt control + Enter + ctrl+shift + Enter + ctrl+alt control + Enter + ctrl+shift + Enter + shift+ctrl+meta control + Enter + ctrl+shift + Enter + ctrl+meta control + Enter + ctrl+shift + Enter + ctrl+meta control + Enter + ctrl+shift + Enter + ctrl+meta
Ctrl+Shift+a control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+a
Ctrl+Shift+A control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+a control + Enter + ctrl+shift + Enter + ctrl+a control + Enter + ctrl+shift + Enter + ctrl+a
F1 f1 f1 f1 f1 f1
Ctrl+F1 control + Enter + ctrl+f1 control + Enter + ctrl+f1 control + Enter + ctrl+f1 control + Enter + ctrl+f1 control + Enter + ctrl+f1

There is still inconsistency on some key combinations. We can observe that Wx and Qt fail on handling uppercase letters. This is due to the fact that these libraries (Wx and Qt) don't treat Caps Lock as a modifier (for us to know if it's on, we would require to use OS specific functions) and every time the user enters a letter it gives us the letter in uppercase, making it difficult to us to know if we should handle it as an uppercase letter or a lowercase letter. We can treat letters as if they were uppercase always too, to get even more consistency.

We can also observe that Wx keeps failing on handling Shif+2.

@tacaswell
Copy link
Member

@tonadev That is an amazing table!

To make sure i am understanding it right, when you write "+ Enter +" you mean there is another line? I think what is going on here is that for e.g. "Ctrl+f1" we are processing two key events, first that ctrl has been pressed and then a second that f1 was pressed while control was held down.

What I meant "What do you mean with "a sometimes modifier key"?" is that for keys that have "an upper case" ('a' vs 'A') we should return the upper case letter ("A") not the modifier and lower case ("shift + a").

@tacaswell
Copy link
Member

In things that are fun, it seems that the order in which you hit the modifiers matters (?!)

It seems that "shifted alt" is "super" or "meta" (I am testing on a branch without these patches with Qt)

(shift then alt)

shift
shift+super

(alt then shift)

alt
alt+shift

I also do not get an event for super being pushed with Qt

I do not think I have an AltGr on my keboard layout. If you use it in combination with other keys do you get the glyphs out that you expect?


I think part of the tension here is that the keyboard input abstraction is leaky with various parts of it being handled at the physical, OS, window manager, GUI toolkit, and application layers.

@tacaswell
Copy link
Member

@tonadev You may also be interested in joining https://gitter.im/matplotlib/incubator

@tonadev
Copy link
Contributor Author

tonadev commented Dec 21, 2020

To make sure i am understanding it right, when you write "+ Enter +" you mean there is another line? I think what is going on here is that for e.g. "Ctrl+f1" we are processing two key events, first that ctrl has been pressed and then a second that f1 was pressed while control was held down.

Yes!, that's right.

What I meant "What do you mean with "a sometimes modifier key"?" is that for keys that have "an upper case" ('a' vs 'A') we should return the upper case letter ("A") not the modifier and lower case ("shift + a").

I think I got it.

@tonadev
Copy link
Contributor Author

tonadev commented Dec 21, 2020

In things that are fun, it seems that the order in which you hit the modifiers matters (?!)

That's true. Actually, that behaviour is consistent between our backends. As a matter of fact, the docstring of backend_bases.KeyEvent allows it:

Notes
-----
Modifier keys will be prefixed to the pressed key and will be in the order
"ctrl", "alt", "super". The exception to this rule is when the pressed key
is itself a modifier key, therefore "ctrl+alt" and "alt+control" can both
be valid key values.

It seems that "shifted alt" is "super" or "meta" (I am testing on a branch without these patches with Qt)

(shift then alt)

shift
shift+super

(alt then shift)

alt
alt+shift

It seems that the other backends do the same. You can see that on the row for Ctrl+Shift+Alt.

I also do not get an event for super being pushed with Qt

Right now, we are not supporting the super key on Qt.

I do not think I have an AltGr on my keboard layout. If you use it in combination with other keys do you get the glyphs out that you expect?

I do (Alt Gr = Alt Graph = the alt to the right of the spacebar).

@tonadev
Copy link
Contributor Author

tonadev commented Dec 22, 2020

I'll use this comment to keep track of the behaviour of the different backends up to date.

Key(s) Pressed WxAgg Qt5Agg WebAgg Gtk3Agg TkAgg
Shif+2 shift + Enter + shift+2 shift + Enter + " shift + Enter + " shift + Enter + " shift + Enter + "
Shif+F1 shift + Enter + shift+f1 shift + Enter + shift+f1 shift + Enter + shift+f1 shift + Enter + shift+f1 shift + Enter + shift+f1
Shif shift shift shift shift shift
Ctrl control control control control control
Alt alt alt alt alt alt
AltGr Nothing Nothing alt iso_level3_shift iso_level3_shift
CapsLock caps_lock caps_lock caps_lock caps_lock caps_lock
A a a A A A
a a a a a a
Shift+a shift + Enter + A shift + Enter + A shift + Enter + A shift + Enter + A shift + Enter + A
Shift+A shift + Enter + A shift + Enter + A shift + Enter + a shift + Enter + a shift + Enter + a
Ctrl+Shift+Alt control + Enter + ctrl+shift + Enter + ctrl+alt control + Enter + ctrl+shift + Enter + ctrl+meta control + Enter + ctrl+shift + Enter + ctrl+meta control + Enter + ctrl+shift + Enter + ctrl+meta control + Enter + ctrl+shift + Enter + ctrl+meta
Ctrl+Shift+a control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+a
Ctrl+Shift+A control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+A control + Enter + ctrl+shift + Enter + ctrl+a control + Enter + ctrl+shift + Enter + ctrl+a control + Enter + ctrl+shift + Enter + ctrl+a
F1 f1 f1 f1 f1 f1
Ctrl+F1 control + Enter + ctrl+f1 control + Enter + ctrl+f1 control + Enter + ctrl+f1 control + Enter + ctrl+f1 control + Enter + ctrl+f1

@tonadev
Copy link
Contributor Author

tonadev commented Dec 24, 2020

@QuLogic @tacaswell Well... I think I got stuck. Most of the remaining inconsistencies are due to limitations by the backend library. For example, wx.KeyEvent docs say:

To summarize: you should handle wxEVT_CHAR if you need the translated key and wxEVT_KEY_DOWN if you only need the value of the key itself, independent of the current keyboard state.

If we handle wxEVT_KEY_DOWN we don't get the translated key, that means by example, if we press shift and then 2 we get exactly that, not "@" (on a US keyboard layout). If we use wxEVT_CHAR we can't get special keys like f1.

On Qt and Wx using wxEVT_KEY_DOWN we always get an uppercased letter, and we can't detect if caps_lock is active (on Qt at least we can know if it was pressed)

And on Tk, when pressing Ctrl+Shift+a the Shift+a part is not being translated.

Any suggestions?

@tacaswell
Copy link
Member

If there are limitations/inconsistencies in the GUI toolkits then there are inconsistencies. You did not introduce them and the have probably been there from the beginning so we should take the win of the stuff you have fixed and document what is not working (that table should probably go in to https://matplotlib.org/users/event_handling.html / https://github.com/matplotlib/matplotlib/blob/master/doc/users/event_handling.rst).

The *matplotlib.backends.backend_qt5.SPECIAL_KEYS* dictionary
contains keys that do *not* return their unicode name
instead they have manually specified names. The name
for *QtCore.Qt.Key_Meta* has changed to ``'meta'`` to be consistent.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for *QtCore.Qt.Key_Meta* has changed to ``'meta'`` to be consistent.
for *QtCore.Qt.Key_Meta* has changed to ``'meta'`` to be consistent with the
other GUI backends.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this instead be titled "harmonized key event data across backends" or something like that? That way it can also note the changes to shift labeling and the fixes to webagg.

I agree these changes are definitely a bug fix, I would bet that there exists more than one user with a non-US keyboard who discovered what keys actually got sent when they hit "shift+2" and code against that (I am confident about this because I also use a non-qwerty layout and have some things configured in these double-negative ways) . This will break them so we should note it, particularly because this is something where there is no (reasonable) way to do warnings or provide an easy way to get back to the old behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't a lot of experience writing documentation nor api changes, also, English is not my main language.

@tacaswell please can you take a look at my lastest commits and don't hesitate to do observations about typos/grammar, formatting, etc.

[event.AltDown, 'alt', 'alt'],
[event.ShiftDown, 'shift', 'shift'],):
if meth() and not key_name == key:
if not (key_name == 'shift' and key.isupper()):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it just gives up on non-ascii (?!) base on the if...elif...else just above this? Am I reading that right?

I think fixing that is out of scope for this PR (to keep it from getting to big, small PRs are easier to review and get in).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key = chr(keyval)
# wx always returns an uppercase, so make it lowercase if the shift
# key is not depressed (NOTE: this will not handle Caps Lock)
if not event.ShiftDown():
    key = key.lower()

Thanks to this fragment of code, we get a lowercase letter if shift is not pressed. If it's, then we get an uppercase letter.
Then, the following line of code makes sure we don't get shift+A and rather get shift, enter and A.

if not (key_name == 'shift' and key.isupper()):

How ever we are still interested on getting shift+2 or shift+] as Wx doesn't translate the keys. Hence only when shift was pressed and the key is an uppercase letter we are interested in not adding the shift prefix. If we don't do this, then there would be one more inconsistency on Wx backend.

@tacaswell
Copy link
Member

This is great work @tonadev !

============== ============================= ============================== ============================= ============================== ==============================
Key(s) Pressed WxPython Qt WebAgg Gtk Tkinter
============== ============================= ============================== ============================= ============================== ==============================
Shift+2 shift, shift+2 shift, " shift, " shift, " shift, "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What layout are you using? shift+2 is @ on US QWERTY keyboards.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A Spanish QWERTY keyboard. Sorry! I forgot to consider that fact.

A a a A A A
a a a a a a
Shift+a shift, A shift, A shift, A shift, A shift, A
Shift+A shift, A shift, A shift, a shift, a shift, a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What keyboard has a capital A already? Do you mean with caps lock on?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I mean with caps lock on.


if not (prefix == 'shift' and unikey):
key = '{0}+{1}'.format(prefix, key)
break
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this break mean you can only add one modifier?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we hit ctrl + shift + alt, then we get ctrl, ctrl + shift and finally ctrl + alt. I noticed it, but haven't been able to work on this PR since I've been a little busy. If someone else want to continue with the work, go ahead! If not, I will work on this when I get more time. I'm sorry for the inconveniences.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming you meant ctrl+shift+alt for the last one, I think that is correct behavior, isn't it?

@tacaswell
Copy link
Member

@tonadev I took the liberty of rebasing, consolidating the API changes notes, and force-pushing to your branch hope you do not mind!

@QuLogic QuLogic merged commit 5ad390d into matplotlib:master Feb 17, 2021
@QuLogic
Copy link
Member

QuLogic commented Feb 17, 2021

Thanks @tonadev! Congratulations on your first PR to Matplotlib 🎉 We hope to hear from you again.

tacaswell added a commit to tacaswell/jupyter-matplotlib that referenced this pull request Mar 17, 2021
tacaswell added a commit to tacaswell/jupyter-matplotlib that referenced this pull request Mar 17, 2021
tacaswell added a commit to tacaswell/jupyter-matplotlib that referenced this pull request Mar 18, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

webagg reports incorrect values for non-alphanumeric key events on non-qwerty keyboards
3 participants