diff options
author | Paulie Peña <203125+paulie4@users.noreply.github.com> | 2025-01-10 12:52:19 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-10 12:52:19 (GMT) |
commit | 688f3a0d4b94874ff6d72af3baafd8bbf911153e (patch) | |
tree | e7145801bd4a6d2a5b7ef5a9949423f48b1b4bab | |
parent | baf65715fc9002e43cd0e1010b8dba9b4c84d503 (diff) | |
download | cpython-688f3a0d4b94874ff6d72af3baafd8bbf911153e.zip cpython-688f3a0d4b94874ff6d72af3baafd8bbf911153e.tar.gz cpython-688f3a0d4b94874ff6d72af3baafd8bbf911153e.tar.bz2 |
gh-128388: pyrepl on Windows: add meta and ctrl+arrow keybindings (GH-128389)
Fix `Lib/_pyrepl/windows_console.py` to support more keybindings, like the
`Ctrl`+`←` and `Ctrl`+`→` word-skipping keybindings and those with meta (i.e. Alt),
e.g. to `kill-word` or `backward-kill-word`.
Specifics: if Ctrl is pressed, emit "ctrl left" and "ctrl right" instead of just "left" or
"right," and if Meta/Alt is pressed, emit the special key code for meta before
emitting the other key that was pressed.
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Co-authored-by: Pieter Eendebak <pieter.eendebak@gmail.com>
-rw-r--r-- | Lib/_pyrepl/windows_console.py | 42 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2025-01-01-19-24-43.gh-issue-128388.8UdMz_.rst | 1 |
2 files changed, 27 insertions, 16 deletions
diff --git a/Lib/_pyrepl/windows_console.py b/Lib/_pyrepl/windows_console.py index d457d2b..e738fd0 100644 --- a/Lib/_pyrepl/windows_console.py +++ b/Lib/_pyrepl/windows_console.py @@ -102,6 +102,10 @@ MOVE_UP = "\x1b[{}A" MOVE_DOWN = "\x1b[{}B" CLEAR = "\x1b[H\x1b[J" +# State of control keys: https://learn.microsoft.com/en-us/windows/console/key-event-record-str +ALT_ACTIVE = 0x01 | 0x02 +CTRL_ACTIVE = 0x04 | 0x08 + class _error(Exception): pass @@ -407,31 +411,37 @@ class WindowsConsole(Console): continue return None - key = rec.Event.KeyEvent.uChar.UnicodeChar + key_event = rec.Event.KeyEvent + raw_key = key = key_event.uChar.UnicodeChar - if rec.Event.KeyEvent.uChar.UnicodeChar == "\r": - # Make enter make unix-like + if key == "\r": + # Make enter unix-like return Event(evt="key", data="\n", raw=b"\n") - elif rec.Event.KeyEvent.wVirtualKeyCode == 8: + elif key_event.wVirtualKeyCode == 8: # Turn backspace directly into the command - return Event( - evt="key", - data="backspace", - raw=rec.Event.KeyEvent.uChar.UnicodeChar, - ) - elif rec.Event.KeyEvent.uChar.UnicodeChar == "\x00": + key = "backspace" + elif key == "\x00": # Handle special keys like arrow keys and translate them into the appropriate command - code = VK_MAP.get(rec.Event.KeyEvent.wVirtualKeyCode) - if code: - return Event( - evt="key", data=code, raw=rec.Event.KeyEvent.uChar.UnicodeChar - ) + key = VK_MAP.get(key_event.wVirtualKeyCode) + if key: + if key_event.dwControlKeyState & CTRL_ACTIVE: + key = f"ctrl {key}" + elif key_event.dwControlKeyState & ALT_ACTIVE: + # queue the key, return the meta command + self.event_queue.insert(0, Event(evt="key", data=key, raw=key)) + return Event(evt="key", data="\033") # keymap.py uses this for meta + return Event(evt="key", data=key, raw=key) if block: continue return None - return Event(evt="key", data=key, raw=rec.Event.KeyEvent.uChar.UnicodeChar) + if key_event.dwControlKeyState & ALT_ACTIVE: + # queue the key, return the meta command + self.event_queue.insert(0, 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) def push_char(self, char: int | bytes) -> None: """ diff --git a/Misc/NEWS.d/next/Library/2025-01-01-19-24-43.gh-issue-128388.8UdMz_.rst b/Misc/NEWS.d/next/Library/2025-01-01-19-24-43.gh-issue-128388.8UdMz_.rst new file mode 100644 index 0000000..5bef0fd --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-01-01-19-24-43.gh-issue-128388.8UdMz_.rst @@ -0,0 +1 @@ +Fix ``PyREPL`` on Windows to support more keybindings, like the :kbd:`Control-←` and :kbd:`Control-→` word-skipping keybindings and those with meta (i.e. :kbd:`Alt`), e.g. :kbd:`Alt-d` to ``kill-word`` or :kbd:`Alt-Backspace` ``backward-kill-word``. |