I use pyautogui to test much of the functionality in my python application. It seems to work fine for left mouse down, up, and right down and up, as well as key down, and keyup. However, when I am see no mouse events for the mouse move calls.
Why not?
How can I test the functionality of my software that has hooked into mouse move events?
import pyHook
import threading
import win32con
import pythoncom
import time
import pyautogui
class WindowsHooksWrapper(object):
"""
Provides a means to subscribe to keyboard and mouse events via Windows Hooks
It is important to note that:
* A thread specific hook (one that is not injected via dll injection) must be registered on the
same thread with the windows msg pump or it will not work and no indication of error is given
"""
def __init__(self):
self.consuming_keyboard_events = False
self.consuming_mouse_events = False
self.hook_manager = None
self.started = False
self.thread = threading.Thread(target=self.thread_proc)
def __del__(self):
self.stop()
def start(self):
if self.started:
self.stop()
self.started = True
self.thread.start()
def stop(self):
if not self.started:
return
self.started = False
self.thread.join()
def consume_mouse_events(self, should_consume_events):
"""
Tell the windows hooks wrapper to consume mouse events or not.
Consumed events will not be passed to other hooks or the process they were intended for.
Injected events will be passed on.
:param should_consume_events: set to True to consume mouse events. Otherwise, False
"""
if should_consume_events:
print 'Consuming mouse events'
else:
print 'No longer consuming mouse events'
self.consuming_mouse_events = should_consume_events
def consume_keyboard_events(self, should_consume_events):
"""
Tell the windows hooks wrapper to consume keyboard events or not.
Consumed events will not be passed to other hooks or the process they were intended for.
Injected events will be passed on.
:param should_consume_events: set to True to consume keyboard events. Otherwise, False
"""
if should_consume_events:
print 'Consuming keyboard events'
else:
print 'No longer consuming keyboard events'
self.consuming_keyboard_events = should_consume_events
def on_keyboard_event(self, event):
"""
Called back from pyHooks library on a keyboard event
:param event: event passed from pyHooks
:return: True if we are to pass the event on to other hooks and the process it was intended
for. False to consume the event.
"""
# Provide a means to stop consuming events while we are consuming all input
if event.KeyID == win32con.VK_ESCAPE:
self.consuming_keyboard_events = False
self.consuming_mouse_events = False
# Consume the event
print 'Escape key hit. Turning input blocking off.'
return False
if not self.consuming_keyboard_events or event.Injected:
print 'MessageName:', event.MessageName
print 'Message:', event.Message
print 'Time:', event.Time
print 'Window:', event.Window
print 'WindowName:', event.WindowName
print 'Ascii:', event.Ascii, chr(event.Ascii)
print 'Key:', event.Key
print 'KeyID:', event.KeyID
print 'ScanCode:', event.ScanCode
print 'Extended:', event.Extended
print 'Injected:', event.Injected
print 'Alt', event.Alt
print 'Transition', event.Transition
print '---'
# Send the event to other handlers and its target
return True
else:
# Consume the event. Any other hooks will not receive the event, nor will the process
# the event was intended for.
print 'Consumed keyboard event'
return False
def on_mouse_event(self, event):
"""
Called back from pyHooks library on a mouse event
:param event: event passed from pyHooks
:return: True if we are to pass the event on to other hooks and the process it was intended
for. False to consume the event.
"""
if not self.consuming_mouse_events or event.Injected:
# Send the event to pub sub
print 'MessageName:', event.MessageName
print 'Message:', event.Message
print 'Time:', event.Time
print 'Window:', event.Window
print 'WindowName:', event.WindowName
print 'Position:', event.Position
print 'Wheel:', event.Wheel
print 'Injected:', event.Injected
print '---'
# Send the event to other handlers and its target
return True
else:
# Consume the event. Any other hooks will not receive the event, nor will the process
# the event was intended for.
print 'Consumed mouse event'
return False
def thread_proc(self):
print "Thread started"
# Evidently, the hook must be registered on the same thread with the windows msg pump or
# it will not work and no indication of error is seen
# Also note that for exception safety, when the hook manager goes out of scope, the
# documentation says that it unregisters all outstanding hooks
self.hook_manager = pyHook.HookManager()
self.hook_manager.KeyAll = self.on_keyboard_event
self.hook_manager.HookKeyboard()
self.hook_manager.MouseAll = self.on_mouse_event
self.hook_manager.HookMouse()
while self.started:
pythoncom.PumpWaitingMessages()
print "Thread exiting..."
self.hook_manager.UnhookKeyboard()
self.hook_manager.UnhookMouse()
self.hook_manager = None
def main():
hook_wrapper = WindowsHooksWrapper()
hook_wrapper.start()
hook_wrapper.consume_keyboard_events(True)
hook_wrapper.consume_mouse_events(True)
pyautogui.moveTo(100, 50)
pyautogui.moveTo(200, 200)
time.sleep(30)
hook_wrapper.stop()
if __name__ == "__main__":
main()
Expected to see mouse move print out in the output.
Related
Hello,
I have the below code that corrects user input and I want to exit the blocking function keyboard.read_event when the control is returned from the correction thread.
The whole program works well but I cannot exit immediately after the corrector thread is finished (the program waits for key press).
I tried using a custom Exception for interrupting the keyboard.read_event function, but I didn't manage to make it work.
import keyboard
import threading
import time
class Interrupt_Custom_Exception(Exception):
"""Base class for other exceptions"""
pass
#########################################################
def delete_and_write(times_to_delete, word_to_write):
print("------------Deleting & Rewrite Started---")
time.sleep(2)
print("------------Deleting & Rewrite Ended---")
# simulate deletion and rewrite
#**here I tried the raise Interrupt_Custom_Exception and tried to catch it at the code in the class, but didn't work**
def write_the_suppressed_string(string):
keyboard.write(string)
#########################################################
class keyboard_monitor(threading.Thread):
def __init__(self,thread_name, threadID, word_typed, keyboard_suppress, counter_for_key_pressed):
threading.Thread.__init__(self)
self.name = thread_name
self.threaID = threadID
self.fstring = word_typed
self.counter_for_key_presses = counter_for_key_pressed
self.suppressed = keyboard_suppress
self.temp = ""
def stop(self):
self._is_running = False
def run(self):
if (self.suppressed is False):
while(True):
event = keyboard.read_event(suppress = self.suppressed)
if (event.event_type == keyboard.KEY_DOWN):
if (event.name == "space"):
suppressed_monitor = keyboard_monitor("suppressed_monitor", 2, self.fstring, True, self.counter_for_key_presses)
suppressed_monitor.start()
suppressed_monitor.join()
print("RETURNED TO MAIN MONITOR")
self.counter_for_key_presses = 0
self.fstring = ""
elif (event.name in "abcdefghijklmnopqrstuvwxyz"):
self.fstring = ''.join([self.fstring, event.name])
self.counter_for_key_presses += 1
elif (self.suppressed is True):
def listen_to_keyboard():
event = keyboard.read_event(suppress=self.suppressed)
# **here is where the program waits and don't continue when the correction thread is finished.**
if (event.event_type == keyboard.KEY_DOWN):
print("---KEYS PRESSED WHILE SUPPRESSED = {}---".format(event.name))
if (event.name in "abcdefghijklmnopqrstuvwxyz"):
self.fstring = ''.join([self.fstring, event.name])
self.counter_for_key_presses += 1
try:
#########################################################
# INITIALY CORRECTING THE WORD PASSED FROM THE NORMAL KEY MONITOR
self.temp = self.fstring
self.fstring = ""
thread_delete_and_rewrite = threading.Thread(
target = delete_and_write, args=(self.counter_for_key_presses, self.temp))
thread_delete_and_rewrite.start()
# raise Interrupt_Custom_Exception
#########################################################
print("-BEFORE WHILE LOOP-")
while(thread_delete_and_rewrite.is_alive() is True): # **this works ok but if the control enters the listen_to_keyboard function waits there until a key is pressed. I want somehow to stop this manually and continue the code after this while**
print("--ENTERING THE WHILE LOOP--")
listen_to_keyboard()
print("----EXITING THE WHILE LOOP----\n")
except Interrupt_Custom_Exception:
print("!!!!!!!!!!!!!!!!!CAUGHT IT!!!!!!!!!!!!!!!!!!!")
print("----EXITING THE WHILE LOOP----\n")
print("------BEFORE FINAL WRITE------")
if (self.fstring != ""):
thread_write = threading.Thread(
target = write_the_suppressed_string, args=(self.fstring, ))
thread_write.start()
thread_write.join()
print("SUPPRESSED ENDED")
self._is_running = False
if __name__ == "__main__":
kb_not_suppressed = keyboard_monitor("not_suppressed_monitor", 1, "", False, 0)
kb_not_suppressed.start()
kb_not_suppressed.join()
Any idea on how to exit this blocking function would be very very useful.
Thanks in advance.
It's not possible unless you find some keyboard.read_event that has a timeout, or does a non-blocking check if there's a event. I haven't found any of those in keyboard module ;/
A big workaround would be to keyboard.press in case you want to exit. Not sure if you can detect if it's not from the user. It's up to you if it's acceptable.
This question already has answers here:
Keyboard input with timeout?
(28 answers)
Closed 3 years ago.
I am writing a program in python that accepts two inputs.
Once the user gives the first input, he gets 10 seconds to give the second input.
If the user is able to provide the second value within those 10 seconds and presses the enter key, the timer stops and goes to the next part of the program.
Is there any functionality in python that allows me to provide an interrupt after the 10 seconds and stop accepting the second input. And if the second input is given, stop the timer.
You can create a custom Timer class and start it in a diffrent thread. Once the timeout occurs (after 10 seconds), you can send a SIGINT signal back to the parent thread, which will raise the KeyboardInterrupt exception that we catch in the main() function. Otherwise you can stop the Timer, after user enters the second input in the right time, which will then stop the Timer thread. Further, we can check if the KeyboardInterrupt happened due to timeout or user action.
Note: While we are sending the signal to the main process, we also need to check, on which platform we are running the programm. See signal.CTRL_C_EVENT and signal.SIGINT.
Demo: https://repl.it/repls/StandardBuoyantProtools
Solution:
import time
import threading
import os
import signal
class Timer(threading.Thread):
_timeout = False
_timer = 0
_stopped = False
def __init__(self, delay):
super(Timer, self).__init__()
self.restart(delay)
def is_timeout(self):
return self._timeout
def stop(self):
self._stopped = True
def restart(self, delay):
self._stopped = False
self._timer = time.time() + delay
def run(self):
while not self._stopped:
time.sleep(0.1)
if time.time() >= self._timer:
break
if not self._stopped:
self._timeout = True
# check os name
if os.name == 'nt':
# we are on Windows
os.kill(os.getpid(), signal.CTRL_C_EVENT)
else:
# we are on a Posix/Unix (or very unlikely on java) system
os.kill(os.getpid(), signal.SIGINT)
def main():
first_input = input('First input:')
delay = 10
timer = Timer(delay)
timer.daemon = True
try:
print('\nStarting the timer for the second input %r second(s)' % delay)
timer.start()
second_input = input('Second input:')
print('\nWell done. Stopping the timer!\n')
timer.stop()
print('Input values: %r %r\n' % (first_input, second_input))
# do your stuff here...
except KeyboardInterrupt:
if timer.is_timeout():
print("\nTimeout!")
else:
print("\nUser interrupted the input")
main()
Recently, I started working on a small user interact program, which collects user mouse click and does some action. I wonder how I can treat mouse as a device, alongside QT, and capture its left, right and middle click, and wrap up into this class.
class UserInputProcessor:
#abc.abstractmethod
def process_user_input(self):
pass
Here is what I did for a speech recognition for macrophone:
class SpeechProcessor(UserInputProcessor):
def __init__(self, json_file_path = "speech_processor.json", credentials = ".credentials.json"):
"""set up microphone """
self.process = True
def process_user_input(self):
with self.__microphone as source:
while self.process:
# Continuously wait for user input
self.__speech_converter_params["audio_data"] = None
while self.__speech_converter_params["audio_data"] == None:
try:
self.__speech_converter_params["audio_data"] = self.__recognizer.listen(
source,
phrase_time_limit = self.__config["phrase_time_limit"],
timeout = self.__config["timeout"])
except sr.WaitTimeoutError:
print("Timing out...")
yield self.__speech_converter_params["audio_data"]
# Process user speech with ASR
str = self.__speech_converter(**self.__speech_converter_params)
yield str
This is what I found for mouse input
selector = selectors.DefaultSelector()
mouse = evdev.InputDevice('/dev/input/event16')
keybd = evdev.InputDevice('/dev/input/event11')
# This works because InputDevice has a `fileno()` method.
selector.register(mouse, selectors.EVENT_READ)
selector.register(keybd, selectors.EVENT_READ)
while True:
for key, mask in selector.select():
device = key.fileobj
for event in device.read():
if event.value == 589825:
print ("left button")
elif event.value == 589827:
print ("middle button")
elif event.value == 589826:
print ("right button")
Thanks to those who helped me figure out I needed to use threading to run a loop in a control script I have run, I now have an issue to try and control the thread - by starting or stopping it based on a function:
I want to start a process to get a motor to cycle through a movement based on a 'start' parameter sent to the controlling function, also I want to send a 'stop' parameter to stop the thread too - here's where I got to:
def looper():
while True:
print 'forward loop'
bck.ChangeDutyCycle(10)
fwd.ChangeDutyCycle(0)
time.sleep(5)
print 'backwards loop'
bck.ChangeDutyCycle(0)
fwd.ChangeDutyCycle(20)
time.sleep(5)
def looper_control(state):
t = threading.Thread(target=looper)
if state == 'start':
t.start()
elif state == 'stop':
t.join()
print 'looper stopped!!'
This starts the thread okay when I call looper_control('start') but throws an error when looper_control('stop'):
File "/usr/lib/python2.7/threading.py", line 657, in join
raise RuntimeError("cannot join thread before it is started")
RuntimeError: cannot join thread before it is started
EDIT: looper_control called from here
if "motor" in tmp:
if tmp[-1:] == '0':
#stop both pin
MotorControl('fwd',0,0)
print 'stop motors'
looper_control('stop')
elif tmp[-1:] == '2':
#loop the motor
print 'loop motors'
looper_control('start')
UPDATE: Ive not been able to stop the thread using the method suggested - I thought I had it!
here's where I am:
class sliderControl(threading.Thread):
def __init__(self,stop_event):
super(sliderControl,self).__init__()
self.stop_event = stop_event
def run(self):
while self.stop_event:
print 'forward loop'
bck.ChangeDutyCycle(10)
fwd.ChangeDutyCycle(0)
time.sleep(5)
print 'backwards loop'
bck.ChangeDutyCycle(0)
fwd.ChangeDutyCycle(20)
time.sleep(5)
def looper_control(state,stop_event):
if state == 'start':
t = sliderControl(stop_event=stop_event)
t.start()
elif state == 'stop':
#time.sleep(3)
stop_event.set()
#t.join()
print 'looper stopped!!'
called via:
if tmp[-1:] == '0':
#stop both pin
MotorControl('fwd',0,0)
print 'stop motors'
#stop_thread_event = threading.Event()
print 'stopping thread'
print stop_thread_event
looper_control('stop',stop_thread_event)
elif tmp[-1:] == '2':
#loop the motor
print 'loop motors'
global stop_thread_event
stop_thread_event = threading.Event()
print stop_thread_event
looper_control('start', stop_thread_event)
It looked like a separate thread event was being called by loop and stop, so I thought a global would sort it out but its just not playing ball. When I start the loop - it runs, but when I try to stop it, I get looper stopped!! , but the process just keeps running
Your top-level thread routine will need to become an event handler that listens to a Queue object (as in from Queue import Queue) for messages, then handles them based on state. One of those messages can be a shutdown command, in which case the worker thread function simply exits, allowing the main thread to join it.
Instead of time.sleep, use threading.Timer with the body of the timer sending a message into your event queue.
This is a substantial refactoring. But especially if you plan on adding more conditions, you'll need it. One alternative is to use a package that handles this kind of thing for you, maybe pykka.
To stop a python thread you can use threading.Event()
try this:
class YourClass(threading.Thread):
def __init__(self, stop_event):
super(YourClass, self).__init__()
self.stop_event = stop_event
def run(self):
while not self.stop_event.is_set():
# do what you need here (what you had in looper)
def looper_control(state, stop_event):
if state == 'start':
t = YourClass(stop_event=stop_event)
t.start()
elif state == 'stop':
stop_event.set()
and call to looper_control:
stop_thread_event = threading.Event()
looper_control(state, stop_thread_event)
you only can "start" once a thread
but you can lock and unlock the thread.
the best way to stop and start a thread is with mutex, Example:
#!/usr/bin/python
import threading
from time import sleep
mutex2 = threading.Lock()
#This thread add values to d[]
class Hilo(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
while True:
mutex2.acquire()
#Add values to d[]
d.append("hi from Peru")
mutex2.release()
sleep(1)
d=[];
hilos = [Hilo()]
#Stop Thread
#If you have more threads you need make a mutex for every thread
mutex2.acquire()
#Start treades, but the thread is lock
for h in hilos:
h.start()
#so you need do
#unlock THREAD<
mutex2.release()
#>START THREAD
#Sleep for 4 seconds
sleep(4)
#And print d[]
print d
print "------------------------------------------"
#WAIT 5 SECONDS AND STOP THE THREAD
sleep(5)
try:
mutex2.acquire()
except Exception, e:
mutex2.release()
mutex2.acquire()
#AND PRINT d[]
print d
#AND NOW YOUR TRHEAD IS STOP#
#When the thread is lock(stop), you only need call: mutex2.release() for unlock(start)
#When your thread is unlock(start) and you want lock(stop):
#try:
# mutex2.acquire()
#except Exception, e:
# mutex2.release()
# mutex2.acquire()
I created a thread for a keylogger that logs in parallel to another thread that produces some sounds ( I want to catch reaction times).
Unfortunately, the thread never finishes although i invoke killKey() and "invoked killkey()" is printed.
I allways get an thread.isActive() = true from this thread.
class KeyHandler(threading.Thread):
hm = pyHook.HookManager()
def __init__(self):
threading.Thread.__init__(self)
def OnKeyboardCharEvent(self,event):
print 'Key:', event.Key
if event.Key=='E':
...
return True
def killKey(self):
KeyHandler.hm.UnhookKeyboard()
ctypes.windll.user32.PostQuitMessage(0)
print "invoked killkey()"
def run(self):
print "keyHandlerstartetrunning"
KeyHandler.hm.KeyDown = self.OnKeyboardCharEvent
KeyHandler.hm.HookKeyboard()
#print "keyboardhooked"
pythoncom.PumpMessages()
to be more precise,
ctypes.windll.user32.PostQuitMessage(0) does nothing
I would favor an external timeout to invoke killKey(), respective ctypes.windll.user32.PostQuitMessage(0) in this thread.
PostQuitMessage has to be posted from the same thread. To do so you need to introduce a global variable STOP_KEY_HANDLER. If you want to quit then just set global STOP_KEY_HANDLER = True from any thread you want and it will quit with the next keystroke. Your key handler has to run on the main thread.
STOP_KEY_HANDLER = False
def main():
pass # here do all you want
#bla bla
global STOP_KEY_HANDLER
STOP_KEY_HANDLER = True # This will kill KeyHandler
class KeyHandler:
hm = pyHook.HookManager()
def OnKeyboardCharEvent(self,event):
if STOP_KEY_HANDLER:
self.killKey()
print 'Key:', event.Key
if event.Key=='E':
pass
return True
def killKey(self):
global STOP_KEY_HANDLER
if not STOP_KEY_HANDLER:
STOP_KEY_HANDLER = True
return None
KeyHandler.hm.UnhookKeyboard()
ctypes.windll.user32.PostQuitMessage(0)
print "invoked killkey()"
def _timeout(self):
if self.timeout:
time.sleep(self.timeout)
self.killKey()
def run(self, timeout=False):
print "keyHandlerstartetrunning"
self.timeout = timeout
threading.Thread(target=self._timeout).start()
KeyHandler.hm.KeyDown = self.OnKeyboardCharEvent
KeyHandler.hm.HookKeyboard()
#print "keyboardhooked"
pythoncom.PumpMessages()
k=KeyHandler()
threading.Thread(target=main).start()
k.run(timeout=100) # You can specify the timeout in seconds or you can kill it directly by setting STOP_KEY_HANDLER to True.
I guess pbackup's solution is fine. Just to conclude I found a solution by simply sending a key myself instead of waiting for the user to input. It's proably not the best but was the fastest an goes parallel in my timing thread with the other timing routines.
STOP_KEY_HANDLER = True
# send key to kill handler - not pretty but works
for hwnd in get_hwnds_for_pid (GUIWINDOW_to_send_key_to.pid):
win32gui.PostMessage (hwnd, win32con.WM_KEYDOWN, win32con.VK_F5, 0)
# sleep to make sure processing is done
time.sleep(0.1)
# kill window
finished()