I'm trying to use pynput to make an autoclicker as my first project, but I'm having a tough time understanding why my code won't work. The code is meant to start/stop clicking when I hit "ctrl + alt + i" and click once every 1 second. Here is my current code. I can't really understand why it doesn't work, but what I have made work so far is that "click_thread.running" is changing from true to false, python listens to my keyboard, and the clicking works ONLY WHEN I set the "self.running" in the "ClickMouse" class to true. The output I get from printing "click_thread.running" seems to change from true to false, but if that's happening then why doesn't the clicking start? I would imagine it has something to do with how it's a subclass of "threading.Thread"? Or maybe I made the class wrong? Either way I've been working on it for a few days now and I feel like I have hit a wall trying to figure it out alone. Any help greatly appreciated!
import time
import threading
from pynput.mouse import Button, Controller
from pynput import keyboard
delay = 1
button = Button.left
class ClickMouse(threading.Thread):
def __init__(self, delay, button):
super().__init__()
self.delay = delay
self.button = button
self.running = False
def run(self):
while self.running == True:
mouse.click(self.button)
time.sleep(self.delay)
def start_clicking(self):
self.running = True
def stop_clicking(self):
self.running = False
mouse = Controller()
click_thread = ClickMouse(delay, button)
click_thread.start()
def on_activate_i():
print('<ctrl>+<alt>+i pressed')
if click_thread.running == False:
click_thread.start_clicking()
else:
click_thread.stop_clicking()
print(click_thread.running)
with keyboard.GlobalHotKeys({'<ctrl>+<alt>+i': on_activate_i,}) as h:
h.join()
As soon as you call click_thread.start(), the start handler is going to call your run function in the new thread. At that point, self.running is False. Thus, your while loop will immediately exit, and the thread will end.
So, set running=True as the default, and don't create the thread until on_activate_i.
Where are you clicking? At random?
Related
I made a simple auto-clicker in python. Every three seconds the script clicks wherever your mouse is. How would I add "on and off" keys? I imagine it is a simple if/else statement but I don't know how to write it.
As of Wed Sep 15 12:10, I do not have an answer that works well.
import pyautogui
import time
def Auto_Click():
width, height = pyautogui.position()
pyautogui.click(width, height)
time.sleep(3)
while True:
Auto_Click()
I'd suggest listening to specific key presses indefinitely to switch clicking on and off. And as there is an indefinite loop for the clicking as well, you will need multithreading (to perform clicking and listening for key presses simultaneously).
Notes
The auto clicker is switched off by default right on start (To avoid clicks at unwanted positions on screen right after running it). Press SHIFT to toggle it after pointing the mouse at wanted position.
Press ESC to exit the program.
I have used SHIFT and ESC keys for toggles so that the key presses won't show up in the next prompt unlike the character keys.
Use the below code if you really need to use pyautogui. Here is the solution using pynput for handling both mouse and keyboard. (My code is basically a modified version which uses keyboard module and pyautogui instead)
import time
import keyboard
import pyautogui
import threading
INTERVAL = 0.5 # Time interval between consecutive clicks
DELAY = 0.5 # Time delay between consecutive program cycles [after the clicks are turned off]
TOGGLE_KEY = 'shift' # Key to toggle the clicking
EXIT_KEY = 'esc' # Key to stop and exit from the program
class AutoClicker(threading.Thread):
def __init__(self, interval, delay):
super(AutoClicker, self).__init__()
self.interval = interval
self.delay = delay
self.running = False
self.program_running = True
def start_clicking(self):
self.running = True
def stop_clicking(self):
self.running = False
def exit(self):
self.stop_clicking()
self.program_running = False
def toggle_clicking(self):
if self.running:
self.stop_clicking()
else:
self.start_clicking()
def click(self):
width, height = pyautogui.position()
pyautogui.click(width, height)
# This function is invoked when the thread starts.
def run(self):
while self.program_running:
while self.running:
self.click()
time.sleep(self.interval)
time.sleep(self.delay)
if __name__ == '__main__':
# Run indefinite loop of clicking on seperate thread
auto_clicker_thread = AutoClicker(INTERVAL, DELAY)
auto_clicker_thread.start() # Invokes run() function of the thread
# So that we can listen for key presses on the main thread
keyboard.add_hotkey(TOGGLE_KEY, lambda: auto_clicker_thread.toggle_clicking())
keyboard.add_hotkey(EXIT_KEY, lambda: auto_clicker_thread.exit())
I am trying to replicate ES6 events behavior in python, so I wrote the following code:
from threading import Thread
from time import sleep
class Event:
def __init__(self, action):
self.action= action
self.flag = False
self.__watchFlag()
def triggerAction(self):
self.flag = True
def __watchFlag(self):
if self.flag:
self.action()
self.flag = False
Thread(target=self.__watchFlag).start()
def action():
print("Event triggered action.")
my_event = Event(action)
my_event.triggerAction()
Which works just fine except when I try to trigger the action two times consecutively, i.e:
my_event.triggerAction()
my_event.triggerAction()
Only 1 event is triggered, but if I add a sleep(1/10) in between each trigger, works well. So I am assuming there is a delay somewhere in the process, any ideas?
NOTE: PLS DON'T RECOMMEND ANY EVENTS LIBRARIES ALREADY EXISTING IN PYTHON, I KNOW THEM, THIS IS NOT MY END GOAL, THX.
If you change your code to:
def triggerAction(self):
print("setting to true")
self.flag = True
when you have:
my_event.triggerAction()
my_event.triggerAction()
you get the following output:
setting to true
setting to true
Event triggered action.
But if you have :
my_event.triggerAction()
sleep(1/10)
my_event.triggerAction()
you got:
setting to true
Event triggered action.
setting to true
Event triggered action.
So in the first case you set flag to true immediately, so you don't given enough time for the context switch to kick in.
So, I've been working on an LED strip connected to my raspberry pi 4, and I've got TouchOSC working between the Pi and my phone. The current problem I'm having is when a toggle button I've pressed is turned off, the program it's designated to run continues running. I have a global variable that's supposed to determine if the "while" loop continues, but instead of setting the button state to zero and terminating the program, it continues to run until it's interrupted by a Ctrl+C in the terminal. I was wondering if anyone would happen to know why the program doesn't stop when the button state is change.
def twinkleBtn(path, tags, args, source):
global twinkleState
twinkleState = int(args[0])
if twinkleState:
turnOff(strip)
while twinkleState:
twinkleTest(strip, False, 10)
if not twinkleState:
turnOff(strip)
This is triggered when the twinkle button is pressed, but the program continues to run when I toggle it back to zero. Below is the code to the function "twinkleTest"
def twinkleTest(strip, onlyOne, count, wait_ms=50):
setPixels(Color(0, 0, 0))
for i in range(count):
strip.setPixelColor(randint(0,LED_COUNT), Color(170, 180, 30))
strip.show()
time.sleep(wait_ms/250.0)
if (onlyOne):
setPixels(Color(0,0,0))
time.sleep(wait_ms/500.0)
I'm not sure if I'm just clueless or what exactly is being done wrong here. I'm pretty new to Python so it may not be the best. Thanks for any help!
Here is a simple threading solution. A thread waits on a threading.Event. twinkleTest is called whenever the event is set. The GUI sets the event, and twinkling will happen in the background until the button is pressed a second time to stop the twinkling.
import threading
def twinkleTest(strip, onlyOne, count, wait_ms=50):
setPixels(Color(0, 0, 0))
for i in range(count):
strip.setPixelColor(randint(0,LED_COUNT), Color(170, 180, 30))
strip.show()
time.sleep(wait_ms/250.0)
if (onlyOne):
setPixels(Color(0,0,0))
time.sleep(wait_ms/500.0)
def twinkler(twinkleEvent):
"""Call twinkleTest whenever the given twinkleEvent event is set
and keeps calling until the event is cleared. Designed to be used in
a separate thread."""
while True:
twinkleEvent.wait()
twinkleTest(strip, False, 10)
def setup_twinkle_daemon_thread():
"""Creates a daemon thread to twinkle screen whenever an event is set.
Returns event, threadhandle"""
twinkleEvent = threading.Event()
twinkleThread = threading.Thread(target=twinker, args=tuple(twinkleEvent))
twinkleThread.daemon = True
twinkleThread.start()
return twinkleEvent, twinkleThread
# controls twinkler
twinkleEvent = twinkleThread = None
def twinkleBtn(path, tags, args, source):
global twinkleEvent, twinkleThread
if twinkleEvent is None:
# start daemon thread on first use
twinkleEvent, twinkleThread = setup_twinkle_daemon_thread()
if twinkleEvent.is_set():
twinkleEvent.clear()
else:
twinkleEvent.set()
I wrote an pyqt gui and used threading to run code which needs a long time to be executed, but I want to have the choice to stop the execution safely. I dont want to use the get_thread.terminate() method. I want to stop the code by a special function (maybe del()). My problem is that, I wrote the code in a own class and just want to abort the class without changing a lot of syntax.
Edit: It was mentioned that one has to pass a flag to the class, which has to be checked constantly. How do I send this flag to the class? Because the flag has to change the value, when one presses the stop button.
Edit 2: My solution so far is, to declerate a global variable with the name running_global. I changed self.get_thread.terminate() to running_global = False and I check constantly in my long_running_prog if the variable has been set False. I think this solution is ugly, so I would be pretty happy if someone has a better idea.
This is my code for the dialog where I start the thread:
class SomeDialog(QtGui.QDialog,
userinterface_status.Ui_status_window):
finished = QtCore.pyqtSignal(bool)
def __init__(self):
"""
:param raster: Coordinates which are going to be scanned.
"""
super(self.__class__, self).__init__() # old version, used in python 2.
self.setupUi(self) # It sets up layout and widgets that are defined
self.get_thread = SomeThread()
# Conencting the buttons
self.start_button.clicked.connect(self.start)
self.stop_button.clicked.connect(self.stop)
self.close_button.clicked.connect(self.return_main)
# Connecting other signals
self.connect(self.get_thread, QtCore.SIGNAL("stop()"), self.stop)
self.connect(self.get_thread, QtCore.SIGNAL("update_status_bar()"), self.update_status_bar)
def return_main(self):
"""
Function is excecuted, when close button is clicked.
"""
print("return main")
self.get_thread.terminate()
self.close()
def start(self):
"""
Starts the thread, which means that the run method of the thread is started.
"""
self.start_button.setEnabled(False)
self.get_thread.start()
def stop(self):
print("Stop programm.")
self.start_button.setEnabled(True)
self.get_thread.quit()
def end(self):
QtGui.QMessageBox.information(self, "Done!", "Programm finished")
def closeEvent(self, event):
"""
This method is called, when the window is closed and will send a signal to the main window to activaete the
window again.
:param event:
"""
self.finished.emit(True)
# close window
event.accept()
In the following class is the code for the thread:
class SomeThread(QtCore.QThread):
finished = QtCore.pyqtSignal(bool)
def __init__(self):
QtCore.QThread.__init__(self)
def __del__(self):
print("del")
self.wait()
def run(self):
self.prog = long_running_prog(self.emit) # Sending from the prog signals
self.prog.run()
self.prog.closeSystem() # Leaving the programm in a safe way.
So if one presses the stop button, the programm should instantly shut down in a save way. Is there a way to abort the class in a save way? For example can I pass a variable to the long_running_prog class which turns True, when one presses the stop button? If somethin like this is possible, could one tell me how?
Thanks for your help in advance
I hope you understand my problem.
Greetings
Hizzy
This is impossible to do unless prog.run(self) would periodically inspect a value of a flag to break out of its loop. Once you implement it, __del__(self) on the thread should set the flag and only then wait.
Is there a way of disabling or locking mouse and keyboard using python? I want to freeze the mouse and disable the keyboard.
I haven't tested (actually I've tested the mouse part, and it annoyingly works) but something like this using pyhook would do what you want:
import pythoncom, pyHook
def uMad(event):
return False
hm = pyHook.HookManager()
hm.MouseAll = uMad
hm.KeyAll = uMad
hm.HookMouse()
hm.HookKeyboard()
pythoncom.PumpMessages()
I have extended Fábio Diniz's answer to a class which provides both a block() and an unblock() function which block (selectively) mouse/keyboard inputs. I also added a timeout functionality which (hopefully) addresses the annoyance of locking oneself out.
import pyHook
from threading import Timer
import win32gui
import logging
class blockInput():
def OnKeyboardEvent(self,event):
return False
def OnMouseEvent(self,event):
return False
def unblock(self):
logging.info(" -- Unblock!")
if self.t.is_alive():
self.t.cancel()
try: self.hm.UnhookKeyboard()
except: pass
try: self.hm.UnhookMouse()
except: pass
def block(self, timeout = 10, keyboard = True, mouse = True):
self.t = Timer(timeout, self.unblock)
self.t.start()
logging.info(" -- Block!")
if mouse:
self.hm.MouseAll = self.OnMouseEvent
self.hm.HookMouse()
if keyboard:
self.hm.KeyAll = self.OnKeyboardEvent
self.hm.HookKeyboard()
win32gui.PumpWaitingMessages()
def __init__(self):
self.hm = pyHook.HookManager()
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
block = blockInput()
block.block()
import time
t0 = time.time()
while time.time() - t0 < 10:
time.sleep(1)
print(time.time() - t0)
block.unblock()
logging.info("Done.")
You can have a look at the main routine for example usage.
For me, just two lines of programming solved the problem:
from ctypes import *
ok = windll.user32.BlockInput(True) #enable block
#or
ok = windll.user32.BlockInput(False) #disable block
Totally different take since all the solutions mentioned above use a quiet outdated library(pyhook) and this pyhook method personally didnt work for me.
import keyboard
from pynput.mouse import Controller
from time import sleep
def blockinput():
global block_input_flag
block_input_flag = 1
t1 = threading.Thread(target=blockinput_start)
t1.start()
print("[SUCCESS] Input blocked!")
def unblockinput():
blockinput_stop()
print("[SUCCESS] Input unblocked!")
def blockinput_start():
mouse = Controller()
global block_input_flag
for i in range(150):
keyboard.block_key(i)
while block_input_flag == 1:
mouse.position = (0, 0)
def blockinput_stop():
global block_input_flag
for i in range(150):
keyboard.unblock_key(i)
block_input_flag = 0
blockinput()
print("now blocking")
sleep(5)
print("now unblocking")
I just slightly modified the #Robert code and instead of the time I used external interrupt to close the program i.e. if you connect any external drive then the program gets close and your mouse and keyboard will be working perfectly.
import pyHook
from threading import Timer
import win32gui
import logging
import win32file
def locate_usb():#this will check any external Drives
drive_list = []
drivebits = win32file.GetLogicalDrives()
# print(drivebits)
for d in range(1, 26):
mask = 1 << d
if drivebits & mask:
# here if the drive is at least there
drname = '%c:\\' % chr(ord('A') + d)
t = win32file.GetDriveType(drname)
if t == win32file.DRIVE_REMOVABLE:
drive_list.append(drname)
return drive_list
class blockInput():
def OnKeyboardEvent(self,event):
return False
def OnMouseEvent(self,event):
return False
def unblock(self):
try: self.hm.UnhookKeyboard()
except: pass
try: self.hm.UnhookMouse()
except: pass
def block(self ,keyboard = True, mouse = True):
while(1):
if mouse:
self.hm.MouseAll = self.OnMouseEvent
self.hm.HookMouse()
if keyboard:
self.hm.KeyAll = self.OnKeyboardEvent
self.hm.HookKeyboard()
win32gui.PumpWaitingMessages()
cg= locate_usb()
if cg:
break
def __init__(self):
self.hm = pyHook.HookManager()
if __name__ == '__main__':
block = blockInput()
block.block()
block.unblock()
I hope this code will help you
Since 2018, you can now use pynput (v1.4+) to suppress keyboard and mouse events on Windows, Mac, and Linux.
import pynput
# Disable mouse and keyboard events
mouse_listener = pynput.mouse.Listener(suppress=True)
mouse_listener.start()
keyboard_listener = pynput.keyboard.Listener(suppress=True)
keyboard_listener.start()
# Enable mouse and keyboard events
mouse_listener.stop()
keyboard_listener.stop()
This also disables mouse scrolling and clicking.
However, this does not stop users from pressing Ctrl+Alt+Del on Windows. But you can run the script in an elevated command prompt, and the mouse and keyboard will still be disabled, even if they opened Task Manager using Ctrl+Alt+Delete, so there is no harm done (apparently there are way to actually prevent Ctrl+Alt+Delete, but do your own research for that)
You can use pyautogui to do this. Though I recommend adding keyboard for making a stopping key. First, you want to install pyautogui and keyboard.
Please note: this only disables the mouse not the keyboard, that is a very bad idea.
pip install pyautogui
pip install keyboard
Ok, with that sorted, we have to actually make the disabler.
import pyautogui
import keyboard
stopKey = "s" #The stopKey is the button to press to stop. you can also do a shortcut like ctrl+s
maxX, maxY = pyautogui.size() #get max size of screen
While True:
if keyboard.is_pressed(stopKey):
break
else:
pyautogui.moveTo(maxX/2, maxY/2) #move the mouse to the center of the screen
Ok, but there is 2 ways to get out of this. pressing S, and also quickly moving the mouse to one of the corners of the screen (that is a pyautogui failsafe, but we can disable that). If you want to disable the failsafe, add this after the imports:
pyautogui.FAILSAFE = False
Please note that disabling the failsafe is NOT recommended!
Ok, so now the only way to exit is the S key. If you want to stop this somewhere else in your program, do this:
pyautogui.press(stopKey)
Ok, so its not perfect, but it will stop you from doing basically anything with your mouse.