1

Python で関数を実装しようとしましたがgetch()、F1-F12 や矢印キーなどの特殊キーの文字のリストも返す必要があります。これらの特別なキーは、連続して複数の文字を生成します。したがってgetch()、ブロッキング モードで 1 文字を読み取り、入力バッファに余分な文字があるかどうかを確認して、それらも取得する必要があります。

call をtermios.FIONREADioctlと共に使用して、入力バッファー内のバイト数を取得しています。バッファにスタックされた非特殊キーの押下をキャッチしますが、特殊キーからの余分な記号は見逃します。2 つの異なるバッファーがあるようです。誰かがこれを説明してくれたらうれしいです。

インタラクティブな例を次に示します。

from time import sleep

def getch():
    import sys, tty, termios
    fd = sys.stdin.fileno()
    # save old terminal settings, because we are changing them
    old_settings = termios.tcgetattr(fd)
    try:
        # set terminal to "raw" mode, in which driver returns
        # one char at a time instead of one line at a time
        #
        # tty.setraw() is just a helper for tcsetattr() call, see
        # http://hg.python.org/cpython/file/c6880edaf6f3/Lib/tty.py
        tty.setraw(fd)
        ch = sys.stdin.read(1)

        # --- check if there are more characters in buffer
        from fcntl import ioctl
        from array import array

        sleep(1)
        buf = array('i', [0])
        ioctl(fd, termios.FIONREAD, buf)
        print "buf queue: %s," % buf[0],
        # ---

    finally:
        # restore terminal settings. Do this when all output is
        # finished - TCSADRAIN flag
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    return ch

char = ''
while char != 'q':
  char = getch()
  print 'sym: %s, ord(%s)' % (char, ord(char))

sleep(1)途中注意。この秒が切れる前に 1 つのキーを押すと、出力は次のようになります。

buf queue: 0, sym: l, ord(108)

1 秒間に 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)

ここで 2 つの質問があります。

  1. 通常のキー押下でキュー内の 4 つのシンボルが破棄されるのはなぜですか? 「生」端末モードに切り替えたためですか?getch()端末を「生」モードのままにしなくても、後続の実行のために文字を保持するにはどうすればよいですか?

  2. ioctl特別なキーを 1 回押すだけのバッファが空になるのはなぜですか? それらのキャラクターは、その後のgetch()実行のためにどこから来ていますか? それらを確認する方法は?

4

1 に答える 1

1

この同じ問題に遭遇しました。一部の検索では、特殊なエスケープ シーケンスを許可するために最大 4 バイト (1 ではなく) を読み取り、( の代わりに) を使用する実際の例が得られましos.readfile.read。これらの違いに基づいて、カーソル キー イベントを認識する小さな Keyboard クラスを作成できました。

#!/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)、読み取りブロック。でos.read(fd, 4)、読み取りがブロックされません。なぜ違いがあるのか​​ わかりませんが、啓発を歓迎します。

于 2012-10-25T12:12:43.047 に答える