Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5ad390d

Browse files
authored
Merge pull request #19146 from tonadev/fix-webagg-values-for-key-events
Fix #19128: webagg reports incorrect values for non-alphanumeric key events on non-qwerty keyboards
2 parents 12ef486 + d4ab1b2 commit 5ad390d

File tree

8 files changed

+131
-112
lines changed

8 files changed

+131
-112
lines changed

doc/api/next_api_changes/behavior/17791-AL.rst

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
1-
GTK/Tk key name changes
2-
~~~~~~~~~~~~~~~~~~~~~~~
1+
Harmonized key event data across backends
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
The different backends wth key translation support, now handle 'shift'
5+
as a sometimes modifier, where the 'shift' prefix won't be added if a
6+
key translation was made.
7+
8+
The *matplotlib.backends.backend_qt5.SPECIAL_KEYS* dictionary contains
9+
keys that do *not* return their unicode name instead they have
10+
manually specified names. The name for *QtCore.Qt.Key_Meta* has
11+
changed to 'meta' to be consistent with the other GUI backends.
12+
13+
The WebAgg backend now handles key translations correctly on non-US
14+
keyboard layouts.
15+
16+
17+
**GTK/Tk key name changes**
318

419
The handling of non-ASCII keypresses (as reported in the KeyEvent passed to
520
``key_press_event``-handlers) in the GTK and Tk backends now correctly reports

doc/users/event_handling.rst

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,35 @@ Event name Class Description
7575
'axes_leave_event' `.LocationEvent` mouse leaves an axes
7676
====================== ================ ======================================
7777

78+
.. note::
79+
When connecting to 'key_press_event' and 'key_release_event' events,
80+
you may encounter inconsistencies between the different user interface
81+
toolkits that Matplotlib works with. This is due to inconsistencies/limitations
82+
of the user interface toolkit. The following table shows some basic examples of
83+
what you may expect to receive as key(s) from the different user interface toolkits,
84+
where a comma separates different keys:
85+
86+
============== ============================= ============================== ============================= ============================== ==============================
87+
Key(s) Pressed WxPython Qt WebAgg Gtk Tkinter
88+
============== ============================= ============================== ============================= ============================== ==============================
89+
Shift+2 shift, shift+2 shift, " shift, " shift, " shift, "
90+
Shift+F1 shift, shift+f1 shift, shift+f1 shift, shift+f1 shift, shift+f1 shift, shift+f1
91+
Shift shift shift shift shift shift
92+
Control control control control control control
93+
Alt alt alt alt alt alt
94+
AltGr Nothing Nothing alt iso_level3_shift iso_level3_shift
95+
CapsLock caps_lock caps_lock caps_lock caps_lock caps_lock
96+
A a a A A A
97+
a a a a a a
98+
Shift+a shift, A shift, A shift, A shift, A shift, A
99+
Shift+A shift, A shift, A shift, a shift, a shift, a
100+
Ctrl+Shift+Alt control, ctrl+shift, ctrl+alt control, ctrl+shift, ctrl+meta control, ctrl+shit, ctrl+meta control, ctrl+shift, ctrl+meta control, ctrl+shift, ctrl+meta
101+
Ctrl+Shift+a control, ctrl+shift, ctrl+A control, ctrl+shift, ctrl+A control, ctrl+shit, ctrl+A control, ctrl+shift, ctrl+A control, ctrl+shift, ctrl+a
102+
Ctrl+Shift+A control, ctrl+shift, ctrl+A control, ctrl+shift, ctrl+A control, ctrl+shit, ctrl+a control, ctrl+shift, ctrl+a control, ctrl+shift, ctrl+a
103+
F1 f1 f1 f1 f1 f1
104+
Ctrl+F1 control, ctrl+f1 control, ctrl+f1 control, ctrl+f1 control, ctrl+f1 control, ctrl+f1
105+
============== ============================= ============================== ============================= ============================== ==============================
106+
78107
Matplotlib attaches some keypress callbacks by default for interactivity; they
79108
are documented in the :ref:`key-event-handling` section.
80109

lib/matplotlib/backends/_backend_tk.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,8 @@ def scroll_event_windows(self, event):
317317
FigureCanvasBase.scroll_event(self, x, y, step, guiEvent=event)
318318

319319
def _get_key(self, event):
320-
key = cbook._unikey_or_keysym_to_mplkey(event.char, event.keysym)
320+
unikey = event.char
321+
key = cbook._unikey_or_keysym_to_mplkey(unikey, event.keysym)
321322

322323
# add modifier keys to the key string. Bit details originate from
323324
# http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm
@@ -328,25 +329,29 @@ def _get_key(self, event):
328329
# however this is not the case on "darwin", so double check that
329330
# we aren't adding repeat modifier flags to a modifier key.
330331
if sys.platform == 'win32':
331-
modifiers = [(17, 'alt', 'alt'),
332-
(2, 'ctrl', 'control'),
332+
modifiers = [(2, 'ctrl', 'control'),
333+
(17, 'alt', 'alt'),
334+
(0, 'shift', 'shift'),
333335
]
334336
elif sys.platform == 'darwin':
335-
modifiers = [(3, 'super', 'super'),
337+
modifiers = [(2, 'ctrl', 'control'),
336338
(4, 'alt', 'alt'),
337-
(2, 'ctrl', 'control'),
339+
(0, 'shift', 'shift'),
340+
(3, 'super', 'super'),
338341
]
339342
else:
340-
modifiers = [(6, 'super', 'super'),
343+
modifiers = [(2, 'ctrl', 'control'),
341344
(3, 'alt', 'alt'),
342-
(2, 'ctrl', 'control'),
345+
(0, 'shift', 'shift'),
346+
(6, 'super', 'super'),
343347
]
344348

345349
if key is not None:
346350
# shift is not added to the keys as this is already accounted for
347351
for bitmask, prefix, key_name in modifiers:
348352
if event.state & (1 << bitmask) and key_name not in key:
349-
key = '{0}+{1}'.format(prefix, key)
353+
if not (prefix == 'shift' and unikey):
354+
key = '{0}+{1}'.format(prefix, key)
350355

351356
return key
352357

lib/matplotlib/backends/backend_gtk3.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -213,17 +213,20 @@ def size_allocate(self, widget, allocation):
213213
self.draw_idle()
214214

215215
def _get_key(self, event):
216+
unikey = chr(Gdk.keyval_to_unicode(event.keyval))
216217
key = cbook._unikey_or_keysym_to_mplkey(
217-
chr(Gdk.keyval_to_unicode(event.keyval)),
218+
unikey,
218219
Gdk.keyval_name(event.keyval))
219220
modifiers = [
220-
(Gdk.ModifierType.MOD4_MASK, 'super'),
221-
(Gdk.ModifierType.MOD1_MASK, 'alt'),
222-
(Gdk.ModifierType.CONTROL_MASK, 'ctrl'),
223-
]
221+
(Gdk.ModifierType.CONTROL_MASK, 'ctrl'),
222+
(Gdk.ModifierType.MOD1_MASK, 'alt'),
223+
(Gdk.ModifierType.SHIFT_MASK, 'shift'),
224+
(Gdk.ModifierType.MOD4_MASK, 'super'),
225+
]
224226
for key_mask, prefix in modifiers:
225227
if event.state & key_mask:
226-
key = '{0}+{1}'.format(prefix, key)
228+
if not (prefix == 'shift' and unikey.isprintable()):
229+
key = '{0}+{1}'.format(prefix, key)
227230
return key
228231

229232
def configure_event(self, widget, event):

lib/matplotlib/backends/backend_qt5.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
SPECIAL_KEYS = {QtCore.Qt.Key_Control: 'control',
2626
QtCore.Qt.Key_Shift: 'shift',
2727
QtCore.Qt.Key_Alt: 'alt',
28-
QtCore.Qt.Key_Meta: 'super',
28+
QtCore.Qt.Key_Meta: 'meta',
29+
QtCore.Qt.Key_Super_L: 'super',
30+
QtCore.Qt.Key_Super_R: 'super',
31+
QtCore.Qt.Key_CapsLock: 'caps_lock',
2932
QtCore.Qt.Key_Return: 'enter',
3033
QtCore.Qt.Key_Left: 'left',
3134
QtCore.Qt.Key_Up: 'up',
@@ -66,9 +69,9 @@
6669
# Elements are (Modifier Flag, Qt Key) tuples.
6770
# Order determines the modifier order (ctrl+alt+...) reported by Matplotlib.
6871
_MODIFIER_KEYS = [
69-
(QtCore.Qt.ShiftModifier, QtCore.Qt.Key_Shift),
7072
(QtCore.Qt.ControlModifier, QtCore.Qt.Key_Control),
7173
(QtCore.Qt.AltModifier, QtCore.Qt.Key_Alt),
74+
(QtCore.Qt.ShiftModifier, QtCore.Qt.Key_Shift),
7275
(QtCore.Qt.MetaModifier, QtCore.Qt.Key_Meta),
7376
]
7477
cursord = {

lib/matplotlib/backends/backend_webagg_core.py

Lines changed: 44 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -27,92 +27,54 @@
2727

2828
_log = logging.getLogger(__name__)
2929

30-
# http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes
31-
_SHIFT_LUT = {59: ':',
32-
61: '+',
33-
173: '_',
34-
186: ':',
35-
187: '+',
36-
188: '<',
37-
189: '_',
38-
190: '>',
39-
191: '?',
40-
192: '~',
41-
219: '{',
42-
220: '|',
43-
221: '}',
44-
222: '"'}
45-
46-
_LUT = {8: 'backspace',
47-
9: 'tab',
48-
13: 'enter',
49-
16: 'shift',
50-
17: 'control',
51-
18: 'alt',
52-
19: 'pause',
53-
20: 'caps',
54-
27: 'escape',
55-
32: ' ',
56-
33: 'pageup',
57-
34: 'pagedown',
58-
35: 'end',
59-
36: 'home',
60-
37: 'left',
61-
38: 'up',
62-
39: 'right',
63-
40: 'down',
64-
45: 'insert',
65-
46: 'delete',
66-
91: 'super',
67-
92: 'super',
68-
93: 'select',
69-
106: '*',
70-
107: '+',
71-
109: '-',
72-
110: '.',
73-
111: '/',
74-
144: 'num_lock',
75-
145: 'scroll_lock',
76-
186: ':',
77-
187: '=',
78-
188: ',',
79-
189: '-',
80-
190: '.',
81-
191: '/',
82-
192: '`',
83-
219: '[',
84-
220: '\\',
85-
221: ']',
86-
222: "'"}
30+
_SPECIAL_KEYS_LUT = {'Alt': 'alt',
31+
'AltGraph': 'alt',
32+
'CapsLock': 'caps_lock',
33+
'Control': 'control',
34+
'Meta': 'meta',
35+
'NumLock': 'num_lock',
36+
'ScrollLock': 'scroll_lock',
37+
'Shift': 'shift',
38+
'Super': 'super',
39+
'Enter': 'enter',
40+
'Tab': 'tab',
41+
'ArrowDown': 'down',
42+
'ArrowLeft': 'left',
43+
'ArrowRight': 'right',
44+
'ArrowUp': 'up',
45+
'End': 'end',
46+
'Home': 'home',
47+
'PageDown': 'pagedown',
48+
'PageUp': 'pageup',
49+
'Backspace': 'backspace',
50+
'Delete': 'delete',
51+
'Insert': 'insert',
52+
'Escape': 'escape',
53+
'Pause': 'pause',
54+
'Select': 'select',
55+
'Dead': 'dead',
56+
'F1': 'f1',
57+
'F2': 'f2',
58+
'F3': 'f3',
59+
'F4': 'f4',
60+
'F5': 'f5',
61+
'F6': 'f6',
62+
'F7': 'f7',
63+
'F8': 'f8',
64+
'F9': 'f9',
65+
'F10': 'f10',
66+
'F11': 'f11',
67+
'F12': 'f12'}
8768

8869

8970
def _handle_key(key):
90-
"""Handle key codes"""
91-
code = int(key[key.index('k') + 1:])
92-
value = chr(code)
93-
# letter keys
94-
if 65 <= code <= 90:
95-
if 'shift+' in key:
71+
"""Handle key values"""
72+
value = key[key.index('k') + 1:]
73+
if 'shift+' in key:
74+
if len(value) == 1:
9675
key = key.replace('shift+', '')
97-
else:
98-
value = value.lower()
99-
# number keys
100-
elif 48 <= code <= 57:
101-
if 'shift+' in key:
102-
value = ')!@#$%^&*('[int(value)]
103-
key = key.replace('shift+', '')
104-
# function keys
105-
elif 112 <= code <= 123:
106-
value = 'f%s' % (code - 111)
107-
# number pad keys
108-
elif 96 <= code <= 105:
109-
value = '%s' % (code - 96)
110-
# keys with shift alternatives
111-
elif code in _SHIFT_LUT and 'shift+' in key:
112-
key = key.replace('shift+', '')
113-
value = _SHIFT_LUT[code]
114-
elif code in _LUT:
115-
value = _LUT[code]
76+
if value in _SPECIAL_KEYS_LUT:
77+
value = _SPECIAL_KEYS_LUT[value]
11678
key = key[:key.index('k')] + value
11779
return key
11880

lib/matplotlib/backends/backend_wx.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@ class _FigureCanvasWxBase(FigureCanvasBase, wx.Panel):
439439
wx.WXK_CONTROL: 'control',
440440
wx.WXK_SHIFT: 'shift',
441441
wx.WXK_ALT: 'alt',
442+
wx.WXK_CAPITAL: 'caps_lock',
442443
wx.WXK_LEFT: 'left',
443444
wx.WXK_UP: 'up',
444445
wx.WXK_RIGHT: 'right',
@@ -718,11 +719,13 @@ def _get_key(self, event):
718719
else:
719720
key = None
720721

721-
for meth, prefix in (
722-
[event.AltDown, 'alt'],
723-
[event.ControlDown, 'ctrl'], ):
724-
if meth():
725-
key = '{0}+{1}'.format(prefix, key)
722+
for meth, prefix, key_name in (
723+
[event.ControlDown, 'ctrl', 'control'],
724+
[event.AltDown, 'alt', 'alt'],
725+
[event.ShiftDown, 'shift', 'shift'],):
726+
if meth() and key_name != key:
727+
if not (key_name == 'shift' and key.isupper()):
728+
key = '{0}+{1}'.format(prefix, key)
726729

727730
return key
728731

lib/matplotlib/backends/web_backend/js/mpl.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -642,29 +642,28 @@ mpl.figure.prototype._key_event_extra = function (_event, _name) {
642642
mpl.figure.prototype.key_event = function (event, name) {
643643
// Prevent repeat events
644644
if (name === 'key_press') {
645-
if (event.which === this._key) {
645+
if (event.key === this._key) {
646646
return;
647647
} else {
648-
this._key = event.which;
648+
this._key = event.key;
649649
}
650650
}
651651
if (name === 'key_release') {
652652
this._key = null;
653653
}
654654

655655
var value = '';
656-
if (event.ctrlKey && event.which !== 17) {
656+
if (event.ctrlKey && event.key !== 'Control') {
657657
value += 'ctrl+';
658658
}
659-
if (event.altKey && event.which !== 18) {
659+
else if (event.altKey && event.key !== 'Alt') {
660660
value += 'alt+';
661661
}
662-
if (event.shiftKey && event.which !== 16) {
662+
else if (event.shiftKey && event.key !== 'Shift') {
663663
value += 'shift+';
664664
}
665665

666-
value += 'k';
667-
value += event.which.toString();
666+
value += 'k' + event.key;
668667

669668
this._key_event_extra(event, name);
670669

0 commit comments

Comments
 (0)