Files
MrBlakeandClaude Opus 5.5 5b7534560f Open the app with the Predator key, bump to 1.3.0
The Predator key sends keyboard usage 0xC9, which lies outside the
logical range the keyboard declares, so the kernel never emits an input
event for it. It is also reported on vendor report 4 of USB interface 2
(04 81 ff on press). predatord now listens there and opens the app in
the active graphical session via the user's systemd manager.

The action is configurable on the System page: open the app, switch to
the next performance mode, or do nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 17:51:21 +02:00

84 lines
2.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Predator key listener.
The PH16-71 Predator key produces no input event: its keyboard usage (0xC9) is outside the
range the keyboard declares, so the kernel drops it. The key is also reported on the
vendor report 4 of USB interface 2: `04 81 ff` on press, `04 00 00` on release.
"""
import os
import pwd
import select
import subprocess
import threading
import time
from .keyboard import HOTKEY_INTERFACE, find_hidraw
PRESS_PREFIX = b"\x04\x81"
def active_session_user():
"""(uid, name) of the active graphical session, or None."""
out = subprocess.run(["loginctl", "list-sessions", "--no-legend"],
capture_output=True, text=True).stdout
for line in out.splitlines():
sid = line.split()[0] if line.split() else None
if not sid:
continue
props = dict(l.split("=", 1) for l in subprocess.run(
["loginctl", "show-session", sid, "-p", "Active", "-p", "Type", "-p", "User", "-p", "Name"],
capture_output=True, text=True).stdout.splitlines() if "=" in l)
if props.get("Active") == "yes" and props.get("Type") in ("wayland", "x11"):
return int(props["User"]), props["Name"]
return None
def launch_in_session(args):
sess = active_session_user()
if not sess:
return False
uid, name = sess
# runs in the user's systemd manager, which carries WAYLAND_DISPLAY/DISPLAY on Plasma
r = subprocess.run(["systemd-run", "--quiet", "--user", "--machine=%s@.host" % name, "--collect",
"--unit=predator-control-launch-%d" % int(time.time() * 1000)] + args,
capture_output=True, text=True)
return r.returncode == 0
class HotkeyListener(threading.Thread):
def __init__(self, on_press, log):
super().__init__(daemon=True)
self.on_press = on_press
self.log = log
def run(self):
while True:
path = find_hidraw(HOTKEY_INTERFACE)
if not path:
time.sleep(5)
continue
try:
fd = os.open(path, os.O_RDONLY)
except OSError as e:
self.log("hotkey: cannot open %s: %s" % (path, e))
time.sleep(5)
continue
last = 0.0
try:
while True:
select.select([fd], [], [])
data = os.read(fd, 64)
if not data:
break
if data.startswith(PRESS_PREFIX) and time.monotonic() - last > 0.4:
last = time.monotonic()
try:
self.on_press()
except Exception as e:
self.log("hotkey: %s" % e)
except OSError:
pass # device vanished (suspend/replug) – reopen
finally:
os.close(fd)
time.sleep(1)