pyHook + pythoncom stop working after too much keys pressed [Python] - python

this is my script:
import pyHook
import pythoncom
hookManager = pyHook.HookManager()
def onKeyboardEvent(event):
if event.KeyID == 113: # F2
#do something#
return True
hookManager.KeyDown = onKeyboardEvent
hookManager.HookKeyboard()
pythoncom.PumpMessages()
after the key specified on the keyboard event, or the F2 key as my script, is pressed for several times, the script stop working...
Anyone knows why? or how to solve it?
I have to restart the script every time this happens, and I have to press the key a lot in my script...

Maybe you can call the function as a Thread to execute asynchronously, add them to your own queue or set a condition to not execute if it's already running, that will stop filling the messagepump which is that is failing.
Option 1. This will add the function execution to the threads queue:
import pythoncom, pyHook, threading
lock = threading.Lock()
def myFunc(i):
lock.acquire() #execute next function until previous has finished
#some code
lock.release()
def OnKeyboardEvent(event):
keyPressed = chr(event.Ascii)
if keyPressed == 'z':
t = threading.Thread(target=myFunc, args=(1,)) #added to queue
t.start()
return True
hm = pyHook.HookManager()
hm.KeyDown = OnKeyboardEvent
hm.HookKeyboard()
pythoncom.PumpMessages()
Option 2. or this will ignore other processing calls if it's busy:
def myFunc(i):
myFunc.isRunning = True
#some code
myFunc.isRunning = False
myFunc.isRunning = False
def OnKeyboardEvent(event):
keyPressed = chr(event.Ascii)
if keyPressed == 'z':
if not myFunc.isRunning: #if function is being executed ignore this call
t = threading.Thread(target=myFunc,args=(1,))
t.start()
return True
of course you should be careful when you add code by capturing exceptions or the thread will stay blocked.

Related

How to get stuck in a for loop?

Hi I have a problem where I need to wait in a for loop for a while till the value of a Boolean variable is changed. I intentionally want to wait in the loop. Sample code
check = True
def change_check_value():
global check
###
after a while check changes to true
###
change_check_vale() #running on a different thread
for i in range(0,10):
print(i)
check = False
## wait till check becomes true and continue the for loop
I want to wait in the for loop till the check becomes true again.. I tried with while loop but I was not able to achieve the functionality. time.sleep() cannot be used because I am not sure of how much time to wait. Can someone help me with this?
Thanks.
You can use the Event object, it may be found under threading and under the asyncio packages.
The event object have a wait() method and while calling it the code will not continue until the Event will set to true.
Once the event will be set to True the code will immediately continue.
asyncio example (source):
async def waiter(event):
print('waiting for it ...')
await event.wait()
print('... got it!')
async def main():
# Create an Event object.
event = asyncio.Event()
# Spawn a Task to wait until 'event' is set.
waiter_task = asyncio.create_task(waiter(event))
# Sleep for 1 second and set the event.
await asyncio.sleep(1)
event.set()
# Wait until the waiter task is finished.
await waiter_task
asyncio.run(main())
Threading example (source):
import threading
import time
import logging
logging.basicConfig(level=logging.DEBUG,
format='(%(threadName)-9s) %(message)s',)
def wait_for_event(e):
logging.debug('wait_for_event starting')
event_is_set = e.wait()
logging.debug('event set: %s', event_is_set)
def wait_for_event_timeout(e, t):
while not e.isSet():
logging.debug('wait_for_event_timeout starting')
event_is_set = e.wait(t)
logging.debug('event set: %s', event_is_set)
if event_is_set:
logging.debug('processing event')
else:
logging.debug('doing other things')
if __name__ == '__main__':
e = threading.Event()
t1 = threading.Thread(name='blocking',
target=wait_for_event,
args=(e,))
t1.start()
t2 = threading.Thread(name='non-blocking',
target=wait_for_event_timeout,
args=(e, 2))
t2.start()
logging.debug('Waiting before calling Event.set()')
time.sleep(3)
e.set()
logging.debug('Event is set')
Try using the method as mentioned in this post : Is there an easy way in Python to wait until certain condition is true?
import time
check = True
def wait_until():
while true:
if check == True: return
def change_check_value():
global check
###
after a while check changes to true
###
change_check_vale() #running on a different thread
for i in range(0,10):
print(i)
check = False
## wait till check becomes true and continue the for loop
wait_until()
Hope it helps.
This can be done in a very straightforward way:
from threading import Event, Thread
event = Event()
def wait_for_it(e):
print('Waiting for something to happen.')
e.wait()
print('No longer waiting.')
e.clear()
print('It can happen again.')
def make_it_happen(e):
print('Making it happen.')
e.set()
print('It happened.')
# create the threads
threads = [Thread(target=wait_for_it, args=(event,)), Thread(target=make_it_happen, args=(event,))]
# start them
for thread in threads:
thread.start()
# make the main thread wait for the others to complete
for thread in threads:
thread.join()

Python: How to terminate multithreaded python program?

I want to create one program in which two lists of hosts are available. I want to read data from each host. It will take around 5-10 seconds so I want to read each host data with different thread.
I created below code and it is working as per my expectations but only problem is when I'm pressing Ctrl+c, program didn't terminate.
My code:
import threading
import time,os,sys
import signal
is_running = True
def signal_handler(signal, frame):
print "cleaning up...please wait..."
v1.stop()
v2.stop()
global is_running
is_running = False
class Thread2(threading.Thread):
def __init__(self, function,args):
self.running = False
self.function = function
self.args = args
super(Thread2, self).__init__()
def start(self):
self.running = True
super(Thread2, self).start()
def run(self):
while is_running:
self.function(self.args)
time.sleep(time_interval)
def stop(self):
self.running = False
def b_iterate(hostnames):
for host_name in hostnames:
v = Thread2(function = read_cet_data,args = host_name)
v.start()
def read_b_data(host):
#
#reading some data from current host (5-10 seconds processing)
#
#here, this thread is not neccessary, want to stop or kill or terminate it
if threading.current_thread().isAlive():
threading.current_thread().stop()
def a_iterate(entp_hostnames):
for host_name in entp_hostnames:
v = Thread2(function = read_entp_data,args = host_name)
v.start()
def read_a_data(host):
#
#reading some data from current host (5-10 seconds processing)
#
#here, this thread is not neccessary, want to stop or kill or terminate it
if threading.current_thread().isAlive():
threading.current_thread().stop()
if __name__ == "__main__":
signal.signal(signal.SIGINT, signal_handler)
#a_hostnmaes & b_hostnmaes are the lists of hostnames
v1 = Thread2(function = a_iterate,args = a_hostnames)
v2 = Thread2(function = b_iterate,args = b_hostnames)
v1.start()
v2.start()
while is_running:
pass
How I can make this program terminate after pressing Ctrl+c. Am I missing something?
If you just want control C to finish everything, there is no need to use a stop function in threads. You can just daemonise them:
v1 = Thread2(function = a_iterate,args = a_hostnames)
v2 = Thread2(function = b_iterate,args = b_hostnames)
v1.daemon = True
v2.daemon = True
v1.start()
v2.start()
As soon as your main program dies, these threads die as well. You need to add .daemon = True to all other locations in the code where a thread is created.
Hannu
You can either
catch KeyboardInterrupt in main thread
set a flag so another threads can detect it and exit
or
catch KeyboardInterrupt
call os._exit()

Python: How to start/stop while True loop on Keyboard event

I am trying to write a little script that emulates mouse-clicking. It should start/stop when a combination of keys is pressed on the keyboard, so I figured every time this combination is pressed I would spawn or terminate a child process that just contains a while True loop and does some clicking. Now I can get the loop to start, but not to terminate. I tried creating a new process just for the HookManager, but i got the same results. Any help with this would be very appreciated
import time
import win32api
import win32con
import pythoncom
import pyHook
import multiprocessing
i=0
def click():
while True:
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0)
time.sleep(0.005)
def OnKeyboardEvent(event):
global i
if (event.Ascii == 4) and (i == 0):
i = 1
c = multiprocessing.Process(target=click())
c.start()
print("started")
elif (event.Ascii == 4) and (i == 1):
i = 0
c.terminate()
print("terminated")
return True
hm = pyHook.HookManager()
hm.KeyDown = OnKeyboardEvent
hm.HookKeyboard()
pythoncom.PumpMessages()
Obviously you dont want to use while True: statement, but something like this:
def worker():
while running:
#do the work
...
def terminateWorker():
running = false
...
running = true
startWorker()
terminateWorker()
Or you can use break in if statement checking loop stop flag.
def click():
while True:
if(stopNow):break
...
stopNow=false

Easy way to receive data from Python child thread

I am working on a simple python script that sends serial communication command to an Arduino.
I have a main-thread which sends the commands and then another child-thread which waits for user input.
This should be simple but I want this process to be very fast.
For example if user inputs "stop", I want to stop the main thread immediately.
The way I was thinking of doing it was by throwing exceptions from the child thread and catch those in the main thread, but I soon realized that I was quite impossible since each thread runs on its own context and child thread can not send an exception to the main thread.
I am now trying to change the child class with attributes and check the attributes in the main thread but I will result on lots of confusing if-statements in the main thread and it is also not a good solution since it does not stop the execution immediately.
class User_input_thread (threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.isPauseRequested = False
self.isStopRequested = False
def run(self):
while (True):
s = raw_input(">")
if s.startswith("pause"):
self.isPauseRequested = True
elif s.startswith("start"):
self.isPauseRequested = False
elif s.startswith("stop"):
self.isStopRequested = True
This is the basically main thread:
def start_demo():
user_input_thread = User_input_thread()
user_input_thread.start()
while (True):
if (not user_input_thread.isPauseRequested):
# DO SOME WORK HERE
time.sleep(10)
if (not user_input_thread.isStopRequested):
# DO SOME WORK HERE
time.sleep(10)
What is an easy way to achieve the behavior I want?
Please don't link to other pages that discuss exceptions between Threads. At least explain how I should use the code or modify my code so I can understand.
EDIT (following code has been tested)
The problem with the following code is that if event takes infinite time there is no way to stop the child process.
Run the example and write "start".... then the child starts to work and then if you send another event "such as stop" it will be ignored.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import threading
import time
class child_thread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.stop_request = threading.Event()
self.start_request = threading.Event()
self.pause_request = threading.Event()
def run(self):
while 1:
if self.stop_request.isSet():
print 'stop request is set!!'
self.stop_request.clear()
while 1:
print "stop running..."
time.sleep(1)
if self.pause_request.isSet():
print 'pause request is set!!'
self.pause_request.clear()
while 1:
print "pause running..."
time.sleep(1)
if self.start_request.isSet():
print 'start request is set!!!'
self.start_request.clear()
while 1:
print "start running..."
time.sleep(1)
def show(self, event='stop'):
if event == 'stop':
self.stop_request.set()
elif event == 'start':
self.start_request.set()
elif event == 'pause':
self.pause_request.set()
elif event == 'exit':
print 'enter exit'
self.join(1)
def main_thread():
t1 = child_thread()
t1.start()
while 1:
s = raw_input(">")
t1.show(event=s)
if s == 'exit':
break
print 'Done! child thread has been killed'
main_thread()
It's not a best practice to for a child thread to control its parent thread. We usually do the other way around.
In your case, you can put user input in the main thread and put your work in the child thread.
Communication between threads in Python is usually done by Event and signal. You can google this if you show interests.
Here is an example for your case. Hope it helps. I simplify the if conditions which is not the key point here. :)
#!/usr/bin/python
# -*- coding: utf-8 -*-
import threading
import time
class child_thread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.stop_request = threading.Event()
self.start_request = threading.Event()
self.pause_request = threading.Event()
def run(self):
while 1:
if self.stop_request.isSet():
print 'stop request is set!!'
break
if self.pause_request.isSet():
print 'pause request is set!!'
break
if self.start_request.isSet():
print 'start request is set!!!'
break
print 'no stop/pause/start is set!!'
time.sleep(1)
def join(self, timeout=None, event='stop'):
if event == 'stop':
self.stop_request.set()
elif event == 'start':
self.start_request.set()
elif event == 'pause':
self.pause_request.set()
super(child_thread, self).join(timeout)
def main_thread():
t1 = child_thread()
t1.start()
while 1:
s = raw_input(">")
t1.join(event=s)
break
print 'Done! chile thread has been killed'
main_thread()
And here is a very good article for communications between threads in Python. http://eli.thegreenplace.net/2011/12/27/python-threads-communication-and-stopping
EDIT:
Here is code for your updated request.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import threading
import time
class child_thread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.stop_request = threading.Event()
self.start_request = threading.Event()
self.pause_request = threading.Event()
def run(self):
while 1:
if self.stop_request.isSet():
print 'stop request is set!!'
self.stop_request.clear()
continue
if self.pause_request.isSet():
print 'pause request is set!!'
self.pause_request.clear()
continue
if self.start_request.isSet():
print 'start request is set!!!'
self.start_request.clear()
continue
def show(self, event='stop'):
if event == 'stop':
self.stop_request.set()
elif event == 'start':
self.start_request.set()
elif event == 'pause':
self.pause_request.set()
elif event == 'exit':
print 'enter exit'
self.join(1)
def main_thread():
t1 = child_thread()
t1.start()
while 1:
s = raw_input("\n>enter exit to exit:")
t1.show(event=s)
if s == 'exit':
break
print 'Done! chile thread has been killed'
main_thread()

Printing Stdout In Command Line App Without Overwriting Pending User Input

In a basic Unix-shell app, how would you print to stdout without disturbing any pending user input.
e.g. Below is a simple Python app that echos user input. A thread running in the background prints a counter every 1 second.
import threading, time
class MyThread( threading.Thread ):
running = False
def run(self):
self.running = True
i = 0
while self.running:
i += 1
time.sleep(1)
print i
t = MyThread()
t.daemon = True
t.start()
try:
while 1:
inp = raw_input('command> ')
print inp
finally:
t.running = False
Note how the thread mangles the displayed user input as they type it (e.g. hell1o wo2rld3). How would you work around that, so that the shell writes a new line while preserving the line the user's currently typing on?
You have to port your code to some way of controlling the terminal as slightly better than a teletype -- e.g. with the curses module in Python's standard library, or other ways to move the cursor away before emitting output, then move it back to where the user's busy inputting stuff.
You could defer writing output until just after you receive some input. For anything more advanced you'll have to use Alex's answer
import threading, time
output=[]
class MyThread( threading.Thread ):
running = False
def run(self):
self.running = True
i = 0
while self.running:
i += 1
time.sleep(1)
output.append(str(i))
t = MyThread()
t.daemon = True
t.start()
try:
while 1:
inp = raw_input('command> ')
while output:
print output.pop(0)
finally:
t.running = False

Categories

Resources