Polling the Keyboard (Detect a Keypress) in Python

Polling the keyboard (detect a keypress) in python

The standard approach is to use the select module.

However, this doesn't work on Windows. For that, you can use the msvcrt module's keyboard polling.

Often, this is done with multiple threads -- one per device being "watched" plus the background processes that might need to be interrupted by the device.

How do I use the Python keyboard module to detect a key press?

I took a look at the documentation located here https://github.com/boppreh/keyboard.

I ran and tested this code on python 3.9

import keyboard
from functools import partial

num = ""

def add(i):
global num
num += str(i)
print(num, end='\r')

for i in range(10): # numbers 0...9
keyboard.add_hotkey(str(i), partial(add, i)) # add hotkeys

keyboard.wait('enter') # block process until "ENTER" is pressed

print("\nNum:{}".format(num))

You could additionally unhook the hotkeys by calling keyboard.unhook_all_hotkeys() after grabbing the number. I imagine you could wait on "+" and "-" if you wanted to implement addition and subtraction of numbers.

How can I detect a key pressed during a pause in python?

While Matteo's answer will do the job, you might still wait a small amount of time after you press q before the polling thread stops. That's because the polling thread waits one second before checking the run variable.

If you instead of a thread, use a Process from the multiprocessing module, you can terminate it as soon as the user presses q and avoid the extra wait time.

Here is an example:

import keyboard
from multiprocessing import Process
import time

def press_a_every_second():
while True:
time.sleep(1)
keyboard.press_and_release('a')

if __name__ == "__main__":
worker = Process(target=press_a_every_second)
keyboard.add_hotkey('q', worker.terminate)
worker.start()
worker.join()

Key Listeners in python?

It's unfortunately not so easy to do that. If you're trying to make some sort of text user interface, you may want to look into curses. If you want to display things like you normally would in a terminal, but want input like that, then you'll have to work with termios, which unfortunately appears to be poorly documented in Python. Neither of these options are that simple, though, unfortunately. Additionally, they do not work under Windows; if you need them to work under Windows, you'll have to use PDCurses as a replacement for curses or pywin32 rather than termios.


I was able to get this working decently. It prints out the hexadecimal representation of keys you type. As I said in the comments of your question, arrows are tricky; I think you'll agree.

#!/usr/bin/env python
import sys
import termios
import contextlib

@contextlib.contextmanager
def raw_mode(file):
old_attrs = termios.tcgetattr(file.fileno())
new_attrs = old_attrs[:]
new_attrs[3] = new_attrs[3] & ~(termios.ECHO | termios.ICANON)
try:
termios.tcsetattr(file.fileno(), termios.TCSADRAIN, new_attrs)
yield
finally:
termios.tcsetattr(file.fileno(), termios.TCSADRAIN, old_attrs)

def main():
print 'exit with ^C or ^D'
with raw_mode(sys.stdin):
try:
while True:
ch = sys.stdin.read(1)
if not ch or ch == chr(4):
break
print '%02x' % ord(ch),
except (KeyboardInterrupt, EOFError):
pass

if __name__ == '__main__':
main()


Related Topics



Leave a reply



Submit