2008-11-15 5 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 

Что такое правильный вещий способ сделать это на Windows? Кроме того, переносимость в Linux не будет плохой, хотя это не требуется.

+0

Просто, чтобы позволить другим людям знать, я обнаружил, что большинство решений, связанных выберите или нить библиотеки не работает правильно с IDLE. Однако они _ ** все ** _ отлично работали на 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 

Спасибо за помощь. Я закончил тем, что писал C DLL под названием PyKeyboardAccess.dll и доступа к функциям элт Conio, экспорт этого дня:

#include <conio.h> 

int kb_inkey() { 
    int rc; 
    int key; 

    key = _kbhit(); 

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

    return rc; 
} 

И я к нему доступ в Python с использованием модуля ctypes (встроенный в Python 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

Вы абсолютно правы! Я неправильно прочитал ваш пост; Я не понял, что есть модуль python, называемый msvcrt! Я просто подумал, что вы имеете в виду «использовать ms crt», а затем меня задумали о потоках и не подключили точки. Вы абсолютно правы. – 2008-11-16 04:33:32

+1

я сделал то же самое с: импорта MSVCRT Защиту kbfunc(): х = msvcrt.kbhit() если х: 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()