Skip to content

Instantly share code, notes, and snippets.

@psqq
Last active June 3, 2025 16:11
Show Gist options
  • Save psqq/bed97027e52d602adc9982c7482ac273 to your computer and use it in GitHub Desktop.
Save psqq/bed97027e52d602adc9982c7482ac273 to your computer and use it in GitHub Desktop.
alternative AutoRun for linux
# alternative https://github.com/divisionind/AutoRun for linux
# usage examples:
# sudo KEYBOARD_DEVICE_NAME="AT Translated Set 2 keyboard" ./.venv/bin/python main.py
# or
# sudo KEYBOARD_DEVICE=/dev/input/event3 ./.venv/bin/python main.py
# better by name
import evdev
import os
import time
class RunLoop:
def __init__(self, uinput: evdev.UInput) -> None:
self.held = False
self.keys = []
self.counter = dict()
self.counter_max_value = 2
# Get keyboard device by name or path
device_path = os.environ.get("KEYBOARD_DEVICE")
device_name = os.environ.get("KEYBOARD_DEVICE_NAME")
done = False
i = 0
while not done:
if device_name:
devices = [evdev.InputDevice(path) for path in evdev.list_devices()]
for device in devices:
if device.name == device_name:
self.kb_dev = device
done = True
break
else:
if i == 10:
raise ValueError(f"Device with name '{device_name}' not found")
else:
time.sleep(0.5)
elif device_path:
self.kb_dev = evdev.InputDevice(device_path)
done = True
else:
raise ValueError("Either KEYBOARD_DEVICE or KEYBOARD_DEVICE_NAME must be set")
self.uinput = uinput
def start_hold_keys(self):
self.held = True
self.counter = dict()
self.keys = self.kb_dev.active_keys(verbose=True)
self.keys = list(filter(lambda k: k[0] != "KEY_PAUSE", self.keys))
print("Start holding keys", self.keys)
for k in self.keys:
self.uinput.write(evdev.ecodes.EV_KEY, k[1], 1)
self.uinput.syn()
def finish_hold_keys(self):
print("Finish holding keys", self.keys)
self.held = False
for k in self.keys:
self.uinput.write(evdev.ecodes.EV_KEY, k[1], 0)
self.uinput.syn()
def on_pause(self):
if self.held:
self.finish_hold_keys()
else:
self.start_hold_keys()
def on_keyboard_event(self, scancode, keystate):
if scancode == evdev.ecodes.KEY_PAUSE and keystate == 1:
self.on_pause()
return
if self.held and keystate == 0:
is_hold_again = False
for paused_key in self.keys:
if scancode == paused_key[1]:
self.uinput.write(evdev.ecodes.EV_KEY, paused_key[1], 1)
self.uinput.syn()
is_hold_again = True
if is_hold_again:
counter_value = self.counter.get(scancode, 0)
counter_value += 1
self.counter[scancode] = counter_value
if counter_value >= self.counter_max_value:
self.finish_hold_keys()
def run(self):
for event in self.kb_dev.read_loop():
if event.type == evdev.ecodes.EV_KEY:
key_event = evdev.categorize(event)
if isinstance(key_event, evdev.events.KeyEvent):
self.on_keyboard_event(
scancode=key_event.scancode, keystate=key_event.keystate
)
def main():
while True:
try:
with evdev.UInput() as uinput:
RunLoop(uinput).run()
except IOError as e:
if e.errno == 19:
print("restart on", e)
else:
raise e
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment