mirror of
https://github.com/lhns/steam-frame-nix.git
synced 2026-10-06 04:04:16 +02:00
Keyboard patch: stable bottom row, AltGr Pos1/End/PgUp/PgDn, Shift+arrows
- every bottom-row key gets explicit normal/shift/AltGr variants: in Steam's stock row the close icon jumps with Shift and keys turn into empty full-width panels with AltGr - AltGr + arrows: Pos1 / End / PgUp / PgDn (shown as small hints) - Shift + arrows go through the helper as real Shift+arrow (Steam's own arrow path drops Shift), so text selection works
This commit is contained in:
1 parent
5e7d631e50
commit
bd341f45c2
2 files changed
+34
-13
No files matched your search
@@ -16,12 +16,13 @@ const ENV = { ...process.env, DISPLAY: process.env.VRKBD_DISPLAY || ':0', LC_ALL
|
|||||||
|
|
||||||
// Allowlist: requests come from Steam's UI JS, so the helper must not be able
|
// 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:
|
// to type ASCII text or press Enter on its behalf. Accepted:
|
||||||
// key:<combo> the extra keys (Esc, Del, Home, End, arrows), optionally with
|
// key:<combo> the extra keys (Esc, Del, Home, End, PgUp/PgDn, arrows),
|
||||||
// modifiers; or ctrl and/or alt (+ optional shift) with one key
|
// 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
|
// type:<char> one character Steam's key emulation can't produce: non-ASCII
|
||||||
// (äöü߀§°´…) or | @ { [ ] } \ ~ ^ `
|
// (äöü߀§°´…) or | @ { [ ] } \ ~ ^ `
|
||||||
// down:<mod> / up:<mod> hold/release ctrl or alt
|
// down:<mod> / up:<mod> hold/release ctrl or alt
|
||||||
const SPECIAL = new Set(['Escape', 'Delete', 'Home', 'End', 'Left', 'Right', 'Up', 'Down']);
|
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 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) {
|
function allowedCombo(combo) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
// executed by helper.mjs with xdotool on :0.
|
// executed by helper.mjs with xdotool on :0.
|
||||||
// Idempotent: safe to evaluate repeatedly.
|
// Idempotent: safe to evaluate repeatedly.
|
||||||
(() => {
|
(() => {
|
||||||
const VERSION = 5;
|
const VERSION = 7;
|
||||||
const send = (msg) => window.__vrkbdKey && window.__vrkbdKey(msg);
|
const send = (msg) => window.__vrkbdKey && window.__vrkbdKey(msg);
|
||||||
const wr = window.__vrkbdWr ||
|
const wr = window.__vrkbdWr ||
|
||||||
(webpackChunksteamui.push([[Symbol('vrkbd')], {}, (r) => { window.__vrkbdWr = r; }]), window.__vrkbdWr);
|
(webpackChunksteamui.push([[Symbol('vrkbd')], {}, (r) => { window.__vrkbdWr = r; }]), window.__vrkbdWr);
|
||||||
@@ -25,18 +25,33 @@
|
|||||||
// left of the space bar, and Steam's arrow keys become four separate keys
|
// left of the space bar, and Steam's arrow keys become four separate keys
|
||||||
// (stock layouts pair them as [Left, Up-when-shifted], [Right, Down-when-shifted]).
|
// (stock layouts pair them as [Left, Up-when-shifted], [Right, Down-when-shifted]).
|
||||||
// Key type "Half" for all added keys; the stylesheet below sets their width.
|
// Key type "Half" for all added keys; the stylesheet below sets their width.
|
||||||
|
// Every entry is a [normal, shifted, altgr] triple: Steam's stock bottom row
|
||||||
|
// lacks explicit variants, so with Shift the close icon jumps and with AltGr
|
||||||
|
// keys turn into empty full-width panels. With AltGr the arrows become
|
||||||
|
// Pos1/Ende/PgUp/PgDn (Shift+arrows stay arrows, for selecting).
|
||||||
const HALF = 2;
|
const HALF = 2;
|
||||||
const k = (key, label) => ({ key, label, type: HALF });
|
const k = (key, label) => ({ key, label, type: HALF });
|
||||||
const MODS = [k('VKX_Escape', 'Esc'), k('Control', 'Ctrl'), k('Alt', 'Alt')];
|
// null as the shifted variant = "same key, no shift label". Steam still draws
|
||||||
const ARROWS = [Layouts.Md, Layouts.GO, Layouts.xl, Layouts.B6] // Steam's ArrowLeft/Up/Down/Right
|
// the AltGr variant as a small secondary label; the stylesheet hides that in
|
||||||
.map((a) => ({ ...a, type: HALF }));
|
// the bottom row (the arrows keep theirs as a Pos1/Ende/Bild hint).
|
||||||
|
const same = (x) => [x, null, x];
|
||||||
|
const MODS = [k('VKX_Escape', 'Esc'), k('Control', 'Ctrl'), k('Alt', 'Alt')].map(same);
|
||||||
|
const half = (a) => ({ ...a, type: HALF });
|
||||||
|
const ARROWS = [ // Steam's ArrowLeft/Up/Down/Right keys
|
||||||
|
[Layouts.Md, k('VKX_Home', 'Pos1')],
|
||||||
|
[Layouts.GO, k('VKX_Prior', 'Bild↑')],
|
||||||
|
[Layouts.xl, k('VKX_Next', 'Bild↓')],
|
||||||
|
[Layouts.B6, k('VKX_End', 'Ende')],
|
||||||
|
].map(([a, alt]) => [half(a), null, alt]);
|
||||||
|
const first = (x) => (Array.isArray(x) ? x.find((y) => y) : x);
|
||||||
const isArrow = (x) => (Array.isArray(x) ? x : [x]).some((y) => y && typeof y.key === 'string' && y.key.startsWith('Arrow'));
|
const isArrow = (x) => (Array.isArray(x) ? x : [x]).some((y) => y && typeof y.key === 'string' && y.key.startsWith('Arrow'));
|
||||||
const bottomRow = (row) => {
|
const bottomRow = (row) => {
|
||||||
const out = [];
|
const out = [];
|
||||||
for (const x of row) {
|
for (const x of row) {
|
||||||
if (x === undefined || isArrow(x)) continue;
|
const key = first(x);
|
||||||
if (x && x.key === ' ') out.push(...MODS);
|
if (!key || isArrow(x)) continue;
|
||||||
out.push(x);
|
if (key.key === ' ') out.push(...MODS);
|
||||||
|
out.push(same(key));
|
||||||
}
|
}
|
||||||
out.splice(out.length - 1, 0, ...ARROWS); // before Close/Done (last entry)
|
out.splice(out.length - 1, 0, ...ARROWS); // before Close/Done (last entry)
|
||||||
return out;
|
return out;
|
||||||
@@ -90,9 +105,13 @@
|
|||||||
const doc = kbPopup.window.document;
|
const doc = kbPopup.window.document;
|
||||||
let style = doc.getElementById('vrkbd-style');
|
let style = doc.getElementById('vrkbd-style');
|
||||||
if (!style) { style = doc.createElement('style'); style.id = 'vrkbd-style'; doc.head.appendChild(style); }
|
if (!style) { style = doc.createElement('style'); style.id = 'vrkbd-style'; doc.head.appendChild(style); }
|
||||||
style.textContent = ['VKX_Escape', 'Control', 'Alt', 'ArrowLeft', 'ArrowUp', 'ArrowDown', 'ArrowRight']
|
style.textContent = ['VKX_Escape', 'Control', 'Alt', 'ArrowLeft', 'ArrowUp', 'ArrowDown', 'ArrowRight',
|
||||||
|
'VKX_Home', 'VKX_Prior', 'VKX_Next', 'VKX_End']
|
||||||
.map((key) => `[data-key="${key}"]`).join(',') + '{ width: 43px !important; }'
|
.map((key) => `[data-key="${key}"]`).join(',') + '{ width: 43px !important; }'
|
||||||
+ '[data-key="AltGr"]{ width: 52px !important; }';
|
+ '[data-key="AltGr"]{ width: 52px !important; }'
|
||||||
|
// Secondary (AltGr) labels in the bottom row, except the arrows' hints.
|
||||||
|
+ `[data-key-row="${Math.max(...[...doc.querySelectorAll('[data-key-row]')].map((e) => +e.getAttribute('data-key-row')))}"]`
|
||||||
|
+ ':not([data-key^="Arrow"]) span ~ span { display: none !important; }';
|
||||||
const el = doc.querySelector('[data-key]');
|
const el = doc.querySelector('[data-key]');
|
||||||
let f = el[Object.keys(el).find((x) => x.startsWith('__reactFiber'))];
|
let f = el[Object.keys(el).find((x) => x.startsWith('__reactFiber'))];
|
||||||
while (f && !(f.stateNode && f.stateNode.TypeKeyInternal)) f = f.return;
|
while (f && !(f.stateNode && f.stateNode.TypeKeyInternal)) f = f.return;
|
||||||
@@ -123,7 +142,8 @@
|
|||||||
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);
|
||||||
const special = key?.startsWith('VKX_');
|
// Extra keys always; Shift+arrow too (Steam's own arrow path drops Shift).
|
||||||
|
const special = key?.startsWith('VKX_') || (shift && key?.startsWith('Arrow'));
|
||||||
const isToggle = key && ['Shift', 'CapsLock', 'Control', 'Alt', 'AltGr'].includes(key);
|
const isToggle = key && ['Shift', 'CapsLock', 'Control', 'Alt', 'AltGr'].includes(key);
|
||||||
if (key && !isToggle && (special || ctrl || alt)) {
|
if (key && !isToggle && (special || ctrl || alt)) {
|
||||||
const sym = keysym(key);
|
const sym = keysym(key);
|
||||||
|
|||||||
Reference in new issue
Block a user