Rename vrKeyboard to steamKeyboardPatch; clipboard-sync on by default

- steamFrame.vrKeyboard -> steamFrame.steamKeyboardPatch (module, service
  and script names follow): it patches Steam's own on-screen keyboard
- clipboardSync.enable defaults to true: without it the nested desktop's
  clipboard is isolated
This commit is contained in:
Pierre Kisters committed 2026-09-27 15:24:52 +02:00
1 parent 4b2885a992
commit d60931ed72
8 files changed
+39 -33

No files matched your search

+8 -4
View File
@@ -11,10 +11,14 @@ let
cfg = config.steamFrame.clipboardSync;
in {
options.steamFrame.clipboardSync = {
enable = lib.mkEnableOption ''
clipboard-sync between the Steam session and the nested desktop
(KDE autostart; on switch, stale builds and duplicates are stopped)
'';
enable = lib.mkOption {
type = lib.types.bool;
default = true; # without it the nested desktop's clipboard is isolated
description = ''
Whether to run clipboard-sync between the Steam session and the nested
desktop (KDE autostart; on switch, stale builds and duplicates are stopped).
'';
};
package = lib.mkOption {
type = lib.types.package;
default = pkgs.rustPlatform.buildRustPackage {
+1 -1
View File
@@ -55,7 +55,7 @@ in {
restart = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
example = [ "vr-keyboard.service" ];
example = [ "steam-keyboard-patch.service" ];
description = "User units restarted on every switch (outer user manager).";
};
stop = lib.mkOption {
@@ -2,7 +2,7 @@
# The keyboard is part of Steam's UI (hardcoded layouts in steamui JS), and in
# VR it can only send text; SteamClient.Input.ControllerKeyboardSetKeyState
# throws "Unknown method". So:
# - vrkbd-patch.js is injected at runtime into Steam's UI through its CEF
# - patch.js is injected at runtime into Steam's UI through its CEF
# DevTools port (127.0.0.1:8080; SteamOS starts Steam with
# -cef-enable-debugging). Steam's files are untouched, so updates don't undo
# it. It rebuilds the bottom row and, while Ctrl/Alt is active (or for Esc),
@@ -10,7 +10,7 @@
# the real Ctrl/Alt down while the toggle is on (Ctrl+scroll), and routes
# characters Steam's key emulation turns into "1" (non-ASCII, AltGr/dead
# keys on the de keymap: |@{[]}\~^`äöü€…) to the helper.
# - vrkbd-helper.mjs keeps that injection alive (Steam restarts, keyboard popup
# - helper.mjs keeps that injection alive (Steam restarts, keyboard popup
# recreated) and presses the combos with `xdotool key` on :0, where gamescope
# keeps X focus on the window selected in VR. It only accepts ctrl/alt
# chords and the extra keys, so the Steam UI can't use it to type text or
@@ -19,21 +19,24 @@
{ config, pkgs, lib, ... }: {
imports = [ ./session.nix ];
options.steamFrame.vrKeyboard.enable = lib.mkEnableOption ''
Esc/Ctrl/Alt/AltGr and arrow keys on Steam's VR keyboard (runtime patch of
Steam's UI through its CEF DevTools port, plus an xdotool helper service)
options.steamFrame.steamKeyboardPatch.enable = lib.mkEnableOption ''
the runtime patch of Steam's on-screen (VR) keyboard: Esc/Ctrl/Alt and four
separate arrow keys, real Ctrl/Alt chords (held while toggled, e.g. for
Ctrl+scroll), and working AltGr/non-ASCII characters. Injected into Steam's
UI through its CEF DevTools port by an xdotool helper service; disabling
it reverts the patch on the next switch
'';
config = lib.mkMerge [
(lib.mkIf config.steamFrame.vrKeyboard.enable {
systemd.user.services.vr-keyboard = {
(lib.mkIf config.steamFrame.steamKeyboardPatch.enable {
systemd.user.services.steam-keyboard-patch = {
Unit.Description = "Modifier keys for Steam's VR keyboard (CEF patch + xdotool)";
Service = {
ExecStart = lib.escapeShellArgs [
"${pkgs.nodejs}/bin/node"
"${./vr-keyboard/vrkbd-helper.mjs}"
"${./vr-keyboard/vrkbd-patch.js}"
"${./vr-keyboard/vrkbd-unpatch.js}"
"${./steam-keyboard-patch/helper.mjs}"
"${./steam-keyboard-patch/patch.js}"
"${./steam-keyboard-patch/unpatch.js}"
"${pkgs.xdotool}/bin/xdotool"
];
Environment = "VRKBD_DISPLAY=:0";
@@ -46,12 +49,12 @@
# Restart on every switch so a changed patch is re-injected (it replaces
# the older version).
steamFrame.userServices.restart = [ "vr-keyboard.service" ];
steamFrame.userServices.restart = [ "steam-keyboard-patch.service" ];
})
# Disabled: stop a still-running helper, which reverts the patch, so the
# stock keyboard is back right away (no Steam restart or reboot).
(lib.mkIf (!config.steamFrame.vrKeyboard.enable) {
steamFrame.userServices.stop = [ "vr-keyboard.service" ];
(lib.mkIf (!config.steamFrame.steamKeyboardPatch.enable) {
steamFrame.userServices.stop = [ "steam-keyboard-patch.service" ];
})
];
}
@@ -1,8 +1,8 @@
// vrkbd-helper: injects vrkbd-patch.js into Steam's UI via CEF DevTools and
// helper.mjs: injects patch.js into Steam's UI via CEF DevTools and
// performs the key requests of the patched VR keyboard with xdotool on :0.
// On SIGTERM/SIGINT it reverts the patch (unpatch.js), so stopping the service
// restores Steam's stock keyboard without restarting Steam.
// usage: node vrkbd-helper.mjs <patch.js> <unpatch.js> [xdotool]
// usage: node helper.mjs <patch.js> <unpatch.js> [xdotool]
import { readFileSync } from 'node:fs';
import { execFile } from 'node:child_process';
@@ -1,4 +1,4 @@
// Injected into Steam's SharedJSContext (CEF, 127.0.0.1:8080) by vrkbd-helper.
// Injected into Steam's SharedJSContext (CEF, 127.0.0.1:8080) by helper.mjs.
// Extends Steam's VR keyboard for gamescope app windows:
// - bottom row: Esc Ctrl Alt [space] AltGr and four separate arrow keys
// - Ctrl/Alt chords and Esc are pressed for real (Steam can't: in VR
@@ -9,7 +9,7 @@
// into "1" -- anything non-ASCII or needing AltGr / a dead key on the X
// keymap -- are typed by the helper instead
// Everything goes through the CDP binding window.__vrkbdKey("<op>:<arg>"),
// executed by vrkbd-helper with xdotool on :0.
// executed by helper.mjs with xdotool on :0.
// Idempotent: safe to evaluate repeatedly.
(() => {
const VERSION = 5;
@@ -1,4 +1,4 @@
// Reverts vrkbd-patch.js in Steam's SharedJSContext; evaluated by vrkbd-helper
// Reverts patch.js in Steam's SharedJSContext; evaluated by helper.mjs
// when it stops (service stopped, module disabled). Every patched function
// keeps its original as __vrkbdOrig. Safe to run when nothing is patched.
(() => {