PythonWin, python thread and PostQuitMessage?

A

arnaud

Hi All,

I'm not so much involved in any Windows programming however I needed
to write a client for the Windows platform. I have this very simple
question which I've been unable to answer. I'm listening for keyboard
strokes using the pyhook library. I'm doing this in a dedicated
thread. The gui just controls the thread. When I want to pause
listening for keyboard strokes I wanted to do a PostQuitMessage() to
the thread. However this does not work since it either kills the whole
app or just does not happen in the thread it's supposed to. I've now
made an ugly workaround using PumpWaitingMessages and a delay.

def run(self):
print "Wkeylog run called"
# Hook Keyboard
self.hm.HookKeyboard()
while self.log:
win32gui.PumpWaitingMessages()
time.sleep(0.02)

i can now just cancel the process by setting self.log to False. I
wanted to do just:

def run(self):
print "Wkeylog run called"
# Hook Keyboard
self.hm.HookKeyboard()
win32gui.PumpMessages()

However I'm unable to stop this process. Can anyone shred al light
here?

Rg,

Arnaud
 
G

Gabriel Genellina

I'm not so much involved in any Windows programming however I needed
to write a client for the Windows platform. I have this very simple
question which I've been unable to answer. I'm listening for keyboard
strokes using the pyhook library. I'm doing this in a dedicated
thread. The gui just controls the thread. When I want to pause
listening for keyboard strokes I wanted to do a PostQuitMessage() to
the thread. However this does not work since it either kills the whole
app or just does not happen in the thread it's supposed to. I've now
made an ugly workaround using PumpWaitingMessages and a delay.

If you have a GUI, then very likely it has its own message loop, so you
should not create another.
def run(self):
print "Wkeylog run called"
# Hook Keyboard
self.hm.HookKeyboard()
while self.log:
win32gui.PumpWaitingMessages()
time.sleep(0.02)

i can now just cancel the process by setting self.log to False. I
wanted to do just:

def run(self):
print "Wkeylog run called"
# Hook Keyboard
self.hm.HookKeyboard()
win32gui.PumpMessages()

Then, if you remove PumpMesages and PumpWaitingMessages, there is nothing
left... so this thread is useless.
Perhaps you want to *process* keyboard events in another thread - in this
case, use a Queue object to send events to the worker thread, from the
main thread where the message loop resides.
 
A

aloonstra

If you have a GUI, then very likely it has its own message loop, so you  
should not create another.






Then, if you remove PumpMesages and PumpWaitingMessages, there is nothing  
left... so this thread is useless.
Perhaps you want to *process* keyboard events in another thread - in this  
case, use a Queue object to send events to the worker thread, from the  
main thread where the message loop resides.

You are right however this case is a bit different. The application is
a keylogger which listens for keyboard events. The GUI is done using
Wx. They are different message loops. Under Linux I have no problem
however in the case of Windows I don't know how to stop the keylogger.

The Keylogger for Windows is very simple, see:
http://retypingdante.svn.sourceforg.../trunk/inferno/src/rtd_Wkeylog.py?view=markup

As you can see in the cancel function I cannot use
win32gui.PostQuitMessage(1) since it kills the whole app, including
Wx, and not just the thread. I cannot mix the eventloops of Windows
and Wx AFAIK so I put it in its own thread. I'm already using Queue
objects to pass the data between threads.

Arnaud
 
G

Gabriel Genellina

You are right however this case is a bit different. The application is
a keylogger which listens for keyboard events. The GUI is done using
Wx. They are different message loops. Under Linux I have no problem
however in the case of Windows I don't know how to stop the keylogger.

The Keylogger for Windows is very simple, see:
http://retypingdante.svn.sourceforg.../trunk/inferno/src/rtd_Wkeylog.py?view=markup

This code uses PumpMessages just because it's a console application, and
those do not have a message loop by default. A windowed application
written in wx *already* has a message loop, so you don't have to provide
your own.

Stopping the keylogger, in that code, means calling the cancel() method,
by any means you want. It has nothing to do with a message loop, AFAICT.
As you can see in the cancel function I cannot use
win32gui.PostQuitMessage(1) since it kills the whole app, including
Wx, and not just the thread. I cannot mix the eventloops of Windows
and Wx AFAIK so I put it in its own thread. I'm already using Queue
objects to pass the data between threads.

I still don't understand why you use a separate message loop. wx provides
its own, and it should be enough - worse, a second message loop may
adversely affect the application. And without a separate message loop, the
separate thread has no sense either.

Anyway, if you insist, it's more efficient to wait using an Event object:

def __init__(...):
...
self.finished = threading.Event()

def run(self):
self.hm.HookKeyboard()
self.finished.wait()

def cancel(self):
self.hm.UnhookKeyboard()
self.finished.set()
 
A

aloonstra

En Fri, 13 Mar 2009 17:59:34 -0200, <[email protected]> escribió:






This code uses PumpMessages just because it's a console application, and  
those do not have a message loop by default. A windowed application  
written in wx *already* has a message loop, so you don't have to provide  
your own.

Stopping the keylogger, in that code, means calling the cancel() method,  
by any means you want. It has nothing to do with a message loop, AFAICT.


I still don't understand why you use a separate message loop. wx provides  
its own, and it should be enough - worse, a second message loop may  
adversely affect the application. And without a separate message loop, the  
separate thread has no sense either.

Anyway, if you insist, it's more efficient to wait using an Event object:

def __init__(...):
   ...
   self.finished = threading.Event()

def run(self):
   self.hm.HookKeyboard()
   self.finished.wait()

def cancel(self):
   self.hm.UnhookKeyboard()
   self.finished.set()

You're right. Last night I dived into all this message looping thing
and I don't even have to use PumpMessages(). I got it working from
within wx using its messageloop. So I don't need a seperate thread no
more.

Thanks for your suggestions.

Arnaud
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,294
Messages
2,571,511
Members
48,206
Latest member
EpifaniaMc

Latest Threads

Top