How to read a single character from the user?

后端 未结 23 2667
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-11-21 04:28

Is there a way of reading one single character from the user input? For instance, they press one key at the terminal and it is returned (sort of like getch()).

23条回答
  •  离开以前
    2020-11-21 05:27

    The ActiveState's recipe seems to contain a little bug for "posix" systems that prevents Ctrl-C from interrupting (I'm using Mac). If I put the following code in my script:

    while(True):
        print(getch())
    

    I will never be able to terminate the script with Ctrl-C, and I have to kill my terminal to escape.

    I believe the following line is the cause, and it's also too brutal:

    tty.setraw(sys.stdin.fileno())
    

    Asides from that, package tty is not really needed, termios is enough to handle it.

    Below is the improved code that works for me (Ctrl-C will interrupt), with the extra getche function that echo the char as you type:

    if sys.platform == 'win32':
        import msvcrt
        getch = msvcrt.getch
        getche = msvcrt.getche
    else:
        import sys
        import termios
        def __gen_ch_getter(echo):
            def __fun():
                fd = sys.stdin.fileno()
                oldattr = termios.tcgetattr(fd)
                newattr = oldattr[:]
                try:
                    if echo:
                        # disable ctrl character printing, otherwise, backspace will be printed as "^?"
                        lflag = ~(termios.ICANON | termios.ECHOCTL)
                    else:
                        lflag = ~(termios.ICANON | termios.ECHO)
                    newattr[3] &= lflag
                    termios.tcsetattr(fd, termios.TCSADRAIN, newattr)
                    ch = sys.stdin.read(1)
                    if echo and ord(ch) == 127: # backspace
                        # emulate backspace erasing
                        # https://stackoverflow.com/a/47962872/404271
                        sys.stdout.write('\b \b')
                finally:
                    termios.tcsetattr(fd, termios.TCSADRAIN, oldattr)
                return ch
            return __fun
        getch = __gen_ch_getter(False)
        getche = __gen_ch_getter(True)
    

    References:

    • https://pypi.python.org/pypi/getch

提交回复
热议问题