Macbook OpenEmu Python send keystrokes - python

I am really impressed by this MarlIO project and want to implement something similar using Python. However, I got the emulator OpenEmu working, however, I don't know how to control the game using Python.
Isn't it just a matter of sending a few keystrokes?! Man, it is not that straightforward on a Mac.
In [41]: cmd1
Out[41]: '\nosascript -e \'tell application "System Events" to key code 48 using {command down}\' \n'
In [42]: cmd2
Out[42]: '\nosascript -e \'tell application "System Events" to keystroke "a"\' \n'
I want to first use COMMAND+TAB to switch to the openEmu and then hit a to jump. However, when I ran the two commands, it only switched to the OpenEmu, looks like the keystroke a did not got sent.
However, when I ran 'cmd2' separately, it was clearly working.
Then I testedit against a different application - sublime, and it seemed to work there.
Can anyone point me to the right direction what I really did wrong with OpenEmu?

I did something like that a few months ago. The keystrokes are sent. However, System Event keystrokes last virtually no time, so the emulator's input mechanism doesn't pick them up.
I couldn't find a way to ask for a duration with AppleScript, so I ended up solving the problem using Quartz event taps, which let you do, for instance, "start pressing key, sleep 0.1s, stop pressing key". I did it in Swift, but you should be able to do it in Python with the ctype module.
Also note that it might be difficult to synchronize on a frame basis with the emulator. I raised that problem with the project maintainers, but I turned away because of the relatively cold response.

Related

How can I send keystrokes and mouse movement to a specific PID?

How can I send keystrokes and mouse movements to a specific running program through its PID. I've used both pywinauto and pynput, and they work great, but I want to send keys to a program that is not in focus. I found this question: How to I send keystroke to Linux process in Python by PID? but it never explains what filePath is a path to.
If you could help solve for this example, that would be great! I want to send the "d" key to an open Minecraft tab for 10 seconds, and then send the "a" key for the next 10 seconds and stop. I would need this to be able to run in the background, so it could not send the keys to the computer as a whole, but only to the Minecraft tab. I am on Windows 10 by the way.
Any help would be appreciated!
Pretty sure you won't be able to, at least not easily let me explain a little bit how all of this works.
Lets start with the hardware and os, the OS has certain functions to read the input you give the computer. This input goes into a "pipe", the OS is reading input, and putting into the pipe, on the other side of the pipe there may be an application running, or it may not. The OS typically manages this (which app to put on the pipe listening) by defining which app/window is active. Apps access this pipe with the API given by the OS, they read the input and decide on it.
The libraries you cited above, change the values of the keyboard and mouse, in other words, they make the OS read other values, not the real ones, then the OS puts them in the "pipe", and are read by the app that is listening on the pipe (the one active). Some apps have their own API's for this, but I would guess Minecraft doesn't. If they don't have an API, what can you do? well, as I said, nothing easy, first of all "hacking" the app, in other words change it to listen to some other input/output rather than the one given by the OS, (this would be you making your own API). The other one would be you changing the OS, which would also be extremely hard, but maybe a tiny bitty easier. It also depends on your OS, I think Microsoft does offer input injection api's
So, simple options, first, run a VM with a GUI and use pywinauto, pyautogui, etc. The other option would be if you can run it in the browser, do so, and use something like Selenium to automate the input.
Quick note, why does selenium works and the browser can read input in the background? Easy, it's not, it just executes the code it would execute if it would have read the input! javascript, cool isn't
With ahk you can do this with Python+AutoHotkey
pip install ahk
pip install "ahk[binary]"
from ahk import AHK
from ahk.window import Window
ahk = AHK()
win = Window.from_pid(ahk, pid='20366')
win.send('abc') # send keys directly to the window
Note that some programs may simply ignore inputs when they are not in focus. However, you can test this works in general even when not in focus by testing with a program like notepad
Full disclosure: I author the ahk library.

How to detect user input (such as a command - ctrl+shift+k) in Python on Mac?

So I'm building this joke program in Python. Basically, what it is and does is it is an app disguised as a game, and when opened, the headphone port is disabled, the audio output is set to computer speakers, volume is set to max, and it says 'gamer alert' many times. The problem I am having is that there is no way to stop it; even if you delete the application while it is running still won't do anything. I need a method of detecting a keyboard shortcut made to stop it. It needs to be compatible with Mac.
Note: if you want to test, you can set it to a lower volume by changing 100 to something around 20 or 30.
I've tried using PyGame, Tkinter, Pynput, Getch, etc. all didn't work. I'm not too sure if it's because I'm not using them right, or if they won't work at all with what I'm trying to do.
import os
while True:
os.system('SwitchAudioSource -s "Built-in Output"')
os.system("osascript -e 'set volume output volume 100'")
os.system("say gamer alert")
I have gotten a few error messages with some of the modules I mentioned above, but otherwise no error messages. The voice might stop after one iteration. Without this kill feature, it works beautifully.

"sh: Error: Can't open display" when I try to start a program from python

I have this really strange problem, basically I want to start xpdf (or Libreoffice) from my Python script, that is started by a systemd-service. When I start the script from terminal everything is working fine, but when I plug in my USB device that start the Service, I'll get this Error in my syslog:
sh[2321]: Error: Can't open Display
This error has something to do with X11, that's what my Google searches tell me.
So, my question is: How can I properly run a program like xpdf or libreoffice from Python?
import subprocess
subprocess.call("/usr/bin/xpdf")
This is it, basically. I know that it has something to do with the graphical enviroment, but I don't know how I can solve it.
The X display system has very good security to stop random local processes from just displaying stuff to the local screen (It was more a problem in the old days of expensive Sun and SGI systems where computer labs would often let users telnet to other boxes. Much fun could be had!).
If the user running the xpdf is the same user as the one who's logged into the X session, then you simply need to tell xpdf where to connect it's UI to. This is usually done by exporting DISPLAY=:0 to the environment, which means "connect to the first local screen". Most X programs also support -display :0 argument.
So do:
/usr/bin/xpdf -display :0
or:
DISPLAY=:0 /usr/bin/xpdf
It's very unlikely that you have more than one X session so :0 will work 99% of the time.
Since the issue is that xpdf isn't finding a display to connect to, we have two basic options: find and authenticate with an existing display, or make a new one. The latter is usually easier, something like:
xinit /usr/bin/xpdf -fullscreen $PDFFILE -- :2
This would start a new X display :2 running only xpdf, not even a window manager.
It finally worked, after trying and going crazy for around 2 weeks.
What worked was
os.system("DISPLAY=:0 /usr/bin/xpdf)
I know that subprocess.call is the better way to call the program, but it doesn't seem to work right now.
I'll try the way that Yann suggested later on, but for now I'm just overwhelmed with joy that it just works.
Thank you all for your help, I really appreciate it!

Can Python be used to send a true key down event to Mac

My question is, is there any way to reliably hold a key down on a mac with applescript/python?
I have search almost everywhere for topics like this, however, none of them cut it. I am attempting to use Python to read serial information from an Arduino, then relay those signals as keypresses. I have seen how to use applescript to send a "key down" to the system event, as shown in the following code:
(Python code)
def SendDown(key):
string = str(key)
cmd = """osascript -e 'tell application "System Events" to key down (key code """ + string + ")'"
os.system(cmd)
This code works generally, however, I want to control the Google flight simulator. When I attempt to do this, the key presses seem to be way to quick and the flight simulator or the basic google earth map moves fractions of what I would expect.
They way I am using this code is essentially as follows (suedocode)
if (ArduinoMessage == "left"):
SendDown(leftKey) #leftKey has been set to 123 -- the code for the left arrow key
etc...
From my point of view, the key down event I'm sending is essentially a quick keystroke and the key is not being held down. I tried programming the key event directly in applescript and had a little bit of success. My code looked something like this:
tell application "System Events"
repeat 50 times
key down (key code 123)
end repeat
key up (key code 123)
end tell
That code moved the google earth map more than I have been getting, but it took a long time to get it to move a small amount (far less than the normal arrow keys). Then I tried to write that applescript into Python and lost all improvement.
So I restate the question -- is there any way to reliably hold a key down on a mac with applescript/python?
I was able to get this to work on Windows fairly easily, however, I was able to use a Windows only library called SendKeys that is designed for applications such as this.
Any help would be appreciated.
Thanks,
Jake
Use PyUserInput.
Try following code.
import time
import pykeyboard
# TODO: Replace following two lines with the code that activate the application.
print('Activate the application 3 seconds.')
time.sleep(3)
k = pykeyboard.PyKeyboard()
k.press_key(k.left_key)
time.sleep(1) # Hold down left key for 1 second.
k.release_key(k.left_key)
Unfortunately I don't have Mac. I tested in Linux, Windows.

Precise response to tablet/mouse events in Windows

How can I tell Windows not to do unhelpful pre-processing on tablet pen events?
I am programming in Python 2.6, targetting tablet PCs running Windows 7 (though I would like my program to work with little modification on XP with a SMART interactive whiteboard, and for mouse users on Linux/Mac). I've written a program which hooks into the normal Windows mouse events, WM_MOUSEMOVE etc., and writes on a canvas.
The problem is that the mouse messages are being fiddled with before they reach my application. I found that if I make long strokes and pause between strokes then the mouse messages are sent properly. But if I make several rapid short strokes, then something is doing unhelpful pre-processing. Specifically, if I make a down-stroke about 10 pixels long, and then make another downstroke about five pixels to the right of the first, then the second WM_MOUSEDOWN reports that it comes from exactly the same place as the first.
This looks like some sort of pre-processing, perhaps so that naive applications don't get confused about double-clicks. But for my application, where I want very faithful response to rapid gestures, it's unhelpful.
I found a reference to the MicrosoftTabletPenServiceProperty atom, and to CS_DBLCLKS window style, and I turned them both off with the following piece of Python code:
hwnd = self.GetHandle()
tablet_atom = "MicrosoftTabletPenServiceProperty"
atom_ID = windll.kernel32.GlobalAddAtomA(tablet_atom)
windll.user32.SetPropA(hwnd,tablet_atom,1)
currentstyle = windll.user32.GetClassLongA(hwnd, win32con.GCL_STYLE)
windll.user32.SetClassLongA(hwnd, win32con.GCL_STYLE, currentstyle & ~win32con.CS_DBLCLKS)
But it has no effect.
I tried writing a low-level hook for the mouse driver, with SetWindowsHookEx, but it doesn't work -- obviously the mouse messages are being pre-processed even before they are sent to my low-level Windows hook.
I would be very grateful for advice about how to turn off this pre-processing. I do not want to switch to RealTimeStylus -- first because it won't work on Windows XP plus SMART interactive whiteboard, second because I can't see how to use RealTimeStylus in CPython, so I would need to switch to IronPython, and then my code would no longer run on Linux/Mac.
Damon.
For raw mouse messages, you can use WM_INPUT on XP and later. Seven added some touch specific stuff: WM_GESTURE and WM_TOUCH

Categories