mirror of
https://github.com/lhns/steam-frame-nix.git
synced 2026-10-06 05:00:24 +02:00
VR keyboard: Shift+Tab moves the focus backwards
Steam sends Tab as the text "\t" and drops Shift. With Shift, Tab now goes to the xdotool helper (shift+Tab, ISO_Left_Tab on any keymap); the suggestions text model resets on it like on Shift+arrows. The helper's allowlist moves to allowlist.mjs with a test (flake check vr-keyboard-extra-keys).
This commit is contained in:
1 parent
50e5991c59
commit
b2babb3859
11 files changed
+94
-43
No files matched your search
@@ -33,7 +33,7 @@ configuration, limitations and how it works.
|
|||||||
|
|
||||||
**VR keyboard** ([docs/keyboard.md](docs/keyboard.md)):
|
**VR keyboard** ([docs/keyboard.md](docs/keyboard.md)):
|
||||||
|
|
||||||
- [Extra keys](docs/keyboard.md#extra-keys) (`keyboard.vr.extraKeys`): Esc/Ctrl/Alt, arrows, Delete, real chords and AltGr/non-ASCII characters.
|
- [Extra keys](docs/keyboard.md#extra-keys) (`keyboard.vr.extraKeys`): Esc/Ctrl/Alt, arrows, Delete, Shift+Tab, real chords and AltGr/non-ASCII characters.
|
||||||
- [Swipe and suggestions](docs/keyboard.md#swipe-and-suggestions) (`keyboard.vr`): swipe typing, corrections, completions, Backspace drag.
|
- [Swipe and suggestions](docs/keyboard.md#swipe-and-suggestions) (`keyboard.vr`): swipe typing, corrections, completions, Backspace drag.
|
||||||
|
|
||||||
**VR "+" menu** ([docs/launcher-menu.md](docs/launcher-menu.md)):
|
**VR "+" menu** ([docs/launcher-menu.md](docs/launcher-menu.md)):
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ modules/
|
|||||||
vr-keyboard-extra-keys/
|
vr-keyboard-extra-keys/
|
||||||
patch.js, unpatch.js Steam: the extra bottom row and key routing
|
patch.js, unpatch.js Steam: the extra bottom row and key routing
|
||||||
xdotool-helper.mjs service steam-keyboard-patch: own injector + xdotool keys
|
xdotool-helper.mjs service steam-keyboard-patch: own injector + xdotool keys
|
||||||
|
allowlist.mjs service: the keys the helper may send
|
||||||
|
check.nix, tests/ test: the allowlist
|
||||||
vr-keyboard.nix swipe, suggestions, Backspace drag (keyboard.vr)
|
vr-keyboard.nix swipe, suggestions, Backspace drag (keyboard.vr)
|
||||||
vr-keyboard/
|
vr-keyboard/
|
||||||
patch.js, unpatch.js Steam: gestures, text model, suggestion strip
|
patch.js, unpatch.js Steam: gestures, text model, suggestion strip
|
||||||
|
|||||||
+13
-4
@@ -25,6 +25,10 @@ backtick, `ä ö ü €`) come out as `1`.
|
|||||||
AltGr and layout keys.
|
AltGr and layout keys.
|
||||||
- AltGr + arrows: Home, End, Page Up, Page Down (hinted on the keys);
|
- AltGr + arrows: Home, End, Page Up, Page Down (hinted on the keys);
|
||||||
Shift + arrows select text.
|
Shift + arrows select text.
|
||||||
|
- Shift + Tab moves the focus backwards (stock Steam drops the Shift);
|
||||||
|
Ctrl + Shift + Tab works too (e.g. previous Firefox tab). A locked Shift
|
||||||
|
is released after it, like a tapped one. Shift + Enter and
|
||||||
|
Shift + Backspace stay plain Enter and Backspace.
|
||||||
- AltGr + the key left of Backspace (`´` on German, `=` on US): Delete,
|
- AltGr + the key left of Backspace (`´` on German, `=` on US): Delete,
|
||||||
labelled like Steam's Delete key in its language (`Entf`; `Del` if that is
|
labelled like Steam's Delete key in its language (`Entf`; `Del` if that is
|
||||||
longer), hinted on the key without AltGr; repeats while held. Layouts with
|
longer), hinted on the key without AltGr; repeats while held. Layouts with
|
||||||
@@ -46,8 +50,10 @@ after Steam restarts. Turning it off reverts the keyboard.
|
|||||||
is harmless, and Esc/Ctrl/Alt/arrows work regardless.
|
is harmless, and Esc/Ctrl/Alt/arrows work regardless.
|
||||||
|
|
||||||
**Security:** the helper service that presses the keys only accepts
|
**Security:** the helper service that presses the keys only accepts
|
||||||
single-key Ctrl/Alt chords, the extra keys, Ctrl/Alt hold/release and single
|
single-key Ctrl/Alt chords, the extra keys, Shift + Tab, Ctrl/Alt
|
||||||
non-ASCII/AltGr characters; it cannot type ASCII text or press Enter.
|
hold/release and single non-ASCII/AltGr characters; it cannot type ASCII
|
||||||
|
text or press Enter (`allowlist.mjs`, tested by the flake check
|
||||||
|
`vr-keyboard-extra-keys`).
|
||||||
|
|
||||||
**Caveat:** depends on Steam UI internals; after a Steam update that changes
|
**Caveat:** depends on Steam UI internals; after a Steam update that changes
|
||||||
them the keyboard stays stock and the journal says why (see
|
them the keyboard stays stock and the journal says why (see
|
||||||
@@ -63,8 +69,11 @@ Steam client 1790377368 (UI build 11041156).
|
|||||||
Steam's `SharedJSContext` over DevTools (`127.0.0.1:8080`) and re-injects
|
Steam's `SharedJSContext` over DevTools (`127.0.0.1:8080`) and re-injects
|
||||||
it after Steam restarts; stopping it (or disabling the option)
|
it after Steam restarts; stopping it (or disabling the option)
|
||||||
runs the unpatch.
|
runs the unpatch.
|
||||||
- Ctrl/Alt chords and Esc are sent with `xdotool key` on `:0` (focus follows
|
- Ctrl/Alt chords, Esc, Shift + arrows and Shift + Tab are sent with
|
||||||
the VR-selected window); a toggled Ctrl/Alt is held down with `xdotool`.
|
`xdotool key` on `:0` (focus follows the VR-selected window); a toggled
|
||||||
|
Ctrl/Alt is held down with `xdotool`. Shift is never held as a real key
|
||||||
|
(Steam types capitals itself); `shift+Tab` is `ISO_Left_Tab` on any
|
||||||
|
keymap.
|
||||||
- Problem characters (non-ASCII, AltGr/dead-key characters on the German
|
- Problem characters (non-ASCII, AltGr/dead-key characters on the German
|
||||||
keymap) are typed with `xdotool type`; everything else goes through
|
keymap) are typed with `xdotool type`; everything else goes through
|
||||||
Steam's own text emulation. On other keymaps those characters are still
|
Steam's own text emulation. On other keymaps those characters are still
|
||||||
|
|||||||
@@ -65,9 +65,10 @@
|
|||||||
}) self.packages;
|
}) self.packages;
|
||||||
|
|
||||||
# Tests of the VR keyboard (text model, corrector, swipe decoder on the
|
# Tests of the VR keyboard (text model, corrector, swipe decoder on the
|
||||||
# default German + English dictionary), the Jellyfin mpv shim, the
|
# default German + English dictionary), the extra keys' xdotool
|
||||||
# Firefox wrapper, the launchers, install.sh cleanup, the
|
# allowlist, the Jellyfin mpv shim, the Firefox wrapper, the launchers,
|
||||||
# applications.menu link and the portal config: nix flake check
|
# install.sh cleanup, the applications.menu link and the portal config:
|
||||||
|
# nix flake check
|
||||||
checks = forSystems (pkgs: {
|
checks = forSystems (pkgs: {
|
||||||
applications-menu = import ./modules/applications-menu/check.nix { inherit pkgs; };
|
applications-menu = import ./modules/applications-menu/check.nix { inherit pkgs; };
|
||||||
cleanup = import ./modules/cleanup/check.nix { inherit pkgs; };
|
cleanup = import ./modules/cleanup/check.nix { inherit pkgs; };
|
||||||
@@ -76,6 +77,7 @@
|
|||||||
launchers = import ./modules/launchers/check.nix { inherit pkgs; };
|
launchers = import ./modules/launchers/check.nix { inherit pkgs; };
|
||||||
portal = import ./modules/portal/check.nix { inherit pkgs; };
|
portal = import ./modules/portal/check.nix { inherit pkgs; };
|
||||||
vr-keyboard = import ./modules/vr-keyboard/check.nix { inherit pkgs; };
|
vr-keyboard = import ./modules/vr-keyboard/check.nix { inherit pkgs; };
|
||||||
|
vr-keyboard-extra-keys = import ./modules/vr-keyboard-extra-keys/check.nix { inherit pkgs; };
|
||||||
});
|
});
|
||||||
|
|
||||||
# nix flake init -t github:lhns/steam-frame-nix
|
# nix flake init -t github:lhns/steam-frame-nix
|
||||||
|
|||||||
@@ -4,12 +4,13 @@
|
|||||||
# "Unknown method" in VR), and its layouts are hardcoded.
|
# "Unknown method" in VR), and its layouts are hardcoded.
|
||||||
# - patch.js (injected over CEF DevTools, 127.0.0.1:8080) adds a bottom row
|
# - patch.js (injected over CEF DevTools, 127.0.0.1:8080) adds a bottom row
|
||||||
# Esc Ctrl Alt [space] AltGr ← ↑ ↓ → (AltGr+arrows = Pos1/PgUp/PgDn/End) and
|
# Esc Ctrl Alt [space] AltGr ← ↑ ↓ → (AltGr+arrows = Pos1/PgUp/PgDn/End) and
|
||||||
# hands chords, Shift+arrows and characters Steam would turn into "1"
|
# hands chords, Shift+arrows, Shift+Tab and characters Steam would turn
|
||||||
# (non-ASCII, AltGr/dead keys) to the helper. AltGr + the key left of
|
# into "1" (non-ASCII, AltGr/dead keys) to the helper. AltGr + the key left
|
||||||
# Backspace = Delete.
|
# of Backspace = Delete.
|
||||||
# - xdotool-helper.mjs keeps it injected (its own injector, not the
|
# - xdotool-helper.mjs keeps it injected (its own injector, not the
|
||||||
# steam-ui-patches service), sends those keys with xdotool on :0 (an
|
# steam-ui-patches service), sends those keys with xdotool on :0 (an
|
||||||
# allowlist: no ASCII text, no Enter) and unpatches on stop.
|
# allowlist, allowlist.mjs: no ASCII text, no Enter) and unpatches on stop.
|
||||||
|
# Tests: vr-keyboard-extra-keys/check.nix (flake check vr-keyboard-extra-keys).
|
||||||
# Tested with Steam client 1790377368 (UI build 11041156).
|
# Tested with Steam client 1790377368 (UI build 11041156).
|
||||||
{ config, pkgs, lib, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
let
|
let
|
||||||
@@ -17,6 +18,14 @@ let
|
|||||||
name = "steam-keyboard-patch";
|
name = "steam-keyboard-patch";
|
||||||
src = ./vr-keyboard-extra-keys/patch.js;
|
src = ./vr-keyboard-extra-keys/patch.js;
|
||||||
};
|
};
|
||||||
|
# The helper imports allowlist.mjs from its own directory.
|
||||||
|
helper = lib.fileset.toSource {
|
||||||
|
root = ./vr-keyboard-extra-keys;
|
||||||
|
fileset = lib.fileset.unions [
|
||||||
|
./vr-keyboard-extra-keys/xdotool-helper.mjs
|
||||||
|
./vr-keyboard-extra-keys/allowlist.mjs
|
||||||
|
];
|
||||||
|
};
|
||||||
cfg = config.steamFrame.keyboard.vr.extraKeys;
|
cfg = config.steamFrame.keyboard.vr.extraKeys;
|
||||||
in {
|
in {
|
||||||
imports = [
|
imports = [
|
||||||
@@ -38,7 +47,7 @@ in {
|
|||||||
Service = {
|
Service = {
|
||||||
ExecStart = lib.escapeShellArgs [
|
ExecStart = lib.escapeShellArgs [
|
||||||
"${pkgs.nodejs}/bin/node"
|
"${pkgs.nodejs}/bin/node"
|
||||||
"${./vr-keyboard-extra-keys/xdotool-helper.mjs}"
|
"${helper}/xdotool-helper.mjs"
|
||||||
"${patch}"
|
"${patch}"
|
||||||
"${./vr-keyboard-extra-keys/unpatch.js}"
|
"${./vr-keyboard-extra-keys/unpatch.js}"
|
||||||
"${pkgs.xdotool}/bin/xdotool"
|
"${pkgs.xdotool}/bin/xdotool"
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// Allowlist of xdotool-helper.mjs: requests come from Steam's UI JS, so the
|
||||||
|
// helper must not be able to type ASCII text or press Enter on its behalf.
|
||||||
|
// Accepted:
|
||||||
|
// key:<combo> the extra keys (Esc, Del, Home, End, PgUp/PgDn, arrows),
|
||||||
|
// optionally with modifiers; ctrl and/or alt (+ optional
|
||||||
|
// shift) with one key; or shift+Tab
|
||||||
|
// type:<char> one character Steam's key emulation can't produce: non-ASCII
|
||||||
|
// (äöü߀§°´…) or | @ { [ ] } \ ~ ^ `
|
||||||
|
// down:<mod> / up:<mod> hold/release ctrl or alt (checked in the helper)
|
||||||
|
const SPECIAL = new Set(['Escape', 'Delete', 'Home', 'End', 'Prior', 'Next', 'Left', 'Right', 'Up', 'Down']);
|
||||||
|
const KEY = /^([a-z0-9]|space|BackSpace|Tab|period|comma|minus|plus|numbersign|less|slash|ssharp|udiaeresis|odiaeresis|adiaeresis)$/;
|
||||||
|
|
||||||
|
export function allowedCombo(combo) {
|
||||||
|
const parts = combo.split('+');
|
||||||
|
const key = parts.pop();
|
||||||
|
const mods = new Set(parts);
|
||||||
|
if (parts.length !== mods.size || ![...mods].every((m) => ['ctrl', 'alt', 'shift'].includes(m))) return false;
|
||||||
|
if (SPECIAL.has(key)) return true;
|
||||||
|
if (key === 'Tab' && mods.size === 1 && mods.has('shift')) return true; // backwards focus
|
||||||
|
return KEY.test(key) && (mods.has('ctrl') || mods.has('alt'));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function allowedChar(c) {
|
||||||
|
if ([...c].length !== 1) return false;
|
||||||
|
const cp = c.codePointAt(0);
|
||||||
|
return (cp > 0xa0 && !/\s|\p{C}/u.test(c)) || '|@{[]}\\~^`'.includes(c);
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# Tests of the extra keys (flake check `vr-keyboard-extra-keys`): the xdotool
|
||||||
|
# helper's allowlist (tests/allowlist.test.mjs).
|
||||||
|
{ pkgs }:
|
||||||
|
pkgs.runCommand "vr-keyboard-extra-keys-checks" { nativeBuildInputs = [ pkgs.nodejs ]; } ''
|
||||||
|
node ${./tests/allowlist.test.mjs} ${./allowlist.mjs} | tee $out
|
||||||
|
''
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
// mkPatch patch (see steam-ui-patches/lib/default.nix); no options. On a
|
// mkPatch patch (see steam-ui-patches/lib/default.nix); no options. On a
|
||||||
// signature mismatch it returns an error and changes nothing. Idempotent.
|
// signature mismatch it returns an error and changes nothing. Idempotent.
|
||||||
((find, sigs) => {
|
((find, sigs) => {
|
||||||
const VERSION = 22;
|
const VERSION = 23;
|
||||||
const send = (msg) => window.__vrkbdKey && window.__vrkbdKey(msg);
|
const send = (msg) => window.__vrkbdKey && window.__vrkbdKey(msg);
|
||||||
const mods = find.resolvePatch('webpackChunksteamui', sigs);
|
const mods = find.resolvePatch('webpackChunksteamui', sigs);
|
||||||
if (typeof mods === 'string') return mods;
|
if (typeof mods === 'string') return mods;
|
||||||
@@ -252,8 +252,9 @@
|
|||||||
const key = st?.strKey;
|
const key = st?.strKey;
|
||||||
const ts = this.state?.toggleStates || {};
|
const ts = this.state?.toggleStates || {};
|
||||||
const ctrl = active(ts.Control), alt = active(ts.Alt), shift = active(ts.Shift);
|
const ctrl = active(ts.Control), alt = active(ts.Alt), shift = active(ts.Shift);
|
||||||
// Extra keys always; Shift+arrow too (Steam's own arrow path drops Shift).
|
// Extra keys always; Shift+arrow and Shift+Tab too (Steam sends arrows
|
||||||
const special = key?.startsWith('VKX_') || (shift && key?.startsWith('Arrow'));
|
// and Tab without Shift: Tab as the text "\t").
|
||||||
|
const special = key?.startsWith('VKX_') || (shift && (key?.startsWith('Arrow') || key === 'Tab'));
|
||||||
const sym = key && !TOGGLES.includes(key) && (special || ctrl || alt) && keysym(key);
|
const sym = key && !TOGGLES.includes(key) && (special || ctrl || alt) && keysym(key);
|
||||||
if (!sym) return orig.call(this, st);
|
if (!sym) return orig.call(this, st);
|
||||||
send('key:' + [ctrl && 'ctrl', alt && 'alt', shift && 'shift', sym].filter(Boolean).join('+'));
|
send('key:' + [ctrl && 'ctrl', alt && 'alt', shift && 'shift', sym].filter(Boolean).join('+'));
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// allowlist.mjs: what the xdotool helper accepts from Steam's UI JS.
|
||||||
|
// usage: node allowlist.test.mjs <allowlist.mjs>
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { pathToFileURL } from 'node:url';
|
||||||
|
|
||||||
|
const { allowedCombo, allowedChar } = await import(pathToFileURL(process.argv[2]).href);
|
||||||
|
const accept = ['shift+Tab', 'ctrl+Tab', 'ctrl+shift+Tab', 'ctrl+shift+t', 'alt+f',
|
||||||
|
'shift+Left', 'Escape', 'Delete', 'shift+End', 'ctrl+BackSpace'];
|
||||||
|
const reject = ['Tab', 'shift+a', 'a', 'Return', 'shift+Return', 'ctrl+Return', 'shift+BackSpace',
|
||||||
|
'shift+shift+Tab', 'super+Tab', 'shift+space', 'ctrl+a+b'];
|
||||||
|
const acceptChar = ['ä', '€', '|', '@', '\\', '`'];
|
||||||
|
const rejectChar = ['a', 'A', '1', ' ', '\n', '\t', 'ab', ' '];
|
||||||
|
for (const c of accept) assert.equal(allowedCombo(c), true, `accepts key:${c}`);
|
||||||
|
for (const c of reject) assert.equal(allowedCombo(c), false, `rejects key:${c}`);
|
||||||
|
for (const c of acceptChar) assert.equal(allowedChar(c), true, `accepts type:${c}`);
|
||||||
|
for (const c of rejectChar) assert.equal(allowedChar(c), false, `rejects type:${JSON.stringify(c)}`);
|
||||||
|
console.log(`allowlist: ${accept.length + reject.length + acceptChar.length + rejectChar.length} cases passed`);
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
// usage: node xdotool-helper.mjs <patch.js> <unpatch.js> [xdotool]
|
// usage: node xdotool-helper.mjs <patch.js> <unpatch.js> [xdotool]
|
||||||
import { readFileSync } from 'node:fs';
|
import { readFileSync } from 'node:fs';
|
||||||
import { execFile } from 'node:child_process';
|
import { execFile } from 'node:child_process';
|
||||||
|
import { allowedCombo, allowedChar } from './allowlist.mjs';
|
||||||
|
|
||||||
const [, , patchPath, unpatchPath, xdotool = 'xdotool'] = process.argv;
|
const [, , patchPath, unpatchPath, xdotool = 'xdotool'] = process.argv;
|
||||||
const PATCH = readFileSync(patchPath, 'utf8');
|
const PATCH = readFileSync(patchPath, 'utf8');
|
||||||
@@ -19,30 +20,7 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|||||||
// :0 is the Steam session's Xwayland, where the VR app windows live.
|
// :0 is the Steam session's Xwayland, where the VR app windows live.
|
||||||
const ENV = { ...process.env, DISPLAY: process.env.VRKBD_DISPLAY || ':0', LC_ALL: 'C.UTF-8' };
|
const ENV = { ...process.env, DISPLAY: process.env.VRKBD_DISPLAY || ':0', LC_ALL: 'C.UTF-8' };
|
||||||
|
|
||||||
// Allowlist: requests come from Steam's UI JS, so the helper must not be able
|
|
||||||
// to type ASCII text or press Enter on its behalf. Accepted:
|
|
||||||
// key:<combo> the extra keys (Esc, Del, Home, End, PgUp/PgDn, arrows),
|
|
||||||
// optionally with modifiers; or ctrl and/or alt (+ optional
|
|
||||||
// shift) with one key
|
|
||||||
// type:<char> one character Steam's key emulation can't produce: non-ASCII
|
|
||||||
// (äöü߀§°´…) or | @ { [ ] } \ ~ ^ `
|
|
||||||
// down:<mod> / up:<mod> hold/release ctrl or alt
|
|
||||||
const SPECIAL = new Set(['Escape', 'Delete', 'Home', 'End', 'Prior', 'Next', 'Left', 'Right', 'Up', 'Down']);
|
|
||||||
const KEY = /^([a-z0-9]|space|BackSpace|Tab|period|comma|minus|plus|numbersign|less|slash|ssharp|udiaeresis|odiaeresis|adiaeresis)$/;
|
|
||||||
const MODKEY = { ctrl: 'Control_L', alt: 'Alt_L' };
|
const MODKEY = { ctrl: 'Control_L', alt: 'Alt_L' };
|
||||||
function allowedCombo(combo) {
|
|
||||||
const parts = combo.split('+');
|
|
||||||
const key = parts.pop();
|
|
||||||
const mods = new Set(parts);
|
|
||||||
if (parts.length !== mods.size || ![...mods].every((m) => ['ctrl', 'alt', 'shift'].includes(m))) return false;
|
|
||||||
if (SPECIAL.has(key)) return true;
|
|
||||||
return KEY.test(key) && (mods.has('ctrl') || mods.has('alt'));
|
|
||||||
}
|
|
||||||
function allowedChar(c) {
|
|
||||||
if ([...c].length !== 1) return false;
|
|
||||||
const cp = c.codePointAt(0);
|
|
||||||
return (cp > 0xa0 && !/\s|\p{C}/u.test(c)) || '|@{[]}\\~^`'.includes(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
const held = new Set(); // modifiers currently held down via keydown
|
const held = new Set(); // modifiers currently held down via keydown
|
||||||
const xdo = (args) => execFile(xdotool, args, { env: ENV }, (err) => err && console.error('xdotool', args.join(' '), err.message));
|
const xdo = (args) => execFile(xdotool, args, { env: ENV }, (err) => err && console.error('xdotool', args.join(' '), err.message));
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
// Steam's events. Debugging: __sfuiSwipeLog, __sfuiSwipePaths
|
// Steam's events. Debugging: __sfuiSwipeLog, __sfuiSwipePaths
|
||||||
// (scripts/vr-keyboard-replay.mjs).
|
// (scripts/vr-keyboard-replay.mjs).
|
||||||
((find, sigs, opts, hooks, D, T, C, DICT) => {
|
((find, sigs, opts, hooks, D, T, C, DICT) => {
|
||||||
const VERSION = 23;
|
const VERSION = 24;
|
||||||
const G = window;
|
const G = window;
|
||||||
const O = opts;
|
const O = opts;
|
||||||
|
|
||||||
@@ -186,9 +186,9 @@
|
|||||||
const key = st?.strKey, ts = this.state?.toggleStates || {};
|
const key = st?.strKey, ts = this.state?.toggleStates || {};
|
||||||
if (typeof key === 'string' && !TOGGLES.has(key) && !/^(SwitchKeys_|IME_)/.test(key)) {
|
if (typeof key === 'string' && !TOGGLES.has(key) && !/^(SwitchKeys_|IME_)/.test(key)) {
|
||||||
// Extra keys typed by keyboard.vr.extraKeys with xdotool (chords, Esc,
|
// Extra keys typed by keyboard.vr.extraKeys with xdotool (chords, Esc,
|
||||||
// arrows, AltGr Delete: text after the cursor) and dead keys: the
|
// arrows, Shift+Tab, AltGr Delete: text after the cursor) and dead
|
||||||
// model can't follow them.
|
// keys: the model can't follow them.
|
||||||
if (on(ts.Control) || on(ts.Alt) || key.startsWith('VKX_') || st.strDeadKeyNext || (on(ts.Shift) && key.startsWith('Arrow'))) {
|
if (on(ts.Control) || on(ts.Alt) || key.startsWith('VKX_') || st.strDeadKeyNext || (on(ts.Shift) && (key.startsWith('Arrow') || key === 'Tab'))) {
|
||||||
reset(`key ${key}`);
|
reset(`key ${key}`);
|
||||||
} else { model.freeze(); refreshLater(); }
|
} else { model.freeze(); refreshLater(); }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user