Skip to content

Windows: properly supporting special key (arrows, etc.) #66

Closed
@Cube707

Description

@Cube707

Problem:

On Windows special keystrokes are sent to all Programs as a combination of two characters. The first one being a \x00 (or \xe0?).
This is reflected in the code by checking the first read byte a and then reading again into b if a meets this condition:

if a == 0 or a == 224:
b = ord(msvcrt.getch())

Then the two characters are used to calculate a number and look that up in a lookup table to find the corresponding constant to return.

However, this lookup table only has rows for a=224 and not for a=0, which is what my windows10 Version uses. This leads to all calculated values being offset by 224 and resulting in a KeyError and returning None.

In #65, some values are corrected to match the calculations with a=0, but the rest is still left as is.

Solution 1:

Add a second entry into the lookup table for every key, so that both calculation return valid results.

Form my perspective this seems stupid, so heres a better solution:

Solution 2:

Ignore a in the calculation. It is not needed anyway, as only the second byte b is actually relevant for the pressed key. Use the value of b
directly as keys.

This also makes it easier to maintain, as now the values listed in the sources can be used directly instead of having to do calculations every time. See Example below.

Discussion:

Which solution should be implemented? I would be willing to provide a pull request for either one.

Removing the while loop:

The msvcrt.getch() already blocks until the next keypress, so I believe the while 1 could be removed. But I might be mistaken and miss an
important detail elsewhere. This would solve the need for #42/#56.

Example:

xlate_dict = {
    # for windows scan codes see:
    #   https://msdn.microsoft.com/en-us/library/aa299374
     1: "key.ESC",
    28: "key.ENTER",
    59: "key.F1",
    60: "key.F2",
    61: "key.F3",
    62: "key.F4",
    63: "key.F5",
    64: "key.F6",
    65: "key.F7",
    66: "key.F8",
    67: "key.F9",
    68: "key.F10",
    87: "key.F11",
    88: "key.F12",
    82: "key.INSERT",
    83: "key.SUPR",
    73: "key.PAGE_UP",
    81: "key.PAGE_DOWN",
    71: "key.HOME",
    79: "key.END",
    72: "key.UP",
    80: "key.DOWN",
    75: "key.LEFT",
    77: "key.RIGHT"
}

def readkey(getchar_fn=None):
    # Get a single character on Windows. if an extended key is pressed, the
    # Windows scan code is translated into a the unicode sequences readchar
    # expects (see key.py).

    ch = msvcrt.getch()
    if ch == b'\x00' or ch == b'\xe0':
        ch2 = msvcrt.getch()

        try:
            return xlate_dict[int.from_bytes(ch2, 'big')]
        except KeyError:
            return None
    else:
        return ch.decode()



if __name__ == '__main__': # -------------------------
    while True:
        print(readkey())

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions