Опрос клавиатуры (обнаружение нажатия клавиши) в python
Как я могу опросить клавиатуру из консольного приложения 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 не будет плохой, хотя это и не требуется.
9 ответов:
стандартный подход заключается в использовании выберите модуль.
однако, это не работает на Windows. Для этого вы можете использовать библиотекой опрос клавиатуры модуля.
часто это делается с несколькими потоками - по одному на устройство, которое "наблюдают" плюс фоновые процессы, которые могут потребоваться прервать устройство.
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
хорошо, так как моя попытка опубликовать мое решение в комментарии не удалась, вот что я пытался сказать. Я мог бы сделать именно то, что я хотел от собственного Python (на Windows, а не где-либо еще) со следующим кодом:
import msvcrt def kbfunc(): x = msvcrt.kbhit() if x: ret = ord(msvcrt.getch()) else: ret = 0 return ret
решение с использованием модуля проклятия. Печать числового значения, соответствующего каждой нажатой клавише:
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)
ни один из этих ответов не работал хорошо для меня. Этот пакет, 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()
вы можете посмотреть как pygame обрабатывает это, чтобы украсть некоторые идеи.
из комментариев:
import msvcrt # built-in module def kbfunc(): return ord(msvcrt.getch()) if msvcrt.kbhit() else 0
Спасибо за помощь. В итоге я написал C DLL под названием PyKeyboardAccess.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; }и я получаю доступ к нему в 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)
Если вы комбинируете время.сон, нитку.Нить, и sys.стандартный ввод.чтение вы можете легко дождаться указанного количества времени для ввода, а затем продолжить, также это должно быть кросс-платформенной совместимостью.
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хотя это ничего не значит, вместо этого вы должны использовать модуль многопроцессорной бассейн вы можете найти здесь: как получить возвращаемое значение из потока в в Python?
Я использую это для проверки нажатия клавиш, не могу получить намного проще:
#!/usr/bin/python3 # -*- coding: UTF-8 -*- import curses, time def main(stdscr): """checking for keypress""" stdscr.nodelay(True) # do not wait for input when calling getch return stdscr.getch() while True: print("key:", curses.wrapper(main)) # prints: 'key: 97' for 'a' pressed # '-1' on no presses time.sleep(1)в то время как проклятия не работают на windows, есть версия "unicurses", предположительно работающая на Linux, Windows, Mac, но я не мог заставить это работать
Comments