Can't check what button is pressed in pynput - python

I have problem with Keys in pynput
on_press function should check if button pressed i 'h' but it gives error
from pynput.keyboard import Key, Listener
def on_press(key):
print(key)
if key == Key.h:
print('done')
def on_release(key):
print('{0} release'.format(key))
if key == Key.esc:
return False
# Collect events until released
with Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()

the error is created by the if key == Key.h: statement inside the on_press function. When i comment this out, it works without error.
So this works:
from pynput.keyboard import Key, Listener
def on_press(key):
print(key)
# if key == Key.h: # <-- cause the error
# print('done') # <-- cause the error
def on_release(key):
print('{0} release'.format(key))
if key == Key.esc:
return False
# Collect events until released
with Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
returns (when i press various buttons etc):
'h'
'h' release
Key.alt_l
Key.tab
Key.alt_l release
Key.tab release
Key.alt_l
Key.tab
Key.alt_l release
It looks like the examples use a try-except block for the equivalent on_press function that you have created.
Here is the link to how it works: https://pynput.readthedocs.io/en/latest/keyboard.html
When i replace the function with this is performs well:
def on_press(key):
print(key)
try:
if key == Key.h:
print('done')
except:
print('something else')
and i get this:
'h'
something else
'h' release
'i'
something else
'i' release
Key.alt_l
something else
Key.tab
something else
Key.alt_l release
Key.tab release
Key.alt_l
You can see that the exception needs to be handled (many time) from the above, which is why the code in the question was broken.

your way to solve this problem doesn't work or maybe it's mine misunderstanding. When i tried to comment every print, to only print 'done' after checking if pressed key is 'h' it doesn't work
def on_press(key):
try:
if key == Key.h:
print('done')
except:
return
def on_release(key):
#print('{0} release'.format(key))
if key == Key.esc:
return False

Related

why is this code not working with library keyboard

If I press ctrl and alt at the same time, my program does nothing. I want if I press ctrl and alt at the same time python will automatically refresh the page 100 times.
Does anyone know why this isn't working and what I need to change?
from pynput import keyboard
def on_press(key):
if key == keyboard.Key.esc:
return False # stop listener
try:
k = key.char # single-char keys
except Exception as ex:
k = key.name # other keys
if k in ['ctl'+'alt']: # keys of interest
# self.keys.append(k) # store it in global-like variable
print('Key pressed: ' + k)
listener = keyboard.Listener(on_press=on_press)
listener.start() # start to listen on a separate thread
listener.join() # remove if main thread is polling self.keys
I have been testing your example and it seems that the library distinguishes between left and right 'Ctrl' and 'Alt'.
You should also note that only ONE KEY is detected, so the expression 'if k in ['ctl'+'alt']:' will never be TRUE.
If you change it to 'if k in ['ctrl_l', 'alt_l']:' (note that I changed the names of the keys as I said before that every key is different) at least one of them will be recognised. The approach given to achieve your goal is not the right one. Check this approach or something like this:
from pynput import keyboard
# The key combination to check
COMBINATION = {keyboard.Key.ctrl_l, keyboard.Key.alt_l}
# The currently active modifiers
current = set()
def on_press(key):
if key in COMBINATION:
current.add(key)
if all(k in current for k in COMBINATION):
print('PRESSED')
if key == keyboard.Key.esc:
listener.stop()
def on_release(key):
try:
current.remove(key)
except KeyError:
pass
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()

Pynput: Count keypresses

I want to write a program which counts, how often a key is pressed on my keyboard (e.g. per day). I can use Pynput to recognize a certain keypress, but I'm struggling with the counting part. Here's what I got so far:
from pynput.keyboard import Key, Listener
i = 0
def on_press(key, pressed):
print('{0} pressed'.format(
key))
if pressed({0}):
i = i + 1
def on_release(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()
That executes the following error:
TypeError: on_press() missing 1 required positional argument: 'pressed'
I also don't know how to seperate all 26 letters and am not really sure what to do now...does anyone have an idea?
I'm trying to figure this exact problem out myself. To answer what the error wants, it wants you to define the parameter "pressed" in your arguments passed to on_press.
ex.
def on_press(key, pressed=0):
print('{0} pressed'.format(
key))
if pressed({0}):
i = i + 1
your i = 0 above that block is out of scope for the on_press block, and therefore cannot be used.
The problem I'm having is, I can get it to count the keystrokes recursively, however it doesn't stop and goes to the max recursion depth with just one keystroke!
I'll reply again if I make any progress. Good luck to you as well!
--- I figured it out! ---
The following link to another StackOverflow post led me in the right direction:
Checking a specific key with pynput in Python
Here's my code. It will display the character typed and increment the count of keys typed:
from pynput.keyboard import Key, Listener
strokes = 0
def on_press(key):
if key == Key.esc:
return False
print('{0} pressed'.format(
key))
global strokes
strokes += 1
print(strokes)
with Listener(
on_press=on_press) as listener:
listener.join()
I hope this helps!
from pynput import keyboard
c=0
with keyboard.Events() as events:
for event in events:
if event.key == keyboard.Key.esc:
break
elif (str(event)) == "Press(key='1')":
c+=1
print(c)
You can use any keys inside "Press(key='1')" like "Press(key='2')" , "Press(key='q')"

Python press key down until another key

I've already looked at previous post, but can't find something that works...
Globally my goal : a script in python that if I press ‘k’ it will start to hold ‘k’ until I press escape.
But the problem is : it doesn’t hold ‘k’ and I don’t know why
If someone might help I’d be glad,
Thank you
from pynput import keyboard
import pyautogui
def on_press(key):
try:
print('alphanumeric key {0} pressed'.format(
key.char))
if key.char == 'k':
return False
except AttributeError:
print('special key {0} pressed'.format(
key))
def on_release(key):
print('{0} released'.format(
key))
if key == keyboard.Key.esc:
# Stop listener
return False
def listening_k():
with keyboard.Listener(
on_press=on_press) as listener:
listener.join()
return True
def listening_esc():
with keyboard.Listener(
on_release=on_release) as listener:
listener.join()
return True
def hold_key(key):
while listening_k() == True :
pyautogui.keyDown(key)
if listening_esc() == True :
break
hold_key('k')
You can make it simple by having a variable that holds the state (boolean value) if 'k' key is on press. Make it True anytime you press 'k' key and False for pressing 'esc' key.

How can I constantly check if a specific key is pressed [duplicate]

I am making a stopwatch type program in Python and I would like to know how to detect if a key is pressed (such as p for pause and s for stop), and I would not like it to be something like raw_input, which waits for the user's input before continuing execution.
Anyone know how to do this in a while loop?
I would like to make this cross-platform but, if that is not possible, then my main development target is Linux.
Python has a keyboard module with many features. Install it, perhaps with this command:
pip3 install keyboard
Then use it in code like:
import keyboard # using module keyboard
while True: # making a loop
try: # used try so that if user pressed other than the given key error will not be shown
if keyboard.is_pressed('q'): # if key 'q' is pressed
print('You Pressed A Key!')
break # finishing the loop
except:
break # if user pressed a key other than the given key the loop will break
For those who are on windows and were struggling to find an working answer here's mine: 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()
The function above will print whichever key you are pressing plus start an action as you release the 'esc' key. The keyboard documentation is here for a more variated usage.
Markus von Broady highlighted a potential issue that is: This answer doesn't require you being in the current window to this script be activated, a solution to windows would be:
from win32gui import GetWindowText, GetForegroundWindow
current_window = (GetWindowText(GetForegroundWindow()))
desired_window_name = "Stopwatch" #Whatever the name of your window should be
#Infinite loops are dangerous.
while True: #Don't rely on this line of code too much and make sure to adapt this to your project.
if current_window == desired_window_name:
with Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
More things can be done with keyboard module.
You can install this module using pip install keyboard
Here are some of the methods:
Method #1:
Using the function read_key():
import keyboard
while True:
if keyboard.read_key() == "p":
print("You pressed p")
break
This is gonna break the loop as the key p is pressed.
Method #2:
Using function wait:
import keyboard
keyboard.wait("p")
print("You pressed p")
It will wait for you to press p and continue the code as it is pressed.
Method #3:
Using the function on_press_key:
import keyboard
keyboard.on_press_key("p", lambda _:print("You pressed p"))
It needs a callback function. I used _ because the keyboard function returns the keyboard event to that function.
Once executed, it will run the function when the key is pressed. You can stop all hooks by running this line:
keyboard.unhook_all()
Method #4:
This method is sort of already answered by user8167727 but I disagree with the code they made. It will be using the function is_pressed but in an other way:
import keyboard
while True:
if keyboard.is_pressed("p"):
print("You pressed p")
break
It will break the loop as p is pressed.
Method #5:
You can use keyboard.record as well. It records all keys pressed and released until you press the escape key or the one you've defined in until arg and returns a list of keyboard.KeyboardEvent elements.
import keyboard
keyboard.record(until="p")
print("You pressed p")
Notes:
keyboard will read keypresses from the whole OS.
keyboard requires root on linux
As OP mention about raw_input - that means he want cli solution.
Linux: curses is what you want (windows PDCurses). Curses, is an graphical API for cli software, you can achieve more than just detect key events.
This code will detect keys until new line is pressed.
import curses
import os
def main(win):
win.nodelay(True)
key=""
win.clear()
win.addstr("Detected key:")
while 1:
try:
key = win.getkey()
win.clear()
win.addstr("Detected key:")
win.addstr(str(key))
if key == os.linesep:
break
except Exception as e:
# No input
pass
curses.wrapper(main)
For Windows you could use msvcrt like this:
import msvcrt
while True:
if msvcrt.kbhit():
key = msvcrt.getch()
print(key) # just to show the result
Use this code for find the which key pressed
from pynput import keyboard
def on_press(key):
try:
print('alphanumeric key {0} pressed'.format(
key.char))
except AttributeError:
print('special key {0} pressed'.format(
key))
def on_release(key):
print('{0} released'.format(
key))
if key == keyboard.Key.esc:
# Stop listener
return False
# Collect events until released
with keyboard.Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
Use PyGame to have a window and then you can get the key events.
For the letter p:
import pygame, sys
import pygame.locals
pygame.init()
BLACK = (0,0,0)
WIDTH = 1280
HEIGHT = 1024
windowSurface = pygame.display.set_mode((WIDTH, HEIGHT), 0, 32)
windowSurface.fill(BLACK)
while True:
for event in pygame.event.get():
if event.key == pygame.K_p: # replace the 'p' to whatever key you wanted to be pressed
pass #Do what you want to here
if event.type == pygame.locals.QUIT:
pygame.quit()
sys.exit()
neoDev's comment at the question itself might be easy to miss, but it links to a solution not mentioned in any answer here.
There is no need to import keyboard with this solution.
Solution copied from this other question, all credits to #neoDev.
This worked for me on macOS Sierra and Python 2.7.10 and 3.6.3
import sys,tty,os,termios
def getkey():
old_settings = termios.tcgetattr(sys.stdin)
tty.setcbreak(sys.stdin.fileno())
try:
while True:
b = os.read(sys.stdin.fileno(), 3).decode()
if len(b) == 3:
k = ord(b[2])
else:
k = ord(b)
key_mapping = {
127: 'backspace',
10: 'return',
32: 'space',
9: 'tab',
27: 'esc',
65: 'up',
66: 'down',
67: 'right',
68: 'left'
}
return key_mapping.get(k, chr(k))
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
try:
while True:
k = getkey()
if k == 'esc':
quit()
else:
print(k)
except (KeyboardInterrupt, SystemExit):
os.system('stty sane')
print('stopping.')
Non-root version that works even through ssh: sshkeyboard. Install with pip install sshkeyboard,
then write script such as:
from sshkeyboard import listen_keyboard
def press(key):
print(f"'{key}' pressed")
def release(key):
print(f"'{key}' released")
listen_keyboard(
on_press=press,
on_release=release,
)
And it will print:
'a' pressed
'a' released
When A key is pressed. ESC key ends the listening by default.
It requires less coding than for example curses, tkinter and getch. And it does not require root access like keyboard module.
You don't mention if this is a GUI program or not, but most GUI packages include a way to capture and handle keyboard input. For example, with tkinter (in Py3), you can bind to a certain event and then handle it in a function. For example:
import tkinter as tk
def key_handler(event=None):
if event and event.keysym in ('s', 'p'):
'do something'
r = tk.Tk()
t = tk.Text()
t.pack()
r.bind('<Key>', key_handler)
r.mainloop()
With the above, when you type into the Text widget, the key_handler routine gets called for each (or almost each) key you press.
I made this kind of game based on this post (using msvcr library and Python 3.7).
The following is the main function of the game, that is detecting the keys pressed:
import msvcrt
def _secret_key(self):
# Get the key pressed by the user and check if he/she wins.
bk = chr(10) + "-"*25 + chr(10)
while True:
print(bk + "Press any key(s)" + bk)
#asks the user to type any key(s)
kp = str(msvcrt.getch()).replace("b'", "").replace("'", "")
# Store key's value.
if r'\xe0' in kp:
kp += str(msvcrt.getch()).replace("b'", "").replace("'", "")
# Refactor the variable in case of multi press.
if kp == r'\xe0\x8a':
# If user pressed the secret key, the game ends.
# \x8a is CTRL+F12, that's the secret key.
print(bk + "CONGRATULATIONS YOU PRESSED THE SECRET KEYS!\a" + bk)
print("Press any key to exit the game")
msvcrt.getch()
break
else:
print(" You pressed:'", kp + "', that's not the secret key(s)\n")
if self.select_continue() == "n":
if self.secondary_options():
self._main_menu()
break
If you want the full source code of the program you can see it or download it from GitHub
The secret keypress is:
Ctrl+F12
Using the keyboard package, especially on linux is not an apt solution because that package requires root privileges to run. We can easily implement this with the getkey package. This is analogous to the C language function getchar.
Install it:
pip install getkey
And use it:
from getkey import getkey
while True: #Breaks when key is pressed
key = getkey()
print(key) #Optionally prints out the key.
break
We can add this in a function to return the pressed key.
def Ginput(str):
"""
Now, this function is like the native input() function. It can accept a prompt string, print it out, and when one key is pressed, it will return the key to the caller.
"""
print(str, end='')
while True:
key = getkey()
print(key)
return key
Use like this:
inp = Ginput("\n Press any key to continue: ")
print("You pressed " + inp)
import cv2
key = cv2.waitKey(1)
This is from the openCV package. The delay arg is the number of milliseconds it will wait for a keypress. In this case, 1ms. Per the docs, pollKey() can be used without waiting.
The curses module does that job.
You can test it running this example from the terminal:
import curses
screen = curses.initscr()
curses.noecho()
curses.cbreak()
screen.keypad(True)
try:
while True:
char = screen.getch()
if char == ord('q'):
break
elif char == curses.KEY_UP:
print('up')
elif char == curses.KEY_DOWN:
print('down')
elif char == curses.KEY_RIGHT:
print('right')
elif char == curses.KEY_LEFT:
print('left')
elif char == ord('s'):
print('stop')
finally:
curses.nocbreak(); screen.keypad(0); curses.echo()
curses.endwin()
Here is a cross-platform solution, both blocking and non-blocking, not requiring any external libraries:
import contextlib as _contextlib
try:
import msvcrt as _msvcrt
# Length 0 sequences, length 1 sequences...
_ESCAPE_SEQUENCES = [frozenset(("\x00", "\xe0"))]
_next_input = _msvcrt.getwch
_set_terminal_raw = _contextlib.nullcontext
_input_ready = _msvcrt.kbhit
except ImportError: # Unix
import sys as _sys, tty as _tty, termios as _termios, \
select as _select, functools as _functools
# Length 0 sequences, length 1 sequences...
_ESCAPE_SEQUENCES = [
frozenset(("\x1b",)),
frozenset(("\x1b\x5b", "\x1b\x4f"))]
#_contextlib.contextmanager
def _set_terminal_raw():
fd = _sys.stdin.fileno()
old_settings = _termios.tcgetattr(fd)
try:
_tty.setraw(_sys.stdin.fileno())
yield
finally:
_termios.tcsetattr(fd, _termios.TCSADRAIN, old_settings)
_next_input = _functools.partial(_sys.stdin.read, 1)
def _input_ready():
return _select.select([_sys.stdin], [], [], 0) == ([_sys.stdin], [], [])
_MAX_ESCAPE_SEQUENCE_LENGTH = len(_ESCAPE_SEQUENCES)
def _get_keystroke():
key = _next_input()
while (len(key) <= _MAX_ESCAPE_SEQUENCE_LENGTH and
key in _ESCAPE_SEQUENCES[len(key)-1]):
key += _next_input()
return key
def _flush():
while _input_ready():
_next_input()
def key_pressed(key: str = None, *, flush: bool = True) -> bool:
"""Return True if the specified key has been pressed
Args:
key: The key to check for. If None, any key will do.
flush: If True (default), flush the input buffer after the key was found.
Return:
boolean stating whether a key was pressed.
"""
with _set_terminal_raw():
if key is None:
if not _input_ready():
return False
if flush:
_flush()
return True
while _input_ready():
keystroke = _get_keystroke()
if keystroke == key:
if flush:
_flush()
return True
return False
def print_key() -> None:
"""Print the key that was pressed
Useful for debugging and figuring out keys.
"""
with _set_terminal_raw():
_flush()
print("\\x" + "\\x".join(map("{:02x}".format, map(ord, _get_keystroke()))))
def wait_key(key=None, *, pre_flush=False, post_flush=True) -> str:
"""Wait for a specific key to be pressed.
Args:
key: The key to check for. If None, any key will do.
pre_flush: If True, flush the input buffer before waiting for input.
Useful in case you wish to ignore previously pressed keys.
post_flush: If True (default), flush the input buffer after the key was
found. Useful for ignoring multiple key-presses.
Returns:
The key that was pressed.
"""
with _set_terminal_raw():
if pre_flush:
_flush()
if key is None:
key = _get_keystroke()
if post_flush:
_flush()
return key
while _get_keystroke() != key:
pass
if post_flush:
_flush()
return key
You can use key_pressed() inside a while loop:
while True:
time.sleep(5)
if key_pressed():
break
You can also check for a specific key:
while True:
time.sleep(5)
if key_pressed("\x00\x48"): # Up arrow key on Windows.
break
Find out special keys using print_key():
>>> print_key()
# Press up key
\x00\x48
Or wait until a certain key is pressed:
>>> wait_key("a") # Stop and ignore all inputs until "a" is pressed.
You can use pygame's get_pressed():
import pygame
while True:
keys = pygame.key.get_pressed()
if (keys[pygame.K_LEFT]):
pos_x -= 5
elif (keys[pygame.K_RIGHT]):
pos_x += 5
elif (keys[pygame.K_UP]):
pos_y -= 5
elif (keys[pygame.K_DOWN]):
pos_y += 5
I was finding how to detect different key presses subsequently until e.g. Ctrl + C break the program from listening and responding to different key presses accordingly.
Using following code,
while True:
if keyboard.is_pressed("down"):
print("Reach the bottom!")
if keyboard.is_pressed("up"):
print("Reach the top!")
if keyboard.is_pressed("ctrl+c"):
break
It will cause the program to keep spamming the response text, if I pressed arrow down or arrow up. I believed because it's in a while-loop, and eventhough you only press once, but it will get triggered multiple times (as written in doc, I am awared of this after I read.)
At that moment, I still haven't went to read the doc, I try adding in time.sleep()
while True:
if keyboard.is_pressed("down"):
print("Reach the bottom!")
time.sleep(0.5)
if keyboard.is_pressed("up"):
print("Reach the top!")
time.sleep(0.5)
if keyboard.is_pressed("ctrl+c"):
break
This solves the spamming issue.
But this is not a very good way as of subsequent very fast taps on the arrow key, will only trigger once instead of as many times as I pressed, because the program will sleep for 0.5 second right, meant the "keyboard event" happened at that 0.5 second will not be counted.
So, I proceed to read the doc and get the idea to do this at this part.
while True:
# Wait for the next event.
event = keyboard.read_event()
if event.event_type == keyboard.KEY_DOWN and event.name == 'down':
# do whatever function you wanna here
if event.event_type == keyboard.KEY_DOWN and event.name == 'up':
# do whatever function you wanna here
if keyboard.is_pressed("ctrl+c"):
break
Now, it's working fine and great!
TBH, I am not deep dive into the doc, used to, but I have really forgetten the content, if you know or find any better way to do the similar function, please enlighten me!
Thank you, wish you have a great day ahead!

How to detect key presses?

I am making a stopwatch type program in Python and I would like to know how to detect if a key is pressed (such as p for pause and s for stop), and I would not like it to be something like raw_input, which waits for the user's input before continuing execution.
Anyone know how to do this in a while loop?
I would like to make this cross-platform but, if that is not possible, then my main development target is Linux.
Python has a keyboard module with many features. Install it, perhaps with this command:
pip3 install keyboard
Then use it in code like:
import keyboard # using module keyboard
while True: # making a loop
try: # used try so that if user pressed other than the given key error will not be shown
if keyboard.is_pressed('q'): # if key 'q' is pressed
print('You Pressed A Key!')
break # finishing the loop
except:
break # if user pressed a key other than the given key the loop will break
For those who are on windows and were struggling to find an working answer here's mine: 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()
The function above will print whichever key you are pressing plus start an action as you release the 'esc' key. The keyboard documentation is here for a more variated usage.
Markus von Broady highlighted a potential issue that is: This answer doesn't require you being in the current window to this script be activated, a solution to windows would be:
from win32gui import GetWindowText, GetForegroundWindow
current_window = (GetWindowText(GetForegroundWindow()))
desired_window_name = "Stopwatch" #Whatever the name of your window should be
#Infinite loops are dangerous.
while True: #Don't rely on this line of code too much and make sure to adapt this to your project.
if current_window == desired_window_name:
with Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
More things can be done with keyboard module.
You can install this module using pip install keyboard
Here are some of the methods:
Method #1:
Using the function read_key():
import keyboard
while True:
if keyboard.read_key() == "p":
print("You pressed p")
break
This is gonna break the loop as the key p is pressed.
Method #2:
Using function wait:
import keyboard
keyboard.wait("p")
print("You pressed p")
It will wait for you to press p and continue the code as it is pressed.
Method #3:
Using the function on_press_key:
import keyboard
keyboard.on_press_key("p", lambda _:print("You pressed p"))
It needs a callback function. I used _ because the keyboard function returns the keyboard event to that function.
Once executed, it will run the function when the key is pressed. You can stop all hooks by running this line:
keyboard.unhook_all()
Method #4:
This method is sort of already answered by user8167727 but I disagree with the code they made. It will be using the function is_pressed but in an other way:
import keyboard
while True:
if keyboard.is_pressed("p"):
print("You pressed p")
break
It will break the loop as p is pressed.
Method #5:
You can use keyboard.record as well. It records all keys pressed and released until you press the escape key or the one you've defined in until arg and returns a list of keyboard.KeyboardEvent elements.
import keyboard
keyboard.record(until="p")
print("You pressed p")
Notes:
keyboard will read keypresses from the whole OS.
keyboard requires root on linux
As OP mention about raw_input - that means he want cli solution.
Linux: curses is what you want (windows PDCurses). Curses, is an graphical API for cli software, you can achieve more than just detect key events.
This code will detect keys until new line is pressed.
import curses
import os
def main(win):
win.nodelay(True)
key=""
win.clear()
win.addstr("Detected key:")
while 1:
try:
key = win.getkey()
win.clear()
win.addstr("Detected key:")
win.addstr(str(key))
if key == os.linesep:
break
except Exception as e:
# No input
pass
curses.wrapper(main)
For Windows you could use msvcrt like this:
import msvcrt
while True:
if msvcrt.kbhit():
key = msvcrt.getch()
print(key) # just to show the result
Use this code for find the which key pressed
from pynput import keyboard
def on_press(key):
try:
print('alphanumeric key {0} pressed'.format(
key.char))
except AttributeError:
print('special key {0} pressed'.format(
key))
def on_release(key):
print('{0} released'.format(
key))
if key == keyboard.Key.esc:
# Stop listener
return False
# Collect events until released
with keyboard.Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
Use PyGame to have a window and then you can get the key events.
For the letter p:
import pygame, sys
import pygame.locals
pygame.init()
BLACK = (0,0,0)
WIDTH = 1280
HEIGHT = 1024
windowSurface = pygame.display.set_mode((WIDTH, HEIGHT), 0, 32)
windowSurface.fill(BLACK)
while True:
for event in pygame.event.get():
if event.key == pygame.K_p: # replace the 'p' to whatever key you wanted to be pressed
pass #Do what you want to here
if event.type == pygame.locals.QUIT:
pygame.quit()
sys.exit()
neoDev's comment at the question itself might be easy to miss, but it links to a solution not mentioned in any answer here.
There is no need to import keyboard with this solution.
Solution copied from this other question, all credits to #neoDev.
This worked for me on macOS Sierra and Python 2.7.10 and 3.6.3
import sys,tty,os,termios
def getkey():
old_settings = termios.tcgetattr(sys.stdin)
tty.setcbreak(sys.stdin.fileno())
try:
while True:
b = os.read(sys.stdin.fileno(), 3).decode()
if len(b) == 3:
k = ord(b[2])
else:
k = ord(b)
key_mapping = {
127: 'backspace',
10: 'return',
32: 'space',
9: 'tab',
27: 'esc',
65: 'up',
66: 'down',
67: 'right',
68: 'left'
}
return key_mapping.get(k, chr(k))
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
try:
while True:
k = getkey()
if k == 'esc':
quit()
else:
print(k)
except (KeyboardInterrupt, SystemExit):
os.system('stty sane')
print('stopping.')
Non-root version that works even through ssh: sshkeyboard. Install with pip install sshkeyboard,
then write script such as:
from sshkeyboard import listen_keyboard
def press(key):
print(f"'{key}' pressed")
def release(key):
print(f"'{key}' released")
listen_keyboard(
on_press=press,
on_release=release,
)
And it will print:
'a' pressed
'a' released
When A key is pressed. ESC key ends the listening by default.
It requires less coding than for example curses, tkinter and getch. And it does not require root access like keyboard module.
You don't mention if this is a GUI program or not, but most GUI packages include a way to capture and handle keyboard input. For example, with tkinter (in Py3), you can bind to a certain event and then handle it in a function. For example:
import tkinter as tk
def key_handler(event=None):
if event and event.keysym in ('s', 'p'):
'do something'
r = tk.Tk()
t = tk.Text()
t.pack()
r.bind('<Key>', key_handler)
r.mainloop()
With the above, when you type into the Text widget, the key_handler routine gets called for each (or almost each) key you press.
I made this kind of game based on this post (using msvcr library and Python 3.7).
The following is the main function of the game, that is detecting the keys pressed:
import msvcrt
def _secret_key(self):
# Get the key pressed by the user and check if he/she wins.
bk = chr(10) + "-"*25 + chr(10)
while True:
print(bk + "Press any key(s)" + bk)
#asks the user to type any key(s)
kp = str(msvcrt.getch()).replace("b'", "").replace("'", "")
# Store key's value.
if r'\xe0' in kp:
kp += str(msvcrt.getch()).replace("b'", "").replace("'", "")
# Refactor the variable in case of multi press.
if kp == r'\xe0\x8a':
# If user pressed the secret key, the game ends.
# \x8a is CTRL+F12, that's the secret key.
print(bk + "CONGRATULATIONS YOU PRESSED THE SECRET KEYS!\a" + bk)
print("Press any key to exit the game")
msvcrt.getch()
break
else:
print(" You pressed:'", kp + "', that's not the secret key(s)\n")
if self.select_continue() == "n":
if self.secondary_options():
self._main_menu()
break
If you want the full source code of the program you can see it or download it from GitHub
The secret keypress is:
Ctrl+F12
Using the keyboard package, especially on linux is not an apt solution because that package requires root privileges to run. We can easily implement this with the getkey package. This is analogous to the C language function getchar.
Install it:
pip install getkey
And use it:
from getkey import getkey
while True: #Breaks when key is pressed
key = getkey()
print(key) #Optionally prints out the key.
break
We can add this in a function to return the pressed key.
def Ginput(str):
"""
Now, this function is like the native input() function. It can accept a prompt string, print it out, and when one key is pressed, it will return the key to the caller.
"""
print(str, end='')
while True:
key = getkey()
print(key)
return key
Use like this:
inp = Ginput("\n Press any key to continue: ")
print("You pressed " + inp)
import cv2
key = cv2.waitKey(1)
This is from the openCV package. The delay arg is the number of milliseconds it will wait for a keypress. In this case, 1ms. Per the docs, pollKey() can be used without waiting.
The curses module does that job.
You can test it running this example from the terminal:
import curses
screen = curses.initscr()
curses.noecho()
curses.cbreak()
screen.keypad(True)
try:
while True:
char = screen.getch()
if char == ord('q'):
break
elif char == curses.KEY_UP:
print('up')
elif char == curses.KEY_DOWN:
print('down')
elif char == curses.KEY_RIGHT:
print('right')
elif char == curses.KEY_LEFT:
print('left')
elif char == ord('s'):
print('stop')
finally:
curses.nocbreak(); screen.keypad(0); curses.echo()
curses.endwin()
Here is a cross-platform solution, both blocking and non-blocking, not requiring any external libraries:
import contextlib as _contextlib
try:
import msvcrt as _msvcrt
# Length 0 sequences, length 1 sequences...
_ESCAPE_SEQUENCES = [frozenset(("\x00", "\xe0"))]
_next_input = _msvcrt.getwch
_set_terminal_raw = _contextlib.nullcontext
_input_ready = _msvcrt.kbhit
except ImportError: # Unix
import sys as _sys, tty as _tty, termios as _termios, \
select as _select, functools as _functools
# Length 0 sequences, length 1 sequences...
_ESCAPE_SEQUENCES = [
frozenset(("\x1b",)),
frozenset(("\x1b\x5b", "\x1b\x4f"))]
#_contextlib.contextmanager
def _set_terminal_raw():
fd = _sys.stdin.fileno()
old_settings = _termios.tcgetattr(fd)
try:
_tty.setraw(_sys.stdin.fileno())
yield
finally:
_termios.tcsetattr(fd, _termios.TCSADRAIN, old_settings)
_next_input = _functools.partial(_sys.stdin.read, 1)
def _input_ready():
return _select.select([_sys.stdin], [], [], 0) == ([_sys.stdin], [], [])
_MAX_ESCAPE_SEQUENCE_LENGTH = len(_ESCAPE_SEQUENCES)
def _get_keystroke():
key = _next_input()
while (len(key) <= _MAX_ESCAPE_SEQUENCE_LENGTH and
key in _ESCAPE_SEQUENCES[len(key)-1]):
key += _next_input()
return key
def _flush():
while _input_ready():
_next_input()
def key_pressed(key: str = None, *, flush: bool = True) -> bool:
"""Return True if the specified key has been pressed
Args:
key: The key to check for. If None, any key will do.
flush: If True (default), flush the input buffer after the key was found.
Return:
boolean stating whether a key was pressed.
"""
with _set_terminal_raw():
if key is None:
if not _input_ready():
return False
if flush:
_flush()
return True
while _input_ready():
keystroke = _get_keystroke()
if keystroke == key:
if flush:
_flush()
return True
return False
def print_key() -> None:
"""Print the key that was pressed
Useful for debugging and figuring out keys.
"""
with _set_terminal_raw():
_flush()
print("\\x" + "\\x".join(map("{:02x}".format, map(ord, _get_keystroke()))))
def wait_key(key=None, *, pre_flush=False, post_flush=True) -> str:
"""Wait for a specific key to be pressed.
Args:
key: The key to check for. If None, any key will do.
pre_flush: If True, flush the input buffer before waiting for input.
Useful in case you wish to ignore previously pressed keys.
post_flush: If True (default), flush the input buffer after the key was
found. Useful for ignoring multiple key-presses.
Returns:
The key that was pressed.
"""
with _set_terminal_raw():
if pre_flush:
_flush()
if key is None:
key = _get_keystroke()
if post_flush:
_flush()
return key
while _get_keystroke() != key:
pass
if post_flush:
_flush()
return key
You can use key_pressed() inside a while loop:
while True:
time.sleep(5)
if key_pressed():
break
You can also check for a specific key:
while True:
time.sleep(5)
if key_pressed("\x00\x48"): # Up arrow key on Windows.
break
Find out special keys using print_key():
>>> print_key()
# Press up key
\x00\x48
Or wait until a certain key is pressed:
>>> wait_key("a") # Stop and ignore all inputs until "a" is pressed.
You can use pygame's get_pressed():
import pygame
while True:
keys = pygame.key.get_pressed()
if (keys[pygame.K_LEFT]):
pos_x -= 5
elif (keys[pygame.K_RIGHT]):
pos_x += 5
elif (keys[pygame.K_UP]):
pos_y -= 5
elif (keys[pygame.K_DOWN]):
pos_y += 5
I was finding how to detect different key presses subsequently until e.g. Ctrl + C break the program from listening and responding to different key presses accordingly.
Using following code,
while True:
if keyboard.is_pressed("down"):
print("Reach the bottom!")
if keyboard.is_pressed("up"):
print("Reach the top!")
if keyboard.is_pressed("ctrl+c"):
break
It will cause the program to keep spamming the response text, if I pressed arrow down or arrow up. I believed because it's in a while-loop, and eventhough you only press once, but it will get triggered multiple times (as written in doc, I am awared of this after I read.)
At that moment, I still haven't went to read the doc, I try adding in time.sleep()
while True:
if keyboard.is_pressed("down"):
print("Reach the bottom!")
time.sleep(0.5)
if keyboard.is_pressed("up"):
print("Reach the top!")
time.sleep(0.5)
if keyboard.is_pressed("ctrl+c"):
break
This solves the spamming issue.
But this is not a very good way as of subsequent very fast taps on the arrow key, will only trigger once instead of as many times as I pressed, because the program will sleep for 0.5 second right, meant the "keyboard event" happened at that 0.5 second will not be counted.
So, I proceed to read the doc and get the idea to do this at this part.
while True:
# Wait for the next event.
event = keyboard.read_event()
if event.event_type == keyboard.KEY_DOWN and event.name == 'down':
# do whatever function you wanna here
if event.event_type == keyboard.KEY_DOWN and event.name == 'up':
# do whatever function you wanna here
if keyboard.is_pressed("ctrl+c"):
break
Now, it's working fine and great!
TBH, I am not deep dive into the doc, used to, but I have really forgetten the content, if you know or find any better way to do the similar function, please enlighten me!
Thank you, wish you have a great day ahead!

Categories