Your thing of using keyboard.press('w') works, but it just doesn't show as it would when you hold a key. You can test this with some kind of game that uses "w" as a movement key, then running your script and you should move forwards for the said amount of time.
Your thing of using keyboard.press('w') works, but it just doesn't show as it would when you hold a key. You can test this with some kind of game that uses "w" as a movement key, then running your script and you should move forwards for the said amount of time.
I think that the keyboard module is not as good of a choice to hold the key down as @Alderven mentioned, but it is great for detecting key presses instead if that helps your code. I would recommend using pyautogui. For example:
import pyautogui
import time
def accelerate():
pyautogui.keyDown('w') #holds the key down
time.sleep(5) #could be replaced with detecting an input
pyautogui.keyUp('w') #releases the key
return 0
Note: When you run the program, in the shell, there will not be a bunch of w's being typed as you'd expect, like this: wwwwwwwwwwwwwwwwwww. Instead, at least for me, only one w was pressed. I don't know why this occurs, although I can tell you that the key w is being pressed and this is NOT an error. I know this because I tried playing a game that involved pressing the key w (just an online web browser racing game), and the code worked. If you truly wanted the output "wwwwwwwwwwwwwwwwwwwwwwwwwww", then you can just use pyautogui's write() function:
pyautogui.write("wwwwwwwwwwwwwwwwwwwwwwwwwwwwww")
and there you go. Since you were referring to a racing game that doesn't involve getting a string of w's, this probably doesn't apply to your code.
If you want to wait for a certain input instead of holding down the key for a certain amount of time like I did, you could instead replace this:
time.sleep(5)
with this:
while True:
if keyboard.is_pressed('del')
break
You would have to import the keyboard module for that to work, since pyautogui cannot detect key presses.
Pynput is another great choice of module besides pyautogui, and there are a lot of other great Stack Overflow posts about pyautogui and pynput, so if this solution doesn't work, you should check those out if you haven't already. It would also help if you clarified about the context of the code, as mentioned by @OysterShucker. If it is a racing game AI, why does it need the user to input the del key so the AI knows when to release the w key, and why not automate it? Those are questions that I would recommend answering.
keypress - Key Presses in Python - Stack Overflow
python - Win32api: Press and Hold key - Stack Overflow
How to make a script that will hold down a key for x seconds
python - How to hold keys down with pynput? - Stack Overflow
Videos
ยป pip install keyboard
Install the pywin32 extensions. Then you can do the following:
import win32com.client as comclt
wsh= comclt.Dispatch("WScript.Shell")
wsh.AppActivate("Notepad") # select another application
wsh.SendKeys("a") # send the keys you want
Search for documentation of the WScript.Shell object (I believe installed by default in all Windows XP installations). You can start here, perhaps.
EDIT: Sending F11
import win32com.client as comctl
wsh = comctl.Dispatch("WScript.Shell")
# Google Chrome window title
wsh.AppActivate("icanhazip.com")
wsh.SendKeys("{F11}")
You could also use PyAutoGui to send a virtual key presses.
Here's the documentation: https://pyautogui.readthedocs.org/en/latest/
import pyautogui
pyautogui.press('Any key combination')
You can also send keys like the shift key or enter key with:
import pyautogui
pyautogui.press('shift')
Pyautogui can also send straight text like so:
import pyautogui
pyautogui.typewrite('any text you want to type')
As for pressing the "A" key 1000 times, it would look something like this:
import pyautogui
for i in range(999):
pyautogui.press("a")
alt-tab or other tasks that require more than one key to be pressed at the same time:
import pyautogui
# Holds down the alt key
pyautogui.keyDown("alt")
# Presses the tab key once
pyautogui.press("tab")
# Lets go of the alt key
pyautogui.keyUp("alt")
Try to hold your keys by using the "with" statement. In my example it holds "alt" and tabs around.
import time
from pynput.keyboard import Key, Controller
keyboard = Controller()
with keyboard.pressed(Key.alt):
keyboard.press(Key.tab)
time.sleep(1)
keyboard.press(Key.tab)
time.sleep(1)
keyboard.press(Key.tab)
time.sleep(1)
You could make a two second loop. (I don't have enough reputation to comment.)
I want pyautogui.keyDown at the same time with 'a' and 'k' and release them together I tried this but understandably there is super small delay between each keyDown
pyautogui.keyDown('a')
pyautogui.keyDown('k')
I tried pyautogui.hotkey but it will instantly press nad release those keys I cant use it as I want to keep keys pressed for a certain period of time.
I am trying to write a Python program to hold down a key event to control a game. I tried this code:
import win32api
import win32con
import time
keys = {
"left" = win32con.VK_LEFT
"right" = win32con.VK_RIGHT
"up" = win32con.VK_UP
"down" = win32con.VK_DOWN
}
def press_key(key, delay=0.1):
if key in keys:
win32api.keybd_event(keys[key], 0, win32con.KEYEVENTF_EXTENDEDKEY, 0)
time.sleep(delay)
win32api.keybd_event(keys[key], 0, win32con.KEYEVENTF_KEYUP, 0)
else:
print("KEY NOT AVAILABLE")
press_key("left", 5)
If I understand correctly, this is supposed to hold the key for delay time and then stop. However, this only registers one press, waits the delay, and then ends. Did I misinterpret what KEYEVENTF_EXTENDEDKEY meant or is there another reason this code only half-works? I tried searching on StackOverflow, but all the solutions given didn't work for me.
Edit: Things I've tried: Replacing KEYEVENTF_EXTENDEDKEY with 0, got the same result.
Edit: WORKING CODE:
def press_key(key, delay=0):
if key in keys:
win32api.keybd_event(keys[key], 0, 0, 0)
stop = time.time() + delay
while time.time() < stop:
time.sleep(0.01)
win32api.keybd_event(keys[key], 0, 0, 0)
win32api.keybd_event(keys[key], 0, win32con.KEYEVENTF_KEYUP, 0)
time.sleep(0.1)
else:
print("KEY NOT AVAILABLE")One of the simplest way I found is to use pynput module.can be found here with nice examples as well
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()
above is the example worked out for me and to install, go
sudo pip install pynput (pip3 if python3.*)
it's actually really simple. just a few lines of code, and its done!
from turtle import *
def a():
print("key is pressed!")
forward(5)
def b():
print("key is not pressed!")
backward(30)
listen()
onkeypress(a," ")
onkeyrelease(b," ")
you can replace " " with any key of your choice, surrounded in "" examples: "a","h","e","Up","y"
Hello, I'm very new to coding and I want to make my program hold down a key like a person would on a keyboard.
I'm currently using pynput like
keyboard.press(button) time.sleep(random.uniform(3, 5)) keyboard.release(button)
But it doesn't hold the key down. It's just one key press. And if I simulate it by using a loop, it still behave different then holding a key on a real keyboard.
Because holding a key on a real keyboard outputs one letter, then a small delay and then it starts printing the letters fast.
Anyone knows the soluion?
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