How to read a single character from the user?

后端 未结 23 2660
爱一瞬间的悲伤
爱一瞬间的悲伤 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:12

    Answered here: raw_input in python without pressing enter

    Use this code-

    from tkinter import Tk, Frame
    
    
    def __set_key(e, root):
        """
        e - event with attribute 'char', the released key
        """
        global key_pressed
        if e.char:
            key_pressed = e.char
            root.destroy()
    
    
    def get_key(msg="Press any key ...", time_to_sleep=3):
        """
        msg - set to empty string if you don't want to print anything
        time_to_sleep - default 3 seconds
        """
        global key_pressed
        if msg:
            print(msg)
        key_pressed = None
        root = Tk()
        root.overrideredirect(True)
        frame = Frame(root, width=0, height=0)
        frame.bind("<KeyRelease>", lambda f: __set_key(f, root))
        frame.pack()
        root.focus_set()
        frame.focus_set()
        frame.focus_force()  # doesn't work in a while loop without it
        root.after(time_to_sleep * 1000, func=root.destroy)
        root.mainloop()
        root = None  # just in case
        return key_pressed
    
    
    def __main():
            c = None
            while not c:
                    c = get_key("Choose your weapon ... ", 2)
            print(c)
    
    if __name__ == "__main__":
        __main()
    

    Reference: https://github.com/unfor19/mg-tools/blob/master/mgtools/get_key_pressed.py

    0 讨论(0)
  • 2020-11-21 05:14

    The build-in raw_input should help.

    for i in range(3):
        print ("So much work to do!")
    k = raw_input("Press any key to continue...")
    print ("Ok, back to work.")
    
    0 讨论(0)
  • 2020-11-21 05:15

    This might be a use case for a context manager. Leaving aside allowances for Windows OS, here's my suggestion:

    #!/usr/bin/env python3
    # file: 'readchar.py'
    """
    Implementation of a way to get a single character of input
    without waiting for the user to hit <Enter>.
    (OS is Linux, Ubuntu 14.04)
    """
    
    import tty, sys, termios
    
    class ReadChar():
        def __enter__(self):
            self.fd = sys.stdin.fileno()
            self.old_settings = termios.tcgetattr(self.fd)
            tty.setraw(sys.stdin.fileno())
            return sys.stdin.read(1)
        def __exit__(self, type, value, traceback):
            termios.tcsetattr(self.fd, termios.TCSADRAIN, self.old_settings)
    
    def test():
        while True:
            with ReadChar() as rc:
                char = rc
            if ord(char) <= 32:
                print("You entered character with ordinal {}."\
                            .format(ord(char)))
            else:
                print("You entered character '{}'."\
                            .format(char))
            if char in "^C^D":
                sys.exit()
    
    if __name__ == "__main__":
        test()
    
    0 讨论(0)
  • 2020-11-21 05:18

    An alternative method:

    import os
    import sys    
    import termios
    import fcntl
    
    def getch():
      fd = sys.stdin.fileno()
    
      oldterm = termios.tcgetattr(fd)
      newattr = termios.tcgetattr(fd)
      newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
      termios.tcsetattr(fd, termios.TCSANOW, newattr)
    
      oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
      fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)
    
      try:        
        while 1:            
          try:
            c = sys.stdin.read(1)
            break
          except IOError: pass
      finally:
        termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
        fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)
      return c
    

    From this blog post.

    0 讨论(0)
  • 2020-11-21 05:18

    If I'm doing something complicated I'll use curses to read keys. But a lot of times I just want a simple Python 3 script that uses the standard library and can read arrow keys, so I do this:

    import sys, termios, tty
    
    key_Enter = 13
    key_Esc = 27
    key_Up = '\033[A'
    key_Dn = '\033[B'
    key_Rt = '\033[C'
    key_Lt = '\033[D'
    
    fdInput = sys.stdin.fileno()
    termAttr = termios.tcgetattr(0)
    
    def getch():
        tty.setraw(fdInput)
        ch = sys.stdin.buffer.raw.read(4).decode(sys.stdin.encoding)
        if len(ch) == 1:
            if ord(ch) < 32 or ord(ch) > 126:
                ch = ord(ch)
        elif ord(ch[0]) == 27:
            ch = '\033' + ch[1:]
        termios.tcsetattr(fdInput, termios.TCSADRAIN, termAttr)
        return ch
    
    0 讨论(0)
  • 2020-11-21 05:19

    Here's a link to a site that says how you can read a single character in Windows, Linux and OSX: http://code.activestate.com/recipes/134892/

    class _Getch:
        """Gets a single character from standard input.  Does not echo to the
    screen."""
        def __init__(self):
            try:
                self.impl = _GetchWindows()
            except ImportError:
                self.impl = _GetchUnix()
    
        def __call__(self): return self.impl()
    
    
    class _GetchUnix:
        def __init__(self):
            import tty, sys
    
        def __call__(self):
            import sys, tty, termios
            fd = sys.stdin.fileno()
            old_settings = termios.tcgetattr(fd)
            try:
                tty.setraw(sys.stdin.fileno())
                ch = sys.stdin.read(1)
            finally:
                termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
            return ch
    
    
    class _GetchWindows:
        def __init__(self):
            import msvcrt
    
        def __call__(self):
            import msvcrt
            return msvcrt.getch()
    
    
    getch = _Getch()
    
    0 讨论(0)
提交回复
热议问题