diff --git a/doc/api/next_api_changes/behavior/17791-AL.rst b/doc/api/next_api_changes/behavior/17791-AL.rst new file mode 100644 index 000000000000..4c2142ea8de6 --- /dev/null +++ b/doc/api/next_api_changes/behavior/17791-AL.rst @@ -0,0 +1,13 @@ +GTK 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. + +The following key names have changed; the new names are consistent with those +reported by the Qt backends: + +- The "Break/Pause" key (keysym 0xff13) is now reported as "pause" instead of + "break" (this is also consistent with the X key name). +- The numpad "delete" key is now reported as "delete" instead of "dec". diff --git a/lib/matplotlib/backends/backend_gtk3.py b/lib/matplotlib/backends/backend_gtk3.py index ae445d19ade1..f03ae0b1c0d1 100644 --- a/lib/matplotlib/backends/backend_gtk3.py +++ b/lib/matplotlib/backends/backend_gtk3.py @@ -88,58 +88,6 @@ def _on_timer(self): class FigureCanvasGTK3(Gtk.DrawingArea, FigureCanvasBase): required_interactive_framework = "gtk3" _timer_cls = TimerGTK3 - - keyvald = {65507: 'control', - 65505: 'shift', - 65513: 'alt', - 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', - } - # Setting this as a static constant prevents # this resulting expression from leaking event_mask = (Gdk.EventMask.BUTTON_PRESS_MASK @@ -259,13 +207,17 @@ def size_allocate(self, widget, allocation): self.draw_idle() def _get_key(self, event): - if event.keyval in self.keyvald: - key = self.keyvald[event.keyval] - elif event.keyval < 256: - key = chr(event.keyval) - else: - key = None - + 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" modifiers = [ (Gdk.ModifierType.MOD4_MASK, 'super'), (Gdk.ModifierType.MOD1_MASK, 'alt'), @@ -274,7 +226,6 @@ def _get_key(self, event): for key_mask, prefix in modifiers: if event.state & key_mask: key = '{0}+{1}'.format(prefix, key) - return key def configure_event(self, widget, event): diff --git a/lib/matplotlib/tests/test_backend_gtk3.py b/lib/matplotlib/tests/test_backend_gtk3.py new file mode 100644 index 000000000000..5442930d117f --- /dev/null +++ b/lib/matplotlib/tests/test_backend_gtk3.py @@ -0,0 +1,51 @@ +from matplotlib import pyplot as plt + +import pytest + + +pytest.importorskip("matplotlib.backends.backend_gtk3agg") + + +@pytest.mark.backend("gtk3agg") +def test_correct_key(): + pytest.xfail("test_widget_send_event is not triggering key_press_event") + + from gi.repository import Gdk, Gtk + fig = plt.figure() + buf = [] + + def send(event): + for key, mod in [ + (Gdk.KEY_a, Gdk.ModifierType.SHIFT_MASK), + (Gdk.KEY_a, 0), + (Gdk.KEY_a, Gdk.ModifierType.CONTROL_MASK), + (Gdk.KEY_agrave, 0), + (Gdk.KEY_Control_L, Gdk.ModifierType.MOD1_MASK), + (Gdk.KEY_Alt_L, Gdk.ModifierType.CONTROL_MASK), + (Gdk.KEY_agrave, + Gdk.ModifierType.CONTROL_MASK + | Gdk.ModifierType.MOD1_MASK + | Gdk.ModifierType.MOD4_MASK), + (0xfd16, 0), # KEY_3270_Play. + (Gdk.KEY_BackSpace, 0), + (Gdk.KEY_BackSpace, Gdk.ModifierType.CONTROL_MASK), + ]: + # This is not actually really the right API: it depends on the + # actual keymap (e.g. on Azerty, shift+agrave -> 0). + Gtk.test_widget_send_key(fig.canvas, key, mod) + + def receive(event): + buf.append(event.key) + if buf == [ + "A", "a", "ctrl+a", + "\N{LATIN SMALL LETTER A WITH GRAVE}", + "alt+control", "ctrl+alt", + "ctrl+alt+super+\N{LATIN SMALL LETTER A WITH GRAVE}", + # (No entry for KEY_3270_Play.) + "backspace", "ctrl+backspace", + ]: + plt.close(fig) + + fig.canvas.mpl_connect("draw_event", send) + fig.canvas.mpl_connect("key_press_event", receive) + plt.show() diff --git a/lib/matplotlib/tests/test_backend_qt.py b/lib/matplotlib/tests/test_backend_qt.py index 3aee9331ce45..ab90da74d51e 100644 --- a/lib/matplotlib/tests/test_backend_qt.py +++ b/lib/matplotlib/tests/test_backend_qt.py @@ -110,9 +110,9 @@ def CustomHandler(signum, frame): ('Key_Alt', ['ControlModifier'], 'ctrl+alt'), ('Key_Aacute', ['ControlModifier', 'AltModifier', 'MetaModifier'], 'ctrl+alt+super+\N{LATIN SMALL LETTER A WITH ACUTE}'), + ('Key_Play', [], None), ('Key_Backspace', [], 'backspace'), ('Key_Backspace', ['ControlModifier'], 'ctrl+backspace'), - ('Key_Play', [], None), ], ids=[ 'shift', @@ -123,9 +123,9 @@ def CustomHandler(signum, frame): 'alt_control', 'control_alt', 'modifier_order', + 'non_unicode_key', 'backspace', 'backspace_mod', - 'non_unicode_key', ] ) @pytest.mark.parametrize('backend', [ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy