#!/usr/bin/env python3 import socket import json from evdev import UInput, ecodes as e # Capabilities for both gamepad and keyboard capabilities = { e.EV_KEY: [ e.BTN_A, e.BTN_B, e.BTN_START, e.BTN_DPAD_UP, e.BTN_DPAD_DOWN, e.BTN_DPAD_LEFT, e.BTN_DPAD_RIGHT, e.KEY_LEFTCTRL, e.KEY_1 ] } # Mapping CEC keys to gamepad buttons or keyboard keys key_map = { 'SELECT': e.BTN_A, 'EXIT': e.BTN_B, 'PLAY': e.BTN_START, 'PAUSE': e.BTN_START, 'UP': e.BTN_DPAD_UP, 'DOWN': e.BTN_DPAD_DOWN, 'LEFT': e.BTN_DPAD_LEFT, 'RIGHT': e.BTN_DPAD_RIGHT # 'CLEAR' handled separately } import time from evdev import InputDevice, ecodes, list_devices, UInput # Define key codes for Ctrl and 1 SHIFT = ecodes.KEY_LEFTSHIFT TAB = ecodes.KEY_TAB # Define virtual keyboard capabilities (DO NOT include EV_SYN) keyboard_events = { ecodes.EV_KEY: [SHIFT,TAB], } # Create the virtual input device keyboard_ui = UInput(events=keyboard_events, name="Virtual Ctrl+1 Injector", bustype=ecodes.BUS_USB) def home(): print("Sending shift+home") keyboard_ui.write(ecodes.EV_KEY, SHIFT, 1) # Press Ctrl keyboard_ui.write(ecodes.EV_KEY, TAB, 1) # Press 1 keyboard_ui.syn() time.sleep(0.1) keyboard_ui.write(ecodes.EV_KEY, SHIFT, 0) # Release 1 keyboard_ui.write(ecodes.EV_KEY, TAB, 0) # Release Ctrl keyboard_ui.syn() last_pressed = None # Track last key to release def create_virtual_device(): return UInput(capabilities, name='CEC Virtual Input', bustype=e.BUS_USB) def handle_press(ui, key): global last_pressed if key == 'CLEAR': home() return code = key_map.get(key) if not code: print(f"Unknown key: {key}") return if code == last_pressed: return handle_release(ui) ui.write(e.EV_KEY, code, 1) ui.syn() last_pressed = code print(f"Pressed {key} ({code})") def handle_release(ui): global last_pressed if last_pressed is None: return if isinstance(last_pressed, tuple): # Release both Ctrl and 1 for code in last_pressed: ui.write(e.EV_KEY, code, 0) print("Released Ctrl+1") else: ui.write(e.EV_KEY, last_pressed, 0) print(f"Released {last_pressed}") ui.syn() last_pressed = None def start_udp_listener(): ui = create_virtual_device() print("Virtual input device ready") sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind(('0.0.0.0', 41234)) print("Listening for UDP input...") while True: data, _ = sock.recvfrom(1024) try: print("new payload") payload = json.loads(data.decode()) if payload['type'] == 'key': event_type = payload.get('event') key_name = payload.get('key', '').upper() if event_type == 'press': handle_press(ui, key_name) elif event_type == 'release': handle_release(ui) except Exception as ex: print(f"Error: {ex}") if __name__ == "__main__": try: start_udp_listener() except KeyboardInterrupt: print("Shutting down...")