From 59d71b064586b1a3be5e867a2e05597a1cd95488 Mon Sep 17 00:00:00 2001 From: Chris Eibl <138194463+chris-eibl@users.noreply.github.com> Date: Sat, 12 Apr 2025 16:01:29 +0200 Subject: [PATCH 1/9] do not swallow characters that have been entered via AltGr --- Lib/_pyrepl/windows_console.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Lib/_pyrepl/windows_console.py b/Lib/_pyrepl/windows_console.py index 47fd3fd8f8909b..19e248e93ad30d 100644 --- a/Lib/_pyrepl/windows_console.py +++ b/Lib/_pyrepl/windows_console.py @@ -472,9 +472,13 @@ def get_event(self, block: bool = True) -> Event | None: continue if key_event.dwControlKeyState & ALT_ACTIVE: - # queue the key, return the meta command - self.event_queue.insert(Event(evt="key", data=key, raw=raw_key)) - return Event(evt="key", data="\033") # keymap.py uses this for meta + # Do not swallow characters that have been entered via AltGr: + # Windows internally converts AltGr to CTRL+ALT, see + # https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-vkkeyscanw + if not key_event.dwControlKeyState & CTRL_ACTIVE: + # queue the key, return the meta command + self.event_queue.insert(Event(evt="key", data=key, raw=raw_key)) + return Event(evt="key", data="\033") # keymap.py uses this for meta return Event(evt="key", data=key, raw=raw_key) return self.event_queue.get() From cca6155fe737ca3d807390fb4157aab3b87b3a64 Mon Sep 17 00:00:00 2001 From: Chris Eibl <138194463+chris-eibl@users.noreply.github.com> Date: Sat, 12 Apr 2025 16:30:13 +0200 Subject: [PATCH 2/9] blurb it --- .../next/Library/2025-04-12-16-29-42.gh-issue-132439.3twrU6.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-04-12-16-29-42.gh-issue-132439.3twrU6.rst diff --git a/Misc/NEWS.d/next/Library/2025-04-12-16-29-42.gh-issue-132439.3twrU6.rst b/Misc/NEWS.d/next/Library/2025-04-12-16-29-42.gh-issue-132439.3twrU6.rst new file mode 100644 index 00000000000000..b4c319700a426d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-04-12-16-29-42.gh-issue-132439.3twrU6.rst @@ -0,0 +1,2 @@ +Fix ``PyREPL`` on Windows: characters entered via AltGr are swallowed. Fix +by Chris Eibl. From 1e615407ef79d486786dd578694c3961c511a14c Mon Sep 17 00:00:00 2001 From: Chris Eibl <138194463+chris-eibl@users.noreply.github.com> Date: Sat, 12 Apr 2025 16:39:18 +0200 Subject: [PATCH 3/9] unrelated stuff worth to do (?) --- Lib/_pyrepl/windows_console.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/_pyrepl/windows_console.py b/Lib/_pyrepl/windows_console.py index 19e248e93ad30d..cc20ade033b3d3 100644 --- a/Lib/_pyrepl/windows_console.py +++ b/Lib/_pyrepl/windows_console.py @@ -459,16 +459,16 @@ def get_event(self, block: bool = True) -> Event | None: key = f"ctrl {key}" elif key_event.dwControlKeyState & ALT_ACTIVE: # queue the key, return the meta command - self.event_queue.insert(Event(evt="key", data=key, raw=key)) + self.event_queue.insert(Event(evt="key", data=key, raw=raw_key)) return Event(evt="key", data="\033") # keymap.py uses this for meta - return Event(evt="key", data=key, raw=key) + return Event(evt="key", data=key, raw=raw_key) if block: continue return None elif self.__vt_support: # If virtual terminal is enabled, scanning VT sequences - self.event_queue.push(rec.Event.KeyEvent.uChar.UnicodeChar) + self.event_queue.push(raw_key) continue if key_event.dwControlKeyState & ALT_ACTIVE: From ed035e53f78e9e7fa5943704fbf2160b028a0fb2 Mon Sep 17 00:00:00 2001 From: Chris Eibl <138194463+chris-eibl@users.noreply.github.com> Date: Sun, 20 Apr 2025 10:31:09 +0200 Subject: [PATCH 4/9] fix missing con.restore() in test_multiline_ctrl_z --- Lib/test/test_pyrepl/test_windows_console.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_pyrepl/test_windows_console.py b/Lib/test/test_pyrepl/test_windows_console.py index 69f2d5af2a4dce..e143721a7c6c4a 100644 --- a/Lib/test/test_pyrepl/test_windows_console.py +++ b/Lib/test/test_pyrepl/test_windows_console.py @@ -341,8 +341,9 @@ def test_multiline_ctrl_z(self): Event(evt="key", data='\x1a', raw=bytearray(b'\x1a')), ], ) - reader, _ = self.handle_events_narrow(events) + reader, con = self.handle_events_narrow(events) self.assertEqual(reader.cxy, (2, 3)) + con.restore() if __name__ == "__main__": From 69e877993f947d98fa4af33fb3c97e257302c649 Mon Sep 17 00:00:00 2001 From: Chris Eibl <138194463+chris-eibl@users.noreply.github.com> Date: Sun, 20 Apr 2025 12:11:22 +0200 Subject: [PATCH 5/9] add WindowsConsoleGetEventTests --- Lib/test/test_pyrepl/test_windows_console.py | 219 +++++++++++++++++++ 1 file changed, 219 insertions(+) diff --git a/Lib/test/test_pyrepl/test_windows_console.py b/Lib/test/test_pyrepl/test_windows_console.py index e143721a7c6c4a..1f4829349fb397 100644 --- a/Lib/test/test_pyrepl/test_windows_console.py +++ b/Lib/test/test_pyrepl/test_windows_console.py @@ -23,6 +23,7 @@ MOVE_DOWN, ERASE_IN_LINE, ) + import _pyrepl.windows_console as wc except ImportError: pass @@ -346,5 +347,223 @@ def test_multiline_ctrl_z(self): con.restore() +class WindowsConsoleGetEventTests(TestCase): + # Virtual-Key Codes: https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes + VK_BACK = 0x08 + VK_RETURN = 0x0D + VK_LEFT = 0x25 + VK_7 = 0x37 + VK_M = 0x4D + # Used for miscellaneous characters; it can vary by keyboard. + # For the US standard keyboard, the '" key. + # For the German keyboard, the Ä key. + VK_OEM_7 = 0xDE + + # State of control keys: https://learn.microsoft.com/en-us/windows/console/key-event-record-str + RIGHT_ALT_PRESSED = 0x0001 + RIGHT_CTRL_PRESSED = 0x0004 + LEFT_ALT_PRESSED = 0x0002 + LEFT_CTRL_PRESSED = 0x0008 + ENHANCED_KEY = 0x0100 + SHIFT_PRESSED = 0x0010 + + + def get_event(self, input_records, **kwargs) -> Console: + self.console = WindowsConsole(encoding='utf-8') + self.mock = MagicMock(side_effect=input_records) + self.console._read_input = self.mock + self.console._WindowsConsole__vt_support = kwargs.get("vt_support", + False) + event = self.console.get_event(block=False) + return event + + def get_input_record(self, unicode_char, vcode=0, control=0): + return wc.INPUT_RECORD( + wc.KEY_EVENT, + wc.ConsoleEvent(KeyEvent= + wc.KeyEvent( + bKeyDown=True, + wRepeatCount=1, + wVirtualKeyCode=vcode, + wVirtualScanCode=0, # not used + uChar=wc.Char(unicode_char), + dwControlKeyState=control + ))) + + def test_EmptyBuffer(self): + # GetNumberOfConsoleInputEvents populates lpcNumberOfEvents with 0 + self.assertEqual(self.get_event([None]), None) + self.assertEqual(self.mock.call_count, 1) + + def test_WINDOW_BUFFER_SIZE_EVENT(self): + ir = wc.INPUT_RECORD( + wc.WINDOW_BUFFER_SIZE_EVENT, + wc.ConsoleEvent(WindowsBufferSizeEvent= + wc.WindowsBufferSizeEvent( + wc._COORD(0, 0)))) + self.assertEqual(self.get_event([ir]), Event("resize", "")) + self.assertEqual(self.mock.call_count, 1) + + def test_KEY_EVENT_up_ignored(self): + ir = wc.INPUT_RECORD( + wc.KEY_EVENT, + wc.ConsoleEvent(KeyEvent= + wc.KeyEvent(bKeyDown=False))) + self.assertEqual(self.get_event([ir]), None) + self.assertEqual(self.mock.call_count, 1) + + def test_unhandled_events(self): + for event in (wc.FOCUS_EVENT, wc.MENU_EVENT, wc.MOUSE_EVENT): + ir = wc.INPUT_RECORD( + event, + # fake data, nothing is read except bKeyDown + wc.ConsoleEvent(KeyEvent= + wc.KeyEvent(bKeyDown=False))) + self.assertEqual(self.get_event([ir]), None) + self.assertEqual(self.mock.call_count, 1) + + def test_enter(self): + ir = self.get_input_record("\r", self.VK_RETURN) + self.assertEqual(self.get_event([ir]), Event("key", "\n", b"\n")) + self.assertEqual(self.mock.call_count, 1) + + def test_backspace(self): + ir = self.get_input_record("\x08", self.VK_BACK) + self.assertEqual( + self.get_event([ir]), Event("key", "backspace", "\x08")) + self.assertEqual(self.mock.call_count, 1) + + def test_m(self): + ir = self.get_input_record("m", self.VK_M) + self.assertEqual(self.get_event([ir]), Event("key", "m", "m")) + self.assertEqual(self.mock.call_count, 1) + + def test_M(self): + ir = self.get_input_record("M", self.VK_M, self.SHIFT_PRESSED) + self.assertEqual(self.get_event([ir]), Event("key", "M", "M")) + self.assertEqual(self.mock.call_count, 1) + + def test_left(self): + # VK_LEFT is sent as ENHANCED_KEY + ir = self.get_input_record("\x00", self.VK_LEFT, self.ENHANCED_KEY) + self.assertEqual(self.get_event([ir]), Event("key", "left", "\x00")) + self.assertEqual(self.mock.call_count, 1) + + def test_left_RIGHT_CTRL_PRESSED(self): + ir = self.get_input_record( + "\x00", self.VK_LEFT, self.RIGHT_CTRL_PRESSED | self.ENHANCED_KEY) + self.assertEqual( + self.get_event([ir]), Event("key", "ctrl left", "\x00")) + self.assertEqual(self.mock.call_count, 1) + + def test_left_LEFT_CTRL_PRESSED(self): + ir = self.get_input_record( + "\x00", self.VK_LEFT, self.LEFT_CTRL_PRESSED | self.ENHANCED_KEY) + self.assertEqual( + self.get_event([ir]), Event("key", "ctrl left", "\x00")) + self.assertEqual(self.mock.call_count, 1) + + def test_left_RIGHT_ALT_PRESSED(self): + ir = self.get_input_record( + "\x00", self.VK_LEFT, self.RIGHT_ALT_PRESSED | self.ENHANCED_KEY) + self.assertEqual(self.get_event([ir]), Event(evt="key", data="\033")) + self.assertEqual( + self.console.get_event(), Event("key", "left", "\x00")) + # self.mock is not called again, since the second time we read from the + # command queue + self.assertEqual(self.mock.call_count, 1) + + def test_left_LEFT_ALT_PRESSED(self): + ir = self.get_input_record( + "\x00", self.VK_LEFT, self.LEFT_ALT_PRESSED | self.ENHANCED_KEY) + self.assertEqual(self.get_event([ir]), Event(evt="key", data="\033")) + self.assertEqual( + self.console.get_event(), Event("key", "left", "\x00")) + self.assertEqual(self.mock.call_count, 1) + + def test_m_LEFT_ALT_PRESSED_and_LEFT_CTRL_PRESSED(self): + # For the shift keys, Windows does not send anything when + # ALT and CTRL are both pressed, so let's test with VK_M. + # get_event() receives this input, but does not + # generate an event. + # This is for e.g. an English keyboard layout, for a + # German layout this returns `µ`, see test_AltGr_m. + ir = self.get_input_record( + "\x00", self.VK_M, self.LEFT_ALT_PRESSED | self.LEFT_CTRL_PRESSED) + self.assertEqual(self.get_event([ir]), None) + self.assertEqual(self.mock.call_count, 1) + + def test_m_LEFT_ALT_PRESSED(self): + ir = self.get_input_record( + "m", vcode=self.VK_M, control=self.LEFT_ALT_PRESSED) + self.assertEqual(self.get_event([ir]), Event(evt="key", data="\033")) + self.assertEqual(self.console.get_event(), Event("key", "m", "m")) + self.assertEqual(self.mock.call_count, 1) + + def test_m_RIGHT_ALT_PRESSED(self): + ir = self.get_input_record( + "m", vcode=self.VK_M, control=self.RIGHT_ALT_PRESSED) + self.assertEqual(self.get_event([ir]), Event(evt="key", data="\033")) + self.assertEqual(self.console.get_event(), Event("key", "m", "m")) + self.assertEqual(self.mock.call_count, 1) + + def test_AltGr_7(self): + # E.g. on a German keyboard layout, '{' is entered via + # AltGr + 7, where AltGr is the right Alt key on the keyboard. + # In this case, Windows automatically sets + # RIGHT_ALT_PRESSED = 0x0001 + LEFT_CTRL_PRESSED = 0x0008 + # This can also be entered like + # LeftAlt + LeftCtrl + 7 or + # LeftAlt + RightCtrl + 7 + # See https://learn.microsoft.com/en-us/windows/console/key-event-record-str + # https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-vkkeyscanw + ir = self.get_input_record( + "{", vcode=self.VK_7, + control=self.RIGHT_ALT_PRESSED | self.LEFT_CTRL_PRESSED) + self.assertEqual(self.get_event([ir]), Event("key", "{", "{")) + self.assertEqual(self.mock.call_count, 1) + + def test_AltGr_m(self): + # E.g. on a German keyboard layout, this yields 'µ' + # Let's use LEFT_ALT_PRESSED and RIGHT_CTRL_PRESSED this + # time, to cover that, too. See above in test_AltGr_7. + ir = self.get_input_record( + "µ", vcode=self.VK_M, control=self.LEFT_ALT_PRESSED | self.RIGHT_CTRL_PRESSED) + self.assertEqual(self.get_event([ir]), Event("key", "µ", "µ")) + self.assertEqual(self.mock.call_count, 1) + + def test_umlaut_a_german(self): + ir = self.get_input_record("ä", self.VK_OEM_7) + self.assertEqual(self.get_event([ir]), Event("key", "ä", "ä")) + self.assertEqual(self.mock.call_count, 1) + + # virtual terminal tests + # Note: wVirtualKeyCode, wVirtualScanCode and dwControlKeyState + # are always zero in this case. + # "\r" and backspace are handled specially, everything else + # is handled in "elif self.__vt_support:" in WindowsConsole.get_event(). + # Hence, only one regular key ("m") and a terminal sequence + # are sufficient to test here, the real tests happen in test_eventqueue + # and test_keymap. + + def test_enter_vt(self): + ir = self.get_input_record("\r") + self.assertEqual(self.get_event([ir], vt_support=True), + Event("key", "\n", b"\n")) + self.assertEqual(self.mock.call_count, 1) + + def test_backspace_vt(self): + ir = self.get_input_record("\x7f") + self.assertEqual(self.get_event([ir], vt_support=True), + Event("key", "backspace", b"\x7f")) + self.assertEqual(self.mock.call_count, 1) + + def test_up_vt(self): + irs = [self.get_input_record(x) for x in "\x1b[A"] + self.assertEqual(self.get_event(irs, vt_support=True), + Event(evt='key', data='up', raw=bytearray(b'\x1b[A'))) + self.assertEqual(self.mock.call_count, 3) + + if __name__ == "__main__": unittest.main() From e67452bb42242651c3128e4c5b440b5cb1058686 Mon Sep 17 00:00:00 2001 From: Chris Eibl <138194463+chris-eibl@users.noreply.github.com> Date: Fri, 25 Apr 2025 21:40:30 +0200 Subject: [PATCH 6/9] Apply suggestions from code review Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> --- .../Library/2025-04-12-16-29-42.gh-issue-132439.3twrU6.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-04-12-16-29-42.gh-issue-132439.3twrU6.rst b/Misc/NEWS.d/next/Library/2025-04-12-16-29-42.gh-issue-132439.3twrU6.rst index b4c319700a426d..8d0778d8d3bc9a 100644 --- a/Misc/NEWS.d/next/Library/2025-04-12-16-29-42.gh-issue-132439.3twrU6.rst +++ b/Misc/NEWS.d/next/Library/2025-04-12-16-29-42.gh-issue-132439.3twrU6.rst @@ -1,2 +1,2 @@ -Fix ``PyREPL`` on Windows: characters entered via AltGr are swallowed. Fix -by Chris Eibl. +Fix ``PyREPL`` on Windows: characters entered via AltGr are swallowed. +Patch by Chris Eibl. From 396f48e4b246de1d29a3d14b901fd5a13729e539 Mon Sep 17 00:00:00 2001 From: Chris Eibl <138194463+chris-eibl@users.noreply.github.com> Date: Fri, 25 Apr 2025 21:44:05 +0200 Subject: [PATCH 7/9] Update Lib/test/test_pyrepl/test_windows_console.py --- Lib/test/test_pyrepl/test_windows_console.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_pyrepl/test_windows_console.py b/Lib/test/test_pyrepl/test_windows_console.py index 1f4829349fb397..a833a7509d8704 100644 --- a/Lib/test/test_pyrepl/test_windows_console.py +++ b/Lib/test/test_pyrepl/test_windows_console.py @@ -391,7 +391,6 @@ def get_input_record(self, unicode_char, vcode=0, control=0): ))) def test_EmptyBuffer(self): - # GetNumberOfConsoleInputEvents populates lpcNumberOfEvents with 0 self.assertEqual(self.get_event([None]), None) self.assertEqual(self.mock.call_count, 1) From 1fbe2406fb63a31eaa7528b28d30d7550804ca69 Mon Sep 17 00:00:00 2001 From: Chris Eibl <138194463+chris-eibl@users.noreply.github.com> Date: Sun, 4 May 2025 11:15:37 +0200 Subject: [PATCH 8/9] revert change in virtual terminal path because it will be part of 131901, anywayy --- Lib/_pyrepl/windows_console.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/_pyrepl/windows_console.py b/Lib/_pyrepl/windows_console.py index 14e797ba0cd6bb..94278c1b704bb4 100644 --- a/Lib/_pyrepl/windows_console.py +++ b/Lib/_pyrepl/windows_console.py @@ -485,7 +485,7 @@ def get_event(self, block: bool = True) -> Event | None: return None elif self.__vt_support: # If virtual terminal is enabled, scanning VT sequences - self.event_queue.push(raw_key) + self.event_queue.push(rec.Event.KeyEvent.uChar.UnicodeChar) continue if key_event.dwControlKeyState & ALT_ACTIVE: From adb89bab0c4be9355988b4615f75660fc9db0094 Mon Sep 17 00:00:00 2001 From: Chris Eibl <138194463+chris-eibl@users.noreply.github.com> Date: Mon, 5 May 2025 17:38:45 +0200 Subject: [PATCH 9/9] remove raw part of Event in get_event() in case of windows_console because it is unused --- Lib/_pyrepl/windows_console.py | 10 +++---- Lib/test/test_pyrepl/test_windows_console.py | 30 ++++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Lib/_pyrepl/windows_console.py b/Lib/_pyrepl/windows_console.py index 94278c1b704bb4..84bf29da41a408 100644 --- a/Lib/_pyrepl/windows_console.py +++ b/Lib/_pyrepl/windows_console.py @@ -464,7 +464,7 @@ def get_event(self, block: bool = True) -> Event | None: if key == "\r": # Make enter unix-like - return Event(evt="key", data="\n", raw=b"\n") + return Event(evt="key", data="\n") elif key_event.wVirtualKeyCode == 8: # Turn backspace directly into the command key = "backspace" @@ -476,9 +476,9 @@ def get_event(self, block: bool = True) -> Event | None: key = f"ctrl {key}" elif key_event.dwControlKeyState & ALT_ACTIVE: # queue the key, return the meta command - self.event_queue.insert(Event(evt="key", data=key, raw=raw_key)) + self.event_queue.insert(Event(evt="key", data=key)) return Event(evt="key", data="\033") # keymap.py uses this for meta - return Event(evt="key", data=key, raw=raw_key) + return Event(evt="key", data=key) if block: continue @@ -494,10 +494,10 @@ def get_event(self, block: bool = True) -> Event | None: # https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-vkkeyscanw if not key_event.dwControlKeyState & CTRL_ACTIVE: # queue the key, return the meta command - self.event_queue.insert(Event(evt="key", data=key, raw=raw_key)) + self.event_queue.insert(Event(evt="key", data=key)) return Event(evt="key", data="\033") # keymap.py uses this for meta - return Event(evt="key", data=key, raw=raw_key) + return Event(evt="key", data=key) return self.event_queue.get() def push_char(self, char: int | bytes) -> None: diff --git a/Lib/test/test_pyrepl/test_windows_console.py b/Lib/test/test_pyrepl/test_windows_console.py index d0a6bc80506fb1..ca90a7058149eb 100644 --- a/Lib/test/test_pyrepl/test_windows_console.py +++ b/Lib/test/test_pyrepl/test_windows_console.py @@ -432,43 +432,43 @@ def test_unhandled_events(self): def test_enter(self): ir = self.get_input_record("\r", self.VK_RETURN) - self.assertEqual(self.get_event([ir]), Event("key", "\n", b"\n")) + self.assertEqual(self.get_event([ir]), Event("key", "\n")) self.assertEqual(self.mock.call_count, 1) def test_backspace(self): ir = self.get_input_record("\x08", self.VK_BACK) self.assertEqual( - self.get_event([ir]), Event("key", "backspace", "\x08")) + self.get_event([ir]), Event("key", "backspace")) self.assertEqual(self.mock.call_count, 1) def test_m(self): ir = self.get_input_record("m", self.VK_M) - self.assertEqual(self.get_event([ir]), Event("key", "m", "m")) + self.assertEqual(self.get_event([ir]), Event("key", "m")) self.assertEqual(self.mock.call_count, 1) def test_M(self): ir = self.get_input_record("M", self.VK_M, self.SHIFT_PRESSED) - self.assertEqual(self.get_event([ir]), Event("key", "M", "M")) + self.assertEqual(self.get_event([ir]), Event("key", "M")) self.assertEqual(self.mock.call_count, 1) def test_left(self): # VK_LEFT is sent as ENHANCED_KEY ir = self.get_input_record("\x00", self.VK_LEFT, self.ENHANCED_KEY) - self.assertEqual(self.get_event([ir]), Event("key", "left", "\x00")) + self.assertEqual(self.get_event([ir]), Event("key", "left")) self.assertEqual(self.mock.call_count, 1) def test_left_RIGHT_CTRL_PRESSED(self): ir = self.get_input_record( "\x00", self.VK_LEFT, self.RIGHT_CTRL_PRESSED | self.ENHANCED_KEY) self.assertEqual( - self.get_event([ir]), Event("key", "ctrl left", "\x00")) + self.get_event([ir]), Event("key", "ctrl left")) self.assertEqual(self.mock.call_count, 1) def test_left_LEFT_CTRL_PRESSED(self): ir = self.get_input_record( "\x00", self.VK_LEFT, self.LEFT_CTRL_PRESSED | self.ENHANCED_KEY) self.assertEqual( - self.get_event([ir]), Event("key", "ctrl left", "\x00")) + self.get_event([ir]), Event("key", "ctrl left")) self.assertEqual(self.mock.call_count, 1) def test_left_RIGHT_ALT_PRESSED(self): @@ -476,7 +476,7 @@ def test_left_RIGHT_ALT_PRESSED(self): "\x00", self.VK_LEFT, self.RIGHT_ALT_PRESSED | self.ENHANCED_KEY) self.assertEqual(self.get_event([ir]), Event(evt="key", data="\033")) self.assertEqual( - self.console.get_event(), Event("key", "left", "\x00")) + self.console.get_event(), Event("key", "left")) # self.mock is not called again, since the second time we read from the # command queue self.assertEqual(self.mock.call_count, 1) @@ -486,7 +486,7 @@ def test_left_LEFT_ALT_PRESSED(self): "\x00", self.VK_LEFT, self.LEFT_ALT_PRESSED | self.ENHANCED_KEY) self.assertEqual(self.get_event([ir]), Event(evt="key", data="\033")) self.assertEqual( - self.console.get_event(), Event("key", "left", "\x00")) + self.console.get_event(), Event("key", "left")) self.assertEqual(self.mock.call_count, 1) def test_m_LEFT_ALT_PRESSED_and_LEFT_CTRL_PRESSED(self): @@ -505,14 +505,14 @@ def test_m_LEFT_ALT_PRESSED(self): ir = self.get_input_record( "m", vcode=self.VK_M, control=self.LEFT_ALT_PRESSED) self.assertEqual(self.get_event([ir]), Event(evt="key", data="\033")) - self.assertEqual(self.console.get_event(), Event("key", "m", "m")) + self.assertEqual(self.console.get_event(), Event("key", "m")) self.assertEqual(self.mock.call_count, 1) def test_m_RIGHT_ALT_PRESSED(self): ir = self.get_input_record( "m", vcode=self.VK_M, control=self.RIGHT_ALT_PRESSED) self.assertEqual(self.get_event([ir]), Event(evt="key", data="\033")) - self.assertEqual(self.console.get_event(), Event("key", "m", "m")) + self.assertEqual(self.console.get_event(), Event("key", "m")) self.assertEqual(self.mock.call_count, 1) def test_AltGr_7(self): @@ -528,7 +528,7 @@ def test_AltGr_7(self): ir = self.get_input_record( "{", vcode=self.VK_7, control=self.RIGHT_ALT_PRESSED | self.LEFT_CTRL_PRESSED) - self.assertEqual(self.get_event([ir]), Event("key", "{", "{")) + self.assertEqual(self.get_event([ir]), Event("key", "{")) self.assertEqual(self.mock.call_count, 1) def test_AltGr_m(self): @@ -537,12 +537,12 @@ def test_AltGr_m(self): # time, to cover that, too. See above in test_AltGr_7. ir = self.get_input_record( "µ", vcode=self.VK_M, control=self.LEFT_ALT_PRESSED | self.RIGHT_CTRL_PRESSED) - self.assertEqual(self.get_event([ir]), Event("key", "µ", "µ")) + self.assertEqual(self.get_event([ir]), Event("key", "µ")) self.assertEqual(self.mock.call_count, 1) def test_umlaut_a_german(self): ir = self.get_input_record("ä", self.VK_OEM_7) - self.assertEqual(self.get_event([ir]), Event("key", "ä", "ä")) + self.assertEqual(self.get_event([ir]), Event("key", "ä")) self.assertEqual(self.mock.call_count, 1) # virtual terminal tests @@ -557,7 +557,7 @@ def test_umlaut_a_german(self): def test_enter_vt(self): ir = self.get_input_record("\r") self.assertEqual(self.get_event([ir], vt_support=True), - Event("key", "\n", b"\n")) + Event("key", "\n")) self.assertEqual(self.mock.call_count, 1) def test_backspace_vt(self):