diff --git a/src/components/n-links/keyboard.tsx b/src/components/n-links/keyboard.tsx index 970d80b7..c64a1d6a 100644 --- a/src/components/n-links/keyboard.tsx +++ b/src/components/n-links/keyboard.tsx @@ -1,5 +1,6 @@ import {useCallback, useContext, useEffect, useMemo} from 'react'; import {matrixKeycodes} from 'src/utils/key-event'; +import { useKeyboardRecord } from 'src/utils/use-keyboard-record'; import fullKeyboardDefinition from '../../utils/test-keyboard-definition.json'; import {VIAKey, DefinitionVersionMap} from '@the-via/reader'; import {useAppDispatch, useAppSelector} from 'src/store/hooks'; @@ -79,6 +80,9 @@ export const ConfigureKeyboard = (props: { } const KeyboardCanvas = getKeyboardCanvas(props.nDimension); + + useKeyboardRecord(); + return ( <> { +export const Test = (props: { dimensions?: DOMRect; nDimension: NDimension }) => { const dispatch = useAppDispatch(); const [path] = useLocation(); const isShowingTest = path === '/test'; @@ -336,7 +340,7 @@ export const Test = (props: {dimensions?: DOMRect; nDimension: NDimension}) => { nDimension={props.nDimension} /> {partitionedPressedKeys && testKeyboardSoundsSettings.isEnabled && ( - + )} ); diff --git a/src/components/panes/settings.tsx b/src/components/panes/settings.tsx index 119f4587..240004f4 100644 --- a/src/components/panes/settings.tsx +++ b/src/components/panes/settings.tsx @@ -24,7 +24,7 @@ import { getThemeName, updateThemeName, getRenderMode, - updateRenderMode, + updateRenderMode, getDisableRecordKeyboard, toggleRecordKeyboard, } from 'src/store/settingsSlice'; import {AccentSelect} from '../inputs/accent-select'; import {THEMES} from 'src/utils/themes'; @@ -57,6 +57,7 @@ export const Settings = () => { const dispatch = useDispatch(); const showDesignTab = useAppSelector(getShowDesignTab); const disableFastRemap = useAppSelector(getDisableFastRemap); + const disableRecordKeyboard = useAppSelector(getDisableRecordKeyboard); const themeMode = useAppSelector(getThemeMode); const themeName = useAppSelector(getThemeName); const renderMode = useAppSelector(getRenderMode); @@ -94,7 +95,7 @@ export const Settings = () => { - + General @@ -120,6 +121,15 @@ export const Settings = () => { /> + + + + dispatch(toggleRecordKeyboard())} + isChecked={!disableRecordKeyboard} + /> + + diff --git a/src/store/settingsSlice.ts b/src/store/settingsSlice.ts index 0355db4a..cfeec016 100644 --- a/src/store/settingsSlice.ts +++ b/src/store/settingsSlice.ts @@ -42,6 +42,9 @@ const settingsSlice = createSlice({ toggleFastRemap: (state) => { toggleBool(state, 'disableFastRemap'); }, + toggleRecordKeyboard: (state) => { + toggleBool(state, 'disableRecordKeyboard'); + }, toggleCreatorMode: (state) => { toggleBool(state, 'showDesignTab'); }, @@ -104,6 +107,7 @@ const settingsSlice = createSlice({ export const { toggleFastRemap, toggleCreatorMode, + toggleRecordKeyboard, setTestMatrixEnabled, setTestKeyboardSoundsSettings, setMacroEditorSettings, @@ -123,6 +127,8 @@ export const getAllowGlobalHotKeys = (state: RootState) => state.settings.allowGlobalHotKeys; export const getDisableFastRemap = (state: RootState) => state.settings.disableFastRemap; +export const getDisableRecordKeyboard = (state: RootState) => + state.settings.disableRecordKeyboard; export const getShowDesignTab = (state: RootState) => state.settings.showDesignTab; export const getRestartRequired = (state: RootState) => diff --git a/src/types/types.ts b/src/types/types.ts index 3b86fb2f..8684819d 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -84,6 +84,7 @@ export type TestKeyboardSoundsSettings = { export type Settings = { showDesignTab: boolean; disableFastRemap: boolean; + disableRecordKeyboard: boolean; renderMode: '3D' | '2D'; themeMode: 'light' | 'dark'; themeName: string; diff --git a/src/utils/device-store.ts b/src/utils/device-store.ts index ecfd1e88..7d254eeb 100644 --- a/src/utils/device-store.ts +++ b/src/utils/device-store.ts @@ -31,6 +31,7 @@ const defaultStoreData = { settings: { showDesignTab: false, disableFastRemap: false, + disableRecordKeyboard: false, renderMode: '2D' as const, themeMode: 'dark' as const, designDefinitionVersion: 'v3' as const, diff --git a/src/utils/key-event.ts b/src/utils/key-event.ts index f749944d..13b7461e 100644 --- a/src/utils/key-event.ts +++ b/src/utils/key-event.ts @@ -1,4 +1,6 @@ +import { mappingKeyboardKey } from 'src/utils/mapping-keyboard-key'; import basicKeyToByte from './key-to-byte/default'; + export const matrixKeycodes = [ // Row 0 basicKeyToByte.KC_ESC, @@ -257,389 +259,10 @@ export function getIndexByEvent(evt: KeyboardEvent): number { } export function mapEvtToKeycode(evt: KeyboardEvent) { - switch (evt.code) { - case 'Digit1': { - return 'KC_1'; - } - case 'Digit2': { - return 'KC_2'; - } - case 'Digit3': { - return 'KC_3'; - } - case 'Digit4': { - return 'KC_4'; - } - case 'Digit5': { - return 'KC_5'; - } - case 'Digit6': { - return 'KC_6'; - } - case 'Digit7': { - return 'KC_7'; - } - case 'Digit8': { - return 'KC_8'; - } - case 'Digit9': { - return 'KC_9'; - } - case 'Digit0': { - return 'KC_0'; - } - case 'KeyA': { - return 'KC_A'; - } - case 'KeyB': { - return 'KC_B'; - } - case 'KeyC': { - return 'KC_C'; - } - case 'KeyD': { - return 'KC_D'; - } - case 'KeyE': { - return 'KC_E'; - } - case 'KeyF': { - return 'KC_F'; - } - case 'KeyG': { - return 'KC_G'; - } - case 'KeyH': { - return 'KC_H'; - } - case 'KeyI': { - return 'KC_I'; - } - case 'KeyJ': { - return 'KC_J'; - } - case 'KeyK': { - return 'KC_K'; - } - case 'KeyL': { - return 'KC_L'; - } - case 'KeyM': { - return 'KC_M'; - } - case 'KeyN': { - return 'KC_N'; - } - case 'KeyO': { - return 'KC_O'; - } - case 'KeyP': { - return 'KC_P'; - } - case 'KeyQ': { - return 'KC_Q'; - } - case 'KeyR': { - return 'KC_R'; - } - case 'KeyS': { - return 'KC_S'; - } - case 'KeyT': { - return 'KC_T'; - } - case 'KeyU': { - return 'KC_U'; - } - case 'KeyV': { - return 'KC_V'; - } - case 'KeyW': { - return 'KC_W'; - } - case 'KeyX': { - return 'KC_X'; - } - case 'KeyY': { - return 'KC_Y'; - } - case 'KeyZ': { - return 'KC_Z'; - } - case 'Comma': { - return 'KC_COMM'; - } - case 'Period': { - return 'KC_DOT'; - } - case 'Semicolon': { - return 'KC_SCLN'; - } - case 'Quote': { - return 'KC_QUOT'; - } - case 'BracketLeft': { - return 'KC_LBRC'; - } - case 'BracketRight': { - return 'KC_RBRC'; - } - case 'Backquote': { - return 'KC_GRV'; - } - case 'Slash': { - return 'KC_SLSH'; - } - case 'Backspace': { - return 'KC_BSPC'; - } - case 'Backslash': { - return 'KC_BSLS'; - } - case 'Minus': { - return 'KC_MINS'; - } - case 'Equal': { - return 'KC_EQL'; - } - case 'IntlRo': { - return 'KC_RO'; - } - case 'IntlYen': { - return 'KC_JYEN'; - } - case 'AltLeft': { - return 'KC_LALT'; - } - case 'AltRight': { - return 'KC_RALT'; - } - case 'CapsLock': { - return 'KC_CAPS'; - } - case 'ControlLeft': { - return 'KC_LCTL'; - } - case 'ControlRight': { - return 'KC_RCTL'; - } - case 'MetaLeft': { - return 'KC_LGUI'; - } - case 'MetaRight': { - return 'KC_RGUI'; - } - case 'OSLeft': { - return 'KC_LGUI'; - } - case 'OSRight': { - return 'KC_RGUI'; - } - case 'ShiftLeft': { - return 'KC_LSFT'; - } - case 'ShiftRight': { - return 'KC_RSFT'; - } - case 'ContextMenu': { - return 'KC_APP'; - } - case 'Apps': { - return 'KC_APP'; - } - case 'Enter': { - return 'KC_ENT'; - } - case 'Space': { - return 'KC_SPC'; - } - case 'Tab': { - return 'KC_TAB'; - } - case 'Delete': { - return 'KC_DEL'; - } - case 'End': { - return 'KC_END'; - } - case 'Help': { - return 'KC_HELP'; - } - case 'Home': { - return 'KC_HOME'; - } - case 'Insert': { - return 'KC_INS'; - } - case 'PageDown': { - return 'KC_PGDN'; - } - case 'PageUp': { - return 'KC_PGUP'; - } - case 'ArrowDown': { - return 'KC_DOWN'; - } - case 'ArrowLeft': { - return 'KC_LEFT'; - } - case 'ArrowRight': { - return 'KC_RGHT'; - } - case 'ArrowUp': { - return 'KC_UP'; - } - case 'Escape': { - return 'KC_ESC'; - } - case 'PrintScreen': { - return 'KC_PSCR'; - } - case 'ScrollLock': { - return 'KC_SLCK'; - } - case 'Pause': { - return 'KC_PAUS'; - } - case 'F1': { - return 'KC_F1'; - } - case 'F2': { - return 'KC_F2'; - } - case 'F3': { - return 'KC_F3'; - } - case 'F4': { - return 'KC_F4'; - } - case 'F5': { - return 'KC_F5'; - } - case 'F6': { - return 'KC_F6'; - } - case 'F7': { - return 'KC_F7'; - } - case 'F8': { - return 'KC_F8'; - } - case 'F9': { - return 'KC_F9'; - } - case 'F10': { - return 'KC_F10'; - } - case 'F11': { - return 'KC_F11'; - } - case 'F12': { - return 'KC_F12'; - } - case 'F13': { - return 'KC_F13'; - } - case 'F14': { - return 'KC_F14'; - } - case 'F15': { - return 'KC_F15'; - } - case 'F16': { - return 'KC_F16'; - } - case 'F17': { - return 'KC_F17'; - } - case 'F18': { - return 'KC_F18'; - } - case 'F19': { - return 'KC_F19'; - } - case 'F20': { - return 'KC_F20'; - } - case 'F21': { - return 'KC_F21'; - } - case 'F22': { - return 'KC_F22'; - } - case 'F23': { - return 'KC_F23'; - } - case 'F24': { - return 'KC_F24'; - } - case 'NumLock': { - return 'KC_NLCK'; - } - case 'Numpad0': { - return 'KC_P0'; - } - case 'Numpad1': { - return 'KC_P1'; - } - case 'Numpad2': { - return 'KC_P2'; - } - case 'Numpad3': { - return 'KC_P3'; - } - case 'Numpad4': { - return 'KC_P4'; - } - case 'Numpad5': { - return 'KC_P5'; - } - case 'Numpad6': { - return 'KC_P6'; - } - case 'Numpad7': { - return 'KC_P7'; - } - case 'Numpad8': { - return 'KC_P8'; - } - case 'Numpad9': { - return 'KC_P9'; - } - case 'NumpadAdd': { - return 'KC_PPLS'; - } - case 'NumpadComma': { - return 'KC_COMM'; - } - case 'NumpadDecimal': { - return 'KC_PDOT'; - } - case 'NumpadDivide': { - return 'KC_PSLS'; - } - case 'NumpadEnter': { - return 'KC_PENT'; - } - case 'NumpadEqual': { - return 'KC_PEQL'; - } - case 'NumpadMultiply': { - return 'KC_PAST'; - } - case 'NumpadSubtract': { - return 'KC_PMNS'; - } - case 'AudioVolumeUp': { - return 'KC_VOLU'; - } - case 'AudioVolumeDown': { - return 'KC_VOLD'; - } - case 'AudioVolumeMute': { - return 'KC_MUTE'; - } - default: - console.error('Unreacheable keydown code', evt); + const key = mappingKeyboardKey[evt.code as keyof typeof mappingKeyboardKey]; + if (key) { + return key; + } else { + console.error('Unreacheable keydown code', evt); } } diff --git a/src/utils/mapping-keyboard-key.ts b/src/utils/mapping-keyboard-key.ts new file mode 100644 index 00000000..4b9f06a7 --- /dev/null +++ b/src/utils/mapping-keyboard-key.ts @@ -0,0 +1,129 @@ +export const mappingKeyboardKey = { + 'Digit1': 'KC_1', + 'Digit2': 'KC_2', + 'Digit3': 'KC_3', + 'Digit4': 'KC_4', + 'Digit5': 'KC_5', + 'Digit6': 'KC_6', + 'Digit7': 'KC_7', + 'Digit8': 'KC_8', + 'Digit9': 'KC_9', + 'Digit0': 'KC_0', + 'KeyA': 'KC_A', + 'KeyB': 'KC_B', + 'KeyC': 'KC_C', + 'KeyD': 'KC_D', + 'KeyE': 'KC_E', + 'KeyF': 'KC_F', + 'KeyG': 'KC_G', + 'KeyH': 'KC_H', + 'KeyI': 'KC_I', + 'KeyJ': 'KC_J', + 'KeyK': 'KC_K', + 'KeyL': 'KC_L', + 'KeyM': 'KC_M', + 'KeyN': 'KC_N', + 'KeyO': 'KC_O', + 'KeyP': 'KC_P', + 'KeyQ': 'KC_Q', + 'KeyR': 'KC_R', + 'KeyS': 'KC_S', + 'KeyT': 'KC_T', + 'KeyU': 'KC_U', + 'KeyV': 'KC_V', + 'KeyW': 'KC_W', + 'KeyX': 'KC_X', + 'KeyY': 'KC_Y', + 'KeyZ': 'KC_Z', + 'Comma': 'KC_COMM', + 'Period': 'KC_DOT', + 'Semicolon': 'KC_SCLN', + 'Quote': 'KC_QUOT', + 'BracketLeft': 'KC_LBRC', + 'BracketRight': 'KC_RBRC', + 'Backquote': 'KC_GRV', + 'Slash': 'KC_SLSH', + 'Backspace': 'KC_BSPC', + 'Backslash': 'KC_BSLS', + 'Minus': 'KC_MINS', + 'Equal': 'KC_EQL', + 'IntlRo': 'KC_RO', + 'IntlYen': 'KC_JYEN', + 'AltLeft': 'KC_LALT', + 'AltRight': 'KC_RALT', + 'CapsLock': 'KC_CAPS', + 'ControlLeft': 'KC_LCTL', + 'ControlRight': 'KC_RCTL', + 'MetaLeft': 'KC_LGUI', + 'MetaRight': 'KC_RGUI', + 'OSLeft': 'KC_LGUI', + 'OSRight': 'KC_RGUI', + 'ShiftLeft': 'KC_LSFT', + 'ShiftRight': 'KC_RSFT', + 'ContextMenu': 'KC_APP', + 'Apps': 'KC_APP', + 'Enter': 'KC_ENT', + 'Space': 'KC_SPC', + 'Tab': 'KC_TAB', + 'Delete': 'KC_DEL', + 'End': 'KC_END', + 'Help': 'KC_HELP', + 'Home': 'KC_HOME', + 'Insert': 'KC_INS', + 'PageDown': 'KC_PGDN', + 'PageUp': 'KC_PGUP', + 'ArrowDown': 'KC_DOWN', + 'ArrowLeft': 'KC_LEFT', + 'ArrowRight': 'KC_RGHT', + 'ArrowUp': 'KC_UP', + 'Escape': 'KC_ESC', + 'PrintScreen': 'KC_PSCR', + 'ScrollLock': 'KC_SLCK', + 'Pause': 'KC_PAUS', + 'F1': 'KC_F1', + 'F2': 'KC_F2', + 'F3': 'KC_F3', + 'F4': 'KC_F4', + 'F5': 'KC_F5', + 'F6': 'KC_F6', + 'F7': 'KC_F7', + 'F8': 'KC_F8', + 'F9': 'KC_F9', + 'F10': 'KC_F10', + 'F11': 'KC_F11', + 'F12': 'KC_F12', + 'F13': 'KC_F13', + 'F14': 'KC_F14', + 'F15': 'KC_F15', + 'F16': 'KC_F16', + 'F17': 'KC_F17', + 'F18': 'KC_F18', + 'F19': 'KC_F19', + 'F20': 'KC_F20', + 'F21': 'KC_F21', + 'F22': 'KC_F22', + 'F23': 'KC_F23', + 'F24': 'KC_F24', + 'NumLock': 'KC_NLCK', + 'Numpad0': 'KC_P0', + 'Numpad1': 'KC_P1', + 'Numpad2': 'KC_P2', + 'Numpad3': 'KC_P3', + 'Numpad4': 'KC_P4', + 'Numpad5': 'KC_P5', + 'Numpad6': 'KC_P6', + 'Numpad7': 'KC_P7', + 'Numpad8': 'KC_P8', + 'Numpad9': 'KC_P9', + 'NumpadAdd': 'KC_PPLS', + 'NumpadComma': 'KC_COMM', + 'NumpadDecimal': 'KC_PDOT', + 'NumpadDivide': 'KC_PSLS', + 'NumpadEnter': 'KC_PENT', + 'NumpadEqual': 'KC_PEQL', + 'NumpadMultiply': 'KC_PAST', + 'NumpadSubtract': 'KC_PMNS', + 'AudioVolumeUp': 'KC_VOLU', + 'AudioVolumeDown': 'KC_VOLD', + 'AudioVolumeMute': 'KC_MUTE', +}; diff --git a/src/utils/use-keyboard-record.ts b/src/utils/use-keyboard-record.ts new file mode 100644 index 00000000..c54e02a8 --- /dev/null +++ b/src/utils/use-keyboard-record.ts @@ -0,0 +1,56 @@ +import { useEffect } from 'react'; +import { getBasicKeyToByte, getSelectedKeyDefinitions } from 'src/store/definitionsSlice'; +import { useAppDispatch, useAppSelector } from 'src/store/hooks'; +import { getSelectedKey, updateKey as updateKeyAction, updateSelectedKey } from 'src/store/keymapSlice'; +import { getDisableFastRemap, getDisableRecordKeyboard } from 'src/store/settingsSlice'; +import { getByteForCode } from 'src/utils/key'; +import { mapEvtToKeycode } from 'src/utils/key-event'; +import { getNextKey } from 'src/utils/keyboard-rendering'; + +export const useKeyboardRecord = () => { + const dispatch = useAppDispatch(); + const selectedKey = useAppSelector(getSelectedKey); + const {basicKeyToByte} = useAppSelector(getBasicKeyToByte); + const disableFastRemap = useAppSelector(getDisableFastRemap); + const selectedKeyDefinitions = useAppSelector(getSelectedKeyDefinitions); + const disableRecordKeyboard = useAppSelector(getDisableRecordKeyboard); + + const updateKey = (value: number) => { + if (selectedKey !== null) { + + dispatch(updateKeyAction(selectedKey, value)); + dispatch( + updateSelectedKey( + disableFastRemap || !selectedKeyDefinitions + ? null + : getNextKey(selectedKey, selectedKeyDefinitions), + ), + ); + } + }; + + useEffect(() => { + if (disableRecordKeyboard) { + return; + } + const updateWithKb = (e: KeyboardEvent) => { + const code = mapEvtToKeycode(e); + + if (selectedKey === null || !code) { + return; + } + + const index = getByteForCode(code, basicKeyToByte); + + if (index !== 0) { + updateKey(index); + } + }; + + document.addEventListener('keydown', updateWithKb); + return () => { + document.removeEventListener('keydown', updateWithKb); + }; + }, [selectedKey]); + +};