I wrote a simple python script that gives control over the cursor to a joystick. My way to find out how this works is documented here. Now that works flawlessly but, as soon as I start the script to use the joystick, the mouse is useless, because my python routine sets the value back to its original, whenever a new joystick event comes in.
Thus I want my joystick events to be ignored as long as a key of the keyboard is pressed. I came across the pygame.key.get_pressed() method but this seems to work only, if the pygame window is in focus. I want this script running in background. Should I start using non-pygame events to listen to the keyboard or are there ways to keep track of the keyboard events analogue to the joystick events, which are recognized in background, via pygame?
I expect pygame sets up its own "sandbox" so that it's hard to detect input from outside its window. Your previous question indicates that you are also using the win32api module. We can use that to detect global key presses.
The correct way to detect key presses at the global scope is to set up a keyboard hook using SetWindowsHookEx. Unfortunately, win32api does not expose that method, so we'll have to use a less efficient method.
The GetKeyState method can be used to determine whether a key is down or up. You can continuously check the state of a key to see if the user has pressed or released it lately.
import win32api
import time
def keyWasUnPressed():
print "enabling joystick..."
#enable joystick here
def keyWasPressed():
print "disabling joystick..."
#disable joystick here
def isKeyPressed(key):
#"if the high-order bit is 1, the key is down; otherwise, it is up."
return (win32api.GetKeyState(key) & (1 << 7)) != 0
key = ord('A')
wasKeyPressedTheLastTimeWeChecked = False
while True:
keyIsPressed = isKeyPressed(key)
if keyIsPressed and not wasKeyPressedTheLastTimeWeChecked:
keyWasPressed()
if not keyIsPressed and wasKeyPressedTheLastTimeWeChecked:
keyWasUnPressed()
wasKeyPressedTheLastTimeWeChecked = keyIsPressed
time.sleep(0.01)
Warning: as with any "while True sleep and then check" loop, this method may use more CPU cycles than the equivalent "set a callback and wait" method. You can extend the length of the sleep period to ameliorate this, but the key detection will take longer. For example, if you sleep for a full second, it may take up to one second between when you press a key and when the joystick is disabled.
when your window gains or looses focus you get an ACTIVEEVENT. It's gain and state attributes tell you which state you've gained or lost. The easisest solution would probably be to catch this events in your main event loop and use them to keep track weather you have focus or not. Then you can just ignore joystick events if you don't have the focus.
Related
import keyboard
import pygame
import mouse
import time
def press_X():
time.sleep(0.2)
keyboard.press('x')
time.sleep(0.6)
keyboard.release('x')
print('Command Executed - press_X')
#SA_R_X V_1.0
#------------------------------------------
while True:
try:
keyboard.add_hotkey('r', press_X)
time.sleep(0.5)
break
except:
keyboard.add_hotkey('r', press_X)
time.sleep(0.5)
break
the problem is the code cannot detect if 'r' is pressed when i am holding 'w' and/or 'space'... (well any key really)
I tried to use a try and except to handle a combination of any key + 'r'. But it did not work. All I need is for the code to be able to detect an 'r' input even if I am pressing/ holding another key at the same time. Then after this the code waits 0.2 seconds before holding down the 'x' key for 0.6 seconds and releasing. Any help is appreciated and it would be very helpful if you included a short explanation on where I went wrong and how you fixed it.
The documentation for this module can be found here. This is where all relevant information can be found.
The best way to do this, from my understanding, is to use an alternative function. If you want the program to continue to run, even though the key has not been pressed, then I suggest using the keyboard.on_press_key() function. This would mean that the rest of your program could still run, and your press_X() function could be run as a callback. Here is an example of how this code could be implemented.
import keyboard
import pygame
import mouse
import time
class App:
running = True
def press_X():
time.sleep(0.2)
keyboard.press('x')
time.sleep(0.6)
keyboard.release('x')
print('Command Executed - press_X')
App.running = False
#SA_R_X V_1.0
#------------------------------------------
keyboard.on_press_key('r', lambda x: press_X()) ## Adds an event listener for the r key
## This will stop execution if there is no code after this point
If you want it to stop the program and wait for the r key to be pressed, then you could use keyboard.wait(). This will basically pause your program until the key is pressed, after which your function would be run. For example, to replace the keyboard.on_press_key('r', lambda x: press_X()):
keyboard.wait('r')
press_X()
From my understanding, keyboard.add_hotkey() does not work in your situation because it is looking for an exact combination of keys being pressed, such as Ctrl+C, and will only go if only the keys in the hotkey are pressed.
I hope this helps, good luck!
I trying to move my mouse inside an FPS game (like valorant/csgo) but doesn't work.
I used PyAutoGui, PyInput, Mouse, PyWin32, and many other libs but I just can simulate a click.
I see something about Interception (by oblitum) and years ago worked but this day doesn't. The game block this intercept.
So I guess I need to build some driver intercept to make moves in Mouse. Another trick is to use Arduino (this works these days) but for my project this isn't a solution. I need to only in python with any mouse.
This depends how you want to move your mouse. I'm assuming according to however you want to move it? If so, try the first code as the second code performs based on a series of commands
Have you tried this code by #flipeador?
#from interception import Interception, MouseFilter, KeyFilter, MouseFlags,\
# MouseState, KeyState, MapVk, Vk, map_virtual_key
RUNNING = True
TIMEOUT = 2500 # ms
interception = Interception()
interception.set_mouse_filter(MouseFilter.ButtonAll)
interception.set_keyboard_filter(KeyFilter.All)
while RUNNING:
device = interception.wait_receive(TIMEOUT)
if device:
print(f'{device.get_hardware_id()}:')
# Mouse
if device.is_mouse:
print('MouseStroke(flags={1},state={2},rolling={0.rolling},x={0.x},y={0.y},info={0.info})'
.format(device.stroke, MouseFlags(device.stroke.flags).name, MouseState(device.stroke.state).name))
# Keyboard
elif device.is_keyboard:
vk = map_virtual_key(device.stroke.code, MapVk.ScToVk)
print('KeyStroke(sc={0.code:03X},vk={2:03X},state={1},info={0.info})'
.format(device.stroke, KeyState(device.stroke.state).name, vk))
# escape = terminate
if vk == Vk.Escape:
RUNNING = False
# switch x and y
elif vk == Vk.X:
device.stroke.code = map_virtual_key(Vk.Y, MapVk.VkToSc)
elif vk == Vk.Y:
device.stroke.code = map_virtual_key(Vk.X, MapVk.VkToSc)
device.send()
print('-'*100)
Do note that you are not allowed to cheat in Valorant, as it blocks a lot of "hacking" and detect if your hacking even if the program your using is not on their block list.
I'm not here to question your morality.
Definitely go the arduino(s) route (you may need two. One to receive python commands and one to emulate the mouse events. Depends on the arduino) and be sure to use some randomization everywhere.
I do question why you'd want this.
I see no fun in cheating and I can't see what you are trying to achieve with this.
Although you said it did not work for you, the package you want to use is pynput. It is possible to simulate mouse movements and clicks as stated in the docs.
from pynput.mouse import Button, Controller
mouse = Controller()
# Move pointer relative to current position
mouse.move(5, -5)
This should give you the behaviour you want.
EDIT: with anti-cheat software in place, it may be very hard (not to say impossible) to simulate mouse movements in games. The game can distinguish organic mouse movement from simulated movement. Python alone might not be able to convince Valorant that your mouse movement is "real" ;)
I've been figuring out how to parse tkinter events via event.state to reduce the number of times that I have to call root.bind() (e.g., I can avoid binding both "<ButtonPress-1>" and "<Shift-ButtonPress-1>" by finding if shift was pressed via event.state). Of course, I've relied heavily on the tkinter source code (specifically the definition for __repr__, starting on line 234) to convert the integer of event.state to something I can understand:
def getStatefromInt(state_int):
# from https://github.com/python/cpython/blob/3.8/Lib/tkinter/__init__.py
if isinstance(state_int, int):
state = state_int
mods = ('Shift', 'Lock', 'Control',
'Mod1', 'Mod2', 'Mod3', 'Mod4', 'Mod5',
'Button1', 'Button2', 'Button3', 'Button4', 'Button5')
s = []
for i, n in enumerate(mods):
if state & (1 << i):
s.append(n)
state = state & ~((1<< len(mods)) - 1)
if state or not s:
s.append(hex(state))
return s
One of the things that keeps coming up out of state when events occur is Mod1. What do Mod1 and the other ModX states represent? I thought the number might correspond to the type of button press, but all types of mouse clicks cause only Mod1. I have not been able to find information on what this means online, and I'm having a hard time seeing from the source code what it might mean.
ModX represents a modification, a Modifier Key.
In computing, a modifier key is a special key (or combination) on a
computer keyboard that temporarily modifies the normal action of
another key when pressed together. By themselves, modifier keys
usually do nothing; that is, pressing any of the ⇧ Shift, Alt, or Ctrl
keys alone does not (generally) trigger any action from the computer.
Tkinter is a crossplatform GUI-Toolkit and uses system specific facilities. Different OS using different methods, for example a PC that runs Linux signals Alt Gr as Mod 5 while a PC running Windows signals the same keystroke as Control-Alt. You can look at the Modifier Keys on tcl-lang.ord.
Event.state is a bit mask indicating which of certain modifier keys and mouse buttons were down or active when the event triggered and is not reliable because of the system specific facilities as pointed out here.
As a side-note the NMT claim that these bitmasks are valid to test during a event:
Mask Modifier
0x0001 Shift.
0x0002 Caps Lock.
0x0004 Control.
0x0008 Left-hand Alt.
0x0010 Num Lock.
0x0080 Right-hand Alt.
0x0100 Mouse button 1.
0x0200 Mouse button 2.
0x0400 Mouse button 3.
Another StackOverflow answer that shows how you could use it.
I need to modify a script in psychopy. The thing I need is the subject to press and hold a buttom in the keyboard, but I'd like to have two responses: one when he/her presses it (and the windows with text has to change), and the second when he/her releases it (and the windows with text has to change again).
I am using event.getKeys function of psychopy, and then I'm using keyboard library.
after inizializing the window screen and the text and importing psychopy and the functions I need and keyboard library as key.
intro.draw()
win.flip() # reset the clock to record a response time and clear events
event.clearEvents('all')
event.globalKeys.clear() #to avoid problems with the keys you pressed before
intro_loop = True
while intro_loop:
intro_keys = kb.getKeys(["space"], waitRelease=True)
if key.is_pressed('space'):
intro.text = 'Hi, please follow these instructions :) '
intro.draw()
win.flip() # reset the clock to record a response time and clear events
if len(intro_keys):
win.close()
intro_loop = False
I did the same in another script (just to try) but instead of having a window text screen I printed two different things, and it worked. in this script, instead, it completely ignores the function "key.is_pressed".
do you have any ideas?
What do I have to do so that the function that I bind with the <KeyPress> event only triggers once, even when I hold the key?
There may be nothing you can do. It could very well be that the keyboard itself is sending multiple events (ie: it's a hardware problem that can't be solved with software).
These events are probably coming very close together -- maybe every 100ms or so. You can use that knowledge to affect how you process events. For example, you can only do something special on a key release if it was at least 200ms after the last press.
Thanks, I hoped tkinter hat something like KeyPressed or KeyPressing Event. I made a kind-off workaround for this problem.
from tkinter import*
m='<KeyPress>'
n='<KeyRelease>'
global kp
kp=0
def press(event):
global kp
if (kp!=event.keysym):
print(event.keysym)
kp=event.keysym
def release(event):
global kp
print(event.keysym)
kp=0
root.bind(m,press)
root.bind(n,release)