From f3bc1c5707d622d8536990e01e935d4cb4252a5c Mon Sep 17 00:00:00 2001 From: Kevin Midboe Date: Sat, 2 Aug 2025 12:54:19 +0200 Subject: [PATCH] init program commit listens for keyboard input on function keys and runs functions mapped to certain keys --- main.py | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 main.py diff --git a/main.py b/main.py new file mode 100644 index 0000000..25baa19 --- /dev/null +++ b/main.py @@ -0,0 +1,147 @@ +#!/usr/bin/python3 +import struct, os, sys, subprocess, threading +from time import sleep, time +from evdev import InputDevice, categorize, ecodes, list_devices +from functools import partial + +USER='kevin' +chromeBin = '/usr/bin/chromium-browser' +BOOKMARK_DIR = f'/home/{USER}/.config/chromium/Default' + +def findKeyboard(): + devices = [InputDevice(path) for path in list_devices()] + for device in devices: + if 'keyboard' in device.name.lower() or 'kbd' in device.name.lower(): + return device + + raise Exception('Keyboard device not found. You may need to run as root.') + +def getBookmarks(): + cmd = f"cat {BOOKMARK_DIR}/Bookmarks | jq '.roots.bookmark_bar.children[0].children[] | .url' | tr '\\n' ' '" + + result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=isinstance(cmd, str), text=True, check=True) + return result.stdout.strip() + +def programRunning(cmd, onlyPrefix=False): + if onlyPrefix: + cmd = cmd.split(' ')[0] + + try: + subprocess.run(["pgrep", "-f", cmd], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True) + return True + except subprocess.CalledProcessError: + return False + +def buildUserCommand(cmd): + userSpaceCmd = f'su - {USER} -c' + userDisplayCmd = 'export DISPLAY=:0; ' + cmdList = userSpaceCmd.split(' ') + cmdList.append(userDisplayCmd + cmd) + return cmdList + +def openBrowser(): + bookmarks = getBookmarks() + browserCmd = chromeBin + ' \ + --no-first-run \ + --disable \ + --hide-crash-restore-bubble \ + --disable-translate \ + --disable-infobars \ + --disable-suggestions-service \ + --disable-save-password-bubble \ + --kiosk ' \ + + bookmarks + + if programRunning(browserCmd, True): + print('browser already running, exiting') + return + + print('launching browser') + runUnclutter() + cmd = buildUserCommand(browserCmd) + subprocess.Popen(cmd) + +def openTerminal(cmd, windowHeight=None, windowY=None): + if programRunning(cmd): + print('terminal already running w/ this command, exiting') + return + + print('launching terminal w/ command:', cmd) + cmd = f'lxterminal -e "{cmd}"' + + cmd = buildUserCommand(cmd) + subprocess.Popen(cmd) + +def runUnclutter(): + program = 'unclutter' + if programRunning(program): + print(f"{program} already running") + return + + print(f"starting {program}") + cmd = buildUserCommand(f'{program} &') + subprocess.run(cmd) + +def startup(): + timeout = 1 + print("waiting {} seconds, then launching chrome".format(timeout)) + sleep(timeout) + openBrowser() + +def listenForInput(): + print("listening for keyboard input") + + try: + dev = findKeyboard() + print(f'Listening to: {dev.name} ({dev.path})') + + for event in dev.read_loop(): + if event.type != ecodes.EV_KEY: + continue + + key_event = categorize(event) + if key_event.keystate != key_event.key_down: + continue + + print(f'Keycode: {key_event.keycode}') + if key_event.keycode not in KEY_EVENT_PROGRAM_MAP: + continue + + KEY_EVENT_PROGRAM_MAP[key_event.keycode]() + + except PermissionError: + print('Permission denied. Try running with sudo or check device permissions.') + except Exception as e: + print(f'Error: {e}') + +KEY_EVENT_PROGRAM_MAP = { + 'KEY_F16': openBrowser, + 'KEY_F17': partial(openTerminal, 'watch -n 1 "sensors | grep temp1"') +} + +def printHelp(): + print("Available key bindings:\n") + for key, func in KEY_EVENT_PROGRAM_MAP.items(): + key = key.replace('KEY_', '') + + if isinstance(func, partial): + func_name = func.func.__name__ + args = ", ".join(repr(arg) for arg in func.args) + print(f"{key}: {func_name}({args})") + else: + func_name = func.__name__ if hasattr(func, '__name__') else str(func) + print(f"{key}: {func_name}()") + +def main(): + backgroundStartupThread = threading.Thread(target=startup) + backgroundStartupThread.start() + + listenForInput() + +if __name__ == '__main__': + if '-h' in sys.argv or '--help' in sys.argv: + printHelp() + sys.exit(0) + else: + main() +