2011-12-23 2 views
1

을 구현하려고합니다. 또한 F1-F12와 화살표 키와 같은 특수 키의 문자 목록을 반환해야합니다. 이러한 특수 키는 시퀀스에서 여러 문자를 생성합니다. 따라서 getch()은 차단 모드에서 하나의 char을 읽은 다음 입력 버퍼에 여분의 문자가 있는지도 검사해야합니다.리눅스 터미널 버퍼의 여분의 문자 확인

입력 버퍼의 바이트 수를 얻기 위해 termios.FIONREAD과 함께 ioctl 콜을 사용하고 있습니다. 버퍼에 쌓여있는 특별하지 않은 키 누름을 잡아 당기지 만 특수 키의 여분의 기호는 누락됩니다. 두 개의 다른 버퍼가있는 것처럼 보입니다. 누군가가 이것을 설명 할 수 있다면 좋을 것입니다. 중간에

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 초에 입력 (예 : 'asdfg'에 대한) (5) 보통의 키에 대해서는

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

, 출력은 다음과 같습니다

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) 
    

    여기에 두 가지 질문이 있습니다

  1. 일반 키 누름이있는 대기열의 4 개 심볼이 삭제되는 이유는 무엇입니까? "원시"터미널 모드로 전환했기 때문입니까? 터미널을 "원시"모드로 두지 않고 다음에 수행 할 getch() 실행을 위해 문자를 유지하는 방법은 무엇입니까?

  2. ioctl 단일 특수 키 누름의 버퍼가 비어 있습니까? 해당 문자는 다음 번에 getch() 실행을 위해 어디에서 왔습니까? 그들을 확인하는 방법?

+0

[파이썬에서 단일 문자 (getch 스타일) 읽기가 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 코드가있는 문자열이 표시됩니다. 예상되는 것은 모든 읽기에 대해 하나의 ESC가있는 문자열을 얻는 것입니다. –

+0

나는 포기했다. 리눅스는 이런 것들을 허용하지 않는다. 나는 여기에 확실하게 물었다 - http://stackoverflow.com/questions/17838339/is-there-a-typeahead-buffer-for-key-presses-in-linux-terminal –

관련 문제