diff --git a/doc/api/next_api_changes/behavior/17791-AL.rst b/doc/api/next_api_changes/behavior/17791-AL.rst index 4c2142ea8de6..d99ab15fb59b 100644 --- a/doc/api/next_api_changes/behavior/17791-AL.rst +++ b/doc/api/next_api_changes/behavior/17791-AL.rst @@ -1,9 +1,9 @@ -GTK key name changes -~~~~~~~~~~~~~~~~~~~~ +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 backends now correctly reports Unicode -characters (e.g., €), and respects NumLock on the numpad. +``key_press_event``-handlers) in the GTK and Tk backends now correctly reports +Unicode characters (e.g., €), and better respects NumLock on the numpad. The following key names have changed; the new names are consistent with those reported by the Qt backends: diff --git a/lib/matplotlib/backends/_backend_tk.py b/lib/matplotlib/backends/_backend_tk.py index c3b37fce99fe..69b57fc15d2a 100644 --- a/lib/matplotlib/backends/_backend_tk.py +++ b/lib/matplotlib/backends/_backend_tk.py @@ -113,70 +113,6 @@ def _on_timer(self): class FigureCanvasTk(FigureCanvasBase): required_interactive_framework = "tk" - keyvald = {65507: 'control', - 65505: 'shift', - 65513: 'alt', - 65515: 'super', - 65508: 'control', - 65506: 'shift', - 65514: 'alt', - 65361: 'left', - 65362: 'up', - 65363: 'right', - 65364: 'down', - 65307: 'escape', - 65470: 'f1', - 65471: 'f2', - 65472: 'f3', - 65473: 'f4', - 65474: 'f5', - 65475: 'f6', - 65476: 'f7', - 65477: 'f8', - 65478: 'f9', - 65479: 'f10', - 65480: 'f11', - 65481: 'f12', - 65300: 'scroll_lock', - 65299: 'break', - 65288: 'backspace', - 65293: 'enter', - 65379: 'insert', - 65535: 'delete', - 65360: 'home', - 65367: 'end', - 65365: 'pageup', - 65366: 'pagedown', - 65438: '0', - 65436: '1', - 65433: '2', - 65435: '3', - 65430: '4', - 65437: '5', - 65432: '6', - 65429: '7', - 65431: '8', - 65434: '9', - 65451: '+', - 65453: '-', - 65450: '*', - 65455: '/', - 65439: 'dec', - 65421: 'enter', - } - - _keycode_lookup = { - 262145: 'control', - 524320: 'alt', - 524352: 'alt', - 1048584: 'super', - 1048592: 'super', - 131074: 'shift', - 131076: 'shift', - } - """_keycode_lookup is used for badly mapped (i.e. no event.key_sym set) - keys on apple keyboards.""" - def __init__(self, figure, master=None, resize_callback=None): super().__init__(figure) self._idle = True @@ -332,16 +268,7 @@ def scroll_event_windows(self, event): FigureCanvasBase.scroll_event(self, x, y, step, guiEvent=event) def _get_key(self, event): - val = event.keysym_num - if val in self.keyvald: - key = self.keyvald[val] - elif (val == 0 and sys.platform == 'darwin' - and event.keycode in self._keycode_lookup): - key = self._keycode_lookup[event.keycode] - elif val < 256: - key = chr(val) - else: - key = None + key = cbook._unikey_or_keysym_to_mplkey(event.char, event.keysym) # add modifier keys to the key string. Bit details originate from # http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm diff --git a/lib/matplotlib/backends/backend_gtk3.py b/lib/matplotlib/backends/backend_gtk3.py index f03ae0b1c0d1..ceb662e4438c 100644 --- a/lib/matplotlib/backends/backend_gtk3.py +++ b/lib/matplotlib/backends/backend_gtk3.py @@ -207,17 +207,9 @@ def size_allocate(self, widget, allocation): self.draw_idle() def _get_key(self, event): - key = chr(Gdk.keyval_to_unicode(event.keyval)) - if not key.isprintable(): - key = Gdk.keyval_name(event.keyval).lower() - if key.startswith("kp_"): # keypad_x (including kp_enter). - key = key[3:] - if key.startswith("page_"): # page_{up,down} - key = key.replace("page_", "page") - if key.endswith(("_l", "_r")): # alt_l, ctrl_l, shift_l. - key = key[:-2] - if key == "enter": - key = "return" + key = cbook._unikey_or_keysym_to_mplkey( + chr(Gdk.keyval_to_unicode(event.keyval)), + Gdk.keyval_name(event.keyval)) modifiers = [ (Gdk.ModifierType.MOD4_MASK, 'super'), (Gdk.ModifierType.MOD1_MASK, 'alt'), diff --git a/lib/matplotlib/cbook/__init__.py b/lib/matplotlib/cbook/__init__.py index 2360f90f5aed..f6e6234ba4fa 100644 --- a/lib/matplotlib/cbook/__init__.py +++ b/lib/matplotlib/cbook/__init__.py @@ -2334,3 +2334,28 @@ def _format_approx(number, precision): Remove trailing zeros and possibly the decimal point. """ return f'{number:.{precision}f}'.rstrip('0').rstrip('.') or '0' + + +def _unikey_or_keysym_to_mplkey(unikey, keysym): + """ + Convert a Unicode key or X keysym to a Matplotlib key name. + + The Unicode key is checked first; this avoids having to list most printable + keysyms such as ``EuroSign``. + """ + # For non-printable characters, gtk3 passes "\0" whereas tk passes an "". + if unikey and unikey.isprintable(): + return unikey + key = keysym.lower() + if key.startswith("kp_"): # keypad_x (including kp_enter). + key = key[3:] + if key.startswith("page_"): # page_{up,down} + key = key.replace("page_", "page") + if key.endswith(("_l", "_r")): # alt_l, ctrl_l, shift_l. + key = key[:-2] + key = { + "enter": "return", + "prior": "pageup", # Used by tk. + "next": "pagedown", # Used by tk. + }.get(key, key) + return key