textual icon indicating copy to clipboard operation
textual copied to clipboard

Look at Windows key handling

Open willmcgugan opened this issue 2 years ago • 14 comments

Holding down shift creates ctrl-at keys.

willmcgugan avatar Oct 11 '22 16:10 willmcgugan

Yes, please!

I believe this issue is prohibiting using anything with shift in windows, where, for example, ctrl+o works fine, shift+ctrl+o creates as you say ctrl-at sequences instead. With Windows Terminal also allocating a lot of shortcuts for itself it would be nice to expand the possible list of keys used, considering windows terminal is almost a prerequisite for performance. Every line after the ctrl+@ was really a shift+ctrl+o: (its the same in "cmd.exe" as windows terminal)

Key(key='ctrl+o', character='\x0f', name='ctrl_o', is_printable=False)
Key(key='ctrl+@', character='\x00', name='ctrl_@', is_printable=False)
Key(key='ctrl+o', character='\x0f', name='ctrl_o', is_printable=False)
Key(key='ctrl+o', character='\x0f', name='ctrl_o', is_printable=False)

sandos avatar Apr 14 '23 08:04 sandos

Oh, I noticed another thing as well, which is maybe even worse: pressing a ctrl+alt-key combo delays / blocks combos that do work, until some class of event happens. For example the lone binding

Binding("ctrl+o", "switch", "Hide hosts", show=True, priority=True),

will be delayed after pressing ctrl+alt+r.

This is also easily observable in "textual keys": initially, pressing ctrl+o gets immediate responses. Pressing ctrl+alt+r once, and then ctrl+o shows nothing happening.. until for example the mouse is hovered over the console.

sandos avatar Apr 14 '23 14:04 sandos

Dragging this into "in progress" and using this as a place to log some other issues with keys and Windows. See also the problem with the default binding for the command palette on Windows and also #3178.

davep avatar Sep 07 '23 10:09 davep

Just as a note - TextArea uses shift for a few of its bindings (shift+arrow keys, ctrl+shift+arrow keys), and they seemed to work fine when testing on Windows.

darrenburns avatar Sep 08 '23 09:09 darrenburns

"Native" Windows, or under Parallels? I was able to recreate the shift issue yesterday with the latest Textual.

davep avatar Sep 08 '23 13:09 davep

Just tested under "native" Windows and I'm seeing the exact same effects as I do when on my Mac under Parallels.

davep avatar Sep 11 '23 09:09 davep

After experimenting while printing out the low-level values coming in via win32.EventMonitor.run, I'm noticing a couple or so things (this isn't a coherent set of facts yet, just observations to make sense of):

Pressing Shift on its own

When Shift is depressed, nothing happens. However, when it is released, two events occur:

Field Value
UnicodeChar '\x00'
AsciiChar b'\x00'
bKeyDown 1
wRepeatCount 1
wVirtualKeyCode 16
wVirtualScanCode 42
dwControlKeyState 16 (SHIFT_PRESSED)

followed immediately by:

Field Value
UnicodeChar '\x00'
AsciiChar b'\x00'
bKeyDown 0
wRepeatCount 1
wVirtualKeyCode 16
wVirtualScanCode 42
dwControlKeyState 0

Pressing Shift as a modifier key

If Shift is pressed to modify another key, there seems to be a key-down event for it, plus a down and up event for the modified version of the other key. For example, if you press Shift and 1, the following events occur:

Field Value
UnicodeChar '\x00'
AsciiChar b'\x00'
bKeyDown 1
wRepeatCount 1
wVirtualKeyCode 16
wVirtualScanCode 42
dwControlKeyState 16 (SHIFT_PRESSED)
Field Value
UnicodeChar '!'
AsciiChar b'!'
bKeyDown 1
wRepeatCount 1
wVirtualKeyCode 0
wVirtualScanCode 0
dwControlKeyState 0
Field Value
UnicodeChar '!'
AsciiChar b'!'
bKeyDown 0
wRepeatCount 1
wVirtualKeyCode 49
wVirtualScanCode 2
dwControlKeyState 16 (SHIFT_PRESSED)

davep avatar Sep 11 '23 12:09 davep

Following on from this, in the heart of the Win32 driver is this bit of code:

if (
    key_event.dwControlKeyState
    and key_event.wVirtualKeyCode == 0
):
    continue

If I'm reading this correctly this looks to be the start of an approach to filtering some keys out, but it doesn't go all the way. It may be that more filtering is needed here. However, this will need to be done in a way that we can be 100% confident that we're not affecting the collection of sequences for valid keys.

davep avatar Sep 11 '23 12:09 davep

If the above bit of code is extended with this:

or (key == "\x00" and key_event.wVirtualKeyCode != 50)

this appears to solve the problem[^1]. That is, it appears to filter out all of the spurious NUL characters, while allowing for Ctrl+space to make it through. I'm not including this here as the solution just yet, but I am including it here as a solution (or at the very least possibly acceptable workaround).

This also does raise the side-issue of why ctrl+space isn't seen as an alias for ctrl+@.

[^1]: Albeit with a magic number; and I'm not a fan of magic numbers. I need to figure out why the virtual key code is 50 here, because I believe VK_SPACE in Windows is 32.[^2] [^2]: After more digging and testing, this makes more sense. This is really Ctrl+2, so the virtual key code is 50 (aka 0x32).

davep avatar Sep 11 '23 14:09 davep

Moving this back to "in progress", as the scope for this has wandered a wee bit, and also there's some variation in how Windows behaves, it seems, that means any fix here can land differently depending on the environment that Windows is in.

So: I think a reset of this issue, and the associated PR, is in order. Filtering out the spurious NULs is easy enough; the question is how to we do that without filtering out a "genuine" NUL (which is often Ctrl+Space); and do we even want to care about that?

There's a cost/benefit decision to make here.

davep avatar Sep 13 '23 09:09 davep

Bumping this over to "Blocked" for now; but something to keep in mind when we review #3411.

davep avatar Sep 28 '23 14:09 davep

@davep is this covered by the work you are doing on keys?

willmcgugan avatar Nov 22 '23 15:11 willmcgugan

Not really; as this one is more about how the Windows driver can cope with the spurious NULs -- unrelated to unknown escape sequences and possibly-incorrect key names.

davep avatar Nov 22 '23 15:11 davep

This just bit me for the second time. I also just noticed (for the first time) that naked ctrl presses also trigger a ctrl+@ /NUL key.

Windows 11, Windows Terminal, Powershell

Textual Diagnostics

Versions

Name Value
Textual 0.45.1
Rich 13.7.0

Python

Name Value
Version 3.9.13
Implementation CPython
Compiler MSC v.1929 64 bit (AMD64)
Executable C:\Users\tedco\AppData\Local...\pypoetry\Cache\virtualenvs\harlequin-XIn5tjID-py3.9\Scripts\python.exe

Operating System

Name Value
System Windows
Release 10
Version 10.0.22621

Terminal

Name Value
Terminal Application Windows Terminal
TERM Not set
COLORTERM Not set
FORCE_COLOR Not set
NO_COLOR Not set

Rich Console options

Name Value
size width=110, height=27
legacy_windows False
min_width 1
max_width 110
is_terminal True
encoding utf-8
max_height 27
justify None
overflow None
no_wrap False
highlight None
markup None
height None

tconbeer avatar Dec 18 '23 19:12 tconbeer