Python 检查Linux终端缓冲区中的额外字符

Python 检查Linux终端缓冲区中的额外字符,python,ioctl,getch,termios,Python,Ioctl,Getch,Termios,我尝试在Python中实现getch()函数,它还应该返回特殊键(如F1-F12和箭头键)的字符列表。这些特殊密钥在一个序列中生成几个字符。因此,getch()在阻塞模式下读取一个字符,然后应该检查输入缓冲区中是否有额外的字符来获取它们 我正在使用ioctlcall与一起获取输入缓冲区中的字节数。它捕捉堆叠在缓冲区中的非特殊按键,但忽略特殊按键的额外符号。似乎有两种不同的缓冲区,如果有人能解释一下,那就太好了 以下是交互式示例: 从时间导入睡眠 def getch(): 导入系统、tty、ter

我尝试在Python中实现
getch()
函数,它还应该返回特殊键(如F1-F12和箭头键)的字符列表。这些特殊密钥在一个序列中生成几个字符。因此,
getch()
在阻塞模式下读取一个字符,然后应该检查输入缓冲区中是否有额外的字符来获取它们

我正在使用
ioctl
call与一起获取输入缓冲区中的字节数。它捕捉堆叠在缓冲区中的非特殊按键,但忽略特殊按键的额外符号。似乎有两种不同的缓冲区,如果有人能解释一下,那就太好了

以下是交互式示例:

从时间导入睡眠
def getch():
导入系统、tty、termios
fd=sys.stdin.fileno()
#保存旧的终端设置,因为我们正在更改它们
旧设置=termios.tcgetattr(fd)
尝试:
#将终端设置为“原始”模式,在该模式下,驱动程序返回
#一次一个字符,而不是一行一行
#
#setraw()只是tcsetattr()调用的助手,请参阅
# http://hg.python.org/cpython/file/c6880edaf6f3/Lib/tty.py
tty.setraw(fd)
ch=系统标准读数(1)
#---检查缓冲区中是否有更多字符
从fcntl导入ioctl
从数组导入数组
睡眠(1)
buf=数组('i',[0])
ioctl(fd、termios.FIONREAD、buf)
打印“buf队列:%s”,%buf[0],
# ---
最后:
#恢复终端设置。在所有输出都已完成时执行此操作
#完成-TCSADRAIN标志
termios.tcsetattr(fd、termios.TCSADRAIN、旧设置)
返回ch
字符=“”
而char!='q':
char=getch()
打印“符号:%s,作战需求(%s)”(字符,作战需求(字符))

No.<代码>睡眠(1)< /代码>。如果在第二个键到期前按一个键,输出将为:

buf queue: 0, sym: l, ord(108)
对于在一秒钟内输入的5个普通键(例如“asdfg”),输出为:

buf queue: 4, sym: a, ord(97)
但对于单个箭头键,输出:

buf queue: 0, sym: , ord(27)
buf queue: 0, sym: [, ord(91)
buf queue: 0, sym: D, ord(68)
这里有两个问题:

  • 为什么普通按键队列中的4个符号被丢弃?是否因为切换到“原始”终端模式?如何在不将终端置于“原始”模式的情况下为后续的
    getch()
    运行保留字符

  • 为什么单个特殊按键的
    ioctl
    缓冲区为空?后续运行
    getch()
    时,这些字符来自哪里?如何检查它们


  • 我遇到了同样的问题。一些搜索产生了一个工作示例,该示例最多读取4个字节(而不是1个字节)以允许特殊转义序列,并使用了
    os.read
    (而不是
    file.read
    )。基于这些差异,我能够编写一个识别光标键事件的小键盘类:

    #!/usr/bin/env python
    
    import os
    import select
    import sys
    import termios
    
    class Keyboard:
      ESCAPE = 27
      LEFT = 1000
      RIGHT = 1001
      DOWN = 1002
      UP = 1003
    
      keylist = {
        '\x1b' : ESCAPE,
        '\x1b[A' : UP,
        '\x1b[B' : DOWN,
        '\x1b[C' : RIGHT,
        '\x1b[D' : LEFT,
      }
    
      def __init__(self):
        self.fd = sys.stdin.fileno()
        self.old = termios.tcgetattr(self.fd)
        self.new = termios.tcgetattr(self.fd)
        self.new[3] = self.new[3] & ~termios.ICANON & ~termios.ECHO
        self.new[6][termios.VMIN] = 1
        self.new[6][termios.VTIME] = 0
        termios.tcsetattr(self.fd, termios.TCSANOW, self.new)
    
      def __enter__(self):
        return self
    
      def __exit__(self, type, value, traceback):
        termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old)
    
      def getFile(self):
        return self.fd
    
      def read(self):
        keys = os.read(self.fd, 4)
        if keys in Keyboard.keylist:
          return Keyboard.keylist[keys]
        else:
          return None
    
    if __name__ == "__main__":
      with Keyboard() as keyboard:
        key = keyboard.read()
        while key != Keyboard.ESCAPE:
          print '%d' % key
          key = keyboard.read()
    

    使用
    file.read(4)
    ,读取块将被阻塞。使用操作系统读取(fd,4),读取不会阻塞。我不知道为什么会有不同,我希望得到启发。

    我遇到了同样的问题。一些搜索产生了一个工作示例,该示例最多读取4个字节(而不是1个字节)以允许特殊转义序列,并使用了
    os.read
    (而不是
    file.read
    )。基于这些差异,我能够编写一个识别光标键事件的小键盘类:

    #!/usr/bin/env python
    
    import os
    import select
    import sys
    import termios
    
    class Keyboard:
      ESCAPE = 27
      LEFT = 1000
      RIGHT = 1001
      DOWN = 1002
      UP = 1003
    
      keylist = {
        '\x1b' : ESCAPE,
        '\x1b[A' : UP,
        '\x1b[B' : DOWN,
        '\x1b[C' : RIGHT,
        '\x1b[D' : LEFT,
      }
    
      def __init__(self):
        self.fd = sys.stdin.fileno()
        self.old = termios.tcgetattr(self.fd)
        self.new = termios.tcgetattr(self.fd)
        self.new[3] = self.new[3] & ~termios.ICANON & ~termios.ECHO
        self.new[6][termios.VMIN] = 1
        self.new[6][termios.VTIME] = 0
        termios.tcsetattr(self.fd, termios.TCSANOW, self.new)
    
      def __enter__(self):
        return self
    
      def __exit__(self, type, value, traceback):
        termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old)
    
      def getFile(self):
        return self.fd
    
      def read(self):
        keys = os.read(self.fd, 4)
        if keys in Keyboard.keylist:
          return Keyboard.keylist[keys]
        else:
          return None
    
    if __name__ == "__main__":
      with Keyboard() as keyboard:
        key = keyboard.read()
        while key != Keyboard.ESCAPE:
          print '%d' % key
          key = keyboard.read()
    

    使用
    file.read(4)
    ,读取块将被阻塞。使用操作系统读取(fd,4),读取不会阻塞。我不知道为什么会有不同,我希望大家能有所启发。

    可能重复的是,如果是重复的话,就连关都不关。如果是重复的话,就连关都不关。很好。我猜file.read()本身就有一些缓冲功能,但仍然不能像预期的那样工作。如果在最后一个while中插入sleep(2),并在暂停期间按ESC键4次,则在下一个os.read()操作中将获得包含4个ESC代码的字符串。我放弃了,因为看起来Linux不允许这样做。我来这里是为了确保钓到好鱼。我猜file.read()本身就有一些缓冲功能,但仍然不能像预期的那样工作。如果在最后一个while中插入sleep(2),并在暂停期间按ESC键4次,则在下一个os.read()操作中将获得包含4个ESC代码的字符串。我放弃了,因为看起来Linux不允许这样做。我来这里是想确定一下-