+
{Array.from({ length: maxKeybindLength }).map((_, i) => {
const key = displayKeys[i];
@@ -99,8 +96,8 @@ export const KeybindRecorder = forwardRef<
-
- {/*
-
- {displayKeys.length < maxKeybindLength && isRecording
- ? l10n.getString('settings-keybinds_now-recording')
- : l10n.getString('settings-keybinds_record-keybind')}
-
- */}
);
diff --git a/gui/src/components/commons/KeybindRecorderModal.tsx b/gui/src/components/commons/KeybindRecorderModal.tsx
index 1071e0e50..0b7f00804 100644
--- a/gui/src/components/commons/KeybindRecorderModal.tsx
+++ b/gui/src/components/commons/KeybindRecorderModal.tsx
@@ -2,67 +2,73 @@ import { BaseModal } from './BaseModal';
import {
Controller,
Control,
- UseFormResetField
+ UseFormResetField,
} from 'react-hook-form';
import { KeybindRecorder } from './KeybindRecorder';
import { Typography } from './Typography';
import { Button } from './Button';
+import './KeybindRow.scss';
import { useLocalization } from '@fluent/react';
export function KeybindRecorderModal({
id,
control,
- resetField,
name,
- delay,
+ resetField,
isVisisble,
onClose,
+ onUnbind,
}: {
id?: string;
control: Control
;
- resetField: UseFormResetField;
name: string;
- delay: string;
+ resetField: UseFormResetField;
isVisisble: boolean;
onClose: () => void;
+ onUnbind: () => void;
}) {
-
const { l10n } = useLocalization();
return (
- Create keybind for {l10n.getString(`settings-keybinds_${id}`)}
+ Assign keybind for {l10n.getString(`settings-keybinds_${id}`)}
(
)}
/>
-
-
diff --git a/gui/src/components/commons/KeybindRow.tsx b/gui/src/components/commons/KeybindRow.tsx
index bcd1a89a0..128e35b45 100644
--- a/gui/src/components/commons/KeybindRow.tsx
+++ b/gui/src/components/commons/KeybindRow.tsx
@@ -55,14 +55,6 @@ export function KeybindRow({
delay={delay}
isVisisble={true}
/>
-
secondsFormat.format(value)}
- min={0}
- max={10}
- step={0.2}
- />
{
+ console.log(keybind.length);
+ if (keybind.length <= 1) {
+ return (
+
+ Click to edit keybind
+
+ );
+ }
return keybind.map((key, i) => {
return (
-
-
+
+
{key ?? ''}
@@ -22,24 +30,60 @@ const createKeybindDisplay = (keybind: string[]): ReactNode | null => {
export function NewKeybindsRow({
id,
- keybind,
- delay,
+ control,
+ index,
+ getValue,
+ openKeybindRecorderModal,
}: {
id?: string;
- keybind?: string[];
- delay?: number;
+ control: Control
;
+ index: number;
+ getValue: UseFormGetValues;
+ openKeybindRecorderModal: (index: number) => void;
}) {
+ const [keybindDisplay, setKeybindDisplay] = useState(null);
+ const [binding, setBinding] = useState();
+ const { currentLocales } = useLocaleConfig();
+ const secondsFormat = new Intl.NumberFormat(currentLocales, {
+ style: 'unit',
+ unit: 'second',
+ unitDisplay: 'narrow',
+ maximumFractionDigits: 2,
+ });
+
+ const handleOpenModal = () => {
+ openKeybindRecorderModal(index);
+ };
+
+ useEffect(() => {
+ setBinding(getValue(`keybinds.${index}.binding`));
+ });
+
+ useEffect(() => {
+ if (binding != null) setKeybindDisplay(createKeybindDisplay(binding));
+ }, [binding]);
+
return (
-
+
- {keybind != null ? createKeybindDisplay(keybind) : ''}
+ {keybindDisplay}
-
{delay}
+
secondsFormat.format(value)}
+ min={0}
+ max={10}
+ step={0.2}
+ />
);
}
diff --git a/gui/src/components/settings/pages/newKeybindSettings.tsx b/gui/src/components/settings/pages/newKeybindSettings.tsx
index a07b17bf9..edf55bbea 100644
--- a/gui/src/components/settings/pages/newKeybindSettings.tsx
+++ b/gui/src/components/settings/pages/newKeybindSettings.tsx
@@ -18,87 +18,102 @@ import {
KeybindT,
RpcMessage,
} from 'solarxr-protocol';
-import { useForm } from 'react-hook-form';
+import { useFieldArray, useForm } from 'react-hook-form';
export type KeybindForm = {
- id: number;
- name: string;
- binding: string[];
- delay: number;
+ keybinds: {
+ id: number;
+ name: string;
+ binding: string[];
+ delay: number;
+ }[];
};
export function NewKeybindSettings() {
const { l10n } = useLocalization();
const { sendRPCPacket, useRPCPacket } = useWebsocketAPI();
const [isOpen, setIsOpen] = useState
(false);
- const [keybinds, setKeybinds] = useState();
- const [selectedKeybind, setSelectedKeybind] = useState(null);
+ const [selectedIndex, setSelectedIndex] = useState(null);
+ const [defaultKeybindsState, setDefaultKeybindsState] = useState(
+ {
+ keybinds: [],
+ }
+ );
- const { control, resetField, reset, handleSubmit, watch } =
- useForm({});
+ const { control, resetField, handleSubmit, reset, setValue, getValues } =
+ useForm({
+ defaultValues: defaultKeybindsState,
+ });
- useEffect(() => {
- const subscription = watch(() => handleSubmit(onSubmit)());
- return () => subscription.unsubscribe();
- }, []);
-
- const onSubmit = (value: KeybindForm) => {
- const changeKeybindRequest = new ChangeKeybindRequestT();
-
- const keybind = new KeybindT();
- keybind.keybindId = value.id;
- keybind.keybindNameId = value.name;
- keybind.keybindValue = value.binding.join('+');
- keybind.keybindDelay = value.delay;
-
- changeKeybindRequest.keybind = keybind;
-
- console.log(`Onsubmit: ${keybind.keybindValue}`);
-
- sendRPCPacket(RpcMessage.ChangeKeybindRequest, changeKeybindRequest);
- };
-
- useRPCPacket(RpcMessage.KeybindResponse, ({ keybind }: KeybindResponseT) => {
- if (!keybind) return;
- setKeybinds(keybind);
+ const { fields } = useFieldArray({
+ control,
+ name: 'keybinds',
});
- const handleOnClick = () => {
- console.log('pressed');
- };
- const handleOpenRecorderModal = (index: number) => {
- if (keybinds == null) return;
- console.log('Handle open recorder modal');
- const kb = keybinds[index];
+ const onSubmit = (value: KeybindForm) => {
+ value.keybinds.forEach((kb) => {
+ const changeKeybindRequest = new ChangeKeybindRequestT();
- setSelectedKeybind(kb);
- setIsOpen(true);
+ const keybind = new KeybindT();
+ keybind.keybindId = kb.id;
+ keybind.keybindNameId = kb.name;
+ keybind.keybindValue = kb.binding.join('+');
+ keybind.keybindDelay = kb.delay;
- reset({
- id: kb.keybindId,
- name: typeof kb.keybindNameId === 'string' ? kb.keybindNameId : '',
- binding:
- typeof kb.keybindValue === 'string' ? kb.keybindValue.split('+') : [],
- delay: kb.keybindDelay,
+ changeKeybindRequest.keybind = keybind;
+
+ sendRPCPacket(RpcMessage.ChangeKeybindRequest, changeKeybindRequest);
});
};
+ useRPCPacket(
+ RpcMessage.KeybindResponse,
+ ({ keybind, defaultKeybinds }: KeybindResponseT) => {
+ if (!keybind) return;
+
+ const mappedDefaults = defaultKeybinds.map((kb) => ({
+ id: kb.keybindId,
+ name: typeof kb.keybindNameId === 'string' ? kb.keybindNameId : '',
+ binding:
+ typeof kb.keybindValue === 'string' ? kb.keybindValue.split('+') : [],
+ delay: kb.keybindDelay,
+ }));
+
+ setDefaultKeybindsState({ keybinds: mappedDefaults });
+
+ const mapped = keybind.map((kb) => ({
+ id: kb.keybindId,
+ name: typeof kb.keybindNameId === 'string' ? kb.keybindNameId : '',
+ binding:
+ typeof kb.keybindValue === 'string' ? kb.keybindValue.split('+') : [],
+ delay: kb.keybindDelay,
+ }));
+ reset({ keybinds: mappedDefaults });
+
+ mapped.forEach((keybind, index) => {
+ setValue(`keybinds.${index}.binding`, keybind.binding);
+ setValue(`keybinds.${index}.delay`, keybind.delay);
+ });
+ }
+ );
+
+ const handleOpenRecorderModal = (index: number) => {
+ console.log('Handle open recorder modal', index);
+ setSelectedIndex(index);
+ setIsOpen(true);
+ };
+
const createKeybindRows = (): ReactNode => {
- if (keybinds == null) return '';
- return keybinds.map((key, i) => {
+ return fields.map((field, index) => {
return (
- handleOpenRecorderModal(i)}>
+
);
@@ -107,7 +122,7 @@ export function NewKeybindSettings() {
useEffect(() => {
sendRPCPacket(RpcMessage.KeybindRequest, new KeybindRequestT());
- }, [isOpen]);
+ }, []);
return (
@@ -122,33 +137,40 @@ export function NewKeybindSettings() {
))}
-
-
-
+
+
+
{createKeybindRows()}
reset(defaultKeybindsState)}
variant="primary"
/>
- {selectedKeybind && (
+ {selectedIndex != null && (
{
- console.log('onclose');
setIsOpen(false);
- setSelectedKeybind(null);
+ setSelectedIndex(null);
+ handleSubmit(onSubmit)()
+ }}
+ onUnbind={() => {
+ setValue(`keybinds.${selectedIndex}.binding`, []);
}}
/>
)}
diff --git a/server/core/src/main/java/dev/slimevr/config/KeybindingsConfig.kt b/server/core/src/main/java/dev/slimevr/config/KeybindingsConfig.kt
index a9457c763..e00f35832 100644
--- a/server/core/src/main/java/dev/slimevr/config/KeybindingsConfig.kt
+++ b/server/core/src/main/java/dev/slimevr/config/KeybindingsConfig.kt
@@ -41,13 +41,6 @@ class KeybindingsConfig {
"CTRL+ALT+SHIFT+O",
0f
)
- keybinds[KeybindId.TEST] =
- KeybindData(
- KeybindId.TEST,
- "test",
- "A+B+C+D",
- 2f
- )
}
}
diff --git a/server/core/src/main/java/dev/slimevr/keybind/KeybindHandler.kt b/server/core/src/main/java/dev/slimevr/keybind/KeybindHandler.kt
index f1ef959cd..6fbb4bb2c 100644
--- a/server/core/src/main/java/dev/slimevr/keybind/KeybindHandler.kt
+++ b/server/core/src/main/java/dev/slimevr/keybind/KeybindHandler.kt
@@ -1,21 +1,19 @@
package dev.slimevr.keybind
import dev.slimevr.VRServer
+import dev.slimevr.config.KeybindingsConfig
import solarxr_protocol.rpc.KeybindT
import java.util.concurrent.CopyOnWriteArrayList
class KeybindHandler(val vrServer: VRServer) {
private val listeners: MutableList = CopyOnWriteArrayList()
var keybinds: MutableList = mutableListOf()
+ var defaultKeybinds: MutableList = mutableListOf()
init {
createKeybinds()
}
- fun sendKeybinds(KeybindName: String) {
- this.listeners.forEach { it.sendKeybind() }
- }
-
fun addListener(listener: KeybindListener) {
this.listeners.add(listener)
}
@@ -26,6 +24,7 @@ class KeybindHandler(val vrServer: VRServer) {
private fun createKeybinds() {
keybinds.clear()
+ defaultKeybinds.clear()
vrServer.configManager.vrConfig.keybindings.keybinds.forEach { (i, keybind) ->
keybinds.add(
KeybindT().apply {
@@ -36,9 +35,20 @@ class KeybindHandler(val vrServer: VRServer) {
},
)
}
+
+ val binds = KeybindingsConfig().keybinds
+ binds.forEach { (i, keybind) ->
+ defaultKeybinds.add(
+ KeybindT().apply {
+ keybindId = keybind.id
+ keybindNameId = keybind.name
+ keybindValue = keybind.binding
+ keybindDelay = keybind.delay
+ },
+ )
+ }
}
- // TODO: Maybe recreating all the keybinds isn't the best idea?
fun updateKeybinds() {
createKeybinds()
}
diff --git a/server/core/src/main/java/dev/slimevr/protocol/rpc/keybinds/RPCKeybindHandler.kt b/server/core/src/main/java/dev/slimevr/protocol/rpc/keybinds/RPCKeybindHandler.kt
index cfed6efb9..2471dd440 100644
--- a/server/core/src/main/java/dev/slimevr/protocol/rpc/keybinds/RPCKeybindHandler.kt
+++ b/server/core/src/main/java/dev/slimevr/protocol/rpc/keybinds/RPCKeybindHandler.kt
@@ -35,6 +35,7 @@ class RPCKeybindHandler(
fbb,
KeybindResponseT().apply {
keybind = api.server.keybindHandler.keybinds.toTypedArray()
+ defaultKeybinds = api.server.keybindHandler.defaultKeybinds.toTypedArray()
}
)
diff --git a/server/desktop/vrconfig.yml.bak b/server/desktop/vrconfig.yml.bak
index e2bd528de..b223a6de9 100644
--- a/server/desktop/vrconfig.yml.bak
+++ b/server/desktop/vrconfig.yml.bak
@@ -85,11 +85,6 @@ keybindings:
name: "pause-tracking"
binding: "CTRL+ALT+SHIFT+O"
delay: 0.0
- "5":
- id: 5
- name: "test"
- binding: "A+B+C+D"
- delay: 2.0
skeleton:
toggles: {}
values: {}
diff --git a/solarxr-protocol b/solarxr-protocol
index 7c273070e..9113fa957 160000
--- a/solarxr-protocol
+++ b/solarxr-protocol
@@ -1 +1 @@
-Subproject commit 7c273070ef850d8dbacc192a64bd1b19819c8952
+Subproject commit 9113fa9576d85e4f2074b906e69fc07bac94eb1b