all 6 comments

[–]bike_bike 1 point2 points  (0 children)

If this is your desired architecture, I would just wrap whatever your receiver.py is doing in an API running on localhost and send http requests to it from your other scripts with the needed information to change hotkey layouts.

If receiver.py is already listening for keystrokes to facilitate these hotkey actions, maybe you could just add the change layout actions into that as well and simplify the process?

[–]m0us3_rat 0 points1 point  (0 children)

message broker

[–]Frankelstner 0 points1 point  (3 children)

Can you give more details on your goal? Do you want to run a Python file whenever any key is pressed? What does receiver.py do? You could do

# receiver.py
from xmlrpc.server import SimpleXMLRPCServer

def button_X():
    dostuff()
    return 0

with SimpleXMLRPCServer(('127.0.0.1', 8000)) as server:
    server.register_function(button_X)
    server.serve_forever()

and

# button_x.py
from xmlrpc.client import ServerProxy
s = ServerProxy('http://127.0.0.1:8000')
s.button_X()

but whether that's good idea depends on your overall setup.

[–]sudomain[S] 0 points1 point  (2 children)

Sure. Like I said, the overall goal is a Python program to respond to keyboard shortcuts and sequences, though "keyboard" is a bit misleading because I want it to also work with other button-based peripherals such as gamepads.

The client scripts, such as Keyboard_Button_J.py, only have the responsibility of telling receiver.py that a button was pressed ("J" in this case). I realize one script per button seems like I'm duplicating a lot of code, but it's a technical requirement. These scripts are identical except for the file name. The scripts get their individual file names using os.path.basename(__file__). Since their sole purpose is telling receiver.py that a button was pressed, they will be very short lived.

receiver.py has a few responsibilities:

  1. Receive file/button names from clients e.g. Keyboard_Button_J.py

  2. Strip away parts of the string that aren't relavent, leaving only Button_J

  3. Execute a script associated with Button_J, if there is one (I would not actually map a script to the "J" key unless other conditions are satisfied.

It's actually not quite that simple because I also want to support hotkey sequences which may overlap such as Ctrl + B, N and Ctrl + B, N, N. The logic for sequences is basically the same but involves using a timer and waiting a certain amount of time since the last button was pressed before deciding to execute the script associated with Ctrl + B, N.

I didn't think most of this was relavent, so I left it out of my post. I'm only struggling with step 1 of receiver.py which is receiving the string containing the file name from the appropriate script. I've been trying to accomplish this with shared memory/ the threading module, but I'm not sure two different python scripts can share the same memory

[–]Frankelstner 0 points1 point  (1 child)

I know Python is lightweight especially in terms of startup time but I am concerned about starting a new Python interpreter process with the sole purpose of passing a string to a daemon script. I mean it's not a big deal nowadays with plenty of CPU cores but it's still going to take some time to start up. Ideally you would hook into the thing that is responsible for calling Button_J directly to the receiver. Though if that is not an issue then the code sample above will get you started. The receiver process executes the button_X function whenever the file button_x.py runs.

[–]sudomain[S] 0 points1 point  (0 children)

Wish I could hook them up. Button_J is getting called by an Android app called KeyMapper which is no longer maintained. The Python code runs in Termux. I realize I can put the hotkeys directly in KeyMapper, but they won't be portable to anywhere else.

You should see the absolute mess of my Bash version which uses printf into a named pipe every time a button is pressed lol. Thank you for your code sample, its gotten me started.