I have made a script that can send keys to any app in the background, but it does not work on DirectX.
I am trying to make my character jump in a game called "roblox".
This is the script
import time
import psutil
import win32con
from win32 import win32gui
from win32 import win32api
from win32 import win32process
keyDict = {" ": 0x20}
for i in range(0x41, 0x5A+1):
keyDict[chr(i)] = i
def CloseExe(exeName):
ID2Handle={}
def get_all_hwnd(hwnd,mouse):
if win32gui.IsWindow(hwnd) and win32gui.IsWindowEnabled(hwnd) and win32gui.IsWindowVisible(hwnd):
nID=win32process.GetWindowThreadProcessId(hwnd)
del nID[0]
for abc in nID:
try:
pro=psutil.Process(abc).name()
except psutil.NoSuchProcess:
pass
else:
if pro == exeName:
win32gui.PostMessage(hwnd,win32con.WM_CLOSE,0,0)
win32gui.EnumWindows(get_all_hwnd, 0)
def SendKeysSensitive(exeName, keysToSend):
mID2Handle={}
def get_all_hwnd(hwnd,mouse):
hwndTwo = win32gui.GetWindow(hwnd, win32con.GW_CHILD)
if win32gui.IsWindow(hwnd) and win32gui.IsWindowEnabled(hwnd) and win32gui.IsWindowVisible(hwnd):
nID=win32process.GetWindowThreadProcessId(hwnd)
del nID[0]
for abc in nID:
try:
pro=psutil.Process(abc).name()
except psutil.NoSuchProcess:
pass
else:
if pro == exeName:
for key in keysToSend:
win32gui.PostMessage(hwndTwo, win32con.WM_CHAR, key, 0)
def SendKeys(exeName, keysToSend):
mID2Handle={}
def get_all_hwnd(hwnd,mouse):
hwndTwo = hwnd
if win32gui.IsWindow(hwnd) and win32gui.IsWindowEnabled(hwnd) and win32gui.IsWindowVisible(hwnd):
nID=win32process.GetWindowThreadProcessId(hwnd)
del nID[0]
for abc in nID:
try:
pro=psutil.Process(abc).name()
except psutil.NoSuchProcess:
pass
else:
if pro == exeName:
for key in keysToSend:
win32gui.PostMessage(hwndTwo, win32con.WM_CHAR, key, 0)
win32gui.EnumWindows(get_all_hwnd, 0)
def TranslateKeys(text):
outKeys = []
for char in text:
outKeys.append(keyDict.get(char.upper()))
return outKeys
def ExE(name):
return name
if __name__ == '__main__':
prog = ExE("RobloxPlayerBeta.exe")
jump = TranslateKeys(" ")
SendKeys(prog, jump)
It does not work due to "RobloxPlayerBeta.exe" being DirectX.
I can not open the app, it 100% needs to be in the background.
Is this possible?
Well I had a problem similar to this and I found a solution. I'm not sure if this is what you're looking for, but there is a library for sending input to DirectX applications
It's called PyDirectInput. It's essentially PyAutoGui but works with DirectX
pip install pydirectinput
As far as roblox, I have used this before and can say it does work.
source code
Related
i'm pretty new to python, so my knowledge is quiet basic. (i'm a system engineer)
i have a raspberry pi, an led strip and a python script to simulate a fire on the led strip :D
now i want to start the script by pressing my flic button. i found the fliclib sdk on github and installed it. my problem is now, how to handle the event correctly. i successfully can start the script, but i'd like to stop it by doublepress the flic button. but it seems like i'm stuck in the fire.py script as soon as i press the button once. can anybody help me how to set this up correctly please? :-)
Edit after suggestion:
i just edited my scripts as the following. i can see when the button is pressed once or twice with this output:
Starting Fire
Stopping Fire
but the led wont turn on, seems like, fire.py isn't opened or something like that.. when i set button=1 in fire.py itself, the fire turns on.
main.py
#!/usr/bin/env /usr/bin/python3
# -*- coding: utf-8 -*-
import flicbutton
import fire
button = 0
flicbutton.py
#!/usr/bin/env /usr/bin/python3
# -*- coding: utf-8 -*-
import fliclib
client = fliclib.FlicClient("localhost")
MyButton1 = '80:e4:da:71:83:42' #turquoise flic button
def got_button(bd_addr):
cc = fliclib.ButtonConnectionChannel(bd_addr)
cc.on_button_single_or_double_click_or_hold = some_handler
cc.on_connection_status_changed = \
lambda channel, connection_status, disconnect_reason: \
print(channel.bd_addr + " " + str(connection_status) + (" " + str(disconnect_reason) if connection_status == fliclib.ConnectionStatus.Disconnected else ""))
client.add_connection_channel(cc)
def got_info(items):
print(items)
for bd_addr in items["bd_addr_of_verified_buttons"]:
got_button(bd_addr)
def some_handler(channel, click_type, was_queued, time_diff):
if channel.bd_addr == MyButton1:
try:
if click_type == fliclib.ClickType.ButtonSingleClick:
print("Starting Fire")
button=1
if click_type == fliclib.ClickType.ButtonDoubleClick:
print("Stopping Fire")
button=2
if click_type == fliclib.ClickType.ButtonHold:
print("ButtonHold has not been assigned an action")
except Exception:
import datetime
print('An error occured: {:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now()))
client.get_info(got_info)
client.on_new_verified_button = got_button
client.handle_events()
fire.py
import RPi.GPIO as GPIO
import threading
import time
import random
import math
R = 17
G = 22
pwms = []
intensity = 1.0
def initialize_gpio():
GPIO.setmode(GPIO.BCM)
GPIO.setup([17,22], GPIO.OUT)
def red_light():
p = GPIO.PWM(R, 300)
p.start(100)
pwms.append(p)
while True:
p.ChangeDutyCycle(min(random.randint(50, 100) * math.pow(intensity + 0.1, 0.75), 100) if intensity > 0 else 0)
rand_flicker_sleep()
def green_light():
global green_dc
p = GPIO.PWM(G, 300)
p.start(0)
pwms.append(p)
while True:
p.ChangeDutyCycle(random.randint(5, 10) * math.pow(intensity, 2) if intensity > 0 else 0)
rand_flicker_sleep()
def rand_flicker_sleep():
time.sleep(random.randint(3,10) / 100.0)
def fan_the_flame(_):
global intensity
intensity = min(intensity + 0.25, 1.0)
def light_candle():
threads = [
threading.Thread(target=red_light),
threading.Thread(target=green_light),
## threading.Thread(target=burning_down)
]
for t in threads:
t.daemon = True
t.start()
for t in threads:
t.join()
def startfire():
try:
initialize_gpio()
print("\nPress ^C (control-C) to exit the program.\n")
light_candle()
except KeyboardInterrupt:
pass
finally:
for p in pwms:
p.stop()
def stopfire():
GPIO.cleanup()
#if __name__ == '__main__':
# main()
if button == 1:
startfire()
if button == 2:
stopfire()
Have a common (global variable) that both codes can read, you can put this in a standalone file that both codes can access. So script 1 updates this variable like
if(single press): variable=1
elif(double press): variable=2
then in fire.py you can poll the variable.
if(varaible==1): start/stop fire
elif(variable==2): stop/start fire
else: #throw error
I'm sure there are more efficient ways to do this, but this method should be the easiest to understand.
I am changing my windows desktop background with the following code
ctypes.windll.user32.SystemParametersInfoW(20, 0, "C:/image/jkk7LGN03aY.jpg" , 0)
my image directory has so many images and I am setting those one by one as follows
for path in image_list:
ctypes.windll.user32.SystemParametersInfoW(20, 0, path , 0)
time.sleep(5)
Desktop background image is changing abruptly but I want a smooth transition. How can I do this?
Here's a pure Python snippet that I use regularly:
It uses pywin32 to enable active desktop and set the wallpaper using a smooth transition (make sure you've not disabled window effects or you won't see any fade effect)
import ctypes
from typing import List
import pythoncom
import pywintypes
import win32gui
from win32com.shell import shell, shellcon
user32 = ctypes.windll.user32
def _make_filter(class_name: str, title: str):
"""https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumwindows"""
def enum_windows(handle: int, h_list: list):
if not (class_name or title):
h_list.append(handle)
if class_name and class_name not in win32gui.GetClassName(handle):
return True # continue enumeration
if title and title not in win32gui.GetWindowText(handle):
return True # continue enumeration
h_list.append(handle)
return enum_windows
def find_window_handles(parent: int = None, window_class: str = None, title: str = None) -> List[int]:
cb = _make_filter(window_class, title)
try:
handle_list = []
if parent:
win32gui.EnumChildWindows(parent, cb, handle_list)
else:
win32gui.EnumWindows(cb, handle_list)
return handle_list
except pywintypes.error:
return []
def force_refresh():
user32.UpdatePerUserSystemParameters(1)
def enable_activedesktop():
"""https://stackoverflow.com/a/16351170"""
try:
progman = find_window_handles(window_class='Progman')[0]
cryptic_params = (0x52c, 0, 0, 0, 500, None)
user32.SendMessageTimeoutW(progman, *cryptic_params)
except IndexError as e:
raise WindowsError('Cannot enable Active Desktop') from e
def set_wallpaper(image_path: str, use_activedesktop: bool = True):
if use_activedesktop:
enable_activedesktop()
pythoncom.CoInitialize()
iad = pythoncom.CoCreateInstance(shell.CLSID_ActiveDesktop,
None,
pythoncom.CLSCTX_INPROC_SERVER,
shell.IID_IActiveDesktop)
iad.SetWallpaper(str(image_path), 0)
iad.ApplyChanges(shellcon.AD_APPLY_ALL)
force_refresh()
if __name__ == '__main__':
set_wallpaper(r'D:\Wallpapers\Cool\enchanted_mountain_4k.jpg')
import win32com
import win32com.client
import win32gui
import win32con
import pythoncom
def getIEServer(hwnd, ieServer):
if win32gui.GetClassName(hwnd) == 'Internet Explorer_Server':
ieServer.append(hwnd)
if __name__ == '__main__':
#pythoncom.CoInitializeEx(0) # not use this for multithreading
mainHwnd = win32gui.FindWindow('windowclass', 'windowtitle')
if mainHwnd:
ieServers = []
win32gui.EnumChildWindows(mainHwnd, getIEServer, ieServers)
if len(ieServers) > 0:
ieServer = ieServers[0]
msg = win32gui.RegisterWindowMessage('WM_HTML_GETOBJECT')
ret, result = win32gui.SendMessageTimeout(ieServer, msg, 0, 0, win32con.SMTO_ABORTIFHUNG, 1000)
ob = pythoncom.ObjectFromLresult(result, pythoncom.IID_IDispatch, 0)
doc = win32com.client.dynamic.Dispatch(ob)
print doc.url
# doc.all['id'].click()
You can get doc (document object) with the above code
If you try doc.getElementById ("some-id")
I get an error like the one below.
TypeError: getElementById () takes 1 positional argument but 2 were given
It will appear in IE11
Please Help Me T0T~
p.s The type of problem is different from the suggested answer.
I think I need to fix the error in pywin32.
I'm writing a Python programme with a GUI which listens for an RFID token being presented (using a USB reader which emulates keyboard input). I'm having issues whereby keyboard/RFID input is only listened for and acted upon if the Terminal from which I launch the script has focus.
If the GUI is focussed, all input is ignored but when the terminal has focus, it works fine and even sends updates to the GUI as well as shell. I've tried drawing a text input box on the GUI, but that didn't work.
I'm wondering if it's something to do with how it needs to use either multiple threads, queues or even processes - can anyone help me to understand it better?
Code is below, thanks in advance!
#!/usr/bin/env python3
import sys
import MySQLdb
try:
# python 2
import Tkinter as tk
import ttk
except ImportError:
# python 3
import tkinter as tk
from tkinter import ttk
from threading import Thread
class Fullscreen_Window:
def __init__(self):
self.tk = tk.Tk()
self.tk.title("Listening for RFID token...")
self.frame = tk.Frame(self.tk)
self.frame.pack()
self.tk.attributes('-zoomed', True)
self.state = False
self.tk.bind("<F11>", self.toggle_fullscreen)
self.tk.bind("<Escape>", self.end_fullscreen)
self.tk.config(cursor="none")
t = Thread(target=self.listen_rfid)
t.daemon = True
t.start()
def toggle_fullscreen(self, event=None):
self.state = not self.state # Just toggling the boolean
self.tk.attributes("-fullscreen", self.state)
return "break"
def end_fullscreen(self, event=None):
self.state = False
self.tk.attributes("-fullscreen", False)
return "break"
def listen_rfid(self):
dbHost = 'localhost'
dbName = 'python'
dbUser = 'python'
dbPass = 'PASSWORD'
dbConnection = MySQLdb.connect(host=dbHost, user=dbUser, passwd=dbPass, db=dbName)
cur = dbConnection.cursor(MySQLdb.cursors.DictCursor)
with open('/dev/stdin', 'r') as tty:
while True:
RFID_input = tty.readline().rstrip()
cur.execute("SELECT * FROM access_list WHERE rfid_code = '%s'" % (RFID_input))
if cur.rowcount != 1:
print("ACCESS DENIED")
ttk.Label(self.tk, text="ACCESS DENIED").pack()
else:
user_info = cur.fetchone()
print("Welcome %s!!" % (user_info['name']))
ttk.Label(self.tk, text="Welcome %s!!" % (user_info['name'])).pack()
tty.close()
if __name__ == '__main__':
w = Fullscreen_Window()
w.tk.mainloop()
After much head scratching, I found this thread again and re-read it properly, then realised it contained the answer I was after, albeit with a tiny bit of work needed from me.
My listen_rfid function now looks like the code below. Hope it's useful for anyone stumbling across my problem!
The key thing is to look in /dev/input/by-id and find your device, there will be a symlink (at least there was on my Raspbian install) to something more elegant like, in my case, "/event0" - as below). You can then use python-evdev to read it.
If you don't have python-evdev, just install it with sudo pip install evdev
Here's the working code:
def listen_rfid(self):
dbHost = 'localhost'
dbName = 'python'
dbUser = 'python'
dbPass = 'PASSWORD'
dbConnection = MySQLdb.connect(host=dbHost, user=dbUser, passwd=dbPass, db=dbName) # ToDo: This needs some error handling for if MySQL has gone away, and reconnect.
cur = dbConnection.cursor(MySQLdb.cursors.DictCursor)
from evdev import InputDevice
from select import select
keys = "X^1234567890XXXXqwertzuiopXXXXasdfghjklXXXXXyxcvbnmXXXXXXXXXXXXXXXXXXXXXXX"
dev = InputDevice('/dev/input/event0')
rfid_presented = ""
while True:
r,w,x = select([dev], [], [])
for event in dev.read():
if event.type==1 and event.value==1:
if event.code==28:
#print("RFID: " + str(rfid_presented))
cur.execute("SELECT * FROM access_list WHERE rfid_code = '%s'" % (rfid_presented))
if cur.rowcount != 1:
#print("ACCESS DENIED")
ttk.Label(self.tk, text="ACCESS DENIED").pack()
else:
user_info = cur.fetchone()
#print("Welcome %s!!" % (user_info['name']))
ttk.Label(self.tk, text="Welcome %s!!" % (user_info['name'])).pack()
rfid_presented = ""
else:
rfid_presented += keys[ event.code ]
import win32com.client as cc
class AgentEvents(object):
def OnClick(self, cid, button, shift, x, y):
peedy.Speak('He he he')
def OnCommand(self, UserInput):
cmdname = cc.Dispatch(UserInput).Name
print(cmdname)
if cmdname == 'hwru':
peedy.Speak('Well. Thank you.')
elif cmdname == 'yoname':
peedy.Speak('My name is Peedy.')
ag = cc.DispatchWithEvents('Agent.Control.2', AgentEvents)
ag.Connected = True
ag.Characters.Load('peedy', 'peedy.acs')
peedy = ag.Characters('peedy')
peedy.Show()
peedy.LanguageID=0x0409
#print(peedy.SRModeID)
peedy.Commands.Add('hwru','how are you','how are you',True,True)
peedy.Commands.Add('yoname',"what's your name","what's your name",True,True)
ag.CommandsWindow.Visible=True
When I run this from pythonwin IDE all works normal, but from windows command line OnCommand events don't work, it prints no errors, COM object methods (like peedy.Speak("Hello")) work normal too.
Is it possible to use win32com activex objects with events from command line?
Solved with:
while True:
# Pump messages so that COM gets a look in
pythoncom.PumpWaitingMessages()