From 934dd3dee25170939a3da996e768bb001b6ec214 Mon Sep 17 00:00:00 2001 From: HannahPadd Date: Thu, 26 Mar 2026 17:45:56 +0100 Subject: [PATCH] Large update to keybindrecorder --- .../components/commons/KeybindRecorder.tsx | 122 +++++++++++++----- gui/src/components/commons/KeybindRow.scss | 38 +++++- gui/src/components/commons/NumberSelector.tsx | 86 ++++++------ .../settings/pages/KeybindSettings.scss | 3 +- solarxr-protocol | 2 +- 5 files changed, 171 insertions(+), 80 deletions(-) diff --git a/gui/src/components/commons/KeybindRecorder.tsx b/gui/src/components/commons/KeybindRecorder.tsx index dd5ef1b58..69374e5d6 100644 --- a/gui/src/components/commons/KeybindRecorder.tsx +++ b/gui/src/components/commons/KeybindRecorder.tsx @@ -1,5 +1,10 @@ import { useLocalization } from '@fluent/react'; -import { useState, forwardRef } from 'react'; +import { useState, forwardRef, useRef } from 'react'; +import { Typography } from './Typography'; + +const excludedKeys = ['CONTROL', ' ', 'SPACE', 'ALT', 'META']; +const keyOffset = 2; +const maxKeybindLength = 4; export const KeybindRecorder = forwardRef< HTMLInputElement, @@ -8,55 +13,104 @@ export const KeybindRecorder = forwardRef< onKeysChange: (v: string[]) => void; } >(function KeybindRecorder({ keys, onKeysChange }, ref) { + const [localKeys, setLocalKeys] = useState(keys); const [isRecording, setIsRecording] = useState(false); const [oldKeys, setOldKeys] = useState([]); + const [invalidSlot, setInvalidSlot] = useState(null); + const [showError, setShowError] = useState(false); + const [errorText, setErrorText] = useState(''); + const inputRef = useRef(null); + const { l10n } = useLocalization(); + const displayKeys = isRecording ? localKeys : keys; + const activeIndex = isRecording ? displayKeys.length : -1; + + const handleKeyDown = (e: React.KeyboardEvent) => { + e.preventDefault(); + const key = e.key.toUpperCase(); + const errorMsg = excludedKeys.includes(key) + ? `Cannot use ${key}!` + : displayKeys.includes(key) + ? `${key} is a Duplicate Key!` + : null; + if (errorMsg) { + setErrorText(errorMsg); + setInvalidSlot(activeIndex); + setShowError(true); + setTimeout(() => { + setInvalidSlot(null); + }, 350); + return; + } + + if (displayKeys.length < maxKeybindLength) { + setShowError(false); + const updatedKeys = [...displayKeys, key]; + setLocalKeys(updatedKeys); + onKeysChange([...keys, key]); + if (updatedKeys.length === maxKeybindLength) { + handleOnBlur(); + } + } + }; + + const handleOnBlur = () => { + console.log(`onblur keys length ${keys.length}`); + if (inputRef != null && typeof inputRef !== 'function') { + inputRef.current?.blur(); + } + setIsRecording(false); + setShowError(false); + if (displayKeys.length == keyOffset) { + onKeysChange(oldKeys); + setLocalKeys(oldKeys); + } + }; + + const handleOnFocus = () => { + const initialKeys = ['CTRL', 'ALT']; + setOldKeys(keys); + setLocalKeys(initialKeys); + onKeysChange(initialKeys); + setIsRecording(true); + }; + return (
- + {!showError ? ( +
+ {errorText} +
+ ) : ( + '' + )} { - setOldKeys(keys); - onKeysChange(['CTRL', 'ALT']); - setIsRecording(true); - }} - onBlur={() => { - setIsRecording(false); - if (keys.length < 4) onKeysChange(oldKeys); - }} - onKeyDown={(e) => { - const key = e.key.toUpperCase(); - if (!keys.includes(key) && keys.length < 4) { - onKeysChange([...keys, key]); - } - }} + onFocus={handleOnFocus} + onBlur={handleOnBlur} + onKeyDown={handleKeyDown} />
- {Array.from({ length: 4 }).map((_, i) => { - const key = keys[i]; - const isActive = isRecording && i === keys.length; + {Array.from({ length: maxKeybindLength }).map((_, i) => { + const key = displayKeys[i]; + const isActive = isRecording && i === activeIndex; + const isInvalid = invalidSlot === i; return (
{key ?? ''} @@ -65,7 +119,7 @@ export const KeybindRecorder = forwardRef< })}
- {keys.length < 4 && isRecording + {displayKeys.length < maxKeybindLength && isRecording ? l10n.getString('settings-keybinds_now-recording') : l10n.getString('settings-keybinds_record-keybind')}
diff --git a/gui/src/components/commons/KeybindRow.scss b/gui/src/components/commons/KeybindRow.scss index 2f81f72dd..eee277b20 100644 --- a/gui/src/components/commons/KeybindRow.scss +++ b/gui/src/components/commons/KeybindRow.scss @@ -11,6 +11,40 @@ gap: 20px; } - .number-selector::after { - gap: 0; +.number-selector::after { + gap: 0; +} + +@keyframes keyslot { + 0%, 100% { + transform: scale(1); + opacity: 0.6; } + + 50% { + transform: scale(1.08); + opacity: 1; + } +} + +@keyframes shake { + 0% { transform: translate(1px, 1px) rotate(0deg); } + 10% { transform: translate(-1px, -2px) rotate(-1deg); } + 20% { transform: translate(-3px, 0px) rotate(1deg); } + 30% { transform: translate(3px, 2px) rotate(0deg); } + 40% { transform: translate(1px, -1px) rotate(1deg); } + 50% { transform: translate(-1px, 2px) rotate(-1deg); } + 60% { transform: translate(-3px, 1px) rotate(0deg); } + 70% { transform: translate(3px, 1px) rotate(-1deg); } + 80% { transform: translate(-1px, -1px) rotate(1deg); } + 90% { transform: translate(1px, 2px) rotate(0deg); } + 100% { transform: translate(1px, -2px) rotate(-1deg); } +} + +.keyslot-animate { + animation: keyslot 1s ease-in-out infinite; +} + +.keyslot-invalid { + animation: shake 0.35s ease; +} diff --git a/gui/src/components/commons/NumberSelector.tsx b/gui/src/components/commons/NumberSelector.tsx index 5e2eb022d..ef1427a60 100644 --- a/gui/src/components/commons/NumberSelector.tsx +++ b/gui/src/components/commons/NumberSelector.tsx @@ -57,60 +57,62 @@ export function NumberSelector({ ( -
- {label} -
-
- {doubleStep !== undefined && ( + render={({ field: { onChange, value } }) => { + return ( +
+ {label?.length != 0 ? {label} : <>} +
+
+ {doubleStep !== undefined && ( + + )} - )} - -
-
- {valueLabelFormat ? valueLabelFormat(value) : value} -
-
- - {doubleStep !== undefined && ( +
+
+ {valueLabelFormat ? valueLabelFormat(value) : value} +
+
- )} + {doubleStep !== undefined && ( + + )} +
-
- )} + ); + }} /> ); } diff --git a/gui/src/components/settings/pages/KeybindSettings.scss b/gui/src/components/settings/pages/KeybindSettings.scss index 442e48500..f635e141d 100644 --- a/gui/src/components/settings/pages/KeybindSettings.scss +++ b/gui/src/components/settings/pages/KeybindSettings.scss @@ -17,6 +17,7 @@ grid-template-columns: subgrid; grid-template-rows: subgrid; - place-items: center; + align-items: left; + gap: 20px; } diff --git a/solarxr-protocol b/solarxr-protocol index bb6f13be5..522d68573 160000 --- a/solarxr-protocol +++ b/solarxr-protocol @@ -1 +1 @@ -Subproject commit bb6f13be590e6815f330536b380414e4fa819212 +Subproject commit 522d685732de611f93e631e860862aca88e4c000