pythonconsole-applicationmsvcrtkeyboard-input

Reading keystrokes in Python with msvcrt.getch()


I am using msvcrt.getch() to read input in a Python script. It works fine, most of the time, but when pressing Shift plus an arrow key, I only receive the code for that arrow key.

Is there a way of reading these key combinations using getch() alone? I'd prefer doing this way rather than with other methods since I'm hoping to write this to work on Linux as well, and from what I can tell anything other than regular input requires root on there.

The reason that I think this may be possible is because PowerShell reads Shift + <arrow keys> to handle text selection. Is this because PowerShell is reading input in a different way? Does it have different permissions?


Solution

  • The Shift key is considered as a special key. According to the documentation

    Read a keypress and return the resulting character as a byte string. Nothing is echoed to the console. This call will block if a keypress is not already available, but will not wait for Enter to be pressed. If the pressed key was a special function key, this will return '\000' or '\xe0'; the next call will return the keycode. The Control-C keypress cannot be read with this function.

    As getch is limited, we can use the ctypes library which provides more information, such as the keystates. We use the & 0x8000 to mask the high bit and if it's not a zero, the shift is held down.

    Here is what it would look like

    import msvcrt
    import ctypes
    
    key = msvcrt.getch()
    
    if key == b'\xe0':  # Escape sequence for special keys
        print("Special key")
        key = msvcrt.getch()
        if key == b'H':
            print("Up arrow")
        elif key == b'P':
            print("Down arrow")
        elif key == b'M':
            print("Right arrow")
        elif key == b'K':
            print("Left arrow")
    
        # Check for Shift using `GetKeyState` from ctypes
        
        if (ctypes.windll.user32.GetKeyState(0x10) & 0x8000) != 0: 
            print(" with Shift")