Опрос клавиатуры (обнаружение нажатия клавиши) в 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 не будет плохой, хотя это не требуется.
Ответы
Ответ 1
Стандартным подходом является использование модуля select.
Однако это не работает в Windows. Для этого вы можете использовать msvcrt опрос клавиатуры модуля.
Часто это делается с несколькими потоками - по одному на каждое "наблюдаемое" устройство и фоновыми процессами, которые могут быть прерваны устройством.
Ответ 2
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
Ответ 3
Решение с использованием модуля curses. Печать числового значения, соответствующего каждой нажатой клавише:
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)
Ответ 4
Хорошо, поскольку моя попытка опубликовать мое решение в комментарии не удалась, вот что я пытался сказать. Я мог бы сделать именно то, что хотел от собственного Python (в Windows, а не где-либо еще) со следующим кодом:
import msvcrt
def kbfunc():
x = msvcrt.kbhit()
if x:
ret = ord(msvcrt.getch())
else:
ret = 0
return ret
Ответ 5
Ни один из этих ответов не помог мне. Этот пакет, 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()
Ответ 6
Вы можете посмотреть, как pygame обрабатывает это, чтобы украсть некоторые идеи.
Ответ 7
Из комментариев:
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 demo the capability
#
while 1:
x = kbfunc()
if x != 0:
print "Got key: %d" % x
else:
time.sleep(.01)
Ответ 8
Я использую это для проверки нажатий клавиш, не может быть намного проще:
#!/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)
Хотя проклятия не работают над окнами, есть версия "unicurses", предположительно работающая на Linux, Windows, Mac, но я не мог заставить это работать
Ответ 9
Если вы комбинируете 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
Хотя это ничего не вернет, вместо этого вы должны использовать модуль многопроцессорного пула, который вы можете найти здесь: как получить возвращаемое значение из потока в python?
Ответ 10
Я сталкивался с кросс-платформенной реализацией kbhit
адресу http://home.wlu.edu/~levys/software/kbhit.py (внес изменения, чтобы удалить неактуальный код):
import os
if os.name == 'nt':
import msvcrt
else:
import sys, select
def kbhit():
''' Returns True if a character is waiting in stdin, False otherwise.
'''
if os.name == 'nt':
return msvcrt.kbhit()
else:
dr,dw,de = select.select([sys.stdin], [], [], 0)
return dr != []
Обязательно read()
ожидающий символ - функция будет возвращать True
пока вы не сделаете!