2008-11-15 134 views
56

如何從控制檯python應用程序輪詢鍵盤?具體而言,我願做這種類似的東西在很多其他的I/O活動(插座選擇,串行端口訪問等)之中:在Python中輪詢鍵盤(檢測按鍵)

while 1: 
     # doing amazing pythonic embedded stuff 
     # ... 

     # periodically do a non-blocking check to see if 
     # we are being told to do something else 
     x = keyboard.read(1000, timeout = 0) 

     if len(x): 
      # ok, some key got pressed 
      # do something 

什麼是正確的Python的方式做這在Windows上?而且,Linux的可移植性不會太差,儘管這不是必需的。

+0

只是爲了讓其他人知道,我發現涉及選擇或線程庫大多數解決方案並沒有從IDLE正常工作。但是,它們_ ** all ** _在CLI上運行良好,即`python/home/pi/poll_keyboard.py` – davidhood2 2016-10-19 11:18:32

回答

26

標準方法是使用select模塊。

但是,這在Windows上不起作用。爲此,您可以使用msvcrt模塊的鍵盤輪詢。

通常,這是通過多個線程完成的 - 每個設備一個被「監視」,加上可能需要被設備中斷的後臺進程。

6

你可以看看pygame如何處理這個來竊取一些想法。

5

從評論:

import msvcrt # built-in module 

def kbfunc(): 
    return ord(msvcrt.getch()) if msvcrt.kbhit() else 0 

感謝您的幫助。我最後寫稱爲PyKeyboardAccess.dll一個C DLL和訪問CRT conio功能,導出該例程:

#include <conio.h> 

int kb_inkey() { 
    int rc; 
    int key; 

    key = _kbhit(); 

    if (key == 0) { 
     rc = 0; 
    } else { 
     rc = _getch(); 
    } 

    return rc; 
} 

我訪問它的使用ctypes的模塊蟒蛇(內置於蟒蛇2.5):

import ctypes 
import time 

# 
# first, load the DLL 
# 


try: 
    kblib = ctypes.CDLL("PyKeyboardAccess.dll") 
except: 
    raise ("Error Loading PyKeyboardAccess.dll") 


# 
# now, find our function 
# 

try: 
    kbfunc = kblib.kb_inkey 
except: 
    raise ("Could not find the kb_inkey function in the dll!") 


# 
# Ok, now let's demo the capability 
# 

while 1: 
    x = kbfunc() 

    if x != 0: 
     print "Got key: %d" % x 
    else: 
     time.sleep(.01) 
+0

這比內置的msvcrt.kbhit()更好嗎?它有什麼優勢? – 2008-11-16 03:33:04

+0

你是對的!我誤解了你的帖子;我沒有意識到有一個叫做msvcrt的python模塊!我只是認爲你的意思是「使用ms crt」,然後我開始思考線程,並沒有連接點。你是絕對正確的。 – 2008-11-16 04:33:32

+1

我做了同樣的事情: 進口MSVCRT 高清kbfunc(): X = msvcrt.kbhit() 如果x: RET = ORD(msvcrt.getch()) 其他: RET = 0 return ret – 2008-11-16 04:34:20

14

好的,因爲我試圖在註釋中發佈我的解決方案失敗,所以我試圖說。我能做什麼,我想從原來的Python(在Windows上,沒有任何其他地方雖然)用下面的代碼:使用詛咒模塊

import msvcrt 

def kbfunc(): 
    x = msvcrt.kbhit() 
    if x: 
     ret = ord(msvcrt.getch()) 
    else: 
     ret = 0 
    return ret 
16

import sys 
import select 

def heardEnter(): 
    i,o,e = select.select([sys.stdin],[],[],0.0001) 
    for s in i: 
     if s == sys.stdin: 
      input = sys.stdin.readline() 
      return True 
    return False 
13

一個解決方案。打印對應於每個按鍵的數值按:

import curses 

def main(stdscr): 
    # do not wait for input when calling getch 
    stdscr.nodelay(1) 
    while True: 
     # get keyboard input, returns -1 if none available 
     c = stdscr.getch() 
     if c != -1: 
      # print numeric value 
      stdscr.addstr(str(c) + ' ') 
      stdscr.refresh() 
      # return curser to start position 
      stdscr.move(0, 0) 

if __name__ == '__main__': 
    curses.wrapper(main) 
0

如果合併time.sleep,threading.Thread和sys.stdin.read您可以輕鬆地等待指定的時間量的輸入,然後繼續, 也應該是跨平臺兼容的。

t = threading.Thread(target=sys.stdin.read(1) args=(1,)) 
t.start() 
time.sleep(5) 
t.join() 

你也可以把這個變成一個功能,像這樣

def timed_getch(self, bytes=1, timeout=1): 
    t = threading.Thread(target=sys.stdin.read, args=(bytes,)) 
    t.start() 
    time.sleep(timeout) 
    t.join() 
    del t 

雖然這不會返回任何所以不是你應該使用多池模塊,你可以找到在這裏:how to get the return value from a thread in python?

7

這些答案都不適合我。這個包,pynput,正是我所需要的。

https://pypi.python.org/pypi/pynput

from pynput.keyboard import Key, Listener 

def on_press(key): 
    print('{0} pressed'.format(
     key)) 

def on_release(key): 
    print('{0} release'.format(
     key)) 
    if key == Key.esc: 
     # Stop listener 
     return False 

# Collect events until released 
with Listener(
     on_press=on_press, 
     on_release=on_release) as listener: 
    listener.join()