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.
Related
def on_press(key):
if key == keyboard.Key.media_play_pause: #to identify paly & pause
print("status got changed")
if key == keyboard.Key.media_next: #to identify forword cammand track
print("Next track started")
if key == keyboard.Key.media_previous: #to identify privous cammand track
print("Previous track started")
def stetaupdate ():
global tapdflag
if (tapdflag == 0)
tapdflag = 1
with keyboard.Listener(on_press=on_press) as listener: #thredding
listener.join()
t = threading.Thread(target = stetaupdate)
This code works fine to detect play and pause events in Windows, but I am using the same code in Linux, and it is missing alternate events for play and pause with earbuds, but next and previous events were working fine.
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.
I am writing a script intended to be used by members of a project team. As part of the script, I am launching a 3rd party proprietary application run through Citrix. I am going to use the script mostly to send keys to this application, but the first step once it launches is for the user to log in.
Because I would like the user to log in while the script is running, rather than asking for user/pass from some kind of GUI input earlier, and because the time it takes Citrix to launch varies, I would like to include some kind of logic that detects when the user has logged in and then resume the script from there, rather than including an obnoxiously long implicit wait or risking the script timing out.
Is there a way to detect user keystrokes using win32com.client (or to detect a change in state of the application itself)? See below for the relevant code to launch the app:
import win32com.client
shell = win32com.client.Dispatch("WScript.Shell")
shell.Run('C:\Citrix\[rest of path])
EDIT:
Per Vasily's suggestion in the comments below, I attempted to adapt the "hook and listen" code to my scenario, but was unsuccessful. When I launch my file, I don't even get an exception message in my terminal, I get a Windows pop-up that says Python encountered a problem and needs to quit.
This is how I adapted it:
#[omitting import lines for brevity]
def on_timer():
"""Callback by timer out"""
win32api.PostThreadMessage(main_thread_id, win32con.WM_QUIT, 0, 0);
def on_event(args):
"""Callback for keyboard and mouse events"""
if isinstance(args, KeyboardEvent):
for i in range(1,100):
time.sleep(1)
if args.pressed_key == 'Lcontrol':
break
def init():
hk = Hook()
hk.handler = on_event
main_thread_id = win32api.GetCurrentThreadId()
t = Timer(55.0, on_timer) # Quit after 55 seconds
t.start()
hk.hook(keyboard=True, mouse=True)
At the point when the 3rd party Citrix app begins to launch in my main script, I call hookandlisten.init().
As a reminder, my goal is to wait until the user sends a certain keystroke (here I chose Control) before proceeding with the rest of the main script.
Solved this by eliminating the timer and unhooking the keyboard upon the correct keystroke:
import win32api
import win32con
from pywinauto.win32_hooks import Hook
from pywinauto.win32_hooks import KeyboardEvent
from pywinauto.win32_hooks import MouseEvent
def on_event(args):
"""Callback for keyboard and mouse events"""
if isinstance(args, KeyboardEvent):
if args.current_key == 'Lcontrol' and args.event_type == 'key down':
print("Success")
hk.unhook_keyboard()
return
def init():
hk.handler = on_event
hk.hook(keyboard=True, mouse=False)
hk = Hook()
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 am trying to make the most simple pythong code that will respond when a button is pressed on a joystick. I used code from several different examples and I still cannot get it to work. The following code will not dispatch the event when I press the trigger (or any button for that matter)
import pygame
joy = []
def handleJoyEvent(e):
if e.type == pygame.JOYBUTTONDOWN:
str = "Button: %d" % (e.dict['button'])
if (e.dict['button'] == 0):
print ("Pressed!\n")
else:
pass
def joystickControl():
while True:
e = pygame.event.wait()
if (e.type == pygame.JOYBUTTONDOWN):
handleJoyEvent(e)
# main method
def main():
pygame.joystick.init()
pygame.display.init()
for i in range(pygame.joystick.get_count()):
myjoy = pygame.joystick.Joystick(i)
myjoy.init()
joy.append(myjoy)
# run joystick listener loop
joystickControl()
# allow use as a module or standalone script
if __name__ == "__main__":
main()
I assume you've tried leaving off the if and just printing str?
Your joystick might also not be working properly. Does it work in other programs?
If you are using linux you might need to install a joystick driver. For Windows, check the device manager.