From 9a75c3313e9741fb34729d07affe7e7b052166ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= Date: Thu, 17 Dec 2020 18:54:36 -0600 Subject: [PATCH 01/22] Improve webagg support for non-alphanumeric key events on non-qwerty keyboards --- .../backends/backend_webagg_core.py | 103 +++--------------- lib/matplotlib/backends/web_backend/js/mpl.js | 16 +-- 2 files changed, 24 insertions(+), 95 deletions(-) diff --git a/lib/matplotlib/backends/backend_webagg_core.py b/lib/matplotlib/backends/backend_webagg_core.py index 5dbfca1cdfcf..0bf919be5f32 100644 --- a/lib/matplotlib/backends/backend_webagg_core.py +++ b/lib/matplotlib/backends/backend_webagg_core.py @@ -27,94 +27,27 @@ _log = logging.getLogger(__name__) -# http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes -_SHIFT_LUT = {59: ':', - 61: '+', - 173: '_', - 186: ':', - 187: '+', - 188: '<', - 189: '_', - 190: '>', - 191: '?', - 192: '~', - 219: '{', - 220: '|', - 221: '}', - 222: '"'} - -_LUT = {8: 'backspace', - 9: 'tab', - 13: 'enter', - 16: 'shift', - 17: 'control', - 18: 'alt', - 19: 'pause', - 20: 'caps', - 27: 'escape', - 32: ' ', - 33: 'pageup', - 34: 'pagedown', - 35: 'end', - 36: 'home', - 37: 'left', - 38: 'up', - 39: 'right', - 40: 'down', - 45: 'insert', - 46: 'delete', - 91: 'super', - 92: 'super', - 93: 'select', - 106: '*', - 107: '+', - 109: '-', - 110: '.', - 111: '/', - 144: 'num_lock', - 145: 'scroll_lock', - 186: ':', - 187: '=', - 188: ',', - 189: '-', - 190: '.', - 191: '/', - 192: '`', - 219: '[', - 220: '\\', - 221: ']', - 222: "'"} +_LUT = {'AltGraph': 'alt', + 'CapsLock': 'caps', + 'ArrowLeft': 'left', + 'ArrowUp': 'up', + 'ArrowRight': 'right', + 'ArrowDown': 'down', + 'NumLock': 'num_lock', + 'ScrollLock': 'scroll_lock'} def _handle_key(key): - """Handle key codes""" - code = int(key[key.index('k') + 1:]) - value = chr(code) - # letter keys - if 65 <= code <= 90: - if 'shift+' in key: - key = key.replace('shift+', '') - else: - value = value.lower() - # number keys - elif 48 <= code <= 57: - if 'shift+' in key: - value = ')!@#$%^&*('[int(value)] - key = key.replace('shift+', '') - # function keys - elif 112 <= code <= 123: - value = 'f%s' % (code - 111) - # number pad keys - elif 96 <= code <= 105: - value = '%s' % (code - 96) - # keys with shift alternatives - elif code in _SHIFT_LUT and 'shift+' in key: - key = key.replace('shift+', '') - value = _SHIFT_LUT[code] - elif code in _LUT: - value = _LUT[code] - key = key[:key.index('k')] + value - return key + """Handle key values""" + value = key + # Only set to lower if key value is an uppercase letter or + # a combination of a modifier and an uppercase letter + # (e.g. "ctrl+C", "A", and "ctrl+alt+T" must remain unaltered). + if not value[-1:].isupper(): + value = value.lower() + if key in _LUT: + value = _LUT[key] + return value class TimerTornado(backend_bases.TimerBase): diff --git a/lib/matplotlib/backends/web_backend/js/mpl.js b/lib/matplotlib/backends/web_backend/js/mpl.js index 05ed0e1b7187..a1180f676832 100644 --- a/lib/matplotlib/backends/web_backend/js/mpl.js +++ b/lib/matplotlib/backends/web_backend/js/mpl.js @@ -636,16 +636,16 @@ mpl.figure.prototype.mouse_event = function (event, name) { }; mpl.figure.prototype._key_event_extra = function (_event, _name) { - // Handle any extra behaviour associated with a key event + // Ha ndle any extra behaviour associated with a key event }; mpl.figure.prototype.key_event = function (event, name) { // Prevent repeat events if (name === 'key_press') { - if (event.which === this._key) { + if (event.key === this._key) { return; } else { - this._key = event.which; + this._key = event.key; } } if (name === 'key_release') { @@ -653,18 +653,14 @@ mpl.figure.prototype.key_event = function (event, name) { } var value = ''; - if (event.ctrlKey && event.which !== 17) { + if (event.ctrlKey && event.key !== 'Control') { value += 'ctrl+'; } - if (event.altKey && event.which !== 18) { + if (event.altKey && event.key !== 'Alt') { value += 'alt+'; } - if (event.shiftKey && event.which !== 16) { - value += 'shift+'; - } - value += 'k'; - value += event.which.toString(); + value += event.key; this._key_event_extra(event, name); From 49db5c40ce2513f813d367bc70d00b8322216e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= Date: Thu, 17 Dec 2020 19:47:23 -0600 Subject: [PATCH 02/22] Fix typo on mpl.js --- lib/matplotlib/backends/web_backend/js/mpl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/backends/web_backend/js/mpl.js b/lib/matplotlib/backends/web_backend/js/mpl.js index a1180f676832..7ee28d350af8 100644 --- a/lib/matplotlib/backends/web_backend/js/mpl.js +++ b/lib/matplotlib/backends/web_backend/js/mpl.js @@ -636,7 +636,7 @@ mpl.figure.prototype.mouse_event = function (event, name) { }; mpl.figure.prototype._key_event_extra = function (_event, _name) { - // Ha ndle any extra behaviour associated with a key event + // Handle any extra behaviour associated with a key event }; mpl.figure.prototype.key_event = function (event, name) { From da8790a7a42833daf3968d497cbc46ab27c03383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= Date: Sat, 19 Dec 2020 18:36:55 -0600 Subject: [PATCH 03/22] Improve WebAgg backend handling of shift as a modifier --- .../backends/backend_webagg_core.py | 72 +++++++++++++------ lib/matplotlib/backends/web_backend/js/mpl.js | 7 +- 2 files changed, 56 insertions(+), 23 deletions(-) diff --git a/lib/matplotlib/backends/backend_webagg_core.py b/lib/matplotlib/backends/backend_webagg_core.py index 0bf919be5f32..27b4a74b8097 100644 --- a/lib/matplotlib/backends/backend_webagg_core.py +++ b/lib/matplotlib/backends/backend_webagg_core.py @@ -27,27 +27,56 @@ _log = logging.getLogger(__name__) -_LUT = {'AltGraph': 'alt', - 'CapsLock': 'caps', - 'ArrowLeft': 'left', - 'ArrowUp': 'up', - 'ArrowRight': 'right', - 'ArrowDown': 'down', - 'NumLock': 'num_lock', - 'ScrollLock': 'scroll_lock'} +_SPECIAL_KEYS_LUT = {'Alt': 'alt', + 'AltGraph': 'alt', + 'CapsLock': 'caps_lock', + 'Control': 'control', + 'Meta': 'meta', + 'NumLock': 'num_lock', + 'ScrollLock': 'scroll_lock', + 'Shift': 'shift', + 'Super': 'super', + 'Enter': 'enter', + 'Tab': 'tab', + 'ArrowDown': 'down', + 'ArrowLeft': 'left', + 'ArrowRight': 'right', + 'ArrowUp': 'up', + 'End': 'end', + 'Home': 'home', + 'PageDown': 'pagedown', + 'PageUp': 'pageup', + 'Backspace': 'backspace', + 'Delete': 'delete', + 'Insert': 'insert', + 'Escape': 'escape', + 'Pause': 'pause', + 'Select': 'select', + 'Dead': 'dead', + 'F1': 'f1', + 'F2': 'f2', + 'F3': 'f3', + 'F4': 'f4', + 'F5': 'f5', + 'F6': 'f6', + 'F7': 'f7', + 'F8': 'f8', + 'F9': 'f9', + 'F10': 'f10', + 'F11': 'f11', + 'F12': 'f12'} def _handle_key(key): """Handle key values""" - value = key - # Only set to lower if key value is an uppercase letter or - # a combination of a modifier and an uppercase letter - # (e.g. "ctrl+C", "A", and "ctrl+alt+T" must remain unaltered). - if not value[-1:].isupper(): - value = value.lower() - if key in _LUT: - value = _LUT[key] - return value + value = key[key.index('k') + 1:] + if 'shift+' in key: + if len(value) == 1: + key = key.replace('shift+', '') + if value in _SPECIAL_KEYS_LUT: + value = _SPECIAL_KEYS_LUT[value] + key = key[:key.index('k')] + value + return key class TimerTornado(backend_bases.TimerBase): @@ -207,7 +236,7 @@ def handle_event(self, event): def handle_unknown_event(self, event): _log.warning('Unhandled message type {0}. {1}'.format( - event['type'], event)) + event['type'], event)) def handle_ack(self, event): # Network latency tends to decrease if traffic is flowing @@ -247,6 +276,7 @@ def _handle_mouse(self, event): self.leave_notify_event() elif e_type == 'scroll': self.scroll_event(x, y, event['step'], guiEvent=guiEvent) + handle_button_press = handle_button_release = handle_dblclick = \ handle_figure_enter = handle_figure_leave = handle_motion_notify = \ handle_scroll = _handle_mouse @@ -259,6 +289,7 @@ def _handle_key(self, event): self.key_press_event(key, guiEvent=guiEvent) elif e_type == 'key_release': self.key_release_event(key, guiEvent=guiEvent) + handle_key_press = handle_key_release = _handle_key def handle_toolbar_button(self, event): @@ -322,7 +353,6 @@ def send_event(self, event_type, **kwargs): class NavigationToolbar2WebAgg(backend_bases.NavigationToolbar2): - # Use the standard toolbar items + download button toolitems = [ (text, tooltip_text, image_file, name_of_method) @@ -442,8 +472,8 @@ def get_javascript(cls, stream=None): extensions = [] for filetype, ext in sorted(FigureCanvasWebAggCore. - get_supported_filetypes_grouped(). - items()): + get_supported_filetypes_grouped(). + items()): extensions.append(ext[0]) output.write("mpl.extensions = {0};\n\n".format( json.dumps(extensions))) diff --git a/lib/matplotlib/backends/web_backend/js/mpl.js b/lib/matplotlib/backends/web_backend/js/mpl.js index 7ee28d350af8..a6960db0e1fa 100644 --- a/lib/matplotlib/backends/web_backend/js/mpl.js +++ b/lib/matplotlib/backends/web_backend/js/mpl.js @@ -656,11 +656,14 @@ mpl.figure.prototype.key_event = function (event, name) { if (event.ctrlKey && event.key !== 'Control') { value += 'ctrl+'; } - if (event.altKey && event.key !== 'Alt') { + else if (event.altKey && event.key !== 'Alt') { value += 'alt+'; } + else if (event.shiftKey && event.key !== 'Shift') { + value += 'shift+'; + } - value += event.key; + value += 'k' + event.key; this._key_event_extra(event, name); From 89ce223ddbdc9cab26285e691b852ae896085107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= Date: Sat, 19 Dec 2020 18:37:59 -0600 Subject: [PATCH 04/22] Improve Wx backend handling of modifier keys combinations --- lib/matplotlib/backends/backend_wx.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/backends/backend_wx.py b/lib/matplotlib/backends/backend_wx.py index 421601039fc9..5ac74c8273a6 100644 --- a/lib/matplotlib/backends/backend_wx.py +++ b/lib/matplotlib/backends/backend_wx.py @@ -439,6 +439,7 @@ class _FigureCanvasWxBase(FigureCanvasBase, wx.Panel): wx.WXK_CONTROL: 'control', wx.WXK_SHIFT: 'shift', wx.WXK_ALT: 'alt', + wx.WXK_CAPITAL: 'caps_lock', wx.WXK_LEFT: 'left', wx.WXK_UP: 'up', wx.WXK_RIGHT: 'right', @@ -718,11 +719,14 @@ def _get_key(self, event): else: key = None - for meth, prefix in ( - [event.AltDown, 'alt'], - [event.ControlDown, 'ctrl'], ): - if meth(): - key = '{0}+{1}'.format(prefix, key) + for meth, prefix, key_name in ( + [event.ControlDown, 'ctrl', 'control'], + [event.AltDown, 'alt', 'alt'], + [event.ShiftDown, 'shift', 'shift'],): + if meth() and not key_name == key: + if not (key_name == 'shift' and key.isupper()): + key = '{0}+{1}'.format(prefix, key) + break return key From 8682cf6462c5e3416717e0a19a4475489ad1d497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= Date: Sat, 19 Dec 2020 18:39:01 -0600 Subject: [PATCH 05/22] Make meta key name consistent with other backends --- lib/matplotlib/backends/backend_qt5.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index afb2bcb483e8..3152c681f4f7 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -25,7 +25,7 @@ SPECIAL_KEYS = {QtCore.Qt.Key_Control: 'control', QtCore.Qt.Key_Shift: 'shift', QtCore.Qt.Key_Alt: 'alt', - QtCore.Qt.Key_Meta: 'super', + QtCore.Qt.Key_Meta: 'meta', QtCore.Qt.Key_Return: 'enter', QtCore.Qt.Key_Left: 'left', QtCore.Qt.Key_Up: 'up', From cfe86ccc1228c6cd2d218a3c3f157f4a3b54bbb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= Date: Mon, 21 Dec 2020 18:19:40 -0600 Subject: [PATCH 06/22] Add Qt backend support for super key --- lib/matplotlib/backends/backend_qt5.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index 3152c681f4f7..c700cb72a447 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -26,6 +26,8 @@ QtCore.Qt.Key_Shift: 'shift', QtCore.Qt.Key_Alt: 'alt', QtCore.Qt.Key_Meta: 'meta', + QtCore.Qt.Key_Super_L: 'super', + QtCore.Qt.Key_Super_R: 'super', QtCore.Qt.Key_Return: 'enter', QtCore.Qt.Key_Left: 'left', QtCore.Qt.Key_Up: 'up', From f2c65cd0a112d8a8074c2d53e2fbe8ad2e0080fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= Date: Mon, 21 Dec 2020 18:26:46 -0600 Subject: [PATCH 07/22] Move Qt backend modifier order for better consistency --- lib/matplotlib/backends/backend_qt5.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index c700cb72a447..b9da5f34cea8 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -68,9 +68,9 @@ # Elements are (Modifier Flag, Qt Key) tuples. # Order determines the modifier order (ctrl+alt+...) reported by Matplotlib. _MODIFIER_KEYS = [ - (QtCore.Qt.ShiftModifier, QtCore.Qt.Key_Shift), (QtCore.Qt.ControlModifier, QtCore.Qt.Key_Control), (QtCore.Qt.AltModifier, QtCore.Qt.Key_Alt), + (QtCore.Qt.ShiftModifier, QtCore.Qt.Key_Shift), (QtCore.Qt.MetaModifier, QtCore.Qt.Key_Meta), ] cursord = { From 0da9d1eca8126b206f0eb2be637d3178ccc0b816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= Date: Mon, 21 Dec 2020 18:42:29 -0600 Subject: [PATCH 08/22] Make Qt backend consistent when pressing multiple modifiers --- lib/matplotlib/backends/backend_qt5.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index b9da5f34cea8..145529aace92 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -411,7 +411,11 @@ def _get_key(self, event): else: key = key.lower() - return '+'.join(mods + [key]) + for mod in mods: + key = '{0}+{1}'.format(mod, key) + break + + return key def flush_events(self): # docstring inherited From 0f9ab5e893dd99d5d57abf4d08dcd4c1ffd5abf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= Date: Mon, 21 Dec 2020 18:45:49 -0600 Subject: [PATCH 09/22] Add Caps Lock key to Qt backend SPECIAL_KEY dictionary --- lib/matplotlib/backends/backend_qt5.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index 145529aace92..c56125e40835 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -28,6 +28,7 @@ QtCore.Qt.Key_Meta: 'meta', QtCore.Qt.Key_Super_L: 'super', QtCore.Qt.Key_Super_R: 'super', + QtCore.Qt.Key_CapsLock: 'caps_lock', QtCore.Qt.Key_Return: 'enter', QtCore.Qt.Key_Left: 'left', QtCore.Qt.Key_Up: 'up', From ec45ae675e1f47d57d358ffc790a87b9603731a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= Date: Mon, 21 Dec 2020 19:07:10 -0600 Subject: [PATCH 10/22] Document change of specified name for meta key on Qt5 backend --- doc/api/next_api_changes/behavior/19128-AG.rst | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 doc/api/next_api_changes/behavior/19128-AG.rst diff --git a/doc/api/next_api_changes/behavior/19128-AG.rst b/doc/api/next_api_changes/behavior/19128-AG.rst new file mode 100644 index 000000000000..2cc3749f9a70 --- /dev/null +++ b/doc/api/next_api_changes/behavior/19128-AG.rst @@ -0,0 +1,7 @@ +Meta Key specified name change on Qt5 Backend +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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. From 6a0ea71a4dab3f485f1153ef24471bbfaf39dea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= Date: Mon, 21 Dec 2020 19:32:36 -0600 Subject: [PATCH 11/22] Improve Gtk3 backend handling of shift as a modifier --- lib/matplotlib/backends/backend_gtk3.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/matplotlib/backends/backend_gtk3.py b/lib/matplotlib/backends/backend_gtk3.py index 86fd208e1226..b021fffcfa57 100644 --- a/lib/matplotlib/backends/backend_gtk3.py +++ b/lib/matplotlib/backends/backend_gtk3.py @@ -1,8 +1,8 @@ import functools import logging import os -from pathlib import Path import sys +from pathlib import Path import matplotlib as mpl from matplotlib import _api, backend_tools, cbook @@ -10,8 +10,6 @@ from matplotlib.backend_bases import ( _Backend, FigureCanvasBase, FigureManagerBase, NavigationToolbar2, StatusbarBase, TimerBase, ToolContainerBase, cursors) -from matplotlib.figure import Figure -from matplotlib.widgets import SubplotTool try: import gi @@ -213,17 +211,21 @@ def size_allocate(self, widget, allocation): self.draw_idle() def _get_key(self, event): + unikey = chr(Gdk.keyval_to_unicode(event.keyval)) key = cbook._unikey_or_keysym_to_mplkey( - chr(Gdk.keyval_to_unicode(event.keyval)), + unikey, Gdk.keyval_name(event.keyval)) modifiers = [ - (Gdk.ModifierType.MOD4_MASK, 'super'), - (Gdk.ModifierType.MOD1_MASK, 'alt'), - (Gdk.ModifierType.CONTROL_MASK, 'ctrl'), - ] + (Gdk.ModifierType.CONTROL_MASK, 'ctrl'), + (Gdk.ModifierType.MOD1_MASK, 'alt'), + (Gdk.ModifierType.SHIFT_MASK, 'shift'), + (Gdk.ModifierType.MOD4_MASK, 'super'), + ] for key_mask, prefix in modifiers: if event.state & key_mask: - key = '{0}+{1}'.format(prefix, key) + if not (prefix == 'shift' and unikey.isprintable()): + key = '{0}+{1}'.format(prefix, key) + break return key def configure_event(self, widget, event): From 3d97ec61daa09716431fcfa49dd63bd715aa3c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= Date: Wed, 23 Dec 2020 17:40:26 -0600 Subject: [PATCH 12/22] Change reference on documentation --- doc/api/next_api_changes/behavior/19128-AG.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/api/next_api_changes/behavior/19128-AG.rst b/doc/api/next_api_changes/behavior/19128-AG.rst index 2cc3749f9a70..05c13f060ec1 100644 --- a/doc/api/next_api_changes/behavior/19128-AG.rst +++ b/doc/api/next_api_changes/behavior/19128-AG.rst @@ -1,7 +1,7 @@ -Meta Key specified name change on Qt5 Backend +Meta key specified name change on Qt5 backend ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``matplotlib.backends.backend_qt5.SPECIAL_KEYS`` dictionary +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. +for `QtCore.Qt.Key_Meta` has changed to ``'meta'`` to be consistent. From 10f0d3365e56e3b16ee0714858f0300b0ebbbe3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= Date: Wed, 23 Dec 2020 17:40:59 -0600 Subject: [PATCH 13/22] Improve Tk backend handling of shift as a modifier --- lib/matplotlib/backends/_backend_tk.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/matplotlib/backends/_backend_tk.py b/lib/matplotlib/backends/_backend_tk.py index 8a541adbe29e..c22b307b6eeb 100644 --- a/lib/matplotlib/backends/_backend_tk.py +++ b/lib/matplotlib/backends/_backend_tk.py @@ -317,7 +317,8 @@ def scroll_event_windows(self, event): FigureCanvasBase.scroll_event(self, x, y, step, guiEvent=event) def _get_key(self, event): - key = cbook._unikey_or_keysym_to_mplkey(event.char, event.keysym) + unikey = event.char + key = cbook._unikey_or_keysym_to_mplkey(unikey, event.keysym) # add modifier keys to the key string. Bit details originate from # http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm @@ -328,26 +329,30 @@ def _get_key(self, event): # however this is not the case on "darwin", so double check that # we aren't adding repeat modifier flags to a modifier key. if sys.platform == 'win32': - modifiers = [(17, 'alt', 'alt'), - (2, 'ctrl', 'control'), + modifiers = [(2, 'ctrl', 'control'), + (17, 'alt', 'alt'), + (0, 'shift', 'shift'), ] elif sys.platform == 'darwin': - modifiers = [(3, 'super', 'super'), + modifiers = [(2, 'ctrl', 'control'), (4, 'alt', 'alt'), - (2, 'ctrl', 'control'), + (0, 'shift', 'shift'), + (3, 'super', 'super'), ] else: - modifiers = [(6, 'super', 'super'), + modifiers = [(2, 'ctrl', 'control'), (3, 'alt', 'alt'), - (2, 'ctrl', 'control'), + (0, 'shift', 'shift'), + (6, 'super', 'super'), ] if key is not None: # shift is not added to the keys as this is already accounted for for bitmask, prefix, key_name in modifiers: if event.state & (1 << bitmask) and key_name not in key: - key = '{0}+{1}'.format(prefix, key) - + if not (prefix == 'shift' and unikey): + key = '{0}+{1}'.format(prefix, key) + break return key def key_press(self, event): From d469a2422fa9c4cca66cb9efe25dc9df692bcca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= Date: Wed, 23 Dec 2020 19:13:51 -0600 Subject: [PATCH 14/22] Fix documentation --- doc/api/next_api_changes/behavior/19128-AG.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api/next_api_changes/behavior/19128-AG.rst b/doc/api/next_api_changes/behavior/19128-AG.rst index 05c13f060ec1..c68045a113da 100644 --- a/doc/api/next_api_changes/behavior/19128-AG.rst +++ b/doc/api/next_api_changes/behavior/19128-AG.rst @@ -1,7 +1,7 @@ Meta key specified name change on Qt5 backend ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The `matplotlib.backends.backend_qt5.SPECIAL_KEYS` dictionary +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. +for *QtCore.Qt.Key_Meta* has changed to ``'meta'`` to be consistent. From 16adba8a4c5b0fcfb6b6208c0193f8aebcd58341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= Date: Thu, 24 Dec 2020 13:55:06 -0600 Subject: [PATCH 15/22] Remove stray changes --- lib/matplotlib/backends/backend_gtk3.py | 4 +++- lib/matplotlib/backends/backend_webagg_core.py | 15 +++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/matplotlib/backends/backend_gtk3.py b/lib/matplotlib/backends/backend_gtk3.py index b021fffcfa57..86adb20e8f43 100644 --- a/lib/matplotlib/backends/backend_gtk3.py +++ b/lib/matplotlib/backends/backend_gtk3.py @@ -1,8 +1,8 @@ import functools import logging import os -import sys from pathlib import Path +import sys import matplotlib as mpl from matplotlib import _api, backend_tools, cbook @@ -10,6 +10,8 @@ from matplotlib.backend_bases import ( _Backend, FigureCanvasBase, FigureManagerBase, NavigationToolbar2, StatusbarBase, TimerBase, ToolContainerBase, cursors) +from matplotlib.figure import Figure +from matplotlib.widgets import SubplotTool try: import gi diff --git a/lib/matplotlib/backends/backend_webagg_core.py b/lib/matplotlib/backends/backend_webagg_core.py index 27b4a74b8097..e25366b22b02 100644 --- a/lib/matplotlib/backends/backend_webagg_core.py +++ b/lib/matplotlib/backends/backend_webagg_core.py @@ -11,19 +11,19 @@ # application, implemented with tornado. import datetime -from io import BytesIO, StringIO import json import logging import os +from io import BytesIO, StringIO from pathlib import Path import numpy as np -from PIL import Image import tornado +from PIL import Image from matplotlib import _api, backend_bases -from matplotlib.backends import backend_agg from matplotlib.backend_bases import _Backend +from matplotlib.backends import backend_agg _log = logging.getLogger(__name__) @@ -236,7 +236,7 @@ def handle_event(self, event): def handle_unknown_event(self, event): _log.warning('Unhandled message type {0}. {1}'.format( - event['type'], event)) + event['type'], event)) def handle_ack(self, event): # Network latency tends to decrease if traffic is flowing @@ -276,7 +276,6 @@ def _handle_mouse(self, event): self.leave_notify_event() elif e_type == 'scroll': self.scroll_event(x, y, event['step'], guiEvent=guiEvent) - handle_button_press = handle_button_release = handle_dblclick = \ handle_figure_enter = handle_figure_leave = handle_motion_notify = \ handle_scroll = _handle_mouse @@ -289,7 +288,6 @@ def _handle_key(self, event): self.key_press_event(key, guiEvent=guiEvent) elif e_type == 'key_release': self.key_release_event(key, guiEvent=guiEvent) - handle_key_press = handle_key_release = _handle_key def handle_toolbar_button(self, event): @@ -353,6 +351,7 @@ def send_event(self, event_type, **kwargs): class NavigationToolbar2WebAgg(backend_bases.NavigationToolbar2): + # Use the standard toolbar items + download button toolitems = [ (text, tooltip_text, image_file, name_of_method) @@ -472,8 +471,8 @@ def get_javascript(cls, stream=None): extensions = [] for filetype, ext in sorted(FigureCanvasWebAggCore. - get_supported_filetypes_grouped(). - items()): + get_supported_filetypes_grouped(). + items()): extensions.append(ext[0]) output.write("mpl.extensions = {0};\n\n".format( json.dumps(extensions))) From 2227748705c958a4a8e6ac4c39a695b41ca7fc80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= Date: Thu, 24 Dec 2020 13:58:16 -0600 Subject: [PATCH 16/22] Remove even more stray changes --- lib/matplotlib/backends/backend_webagg_core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/backends/backend_webagg_core.py b/lib/matplotlib/backends/backend_webagg_core.py index e25366b22b02..fb72bf46d5a6 100644 --- a/lib/matplotlib/backends/backend_webagg_core.py +++ b/lib/matplotlib/backends/backend_webagg_core.py @@ -11,19 +11,19 @@ # application, implemented with tornado. import datetime +from io import BytesIO, StringIO import json import logging import os -from io import BytesIO, StringIO from pathlib import Path import numpy as np -import tornado from PIL import Image +import tornado from matplotlib import _api, backend_bases -from matplotlib.backend_bases import _Backend from matplotlib.backends import backend_agg +from matplotlib.backend_bases import _Backend _log = logging.getLogger(__name__) From 57d4c8a3abd654b34fdb2a0c91bb4e1e203424d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= Date: Sun, 27 Dec 2020 16:38:12 -0600 Subject: [PATCH 17/22] Add to user's event handling documentation a note about inconsistencies on keyboard events between user interface tookits --- doc/users/event_handling.rst | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/doc/users/event_handling.rst b/doc/users/event_handling.rst index 7c821762b5bc..3a368d3b5312 100644 --- a/doc/users/event_handling.rst +++ b/doc/users/event_handling.rst @@ -75,6 +75,35 @@ Event name Class Description 'axes_leave_event' `.LocationEvent` mouse leaves an axes ====================== ================ ====================================== +.. note:: + When connecting to 'key_press_event' and 'key_release_event' events, + you may encounter inconsistencies between the different user interface + toolkits that Matplotlib works with. This is due to inconsistencies/limitations + of the user interface toolkit. The following table shows some basic examples of + what you may expect to receive as key(s) from the different user interface toolkits, + where a comma separates different keys: + + ============== ============================= ============================== ============================= ============================== ============================== + Key(s) Pressed WxPython Qt WebAgg Gtk Tkinter + ============== ============================= ============================== ============================= ============================== ============================== + Shift+2 shift, shift+2 shift, " shift, " shift, " shift, " + Shift+F1 shift, shift+f1 shift, shift+f1 shift, shift+f1 shift, shift+f1 shift, shift+f1 + Shift shift shift shift shift shift + Control 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, A shift, A shift, A shift, A shift, A + Shift+A shift, A shift, A shift, a shift, a shift, a + 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 + 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 + 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 + F1 f1 f1 f1 f1 f1 + Ctrl+F1 control, ctrl+f1 control, ctrl+f1 control, ctrl+f1 control, ctrl+f1 control, ctrl+f1 + ============== ============================= ============================== ============================= ============================== ============================== + Matplotlib attaches some keypress callbacks by default for interactivity; they are documented in the :ref:`key-event-handling` section. From 84cdf22c0fa8dac6d9380f0d318eb4f0401bf4af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= Date: Sun, 27 Dec 2020 16:54:11 -0600 Subject: [PATCH 18/22] Report the changes in the behaviour of the backends --- doc/api/next_api_changes/behavior/19128-AG.rst | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/api/next_api_changes/behavior/19128-AG.rst b/doc/api/next_api_changes/behavior/19128-AG.rst index c68045a113da..139314c55cbe 100644 --- a/doc/api/next_api_changes/behavior/19128-AG.rst +++ b/doc/api/next_api_changes/behavior/19128-AG.rst @@ -1,7 +1,15 @@ -Meta key specified name change on Qt5 backend +Harmonized key event data across backends ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The different backends wth key translation support, +now handle 'shift' as a sometimes modifier, where +the 'shift' prefix won't be added if a key translation was made. + 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. +for *QtCore.Qt.Key_Meta* has changed to 'meta' to be consistent +with the other GUI backends. + +The WebAgg backend now handles key translations correctly on +non-US keyboard layouts. From a545253090ea60bbea2f28311cc794196fda8dce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= <33518446+tonadev@users.noreply.github.com> Date: Tue, 9 Feb 2021 18:33:20 -0600 Subject: [PATCH 19/22] Make if condition cleaner on lib/matplotlib/backends/backend_wx.py Co-authored-by: Elliott Sales de Andrade --- lib/matplotlib/backends/backend_wx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/backends/backend_wx.py b/lib/matplotlib/backends/backend_wx.py index 5ac74c8273a6..571d7d866d6f 100644 --- a/lib/matplotlib/backends/backend_wx.py +++ b/lib/matplotlib/backends/backend_wx.py @@ -723,7 +723,7 @@ def _get_key(self, event): [event.ControlDown, 'ctrl', 'control'], [event.AltDown, 'alt', 'alt'], [event.ShiftDown, 'shift', 'shift'],): - if meth() and not key_name == key: + if meth() and key_name != key: if not (key_name == 'shift' and key.isupper()): key = '{0}+{1}'.format(prefix, key) break From 87012a51c2d80dcfecfcb30808468515a11f4926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa?= <33518446+tonadev@users.noreply.github.com> Date: Tue, 9 Feb 2021 18:34:01 -0600 Subject: [PATCH 20/22] Remove extra space on lib/matplotlib/backends/web_backend/js/mpl.js Co-authored-by: Elliott Sales de Andrade --- lib/matplotlib/backends/web_backend/js/mpl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/backends/web_backend/js/mpl.js b/lib/matplotlib/backends/web_backend/js/mpl.js index a6960db0e1fa..4adeb987653f 100644 --- a/lib/matplotlib/backends/web_backend/js/mpl.js +++ b/lib/matplotlib/backends/web_backend/js/mpl.js @@ -663,7 +663,7 @@ mpl.figure.prototype.key_event = function (event, name) { value += 'shift+'; } - value += 'k' + event.key; + value += 'k' + event.key; this._key_event_extra(event, name); From d19bdd767ded48ba77364a36c028fdb360148842 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Wed, 17 Feb 2021 15:28:13 -0500 Subject: [PATCH 21/22] DOC: consolidate API change notes --- .../next_api_changes/behavior/17791-AL.rst | 19 +++++++++++++++++-- .../next_api_changes/behavior/19128-AG.rst | 15 --------------- 2 files changed, 17 insertions(+), 17 deletions(-) delete mode 100644 doc/api/next_api_changes/behavior/19128-AG.rst diff --git a/doc/api/next_api_changes/behavior/17791-AL.rst b/doc/api/next_api_changes/behavior/17791-AL.rst index d99ab15fb59b..64147f2122f1 100644 --- a/doc/api/next_api_changes/behavior/17791-AL.rst +++ b/doc/api/next_api_changes/behavior/17791-AL.rst @@ -1,5 +1,20 @@ -GTK/Tk key name changes -~~~~~~~~~~~~~~~~~~~~~~~ +Harmonized key event data across backends +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The different backends wth key translation support, now handle 'shift' +as a sometimes modifier, where the 'shift' prefix won't be added if a +key translation was made. + +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 with the other GUI backends. + +The WebAgg backend now handles key translations correctly on non-US +keyboard layouts. + + +**GTK/Tk key name changes** The handling of non-ASCII keypresses (as reported in the KeyEvent passed to ``key_press_event``-handlers) in the GTK and Tk backends now correctly reports diff --git a/doc/api/next_api_changes/behavior/19128-AG.rst b/doc/api/next_api_changes/behavior/19128-AG.rst deleted file mode 100644 index 139314c55cbe..000000000000 --- a/doc/api/next_api_changes/behavior/19128-AG.rst +++ /dev/null @@ -1,15 +0,0 @@ -Harmonized key event data across backends -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The different backends wth key translation support, -now handle 'shift' as a sometimes modifier, where -the 'shift' prefix won't be added if a key translation was made. - -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 -with the other GUI backends. - -The WebAgg backend now handles key translations correctly on -non-US keyboard layouts. From d4ab1b2959beab24c29e3bbdc2aa9f2d9aa36097 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Wed, 17 Feb 2021 15:34:58 -0500 Subject: [PATCH 22/22] FIX: allow many modifiers --- lib/matplotlib/backends/_backend_tk.py | 2 +- lib/matplotlib/backends/backend_gtk3.py | 1 - lib/matplotlib/backends/backend_qt5.py | 6 +----- lib/matplotlib/backends/backend_wx.py | 1 - 4 files changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/backends/_backend_tk.py b/lib/matplotlib/backends/_backend_tk.py index c22b307b6eeb..c13546ddca04 100644 --- a/lib/matplotlib/backends/_backend_tk.py +++ b/lib/matplotlib/backends/_backend_tk.py @@ -352,7 +352,7 @@ def _get_key(self, event): if event.state & (1 << bitmask) and key_name not in key: if not (prefix == 'shift' and unikey): key = '{0}+{1}'.format(prefix, key) - break + return key def key_press(self, event): diff --git a/lib/matplotlib/backends/backend_gtk3.py b/lib/matplotlib/backends/backend_gtk3.py index 86adb20e8f43..246cab755490 100644 --- a/lib/matplotlib/backends/backend_gtk3.py +++ b/lib/matplotlib/backends/backend_gtk3.py @@ -227,7 +227,6 @@ def _get_key(self, event): if event.state & key_mask: if not (prefix == 'shift' and unikey.isprintable()): key = '{0}+{1}'.format(prefix, key) - break return key def configure_event(self, widget, event): diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index c56125e40835..0c2d32e1e8d1 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -412,11 +412,7 @@ def _get_key(self, event): else: key = key.lower() - for mod in mods: - key = '{0}+{1}'.format(mod, key) - break - - return key + return '+'.join(mods + [key]) def flush_events(self): # docstring inherited diff --git a/lib/matplotlib/backends/backend_wx.py b/lib/matplotlib/backends/backend_wx.py index 571d7d866d6f..109cfc155216 100644 --- a/lib/matplotlib/backends/backend_wx.py +++ b/lib/matplotlib/backends/backend_wx.py @@ -726,7 +726,6 @@ def _get_key(self, event): if meth() and key_name != key: if not (key_name == 'shift' and key.isupper()): key = '{0}+{1}'.format(prefix, key) - break return key