Simultaneous mouse press events in Python using Pynput - python

I am using scrcpy to mirror an Android phone to my computer in order to play a game. The issue is that scrcpy does not support keyboard mapping natively, so I'm writing a Python script to map the keyboard to execute the key presses I need to play the game (using WASD to move around, space to jump, etc.).
I'm fairly new to programing in general and to Python in particular, but so far it's been going pretty well using Pynput. Basically, I am mapping different keys on my keyboard to correspond to mouse clicks on different areas of the screen. My issue is that, as written, my script can only push one left mouse press event at a time.
For example, pressing "w" (to move forward) and space (jump) at the same time will move the cursor to different areas on the screen, and will therefore not result in the desired outcome. The game itself supports simultaneous touch input when played on an Android screen (I can press different areas on the screen at the same time to execute certain actions), so ideally I would need my script to be able to recreate this behavior.
I was wondering if there was a way to do this in Python?
from pynput.mouse import Button, Controller
from pynput.keyboard import Key, KeyCode, Listener
global MOUSE
MOUSE = Controller()
global CENTER
global HEIGHT
CENTER = 315
HEIGHT = 800
global LISTEN
def cust_click(x,y):
MOUSE.position = (x,y)
MOUSE.press(Button.left)
def cust_mvmt_click(x, y):
MOUSE.position = (CENTER, HEIGHT)
MOUSE.press(Button.left)
MOUSE.move(x, y)
#WASD movement
def w():
cust_mvmt_click(0, -100)
def s():
cust_mvmt_click(0, 100)
def a():
cust_mvmt_click(-100, 0)
def d():
cust_mvmt_click(100, 0)
#Miscellaneous
def space():
cust_click(CENTER*5.75,HEIGHT*0.95)
def c():
cust_click(CENTER*5.15, HEIGHT*1.2)
#Weapon controls
def r():
cust_click(CENTER*4.75, HEIGHT*1.15)
def f():
cust_click(CENTER*0.5, HEIGHT*0.7)
def ctrl():
cust_click(CENTER*5.15, HEIGHT)
def q():
cust_click(CENTER*5.3, HEIGHT*0.77)
def switch1():
cust_click(CENTER*2.75, HEIGHT*1.15)
def switch2():
cust_click(CENTER*3.3, HEIGHT*1.15)
def switch3():
cust_click(CENTER*3, HEIGHT*1.05)
def on_press(key):
if key == KeyCode(char='w'):
w()
elif key == KeyCode(char='f'):
f()
elif key == Key.shift_l:
ctrl()
elif key == KeyCode(char='q'):
q()
elif key == KeyCode(char='s'):
s()
elif key == KeyCode(char='a'):
a()
elif key == KeyCode(char='d'):
d()
elif key == KeyCode(char='c'):
c()
elif key == KeyCode(char='r'):
r()
elif key == Key.space:
space()
elif key == KeyCode(char='1'):
switch1()
elif key == KeyCode(char='2'):
switch2()
elif key == KeyCode(char='3'):
switch3()
elif key == Key.tab:
LISTEN.stop()
def on_release(key):
if key == Key.shift_l or key == KeyCode(char='1') or key == KeyCode(char='f') or key == KeyCode(char='2') or key == KeyCode(char='3') or key == KeyCode(char='r') or key == KeyCode(char='c') or key == KeyCode(char='s') or key == KeyCode(char='a') or key == KeyCode(char='d') or key == Key.space or key == KeyCode(char='q') or key == KeyCode(char='w'):
MOUSE.release(Button.left)
MOUSE.position = (CENTER*390/100,HEIGHT*70/100) #1235, 565
# Collect events until released
with Listener(
on_press=on_press,
on_release=on_release) as LISTEN:
LISTEN.join()

You can use pydirectinput or pydirectinput-rgx for clicking. Check
https://www.google.com/url?sa=t&source=web&rct=j&url=https://pypi.org/project/PyDirectInput/&ved=2ahUKEwi9sbb7w6b6AhXE23MBHV85ChgQFnoECBEQAQ&usg=AOvVaw2EChi0UGXZlMafbw1aHhod
for its documentation.

Related

How to use long key presses in python and raspberry pi?

I have a raspberry pi with a few motors. I have tried pynput but when I hold a button it continuously activates the function. I want to make it activate a function until I let go of the button. How would I go about doing that?
This is the janky code I have right now.
def show(key):
if key == Key.delete:
return False
elif key == Key.up:
print("forward")
left_turn(0.1)
elif key == Key.right:
print("right")
forward(0.1)
elif key == Key.left:
print("left")
reverse(0.1)
elif key == Key.down:
print("reverse")
right_turn(0.1)
# Collect all event until released
with Listener(on_press = show) as listener:
listener.join()

User key keyboard input

How do I get a user keyboard input with python and print the name of that key ?
e.g:
user clicked on "SPACE" and output is "SPACE"
user clicked on "CTRL" and output is "CTRL".
for better understanding i'm using pygame libary. and i built setting controller for my game. its worked fine but i'm able to use only keys on my dict. i dont know how to add the other keyboard keys.
see example:
class KeyboardSettings():
def __init__(self,description,keyboard):
self.keyboard = keyboard
self.default = keyboard
self.description = description
self.active = False
def activate_change(self,x,y):
fixed_rect = self.rect.move(x_fix,y_fix)
pos = pygame.mouse.get_pos()
if fixed_rect.collidepoint((pos)):
if pygame.mouse.get_pressed()[0]:
self.active = True
elif pygame.mouse.get_pressed()[0]:
self.active = False
This is a part of my class. in my script i loading all related object to that class. the related object are the optional keys in the game.
e.g
SHOOT1 = KeyboardSettings("SHOOT","q")
move_right = KeyboardSettings("move_right","d")
#and more keys
key_obj_lst = [SHOOT1,move_right....]
#also i built a dict a-z, 0,9
dict_key = { 'a' : pygame.K_a,
'b' : pygame.K_b,
'c' : pygame.K_c,
...
'z' : pygame.K_z,
'0' : pygame.K_0,
...
'1' : pygame.K_1,
'9' : pygame.K_9,
then in game loop:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
for k in key_obj_lst:
#define each key by user
if k.active:
k.keyboard = event.unicode
default = False
if k.keyboard in dict_key:
if event.key == dict_key[k.keyboard]:
if k.description == 'Moving Right':
moving_right = True
if k.description == 'SHOOT':
SHOOT = True
The code worked perfectly but i trully dont know how to add keys that not letters and numbers such as "ENTER","SPACE" etc.
pygame provides a function for getting the name of the key pressed:
pygame.key.name
And so you can use it to get the name of the key, there is no need to use a dictionary for this:
import pygame
pygame.init()
screen = pygame.display.set_mode((500, 400))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
if event.type == pygame.KEYDOWN:
key_name = pygame.key.name(event.key)
print(key_name)
pip install keyboard
import keyboard #use keyboard module
while True:
if keyboard.is_pressed('SPACE'):
print('You pressed SPACE!')
break
elif keyboard.is_pressed("ENTER"):
print("You pressed ENTER.")
break
Use keyboard module
import keyboard
while True:
print(f"You pressed {keyboard.get_hotkey_name()})

Make a "Key Released" In Python With No Library?

I have been trying to use some "key released" functions from libraries like pynput and so, but I ran in to the problem that if I try using them together with a library called pyglet, that is a library for window-based apps, it won't let me and the program would crash.
I was wondering if there is any way detect key releases without libraries.
P.S: I've tried using the on_key_release function from pyglet but it was buggy for me and even though I wrote something for it to upon key release it usually didn't do it. I have checked my code a thousand times and it's not a problem on my part.
Pressing = False # var to indicate when the user is doing a long press and when he is not
#window.event
def on_key_release(symbol, modifiers):
global Pressing
if((symbol == key.A) | (symbol == key.S) | (symbol == key.W) | (symbol == key.D)):
Pressing = False
pass
and that code causes my player to freeze after i start moving him, and it does this even if i do nothing and just leach the whole on_key_release dunction empty. really weird.
So, your issue is most likely that you're doing Pressing = False if any key is released. Forcing your player object to freeze due to Pressing being False as soon as you release any of your keys.
To work around this, you should store the states of your keys in a variable (I'll call it self.keys), and just before you render stuff, update/check the keys and update your player object accordingly.
Here's a working example of movement on a player object (a red square in this case):
from pyglet import *
from pyglet.gl import *
key = pyglet.window.key
class main(pyglet.window.Window):
def __init__ (self, width=800, height=600, fps=False, *args, **kwargs):
super(main, self).__init__(width, height, *args, **kwargs)
self.x, self.y = 0, 0
self.keys = {}
self.mouse_x = 0
self.mouse_y = 0
square = pyglet.image.SolidColorImagePattern((255, 0, 0, 255)).create_image(40, 40)
self.player_object = pyglet.sprite.Sprite(square, x=self.width/2, y=self.height/2)
self.alive = 1
def on_draw(self):
self.render()
def on_close(self):
self.alive = 0
def on_mouse_motion(self, x, y, dx, dy):
self.mouse_x = x
def on_key_release(self, symbol, modifiers):
try:
del self.keys[symbol]
except:
pass
def on_key_press(self, symbol, modifiers):
if symbol == key.ESCAPE: # [ESC]
self.alive = 0
self.keys[symbol] = True
def render(self):
self.clear()
## Movement logic,
# check if key.W is in self.keys (updated via key_press and key_release)
if key.W in self.keys:
self.player_object.y += 1
if key.S in self.keys:
self.player_object.y -= 1
if key.A in self.keys:
self.player_object.x -= 1
if key.D in self.keys:
self.player_object.x += 1
self.player_object.draw()
self.flip()
def run(self):
while self.alive == 1:
self.render()
# -----------> This is key <----------
# This is what replaces pyglet.app.run()
# but is required for the GUI to not freeze
#
event = self.dispatch_events()
if __name__ == '__main__':
x = main()
x.run()
I've moved away from #window.event because it's easier for me to just copy paste this class/inheritance example since I had it laying around. But you could apply this logic any way you want. Just make sure you don't defined a solid state of pressing or not pressing, check individual keys and update accordingly before you render.

How do I make it so that while a key is pressed and another key is released an action occurs? (Pygame/python)

So basically I'm making a quiz game in which the user must "lock in" their answer. In order to do that the user must press a certain key while pressing another. For example: holding the "w" key while pressing and letting go of the space bar.But when I try to achieve this, nothing happens. Here is what I have so far:
if (event.type == pygame.KEYDOWN) and (event.key == pygame.K_w) and (event.type == pygame.KEYUP) and (event.key == pygame.K_SPACE):
print(1)
why doesn't this work?
One way is to use pygame.key.get_pressed(). Example -
keys = pygame.keys.get_pressed()
if keys[pygame.K_w] and keys[pygame.K_SPACE]:
print(1)
EDIT : This is how I implemented it -
#!/usr/bin/python3
import pygame
from pygame.locals import *
from sys import exit
#initializing variables
pygame.init()
screen=pygame.display.set_mode((640,480),0,24)
pygame.display.set_caption("Key Press Test")
f1=pygame.font.SysFont("comicsansms",24)
#main loop which displays the pressed keys on the screen
while True:
for i in pygame.event.get():
a=100
screen.fill((255,255,255))
if pygame.key.get_focused():
press=pygame.key.get_pressed()
# checking if they are pressed at the same time or not.
if press[pygame.K_w] and press[pygame.K_SPACE]:
print (1)
for i in xrange(0,len(press)):
if press[i]==1:
name=pygame.key.name(i)
text=f1.render(name,True,(0,0,0))
screen.blit(text,(100,a))
a=a+100
pygame.display.update()
question_num = general_knowlege_questions[0]
keys = pygame.key.get_pressed()
if keys[pygame.K_w] and (General_knowledge[question_num][5] == "a"):
test = 1
if keys[pygame.K_d] and (General_knowledge[question_num][5] == "b"):
test = 1
if keys[pygame.K_s] and (General_knowledge[question_num][5] == "c"):
test = 1
if keys[pygame.K_a] and (General_knowledge[question_num][5] == "d"):
test = 1
so basically this is my code to recognize my answer for the quiz, but it ends up not recognizing the correct answer. Btw the General_knowledge variable is a list, question number is self explanitory and 5 is the index that contains the answer.

Tkinter getting key pressed event from a function

I have the following code,
If I press 'Left Arrow Key', it only prints move player to left
But I need a functionality in which pressing the given arrow key moves the player in the given direction.
Is there a way in which I can detect key press event in my move_dir function
PS: fairly new to python
import Tkinter as tk
move = 1
pos = -1
def move_dir():
global move
global pos
while move ==1:
if pos == 0:
print 'move player to left'
elif pos == 1:
print 'move player to right'
elif pos == -1:
print 'stop moving!'
def kr(event):
global move
global pos
global root
if event.keysym == 'Right':
move = 1
pos = 0
move_dir()
print 'right ended'
elif event.keysym == 'Left':
move = 1
pos = 1
move_dir()
print 'left ended'
elif event.keysym == 'Space':
move = 0
move_dir()
elif event.keysym == 'Escape':
root.destroy()
root = tk.Tk()
print( "Press arrow key (Escape key to exit):" )
root.bind_all('<KeyRelease>', kr)
root.mainloop()
If you're wanting to animate something, you should use after to set up an animation loop. An animation loop looks like this:
def animate():
<draw one frame of your animation>
after(<delay>, animate)
You can put whatever code you want to draw a frame. In your case it sounds like you want to move something left or right. The <delay> parameter defines your frame rate. For example, to get 30FPS your delay would be about 33 (1000ms / 30). The only important thing to be aware of is that <draw one from of your animation> needs to run pretty quickly (10's of milliseconds or less) in order to not block the GUI.
For your particular problem, you can set a variable to define the direction when the user presses a key, then unset the variable when they release the key. Your event handler and animate function might look something like this:
def animate():
if direction is not None:
print "move player to the ", direction
after(33, animate)
def on_keypress(event):
global direction
if event.keysym == "Left":
direction = "left"
elif event.keysum == "right":
direction = "right"
def on_keyrelease(event):
global direction
direction = None
See how that works? When you press a key it defines the direction. Then, every 33 milliseconds you check for the direction, and move your player if the direction is defined. When the user releases the button, the direction becomes undefined and the movement stops.
Putting it all together, and using a class to avoid using global variables, it looks something like the following. This creates a ball on a canvas which you can move left, right, up and down:
import Tkinter as tk
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.direction = None
self.canvas = tk.Canvas(width=400, height=400)
self.canvas.pack(fill="both", expand=True)
self.canvas.create_oval(190, 190, 210, 210,
tags=("ball",),
outline="red", fill="red")
self.canvas.bind("<Any-KeyPress>", self.on_press)
self.canvas.bind("<Any-KeyRelease>", self.on_release)
self.canvas.bind("<1>", lambda event: self.canvas.focus_set())
self.animate()
def on_press(self, event):
delta = {
"Right": (1,0),
"Left": (-1, 0),
"Up": (0,-1),
"Down": (0,1)
}
self.direction = delta.get(event.keysym, None)
def on_release(self, event):
self.direction = None
def animate(self):
if self.direction is not None:
self.canvas.move("ball", *self.direction)
self.after(50, self.animate)
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
EDIT 4
You have a while loop that you want to combine with the Tkinter mainloop.
In this case you want to move when the key is pressed and stop moving when a key is released.
The code below allows you to do this:
import Tkinter as tk
from guiLoop import guiLoop # https://gist.github.com/niccokunzmann/8673951#file-guiloop-py
direction = 0
pos = 0 # the position should increase and decrease depending on left and right
# I assume pos can be ... -3 -2 -1 0 1 2 3 ...
#guiLoop
def move_dir():
global pos
while True: # edit 1: now looping always
print 'moving', direction
pos = pos + direction
yield 0.5 # move once every 0.5 seconds
def kp(event):
global direction # edit 2
if event.keysym == 'Right':
direction = 1 # right is positive
elif event.keysym == 'Left':
direction = -1
elif event.keysym == 'Space':
direction = 0 # 0 is do not move
elif event.keysym == 'Escape':
root.destroy()
def kr(event):
global direction
direction = 0
root = tk.Tk()
print( "Press arrow key (Escape key to exit):" )
root.bind_all('<KeyPress>', kp)
root.bind_all('<KeyRelease>', kr)
move_dir(root)
root.mainloop()
To see how this is implemented you can read the source code or read the second answer by Bryan Oakley.
EDIT 3
There is no way to detect a keypress in the move_dir function directly.
You can use root.update() in your move_dir function to make it possible for kr, kp to be executed when root.update is called. root.update() alse repaints the windows so that changes can be seen by the user.
root.mainloop() can be seen as while True: root.update()

Categories

Resources