fix(host/windows): layout-correct keyboard injection - semantic vs positional VKs
First-party punktfunk clients send US-positional VKs (the physical key's US-layout VK), GameStream/Moonlight clients send layout-semantic VKs (Sunshine's model). The SendInput injector previously resolved everything through the SYSTEM service's layout - on a German host that is the y/z swap and u-umlaut-on-o-umlaut scramble. GameStream ingest now tags its key events KEY_FLAG_SEMANTIC_VK (stripped from punktfunk/1 wire events so a network client can't flip the convention); the injector maps semantic VKs under the foreground app's layout and positional VKs through a fixed scancode table. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,13 +5,23 @@
|
||||
//! protocols — `zwlr_virtual_pointer_manager_v1` + `zwp_virtual_keyboard_manager_v1` — which
|
||||
//! Sway always advertises. We connect as an ordinary Wayland client (the host process
|
||||
//! inherits Sway's `WAYLAND_DISPLAY`/`XDG_RUNTIME_DIR`), bind the two managers, and translate
|
||||
//! events into virtual pointer/keyboard requests. Keyboard codes are Linux evdev; we upload a
|
||||
//! standard evdev/US xkb keymap and track modifier state so the compositor resolves shifted
|
||||
//! keysyms correctly.
|
||||
//! events into virtual pointer/keyboard requests. Keyboard codes are Linux evdev; we upload an
|
||||
//! xkb keymap (the host's layout via `XKB_DEFAULT_LAYOUT` et al., defaulting to evdev/US) and
|
||||
//! track modifier state so the compositor resolves shifted keysyms correctly.
|
||||
|
||||
use anyhow::Result;
|
||||
use punktfunk_core::input::{InputEvent, InputKind};
|
||||
|
||||
/// In-process tag on a key event's `flags`: the VK in `code` is **layout-semantic** (already
|
||||
/// resolved under the sending client's keyboard layout — the GameStream/Moonlight convention)
|
||||
/// rather than the punktfunk-native **US-positional** convention (the physical key's US-layout VK,
|
||||
/// which every first-party client sends — the client's local layout never touches the wire).
|
||||
/// The Windows injector maps semantic VKs through the foreground app's layout and positional VKs
|
||||
/// through a fixed table; conflating the two is exactly the German y↔z / ö→ü scramble.
|
||||
/// Set ONLY by `gamestream::input::decode`; the punktfunk/1 ingest strips it from wire events, so
|
||||
/// a network client can never flip the host's key-decoding convention.
|
||||
pub const KEY_FLAG_SEMANTIC_VK: u32 = 0x8000_0000;
|
||||
|
||||
/// Injects input events into the host session. Not `Send`: an injector owns compositor
|
||||
/// resources (a Wayland connection, an xkb state) and lives entirely on the control thread
|
||||
/// that creates it.
|
||||
|
||||
Reference in New Issue
Block a user