2014-03-14 27 views
20

我正在嘗試查找本地系統分配給箭頭鍵的值,特別是在Python中。我使用下面的腳本來做到這一點:在Python中查找箭頭鍵的值:它們爲什麼是三元組?

import sys,tty,termios 
class _Getch:  
    def __call__(self): 
      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 

def get(): 
    inkey = _Getch() 
    while(1): 
      k=inkey() 
      if k!='':break 
    print 'you pressed', ord(k) 

def main(): 
    for i in range(0,25): 
     get() 

if __name__=='__main__': 
    main() 

然後我跑了劇本,並創下UP DOWN RIGHT LEFT,這給了我這樣的輸出:

$ python getchar.py 
you pressed 27 
you pressed 91 
you pressed 65 
you pressed 27 
you pressed 91 
you pressed 66 
you pressed 27 
you pressed 91 
you pressed 67 
you pressed 27 
you pressed 91 
you pressed 68 

這是不正常的,因爲它表明,箭頭鍵在我的系統中被註冊爲某種形式的三元組(27-91-6x),因爲每按一次箭頭鍵就會佔用get()的三個實例。相比之下,按A,B,C和CTRL-C給出:

you pressed 97 
you pressed 98 
you pressed 99 
you pressed 3 

任何人都可以向我解釋爲什麼我的箭頭鍵的值似乎被存儲爲三元?這是爲什麼?這在所有平臺上都是一樣的嗎? (我使用的是Debian Linux。)如果不是,我該如何去存儲箭頭鍵的值?

這裏的最終目標是我正在編寫一個程序,它需要正確識別箭頭鍵並根據哪個箭頭鍵被按下來執行一個功能。

+0

即使缺少由鍵盤發送的轉義碼的清晰部分,我也會建議[ANSI轉義碼](http://en.wikipedia.org/wiki/ANSI_escape_code)它們的格式與從程序發送到終端的格式相同。 –

+0

這似乎是相關的:http://stackoverflow.com/questions/4130048/recognizing-arrow-keys-with-stdin – Newb

+0

爲什麼你有'_Gall'類'__call__'方法,而不是一個'getch'函數? – user2357112

回答

22

我想我想通了。

我從here瞭解到每個箭頭鍵都由一個唯一的ANSI轉義碼錶示。然後我瞭解到ANSI轉義碼因系統和應用而異:在我的終端中,打到cat並按向上箭頭給出^[[A,在C中似乎是\033[A等。後一部分[A保持不變,但前面Escape的代碼可以是十六進制(以x開頭),八進制(以0開頭)或十進制(數字中不含前導)。

然後我打開python控制檯,並插入我以前收到的三元組,試圖找到他們的字符值。事實證明,chr(27)給出\x1b,chr(91)給出[,並且分別在65,66,67,68上調用chr返回A,B,C,D。那麼很明顯:\x1b是逃跑代碼!

然後我注意到ANSI中的箭頭鍵表示爲三元組,當然表示爲三個字符,所以我需要修改我的代碼以便一次讀入三個字符。下面是結果:

import sys,tty,termios 
class _Getch: 
    def __call__(self): 
      fd = sys.stdin.fileno() 
      old_settings = termios.tcgetattr(fd) 
      try: 
       tty.setraw(sys.stdin.fileno()) 
       ch = sys.stdin.read(3) 
      finally: 
       termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) 
      return ch 

def get(): 
     inkey = _Getch() 
     while(1): 
       k=inkey() 
       if k!='':break 
     if k=='\x1b[A': 
       print "up" 
     elif k=='\x1b[B': 
       print "down" 
     elif k=='\x1b[C': 
       print "right" 
     elif k=='\x1b[D': 
       print "left" 
     else: 
       print "not an arrow key!" 

def main(): 
     for i in range(0,20): 
       get() 

if __name__=='__main__': 
     main() 
+0

在main中使用循環的良好調用,允許您將多個ascii值(escape和following chars)傳遞給getch()函數。如果你把'for'循環放在_Getch函數中,效率會更高。 – JFA

+0

可以通過ctrl + c(和其他信號)中斷嗎? – ThorSummoner

+0

@ThorSummoner是的。您可以使用get()函數,只需添加另一個'elif',並觀察像ctrl + c這樣的信號。但是,有更簡單的方法來做到這一點。 – Newb

3

我使用Mac和我用下面的代碼,效果不錯: 我得到的值,我的方向鍵0,1,2,3(上,下,左,右): 總是要記住ESC鍵的代碼27。 此致敬禮!

while True: 
    key = cv2.waitKey(1) & 0xFF 

    # if the 'ESC' key is pressed, Quit 
    if key == 27: 
     quit() 
    if key == 0: 
     print "up" 
    elif key == 1: 
     print "down" 
    elif key == 2: 
     print "left" 
    elif key == 3: 
     print "right" 
    # 255 is what the console returns when there is no key press... 
    elif key != 255: 
     print(key) 
相關問題