2011-12-23 5 views
1

の機能をPythonで実装しようとしています。F1-F12や矢印キーなどの特殊キーのリストも返す必要があります。これらの特殊キーは、シーケンス内に複数の文字を生成します。したがって、getch()は、ブロックモードで1つのcharを読み込み、入力バッファに余分な文字があるかどうかをチェックして、それらも取得する必要があります。Linuxターミナルバッファーで余分な文字がないか確認してください

私はtermios.FIONREADと一緒に呼び出して、入力バッファーのバイト数を取得しています。バッファーに積み重ねられた非特殊キープレスをキャッチしますが、特別なキーから余分な記号を逃します。 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):ここ

は、インタラクティブな例です。この第二の有効期限が切れる前に、あなたが一つのキーをヒットした場合、出力は次のようになります。

5つの通常のキー(例えば「asdfg」)については
buf queue: 0, sym: l, ord(108) 

1秒で入力し、出力は次のようになります。

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つのシンボルが破棄されるのはなぜですか? 「raw」端末モードに切り替えるのはそれですか?端末を「生」モードにしないで、その後のgetch()の実行で文字を保持する方法はありますか?

  2. ioctlなぜ特殊キープレスのバッファが空白なのですか?その後の文字はどこから来ていますか?getch()が実行されていますか?それらをチェックする方法?

+0

[[Pythonで単一文字(ゲッチ形式)を読む]がUnixで動作しない](http://stackoverflow.com/questions/1052107/reading-a-single-character-getch-style-in- Python-is-not-un-unix) –

+0

重複していても閉じていません。 –

答えて

1

この同じ問題が発生しました。いくつかの検索では、特殊なエスケープシーケンスを可能にするために最大で4バイト(1ではなく)を読み取って、file.readの代わりにos.readを使用する実例がありました。 file.read(4)

#!/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() 

、読み取りブロック:これらの違いに基づいて、私はカーソルキーイベントを認識し、ほとんどキーボードクラスを記述することができました。 os.read(fd, 4)では、読み取り値はブロックされません。どうして違いがあり、悟りを歓迎するのか分かりません。

+0

良いキャッチ。私はfile.read()が独自のバッファリングをしていると思います。 –

+0

まだ期待どおりに動作しません。最後にsleep(2)を挿入し、一時停止中にESCを4回押すと、次のos.read()操作で4つのESCコードを含む文字列を取得します。期待されるのは、読み込みごとに1つのESCで文字列を取得することです。 –

+0

私はあきらめました - それはLinuxがこのようなことを許可しないように見えます。私はここで確かめるように頼んだ - http://stackoverflow.com/questions/17838339/is-there-a-typeahead-buffer-for-key-presses-in-linux-terminal –

関連する問題