Files
qmk-host/src/app_monitor.rs
T
rootiest d00c4aa371 feat: initial qmk-host Raw HID bridge implementation
Add a Rust daemon that connects to QMK keyboards over their Raw HID
interface (VID 0x3434, usage page 0xFF60 / usage 0x0061) and provides:

- Bi-directional layer sync: CMD_LAYER_SYNC (0x40) packets are bridged
  between all connected keyboards so their active layers stay in sync.
  On connect, a FLAG_QUERY packet requests the current state from each
  keyboard. A second keyboard (numpad) is stubbed and ready to enable.

- Volume monitoring: polls `pactl get-sink-volume @DEFAULT_SINK@` every
  2 s and pushes CMD_VOLUME (0x41) packets on change. Compatible with
  both PulseAudio and PipeWire on KDE6/Wayland.

- Brightness monitoring: polls /sys/class/backlight on the same interval
  and pushes CMD_BRIGHTNESS (0x42) packets on change.

- Active-app stub: CMD_ACTIVE_APP (0x43) is reserved with detailed notes
  on KDE6/Wayland implementation approaches (KWin D-Bus, foreign
  toplevel protocol) for a future commit.

Each keyboard runs a single combined read/write IO thread using a 10 ms
read timeout to interleave HID reads and queued writes without needing
two file handles. Protocol constants in src/protocol.rs mirror
hid_protocol.h in the QMK firmware exactly.

Licensed under GPL-3.0-or-later.
2026-04-10 14:42:09 -04:00

47 lines
1.9 KiB
Rust

// Copyright 2026 rootiest
// SPDX-License-Identifier: GPL-3.0-or-later
//! Active application / window monitor — **reserved, not yet implemented**.
//!
//! When implemented this module will detect the active window on a KDE6
//! Wayland desktop and send `CMD_ACTIVE_APP` (0x43) packets containing the
//! application name (null-terminated UTF-8, max 28 bytes) to all connected
//! keyboards.
//!
//! # Implementation notes for KDE6 / Wayland
//!
//! Candidate approaches (to evaluate during the brainstorming phase):
//!
//! 1. **KWin D-Bus interface** — `org.kde.KWin` exposes `activeWindow()` on
//! the scripting API. The window object has `resourceName` / `caption`
//! properties. Can subscribe to `windowActivated` signal.
//! → easiest; requires D-Bus session access.
//!
//! 2. **KWin Script** — inject a tiny `.kwinscript` that emits a custom
//! D-Bus signal or writes to a FIFO on `windowActivated`.
//! → portable across KWin versions; slightly invasive.
//!
//! 3. **`xdg-foreign` / `wlr-foreign-toplevel`** — Wayland protocols for
//! enumerating toplevels. KWin supports `ext-foreign-toplevel-list-v1`.
//! → protocol-level, no D-Bus, but requires a Wayland client loop.
//!
//! 4. **`qdbus6` / `busctl` polling** — parse output of
//! `busctl call org.kde.KWin /KWin org.kde.KWin activeWindow`
//! in a poll loop. Simple but coarse.
//!
//! The chosen approach will be implemented here once the brainstorming is
//! complete. The `Packet::active_app()` constructor in `protocol.rs` is
//! already in place.
use log::info;
use crate::keyboard::Keyboard;
/// Monitor the active application and notify keyboards.
/// Currently a no-op stub — safe to call, does nothing.
pub fn monitor(_keyboards: Vec<Keyboard>) {
info!("Active-application monitor: not yet implemented (stub)");
// Future: block here in an event loop and send Packet::active_app()
// packets to keyboards whenever the active window changes.
}