在python中轮询键盘(检测按键)

时间:2008-11-15 03:29:10

标签: python console keyboard blocking nonblocking

如何从控制台python app轮询键盘?具体来说,我想在许多其他I / O活动(套接字选择,串行端口访问等)中做类似的事情:

   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上执行此操作的正确pythonic方法是什么?此外,Linux的可移植性也不错,但并不是必需的。

10 个答案:

答案 0 :(得分:31)

标准方法是使用select模块。

但是,这在Windows上不起作用。为此,您可以使用msvcrt模块的键盘轮询。

通常,这是通过多个线程完成的 - 每个设备被“监视”一个加上可能需要被设备中断的后台进程。

答案 1 :(得分: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

答案 2 :(得分:16)

使用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)

答案 3 :(得分:14)

好的,因为我试图在评论中发布我的解决方案失败了,这就是我想说的。我可以使用以下代码完成我想要的原生Python(在Windows上,而不是其他任何地方):

import msvcrt 

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

答案 4 :(得分:11)

这些答案都不适合我。这个包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()

答案 5 :(得分:5)

你可能会看看pygame如何处理这个问题来窃取一些想法。

答案 6 :(得分: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模块(内置于python 2.5中)在python中访问它:

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)

答案 7 :(得分:1)

我用这个来检查按键,可以简化得多:

#!/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)

虽然curses没有在Windows上工作,但是有一个&#39; unicurses&#39;据说可能在Linux,Windows,Mac上工作,但是我无法使用它

答案 8 :(得分:0)

If you combine time.sleep, threading.Thread, and sys.stdin.read you can easily wait for a specified amount of time for input and then continue, also this should be cross-platform compatible.

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

You could also place this into a function like so

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

Although this will not return anything so instead you should use the multiprocessing pool module you can find that here: how to get the return value from a thread in python?

答案 9 :(得分:0)

我在http://home.wlu.edu/~levys/software/kbhit.py遇到了kbhit的跨平台实现(进行编辑以删除不相关的代码):

import os
if os.name == 'nt':
    import msvcrt
else:
    import sys, select

def kbhit():
    ''' Returns True if a keypress is waiting to be read in stdin, False otherwise.
    '''
    if os.name == 'nt':
        return msvcrt.kbhit()
    else:
        dr,dw,de = select.select([sys.stdin], [], [], 0)
        return dr != []

请确保read()个等待字符-函数将一直返回True,直到您这样做!