Win32api: Press and Hold key - python

I'm looking for a way to press a key and hold it for a specific amount of time. I have tried:
# Method 1
shell = win32com.client.Dispatch("WScript.Shell")
shell.SendKeys
# Method 2
win32api.SendMessage
# Method 3
win32api.keybd_event
All of these methods, only seem to press a key once. I need to hold the key down.
I have looked at these resources: python simulate keydown (SO), win32api.keybd_event, press-and-hold-with-pywin32 (SO), simulate-a-hold-keydown-event-using-pywin32 (SO), Vitual keystroke (Github)

If you can use PyAutoGUI, this would do it:
import pyautogui
import time
def hold_key(key, hold_time):
start = time.time()
while time.time() - start < hold_time:
pyautogui.keyDown(key)
hold_key('a', 5)
It will keep the 'a' key pressed for 5 seconds.

Related

How could I make a dash in a 2D pygame python program?

If the pygame program is just a basic entity you can move normally with arrow keys, how could i make it so that if space is pressed, based on the arrow key that was being held at the moment of pressing, a player dashes slightly to the specified direction? My idea is that when the space is pressed, program checks if other keys are being held down and based on that it rapidly increases the x and/or y coordinate and then stops at specific time, but I don't know how to make it stop as all of this is happening inside a main game loop. Any insight is highly appreciated.
You can use time.perf_counter.
So for using that function you will need to import module time
import time
And now you can store the value of time.perf_counter in a variable when space is pressed.
import time
jumping = False
start_time = 0
while True:
if ("space is pressed"): # Replace condition with what you want
jumping = True
start_time = time.perf_counter()
# Add your code here
if jumping:
# change of x, y and other jumping mechanism code here
if jumping and time.perf_counter() - start_time > 1: # Replace 1 with the amount you want this if condition to trigger, also add value in seconds
jumping = False
I'm not sure what your code is like, but this is how I'd go about it:
def dash(self):
keys = pygame.keys.get_pressed()
if keys[pygame.K_SPACE] and not self.dashing and self.jumping:
# ^^ Can be any key
if self.facing_right:
self.x += 20
if self.facing_left:
self.x -= 20
self.dashing = True
Make sure that when you hit the ground it does self.dashing = False else you will be able to dash forever.
Just put this function in the player class if you are doing it OOP.
Else if you are not using classes, put it anywhere in the file and take out all self..

Python simple counting script

Im trying to make a script that automatically counts and uses SendKeys to print out a range of numbers ,say 1 - 100. I can make the list but I dont know how to convert the numbers so SendKeys can type them out because so far I can only make it type keys.
from pynput.keyboard import Key, Controller
import time
keyboard = Controller()
count = 0
for i in range (1, 100) :
count = count + 1
time.sleep(5)
keyboard.press(i)
keyboard.release(i)
You're basically there. You don't need count, and you need to send the string of the key you want to press, and presumably a new line. As a shortcut you could use the Controller.type method.
from pynput.keyboard import Controller, Key
import time
keyboard = Controller()
def send_range(start, end, wait_time):
for i in range(start, end+1):
keyboard.type(str(i))
keyboard.press(Key.enter)
time.sleep(wait_time)
send_range(1, 100, 5)
import time
from pynput.keyboard import Controller
keyboard = Controller()
for i in range(0,101):
keyboard.type(str(i)+'\n')
time.sleep(5)
Remove '\n' if u want to print in same line
If you want the easiest solution, you can use keyboard.type() to send the characters in the integer one after another.
from pynput.keyboard import Controller, Key
import time
keyboard = Controller()
for i in range(1,100):
time.sleep(5)
keyboard.type(i)
If you still want to use keyboard.press() and keyboard.release(), for example if you want to sleep between each key press rather than between each integer in the list, then you can convert your integer into a string and then iterate through the string, like so
from pynput.keyboard import Controller, Key
import time
keyboard = Controller()
for i in range(1,100):
time.sleep(5)
for j in str(i):
keyboard.press(j)
keyboard.release(j)

I need the "if" to go once but not end the loop

I'm making a program to control the mouse with WASD but whenever I press the button the mouse just moves to the top of the screen when I need it to move slightly then be able to move again if I press the key again
I've tried to have the loop turn off then back on but it just ends the loop before it can switch back on.
import keyboard
from pynput.mouse import Controller
mouse = Controller()
repeat = True
while repeat:
if keyboard.is_pressed('w'):
mouse.move(0, -5)
if keyboard.is_pressed('s'):
mouse.move(0, 5)
I need it to move up slightly when I press w but stop when it isn't pressed so I can press it again.
You might want your keyboard not to be so sensitive, so you may need to sample the pressing time. sleep can help in this case. In the code below, the program will sleep for 0.2 seconds every time it enters while loop.
import keyboard
import time
repeat = True
while repeat:
time.sleep(0.2)
if keyboard.is_pressed('w'):
mouse.move(0, -5)
if keyboard.is_pressed('s'):
mouse.move(0, 5)
# do something
EDIT: I was misunderstanding what you want, just sleep is enough for this. The problem is because your computer does everything too fast, so a while loop might be completed in a microsecond or less. So it sees that you are pressing the key for too long (though you think you did fast) then it just repeats the loop until you release the key. That's why your mouse always moves to the top.
Sampling is the way to tell computer "if you've done, then sleep, don't do anything else".
Another way is to count how many times it loops (ie, scaling), but it looks like dump since the computer has to do worthless things.
import keyboard
from pynput.mouse import Controller
mouse = Controller()
repeat = True
w_count, s_count = 0, 0
while repeat:
if keyboard.is_pressed('w'):
w_count += 1
if w_count == 10: # i'm scaling it
mouse.move(0, -5)
w_count = 0
if keyboard.is_pressed('s'):
s_count += 1
if s_count == 10: # i'm scaling it
mouse.move(0, 5)
s_count = 0
There are also other ways: measure the pressing time, edge detection (detect key release)... You can search about "software debouncing" for more ideas and find one best fits your requirement.

Count number of times function with varying arguments executed, then reset count when ENTER key pressed

I would like to be able to count the number of times a defined function that requires a varying argument is executed, then reset that counter to 0 every time the ENTER key is pressed. I want to be able to utilize this action with the defined function below:
def draw(x):
global drawing
q.put(x)
process = False
drawingLock.acquire()
if not drawing:
process = True
drawing = True
drawingLock.release()
if process:
if not q.empty():
x()
drawingLock.acquire()
drawing = False
drawingLock.release()
This function is a queue that takes function arguments and executes them one by one, and the arguments for this function are functions that draw letters in the turtle graphics window. Additionally, this function gets called by a keypress of a certain letter that corresponds to the letter drawn. For example:
onkey(lambda: draw(draw_A), "a")
# This draws an "A" in the Turtle Graphics window when "a" is pressed on the keyboard
# If multiple "A"s pressed, it draws them one by one
How would I count how many times this draw() function has been executed by the user in the turtle graphics window, and then reset it every time the ENTER key is pressed? I have tried creating a decorator for this, but the ones I have created does not return ANYTHING with turtle graphics, and does not seem to work with functions whose arguments can vary with those chosen by the user. Any help regarding this issue is greatly appreciated! :)
Functions allow attributes:
def draw(x):
if not hasattr(draw, 'counter'):
draw.counter = 0
draw.counter += 1
# body
Catch the ENTER from the user:
def handle_enter():
draw.counter = 0
onkey(handle_enter, 'Enter')
Find out how many times it has been called:
print('`draw` has been called {} times'.format(draw.counter))

Write out only first result in while loop in psychopy

I want to print my trial onset time to my logfile. However, I need to write to the logfile within a while (timer) loop, which means what whatever I do in that loop will be done for every screen refresh.
The problem is that I only want to write the result of the first clock.getTime() call to the logfile. If I do this:
while timer.getTime() >0: # while time isn't up (turns neg when time's up)
for key in event.getKeys():
if key in ['escape']:
core.quit() # quit if they press escape
timeText.draw(window)
timeline.draw(window)
cursorImage.draw(window)
## flip so it actually appears
window.flip()
OnsetTime = clock.getTime()
logfile.write('OnsetTime, %s' % OnsetTime)
I get a bunch of lines of my logfile that say 'OnsetTime' and the time - one for every refresh.
I only want the first one to be printed, but I'm not sure how to do that.
This is just another way of doing what CasualDemon's proposing, but one which I think is more elegant (three lines of code for the logging instead of 5):
def logOnsetTime():
"""Function which allows launching this code right after a window.flip()"""
logfile.write('OnsetTime, %s' % clock.getTime())
window.callOnFlip(logOnsetTime) # runs on first flip
while timer.getTime() >0: # while time isn't up (turns neg when time's up)
for key in event.getKeys():
if key in ['escape']:
core.quit() # quit if they press escape
timeText.draw(window)
timeline.draw(window)
cursorImage.draw(window)
## flip so it actually appears.
window.flip()
If you want a log for every keypress, put the window.callOnFlip(logOnsetTime) inside the while loop. There's also a window.logOnFlip method specifically for logging, but that just saves an input string to the log, timestamped to a global clock, so it wouldn't save the time of your clock.
I think you want something like this:
while timer.getTime() >0: # while time isn't up (turns neg when time's up)
first = True
for key in event.getKeys():
if key in ['escape']:
core.quit() # quit if they press escape
timeText.draw(window)
timeline.draw(window)
cursorImage.draw(window)
## flip so it actually appears
window.flip()
OnsetTime = clock.getTime()
if first:
logfile.write('OnsetTime, %s' % OnsetTime)
first = False
However if you only want the very first one, first = True will have to be outside the While loop instead.

Categories