import signal, sys from AppKit import NSWorkspace from Foundation import NSRunLoop, NSDate import hid VID, PID = 0x3384, 0x0009 USAGE_PAGE, USAGE = 0xFF60, 0x61 CMD_SET_FOCUSED_APP = 0x80 def find_keyboard_path(): for info in hid.enumerate(VID, PID): if info["usage_page"] == USAGE_PAGE and info["usage"] == USAGE: return info["path"] return None def send_app_name(dev, name): payload = name.encode("utf-8", errors="ignore")[:31] payload = payload.decode("utf-8", errors="ignore").encode("utf-8") data = bytes([0x00, CMD_SET_FOCUSED_APP]) + payload + b"\x00" * (32 - 1 - len(payload)) dev.write(data) dev.read(32, timeout=1000) def main(): signal.signal(signal.SIGINT, lambda *_: sys.exit(0)) ws = NSWorkspace.sharedWorkspace() dev = None last_app = None while True: connected = find_keyboard_path() is not None # Detect disconnect if dev is not None and not connected: print("Keyboard disconnected") dev = None last_app = None # Connect and send current app if dev is None and connected: try: dev = hid.Device(path=find_keyboard_path()) print("Keyboard connected") last_app = ws.frontmostApplication().localizedName() print(f"App: {last_app}") send_app_name(dev, last_app) except Exception: dev = None # App change if dev is not None: app = ws.frontmostApplication().localizedName() if app != last_app: print(f"App: {app}") last_app = app try: send_app_name(dev, app) except Exception: print("Keyboard disconnected") dev = None last_app = None NSRunLoop.currentRunLoop().runUntilDate_( NSDate.dateWithTimeIntervalSinceNow_(0.25) ) if __name__ == "__main__": main()