I have this relatively simple program that listens for mouse clicks and when the mouse button is held down prints "1"s. Unfortunately when I let go of the mouse it just keeps printing "1"s, even though there is an if statement which checks if the mouse is clicked and should stop the loop if it is not. I am using the pynput.mouse module for the mouse interaction.
Here is my code:
import time
from pynput.mouse import Listener
def clicked(x, y, button, pressed):
if pressed == True:
while button == button.left:
print("1")
time.sleep(1)
if pressed == False:
break
with Listener(on_click=clicked) as listener:
listener.join()
My theory is that once the loops starts it stops listening for mouse clicks, so it can never stop the loop. Would it be necessary to create a new thread for the loop? If yes, how would I do that?
Thanks!
Your current logic makes it impossible to get out of the loop, since pressed doesn't change within the loop. There is not a statement that checks if the mouse is clicked: your only if statements check whether the mouse was clicked when you entered the function. pressed doesn't change within the function.
Look at the critical logiic:
if pressed == True:
while ...
...
if pressed == False:
break
There is nothing in here to change the value of pressed; the first if guarantees that it's True anywhere within the loop.
Yes, you need to set up another listener that operates within the loop. You already know the building blocks: create a new one within the function and bind it to another operation that breaks the loop. For instance, you might "cheat" and have it reset pressed as a global variable.
You could also research how to do this in other answers, if you want an overall handler solution. keypress and keyrelease have been done often enough.
import pyautogui, random, time
import pynput
keys = ['w', 's', 'a', 'd']
def on_press(key):
p = True
if key == pynput.keyboard.Key.esc:
return False
else:
while p == True:
press = keys[random.randint(0,3)]
pyautogui.keyDown(press)
pyautogui.keyUp(press)
p = False
with pynput.keyboard.Listener(on_press=on_press) as L:
L.join()
a code like this will work instead of what you did.
BTW, that is just an example; feel free to visit my GitHub page: github.com/ironnicko
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 made an autoclicker and i can stop it by pressing b but only at the right timing. I didn't find anything that would allow me to stop the program by pressing a button at any time without accessing the console
Here's the program:
from time import sleep
import keyboard
import mouse
state=True
while state:
if keyboard.is_pressed("b"):
state=False
else:
mouse.click()
sleep(1)
I already answered at Using a key listener to stop a loop
You can simply use the add_hotkey method.
Example:
import keyboard
state = True
def stop():
state = False # The function you want to execute to stop the loop
keyboard.add_hotkey("b", stop) # add the hotkey
I am making a program in python to detect what key is pressed and based on my keyboard it will make a decision.
I want to implement it using keyboard module in python.
I would do something like this,
import keyboard
while True:
if keyboard.read_key() == 'enter':
print('Enter is pressed)
if keyboard.read_key() == 'q':
print('Quitting the program)
break
if keyboard.read_key() == 's':
print('Skiping the things')
But it doesn't work. When I execute this program, I have to press s twice to execute the "s" block.
Also, I have a problem that is after the execution is finished, it writes all the keys in my command prompt is it possible to fix that?
As per Keyboard documentation:
Other applications, such as some games, may register hooks that swallow all key events. In this case keyboard will be unable to report events.
One way to solve your problem with keyboard module is keyboard.wait('key')
# Blocks until you press esc
keyboard.wait('esc')
Something work around is as below:
import keyboard
keyboard.wait('enter')
print('Enter is pressed')
keyboard.wait('q')
print('Quitting the program')
keyboard.wait('s')
print('Skiping the things')
As Far I Know There is only one efficient way to Detect user input weather it keybored or mouse input Which is library called pynput ......
from pynput.keyboard import Key , Listener , Controller
keyboard = Controller()
DoubleShot=False
shot=False
def on_press(key):
global DoubleShot
global shot
if Key.num_lock == key:
print("activate")
DoubleShot=True
if DoubleShot:
if Key.shift == key:
shot = not shot
if shot:
keyboard.press(Key.shift)
keyboard.release(Key.shift)
def on_release(key):
if key == Key.esc:
return False
with Listener(on_press=on_press , on_release=on_release) as listener:
listener.join()
i create this for a game to shoot multiple time on 'shift' clicked
code activate only when ' numlock ' clicked.....
Controller is for clicking any key you want
Note:
In My case infinity looping was a problem that's why shot variable is there to stop looping
import pynput
import time
def poschange(x,y):
#print(f"{x},{y}")
print("poschange called")
pynput.mouse.Controller().position = (0,0)
def stop(key):
#print(key)
try:
if key.char == 'a':
print("stopped")
keyli.stop()
mouli.stop()
exit()
except:
pass
keyli = pynput.keyboard.Listener(on_press = stop)
keyli.start()
mouli = pynput.mouse.Listener(on_move = poschange)
mouli.start()
keyli.join()
mouli.join()
I just want to lock the mouse position when of the the mouse to (0,0) until I press the 'a' key on the keyboard and then the program terminates and i get control my mouse again.
To my knowledge in this code when ever i move the mouse the poschange() method is called and the mouse position must be set back to (0,0) and repeat again until the mouse listener thread is terminated, but it just works twice, the print statement in the poschange() function is printed twice in the console and then the mouse becomes sluggish and moves slowly, when I press 'a' the listeners must stop and program must terminate but it doesn't I have to manually do it and only the the mouse becomes fast and normal again. But when I remove the line pynput.mouse.Controller().position = (0,0) from the code the thing works as i intend, it prints the print statement "poschange called" every time I move the mouse and the program terminates as expected when I press the 'a' key.
can someone please tell me why and tell me whats wrong with this. Thanks in advance.
You've created a recursion with that call to .position as you move the cursor position in a callback triggered when a cursor changes its position.
I suppose you may get expected behavior by calling that
pynput.mouse.Controller().position = (0,0)
upon application start and by preventing the event propagation with:
mouli = pynput.mouse.Listener(on_move=poschange, suppress=True)
At the moment I'm trying to use Python to detect when the left mouse button is being held and then start to rapidly send this event instead of only once. What I basically want to do is that when the left mouse button is held it clicks and clicks again until you let it go. But I'm a bit puzzled with the whole Xlib, I think it's very confusing actually. Any help on how to do this would be really awesome. That's what I've got so far:
#!/usr/bin/env python
import Xlib
import Xlib.display
def main():
display = Xlib.display.Display()
root = display.screen().root
while True:
event = root.display.next_event()
print event
if __name__ == "__main__":
main()
But there is unfortunately no output in the console. After a quick search on the internet I found the following:
root.change_attributes(event_mask=Xlib.X.KeyPressMask)
root.grab_key(keycode, Xlib.X.AnyModifier, 1, Xlib.X.GrabModeAsync,
Xlib.X.GrabModeAsync)
This is seemingly import to catch a special event with the given keycode. But firstly what keycode does the left-mouse click have, if any at all? And secondly how can I detect when it is being held down and then start sending the mouseclick event rapidly. I would be really grateful for help. (Maybe a way to stop this script with a hotkey would be cool aswell...)
Actually you want Xlib.X.ButtonPressMask | Xlib.X.ButtonReleaseMask, to get events for button presses and releases (different from key presses and releases). The events are ButtonPress and ButtonRelease, and the detail instance variable gives you the button number. From when you get the press event, to when you get the release event, you know the button is being held down. Of course you can also receive key events and do something else (e.g. exit your script) when a certain key is pressed.
Edit: this version works fine for me, for example...:
import Xlib
import Xlib.display
def main():
display = Xlib.display.Display(':0')
root = display.screen().root
root.change_attributes(event_mask=
Xlib.X.ButtonPressMask | Xlib.X.ButtonReleaseMask)
while True:
event = root.display.next_event()
print event
if __name__ == "__main__":
main()