I want to trigger certain functions when pressing certain arrows, it must be captured without being in console and pressing enter each time.
edit: I found now that "left arrow" registers left arrow etc BUT it triggered hundreds of times when pressed
import keyboard
while True:
if keyboard.is_pressed("left arrow"):
print("mkay")Everytime I press, it's very important that it only registeres once, any suggestions how to do that in an efficient manner?
I've got it working pretty good using sleep() efter each press but surely there must be a better way?
It's the same with pyautogui, and keyboard. Just use the word for direction. For example, 'right', or 'left'. Like this:
import keyboard
keyboard.press_and_release('left') #presses left arrow key
I recommend looking at the documentation to find key codes, as to find the difference between arrows on the numpad and normal layout can be difficult, and just for general reference in the future.
You can use the below code snippet to access the arrow keys. I have made use of the keyboard library inorder to do that.
- UP ARROW KEY -> "up"
- DOWN ARROW KEY -> "down"
- LEFT ARROW KEY -> "left"
- RIGHT ARROW KEY -> "right"
Here is a sample code
import keyboard
# To Press UP ARROW KEY
keyboard.press("up")
Hope it helps!!!
input - Finding the Values of the Arrow Keys in Python: Why are they triples? - Stack Overflow
How to implement using arrow keys for the game? Maybe a command recall?
python get arrow keys from command line - Stack Overflow
click - Python, check if arrow key pressed - Stack Overflow
Videos
The keyboard module has simple solutions for instances like these, they use event-triggered activation rather than polling as is used in your attempt.
example code:
import keyboard
def handleLeftKey(e):
if keyboard.is_pressed("4"):
print("left arrow was pressed w/ key 4")
# work your magic
keyboard.on_press_key("left", handleLeftKey)
# self-explanitory: when the left key is pressed down then do something
keyboard.on_release_key("left", handleLeftKey02)
# also self-explanitory: when the left key is released then do something
# don't use both ...on_release & ...on_press or it will be
# triggered twice per key-use (1 up, 1 down)
Replace the code below and change it to suit your needs.
if __name__ == "__main__":
while True:
code = []
try:
for key in keys:
if keyboard.is_pressed(key):
print(keyboard.key_to_scan_codes(key))
print(f"{key} pressed")
code.append(1)
else:
code.append(0)
Another, more dynamic approach would look like:
import keyboard
keys = [
"down",
"up",
"left",
"right",
"w",
"s",
"a",
"d",
"1",
"2",
"3",
"4",
"q",
"e",
"f"
]
def kbdCallback(e):
found = False
for key in keys:
if key == keyboard.normalize_name(e.name):
print(f"{key} was pressed")
found = True
# work your magic
if found == True:
if e.name == "left":
if keyboard.is_pressed("4"):
print("4 & left arrow were pressed together!")
# work your magic
keyboard.on_press(kbdCallback)
# same as keyboard.on_press_key, but it does this for EVERY key
Another issue I noticed was that you were using "left arrow" when really it was recognized as "left" (at least on my system, it may be different on yours, but I assume you want it to work on all systems so it'd be safer using "left" instead)
The last method you could use is very statically typed and has no dynamic capabilities, but would work in the case of "4+left" or "left+4"
import keyboard
def left4trigger:
print("the keys were pressed")
keyboard.add_hotkey("4+left", left4trigger)
# works as 4+left or left+4 (all of the examples do)
You seem smart enough to figure out the rest from there.
Beware, language may play a role! In my case the 'up' arrow was translated to my local language, you can run the following code to get the key value for your computer:
import keyboard
def onkeypress(event):
print(event.name)
keyboard.on_press(onkeypress)
#Use ctrl+c to stop
while True:
pass
I think I figured it out.
I learned from here that each arrow key is represented by a unique ANSI escape code. Then I learned that the ANSI escape codes vary by system and application: in my terminal, hitting cat and pressing the up-arrow gives ^[[A, in C it seems to be \033[A, etc. The latter part, the [A, remains the same, but the code for the preceding Escape can be in hex(beginning with an x), octal (beginning with a 0), or decimal(no lead in number).
Then I opened the python console, and plugged in the triples I had previously received, trying to find their character values. As it turned out, chr(27) gave \x1b, chr(91) gave [, and calling chr on 65,66,67,68 returned A,B,C,D respectively. Then it was clear: \x1b was the escape-code!
Then I noted that an arrow key, in ANSI represented as a triple, is of course represented as three characters, so I needed to amend my code so as to read in three characters at a time. Here is the result:
import sys,tty,termios
class _Getch:
def __call__(self):
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(3)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
def get():
inkey = _Getch()
while(1):
k=inkey()
if k!='':break
if k=='\x1b[A':
print "up"
elif k=='\x1b[B':
print "down"
elif k=='\x1b[C':
print "right"
elif k=='\x1b[D':
print "left"
else:
print "not an arrow key!"
def main():
for i in range(0,20):
get()
if __name__=='__main__':
main()
I am using Mac and I used the following code and it worked well: I got the values for my arrow keys as 0,1,2,3 (Up, Down, Left, Right): Always good to remember code 27 for ESC key too. Best regards!
while True:
key = cv2.waitKey(1) & 0xFF
# if the 'ESC' key is pressed, Quit
if key == 27:
quit()
if key == 0:
print "up"
elif key == 1:
print "down"
elif key == 2:
print "left"
elif key == 3:
print "right"
# 255 is what the console returns when there is no key press...
elif key != 255:
print(key)
In your terminal (or anacoonda prompt) run this command to install pynput library:
pip install pynput
And, in your editor
from pynput import keyboard
from pynput.keyboard import Key
def on_key_release(key):
if key == Key.right:
print("Right key clicked")
elif key == Key.left:
print("Left key clicked")
elif key == Key.up:
print("Up key clicked")
elif key == Key.down:
print("Down key clicked")
elif key == Key.esc:
exit()
with keyboard.Listener(on_release=on_key_release) as listener:
listener.join()
More info
By using listeners you will not have to play an infinite loop. Which I think is more elegant. This code will help you:
from pynput import keyboard
def on_press(key):
if key == keyboard.Key.up:
print('PRESSED')
if key == keyboard.Key.esc:
listener.stop()
with keyboard.Listener(on_press=on_press) as listener:
listener.join()
Note that with 'keyboard.Key' you can detect the key that you want. You can even reproduce the case of holding two keys at the same time and detecting a combination!
curses is exactly what you want. In fact I believe vim implements its interface with curses.
Try to put the following code into a file called test_curses.py:
import curses
screen = curses.initscr()
screen.addstr("Hello World!!!")
screen.refresh()
screen.getch()
curses.endwin()
Now open a terminal (not IDLE! a real terminal!) and run it via:
python test_curses.py
You should see that the terminal was cleared and an Hello World!!! writing appeared. Press any key and the program will stop, restoring the old terminal contents.
Note that the curses library isn't as easy and "user-friendly" as you may be accustomed to. I suggest reading the tutorial (unfortunately for the C language, but the python interface is mostly the same)
I know that I'm late to the party, but I really liked click package mentioned by @elbaschid. I don't know why he wasn't upvoted - maybe because his example doesn't show how to handle specifically cursor keys.
Here is my $0.02 on that:
#!/usr/bin/python
import click
printable = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
while True:
click.echo('Continue? [yn] ', nl=False)
c = click.getchar()
click.echo()
if c == 'y':
click.echo('We will go on')
elif c == 'n':
click.echo('Abort!')
break
elif c == '\x1b[D':
click.echo('Left arrow <-')
elif c == '\x1b[C':
click.echo('Right arrow ->')
else:
click.echo('Invalid input :(')
click.echo('You pressed: "' + ''.join([ '\\'+hex(ord(i))[1:] if i not in printable else i for i in c ]) +'"' )
This handles cursor keys and as a bonus prints py-string representation of any keyboard shortcut it doesn't yet recognize. For example Ctrl-s is "\x13". You can later use it inside another
elif c == ??
I've tried to add edit to @elbaschid answer but it was rejected ยฏ\_(ใ)_/ยฏ. Please give him credit if you also like my answer
Awesome library for quick command-line prototyping.
I'm making a code to take a simulate a press key when a certain color is detected, now I've made the code up until I started to integrate the keyboard library.
Does the library work with arrow keys?
Since I'm not getting any response out of them unfortunately. Tried with other keys and functions and it works just fine.This is one of my snippets:
if right_arrow[0] == 176 and right_flag == 0:
print("right") keyboard.press_and_release('right')
right_flag = 1Am I doing something wrong?
System sends to programs information about pressed key ("events") only when key changes state from not-pressed to pressed or from pressed to not-pressed (released). It doesn't send events when you hold down key.
You have to use onkeypressed() to set arrow_up_pressed = True and onkeyreleased() to reset arrow_up_pressed = False and ontimer() to run repeatedly code which checks if arrow_up_pressed is True and move object up. The same you should do with arrow_down_pressed, etc.
Or you can use variable speed instead of arrow_up_pressed and arrow_down_pressed so you can assing +15 or -15 to the same variable (or 0 when keys are released). And again you need ontimer to run repeatedly code which add speed to position.
In example I use second method.
Minimal working code
import turtle
def paddle_a_up():
global a_speed_y
a_speed_y = +15
def paddle_a_down():
global a_speed_y
a_speed_y = -15
def paddle_a_left():
global a_speed_x
a_speed_x = -15
def paddle_a_right():
global a_speed_x
a_speed_x = +15
def paddle_a_stop_y():
global a_speed_y
a_speed_y = 0
def paddle_a_stop_x():
global a_speed_x
a_speed_x = 0
def update_frame():
x, y = paddle_a.position()
y += a_speed_y
x += a_speed_x
paddle_a.goto(x, y)
# here update position for other objects - ie. move ball
# run again after 50ms
wn.ontimer(update_frame, 50) # 50ms means ~20 FPS (Frames Per Second) (1000/50 = 20)
# --- main ---
# default values at start
a_speed_x = 0
a_speed_y = 0
wn = turtle.Screen()
paddle_a = turtle.Turtle()
# run first time after 50ms
wn.ontimer(update_frame, 50) # 50ms means ~20 FPS (Frames Per Second) (1000ms / 50ms = 20)
# binds
wn.onkeypress(paddle_a_up, "Up")
wn.onkeypress(paddle_a_down, "Down")
wn.onkeypress(paddle_a_left, "Left")
wn.onkeypress(paddle_a_right, "Right")
wn.onkeyrelease(paddle_a_stop_y, "Up")
wn.onkeyrelease(paddle_a_stop_y, "Down")
wn.onkeyrelease(paddle_a_stop_x, "Left")
wn.onkeyrelease(paddle_a_stop_x, "Right")
wn.listen()
wn.mainloop()
BTW: The same way you would have to do this in PyGame or Pyglet.
You get better result if you add/substract value to speed instead of assigning - because when you press left and right at the same time then it will stop move (because speed +15 and -15 will gives 0), and when you release only one - ie. left - then it will again move right. In previous version when you release one but you still keep pressed other then it doesn't move again.
import turtle
def paddle_a_up_pressed():
global a_speed_y
a_speed_y += 15
def paddle_a_down_pressed():
global a_speed_y
a_speed_y -= 15
def paddle_a_left_pressed():
global a_speed_x
a_speed_x -= 15
def paddle_a_right_pressed():
global a_speed_x
a_speed_x += 15
def paddle_a_up_released():
global a_speed_y
a_speed_y -= 15
def paddle_a_down_released():
global a_speed_y
a_speed_y += 15
def paddle_a_left_released():
global a_speed_x
a_speed_x += 15
def paddle_a_right_released():
global a_speed_x
a_speed_x -= 15
def update_frame():
x, y = paddle_a.position()
x += a_speed_x
y += a_speed_y
paddle_a.goto(x, y)
# run again after 50ms
wn.ontimer(update_frame, 50) # 50ms means ~20 FPS (Frames Per Second) (1000/50 = 20)
# --- main ---
# default values at start
a_speed_x = 0
a_speed_y = 0
wn = turtle.Screen()
paddle_a = turtle.Turtle()
# run first time after 50ms
wn.ontimer(update_frame, 50) # 50ms means ~20 FPS (Frames Per Second) (1000/50 = 20)
# binds
wn.onkeypress(paddle_a_up_pressed, "Up")
wn.onkeypress(paddle_a_down_pressed, "Down")
wn.onkeypress(paddle_a_left_pressed, "Left")
wn.onkeypress(paddle_a_right_pressed, "Right")
wn.onkeyrelease(paddle_a_up_released, "Up")
wn.onkeyrelease(paddle_a_down_released, "Down")
wn.onkeyrelease(paddle_a_left_released, "Left")
wn.onkeyrelease(paddle_a_right_released, "Right")
wn.listen()
wn.mainloop()
The tail end of the existing answer is good, suggesting an update loop with decoupled event handlers.
But I'd go a step further. Instead of applying movement in the key handlers as done in that answer, I'd only record which keys are pressed in the handler. Then handle movement fully in the update loop based on which keys are pressed for that frame.
You can also take advantage of dicts, sets and loops to avoid repetition.
from turtle import Screen, Turtle
def update_frame():
x, y = paddle_a.position()
for key in keys:
dx, dy = movements[key]
x += dx
y += dy
paddle_a.goto(x, y)
wn.ontimer(update_frame, 1000 // 30)
def bind(key):
wn.onkeypress(lambda: keys.add(key), key)
wn.onkeyrelease(lambda: keys.remove(key), key)
step_size = 8
movements = {
"Up": (0, step_size),
"Down": (0, -step_size),
"Left": (-step_size, 0),
"Right": (step_size, 0),
}
keys = set()
paddle_a = Turtle()
wn = Screen()
for key in movements.keys():
bind(key)
wn.listen()
update_frame()
wn.exitonclick()
See also:
- How to bind several key presses together in turtle graphics?
- How do I add collision between two player controlled turtles