Really more of a question here. Based on pyHook's tutorial, the .HookManager().OnMouseEvent event variable in the function has a .Injected attribute. I couldn't find any information about it, does anyone know what it is? I tried doing
event.Injected = '<char to inject>'
but it didn't work.
Disclaimer: I'm not expert of this stuff,
I'm just sharing my observations about the tutorial and the documentation,
in the hope that it will be helpful.
The attributes on event are not for you to set manually,
but for your event handlers to read and act upon.
As you can see in the documentation of KeyboardEvent and MouseEvent,
the purpose of the Injected instance variables is to check if the event was generated programmatically or not.
I think, this means events that your handlers receive from mouse and keyboard activity, will always have this variable False.
And there is a way to generate events programmatically,
I imagine for the purpose of testing your handlers.
And the method appear to be HookManager.KeyboardSwitch and HookManager.MouseSwitch.
Try this for example. Create a simple program to see the details of some real keyboard events:
import pythoncom, pyHook
def OnKeyboardEvent(event):
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 '---'
# return True to pass the event to other handlers
return True
# create a hook manager
hm = pyHook.HookManager()
# watch for key press events
hm.KeyDown = OnKeyboardEvent
# set the hook
hm.HookKeyboard()
# wait forever
pythoncom.PumpMessages()
Press a couple of keys and observe the outputs. Press Control-C to terminate the program.
Then, to generate some events programmatically and see what they look like,
try something like this:
import pythoncom, pyHook
def OnKeyboardEvent(event):
# ... same code as in previous sample ...
# create a hook manager
hm = pyHook.HookManager()
# watch for key press events
hm.KeyDown = OnKeyboardEvent
# set the hook
hm.HookKeyboard()
# send keyboard event programmatically
msg = ... # a value like in the "Message: ..." output in the previous run
vk_code = ... # a value like in the "KeyID: ..." output in the previous run
scan_code = ... # a value like in the "ScanCode: ..." output in the previous run
ascii = ... # a value like in the "Ascii: ..." output in the previous run
flags = 0x10 # see http://pyhook.sourceforge.net/doc_1.5.0/pyhook.HookManager-pysrc.html#KeyboardEvent.IsInjected
time = ... # a value like in the "Time: ..." output in the previous run
hwnd = ... # a value like in the "Window: ..." output in the previous run
win_name = ... # a value like in the "WindowName: ..." output in the previous run
hm.KeyboardSwitch(msg, vk_code, scan_code, ascii, flags, time, hwnd, win_name)
After you set appropriate values,
and run this program,
you should see "Injected: True" in the output.
I think this is the basic idea, and similarly for mouse events.
Unfortunately I'm not able to test this,
because it seems pyHook is a library for Windows OS, which I don't have.
Related
Here is my Python 2.7.13 script that is basically a so called "one key macro" for a video game. Based on information captured from a part of the game screen it presses the right key combinations instead of the player. So the player is spamming the f key and the script presses other keys alongside f.
It is working as is, however at random times (1-5 minutes after start) the script just stops or something similar. I can see in windows task manager that the script is running, however nothing happens when I press the f key.
At the beggining I was wrote the code a little bit more unoptimised and it took a screenshot more than once / keypress. The script "froze" more often back then.
Can this be beacause of too many screenshots? Or did I messed up somewhere?
import pyautogui, pythoncom, pyHook
# Determine if an ability is ready or not
def ready(x,y, im):
if (im.getpixel((x,y)) != (0,0,0)):
return True
else:
return False
def ability1(im):
return (ready(17, 16, im) or ready(35, 16, im))
def ability2(im):
return ready(134, 9, im)
# Listen for keypress
def OnKeyboardEvent(event):
im = pyautogui.screenshot(region=(249, 770, 194, 26))
if (event.KeyID == 70): # Pressed the "f" key
if (ability1(im)):
pyautogui.hotkey('shift','4')
return True
if (ability2(im)):
pyautogui.press('-')
return True
pyautogui.press('1')
return True
# create a hook manager
hm = pyHook.HookManager()
# watch for all mouse events
hm.KeyDown = OnKeyboardEvent
# set the hook
hm.HookKeyboard()
# wait forever
pythoncom.PumpMessages()
If you're running this on live servers, this could be due to increased checks/interference from Warden.
I advise against using such automation on live servers, could lead to a ban if noticed.
I was playing around with info I can get from key presses and mouse events in python and everything seems to work except when I quit the program I get this error.
runtime error R6031 - Attempt to initialize the CRT more than once. This indicates a bug in your application.
Here is my code not that it only happens when I press 'q' and the program quits.
import pythoncom, pyHook, sys
def OnMouseEvent(event):
# called when mouse events are received
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 '---'
return True
def OnKeyboardEvent(event):
print "Message Name: ", 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 '---'
if chr(event.Ascii) == 'q':
sys.exit()
return True
hm = pyHook.HookManager()
hm.KeyDown = OnKeyboardEvent
hm.MouseDown = OnMouseEvent
hm.HookKeyboard()
hm.HookMouse()
pythoncom.PumpMessages()
Thanks in advance for the help!
You have to "unhook" the hooks that you created to do a proper exit.
To terminate the "pythoncom.PumpMessages()" ever-lasting-loop:
if chr(event.Ascii) == 'q':
ctypes.windll.user32.PostQuitMessage(0)
The following code works correctly on Windows 7 with Python 2.7.6.
I haven't yet figured out how to make it work under Python 3.4, but I'll be back when I know!
import pythoncom, pyHook
import ctypes
import sys
def OnMouseEvent(event):
# called when mouse events are received
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('---')
return True
def OnKeyboardEvent(event):
print("Message Name: ", 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('---')
if chr(event.Ascii) == 'q':
ctypes.windll.user32.PostQuitMessage(0)
return True
print("")
print('Python version:')
print((sys.version))
print("")
hm = pyHook.HookManager() # create a hook manager
hm.MouseAll = OnMouseEvent # watch for all mouse events
hm.HookMouse() # set the hook
hm.KeyDown = OnKeyboardEvent # watch for "OnKeyboardEvent"
hm.HookKeyboard() # set the hook
pythoncom.PumpMessages()
# if you reached this point you have terminated the program correctly!
# flush and close any open files etc.
hm.UnhookMouse()
hm.UnhookKeyboard()
print("")
print("The end of Mouse and KBD test!")
print("")
LushIsTheLanguage's answer does not solve the error.
The error comes on 64 bit Python installations, not 32 bit.
It is caused by HookMouse, if that is disabled then the error disappears.
So, it's a bug in PyHook/HookMouse for 64 bit Python installations. The quickest solution is to switch to 32 bit Python.
The suggestion of LushIsTheLanguage has partly solved one problem I was facing for long time. I have embedded python interpreter in one multithreaded C code with GTK. I could run my *.py script (with pyHook imported in it) from the GTK based GUI only for first time. Next time when I used to run it the full code used to crash. Without pyHook imported scripts I could run any number of times from my GUI.
Now after calling hm.UnhookMouse() and hm.UnhookKeyboard() at the end of the python script I can run it more that one time from my GUI. However still it is crashing after four or five times.
In my *.py script I am not using "pythoncom.PumpMessages()", rather I am using while loop with "pythoncom.PumpWaitingMessages()", so that I can break it once any key is pressed.
key_scn_code = -1
while key_scn_code < 0:
time.sleep(0.05)
if os.name == 'nt':
pythoncom.PumpWaitingMessages()
my callback for keyboard-events is something like the following
def kbevent_callback( key_event ):
global key_scn_code
key_scn_code = key_event.ScanCode
return True
I have checked it in Win-7 64-bit (python 2.7 32-bit) and Linux 64-bit (using pyxhook) with python 2.7. Both have similar problem. Does any one have any suggestion.
I need to check whether the Escape key has been pressed during execution of some non-GUI code. (The code is in Python, but can easily call into C if necessary.) The code received a function from the GUI that it occasionally calls to check whether it has been interrupted. The question is how to implement this check.
By looking at the documentation, gdk_event_peek seems like an excellent choice for this:
def _check_esc(self):
event = gtk.gdk.event_peek()
if event is None or event.type not in (gtk.gdk.KEY_PRESS, gtk.gdk.KEY_RELEASE):
return False
return gtk.gdk.keyval_name(event.keyval) == 'Escape'
This doesn't work, however: the event returned from gtk.gdk.event_peek() is always None when the main loop is not running. Changing it to gtk.gdk.display_get_default().peek_event() doesn't help either. I assume the events are in the X event queue and are not yet moved to the GDK event queue. The documentation says:
Note that this function will not get more events from the windowing
system. It only checks the events that have already been moved to the
GDK event queue.
So, how does one transfer the event to the GDK event queue or? In other words, when does gtk.gdk.peek_event() ever return an event? Calling gtk.events_pending() doesn't have any effect.
Here is a minimal program to test it:
import gtk, gobject
import time
def code(check):
while 1:
time.sleep(.1)
if check():
print 'interrupted'
return
def _check_esc():
event = gtk.gdk.event_peek()
print 'event:', event
if event is None or event.type not in (gtk.gdk.KEY_PRESS, gtk.gdk.KEY_RELEASE):
return False
return gtk.gdk.keyval_name(event.keyval) == 'Escape'
def runner():
code(_check_esc)
gtk.main_quit()
w = gtk.Window()
w.show()
gobject.idle_add(runner)
gtk.main()
When running the code, the event printed is always None, even if you press Escape or move the mouse.
I also considered installing a handler for Escape and having the checker process events with the while gtk.events_pending(): gtk.main_iteration() idiom. This results in unqueuing and dispatch of all pending events, including keyboard and mouse events. The effect is that the GUI is responsive enabled while the code runs, which doesn't look well and can severely interfere with the execution of the code. The only event processed during execution should be the escape key to interrupt it.
I came up with a runner implementation that satisfies the criteria put forward in the question:
def runner():
# _check_esc searches for Escape in our queue
def _check_esc():
oldpos = len(queue)
while gtk.events_pending():
gtk.main_iteration()
new = itertools.islice(queue, oldpos, None)
return any(event.type == gtk.gdk.KEY_PRESS \
and gtk.gdk.keyval_name(event.keyval) == 'Escape'
for event in new)
queue = []
# temporarily set the global event handler to queue
# the events
gtk.gdk.event_handler_set(queue.append)
try:
code(_check_esc)
finally:
# restore the handler and replay the events
handler = gtk.main_do_event
gtk.gdk.event_handler_set(gtk.main_do_event)
for event in queue:
handler(event)
gtk.main_quit()
Compared to a peek-based solution, its advantage is that it handles the case when another event arrives after the keypress. The disadvantage is that it requires fiddling with the global event handler.
I'm using pyhook and pyhk to map keystrokes on a windows XP machine, and it works fine except for when the keystroke (say, ctrl+z) already exists in the application. In that case, the ctrl+z passes to the application and triggers the action that has been mapped to it.
If you are familiar with autohotkey, note that autohotkey gets around this by defining hotkeys that can optionally be passed to the underlying application. Here's a bit of codes that gets at the idea. Note that I'm trying to keep track of when the ctrl key is down.
import pythoncom, pyHook
control_down = False
def OnKeyboardEvent_up(event):
global control_down
if event.Key=='Lcontrol' or event.Key=='Rcontrol':
control_down=False
return True
def OnKeyboardEvent(event,action=None,key='Z',context=None):
global control_down
if event.Key=='Lcontrol' or event.Key=='Rcontrol':
control_down=True
if control_down and event.Key==key:
print 'do something'
return False
if event.Key=='Pause':
win32gui.PostQuitMessage(1)
return False
# return True to pass the event to other handlers
return True
if __name__ == '__main__':
hm = pyHook.HookManager()
hm.KeyDown = OnKeyboardEvent
hm.KeyUp = OnKeyboardEvent_up
hm.HookKeyboard() # set the hook
pythoncom.PumpMessages() # wait forever
Any help appreciated.
Thanks!
If you're insterested in Windows only, you can use win API, e.g. via ctypes:
>>> from ctypes import windll
>>> windll.user32.RegisterHotKey(0, -1, 0x0002, 0x5a)
After running these lines of code Ctrl (code = 0x0002) + Z (code = 0x5a) combination doesn't work any more in Python REPL.
So you should better look at what windows are those hotkey registered. More information you can find in MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/ms646309(v=vs.85).aspx
I may totally wrong here, but from my understanding of the pyHook documentation, in order to prevent the key presses from being sent to another application you need to change the return True in def OnKeyboardEvent_up(event): and OnKeyboardEvent(event,action=None,key='Z',context=None): to return False (or anything else other than True.
In windows I noticed that if the code "Do something" takes too long than the key codes are passed to the application even if you return False in the OnKeyboardEvent handler. The solution for me was to pack the code in a thread launched by the key or key combination press. This is sufficiently fast to make the return False work as expected.
def OnKeyboardEvent(event):
if event.key == myKey:
myThred = threading.Thread(target=doSomething_Function).start()
return False
I have a Python program that sends keystrokes to another application using SendKeys. Some of the keystrokes, however, must be sent to the application after it does some processing (which takes an unknown amount of time). So far I have had to let the Python application know the processing was finished by Alt+Tabbing back to the DOS window and hitting Enter. I'd like to have a key combination (Shift+F1 or something like that) that I can hit in the receiving application that signals the Python program to continue without me having to switch back to the DOS window. How would I make it so I can detect keystrokes in Python even though the focus is on another window?
Have a look at pyHook.
It allows Keyboard hooking:
import pythoncom, pyHook
def OnKeyboardEvent(event):
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 '---'
# return True to pass the event to other handlers
return True
# create a hook manager
hm = pyHook.HookManager()
# watch for all mouse events
hm.KeyDown = OnKeyboardEvent
# set the hook
hm.HookKeyboard()
# wait forever
pythoncom.PumpMessages()