From 33ceacc759871a29771edc54a4cf5ef34f8ae120 Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Sun, 26 Jul 2026 23:37:01 +0200 Subject: [PATCH 1/2] fix(keymap): restore handling of shift/capslock (@fehmer) --- .../src/ts/components/pages/test/Keymap.tsx | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/frontend/src/ts/components/pages/test/Keymap.tsx b/frontend/src/ts/components/pages/test/Keymap.tsx index 4194e840dd20..7bf4b129f05e 100644 --- a/frontend/src/ts/components/pages/test/Keymap.tsx +++ b/frontend/src/ts/components/pages/test/Keymap.tsx @@ -35,25 +35,26 @@ export function Keymap() { function Keyboard(props: { displayName: string; layoutData: LayoutObject }) { const layer = createMemo(() => { const { alt, shift } = getModifierState(); + const isShifted = isMacLike() + ? shift || isCapsLockOn() + : shift !== isCapsLockOn(); switch (getConfig.keymapLegendStyle) { case "blank": - return -1; + return { index: -1 }; case "lowercase": - return 0; + return { index: 0 }; case "uppercase": - return 1; + return { index: 1 }; case "dynamic": { if (shift && alt) { - return 3; + return { index: 3 }; } else if (alt) { - return 2; - } else if (shift || isCapsLockOn()) { - return 1; + return { index: 2 }; } - return 0; + return { index: isShifted ? 1 : 0, firstRow: shift ? 1 : 0 }; } default: - return 0; + return { index: 0 }; } }); @@ -93,7 +94,7 @@ function Keyboard(props: { displayName: string; layoutData: LayoutObject }) { function KeyboardDefinitionRenderer(props: { keyboardDef: KeyboardDefinition; - layer: number; + layer: { index: number; firstRow?: number }; showFirstRow: boolean; flashState: Record; }) { @@ -118,9 +119,9 @@ function KeyboardDefinitionRenderer(props: { {(key) => { const label = () => { const layer = - rowNum() === 0 && isMacLike() && isCapsLockOn() - ? props.layer - 1 - : props.layer; + rowNum() === 0 + ? (props.layer.firstRow ?? props.layer.index) + : props.layer.index; return key.legends[layer] ?? ""; }; const flashEntry = () => From e518014f292420c38f664fc99b25c485bcd3db79 Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Mon, 27 Jul 2026 19:37:16 +0200 Subject: [PATCH 2/2] don't shift symbols --- .../src/ts/components/pages/test/Keymap.tsx | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/frontend/src/ts/components/pages/test/Keymap.tsx b/frontend/src/ts/components/pages/test/Keymap.tsx index 7bf4b129f05e..445b6b39ea43 100644 --- a/frontend/src/ts/components/pages/test/Keymap.tsx +++ b/frontend/src/ts/components/pages/test/Keymap.tsx @@ -21,6 +21,8 @@ import { Button } from "../../common/Button"; import { convertLayoutToKeymap } from "./keymapConverter"; import { KeyboardDefinition, KeyDefinition } from "./keymapLayouts"; +const symbolsPattern = /^[^\p{L}\p{N}]{1}$/u; + export function Keymap() { return ( @@ -35,23 +37,30 @@ export function Keymap() { function Keyboard(props: { displayName: string; layoutData: LayoutObject }) { const layer = createMemo(() => { const { alt, shift } = getModifierState(); + + // MacOS has different CapsLock and Shift logic than other operating systems + // Windows and Linux only capitalize letters if either Shift OR CapsLock are + // pressed, but not both at once. + // MacOS instead capitalizes when either or both are pressed, + // so we have to check for that. const isShifted = isMacLike() ? shift || isCapsLockOn() : shift !== isCapsLockOn(); + switch (getConfig.keymapLegendStyle) { case "blank": return { index: -1 }; case "lowercase": return { index: 0 }; case "uppercase": - return { index: 1 }; + return { index: 1, symbolIndex: 0 }; case "dynamic": { if (shift && alt) { return { index: 3 }; } else if (alt) { return { index: 2 }; } - return { index: isShifted ? 1 : 0, firstRow: shift ? 1 : 0 }; + return { index: isShifted ? 1 : 0, symbolIndex: shift ? 1 : 0 }; } default: return { index: 0 }; @@ -94,7 +103,7 @@ function Keyboard(props: { displayName: string; layoutData: LayoutObject }) { function KeyboardDefinitionRenderer(props: { keyboardDef: KeyboardDefinition; - layer: { index: number; firstRow?: number }; + layer: { index: number; symbolIndex?: number }; showFirstRow: boolean; flashState: Record; }) { @@ -118,11 +127,21 @@ function KeyboardDefinitionRenderer(props: { {(key) => { const label = () => { - const layer = - rowNum() === 0 - ? (props.layer.firstRow ?? props.layer.index) - : props.layer.index; - return key.legends[layer] ?? ""; + let label = key.legends[props.layer.index]; + + if (props.layer.symbolIndex !== undefined) { + const keyIsSymbol = [ + key.legends[props.layer.index], + key.legends[props.layer.symbolIndex], + ].some((character) => + symbolsPattern.test(character ?? ""), + ); + + if (keyIsSymbol) { + label = key.legends[props.layer.symbolIndex]; + } + } + return label ?? ""; }; const flashEntry = () => key.legends