mirror of
https://github.com/SlimeVR/SlimeVR-Server.git
synced 2026-04-06 02:01:58 +02:00
It wokie
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useLocalization } from '@fluent/react';
|
||||
import { useState, forwardRef, useRef } from 'react';
|
||||
import { Typography } from './Typography';
|
||||
import { RecordIcon } from './icon/RecordIcon';
|
||||
|
||||
const excludedKeys = [' ', 'SPACE', 'META'];
|
||||
const maxKeybindLength = 4;
|
||||
@@ -44,21 +44,17 @@ export const KeybindRecorder = forwardRef<
|
||||
setShowError(false);
|
||||
const updatedKeys = [...displayKeys, key];
|
||||
setLocalKeys(updatedKeys);
|
||||
onKeysChange([...keys, key]);
|
||||
if (updatedKeys.length === maxKeybindLength) {
|
||||
handleOnBlur();
|
||||
onKeysChange(updatedKeys);
|
||||
if (updatedKeys.length == maxKeybindLength) {
|
||||
inputRef.current?.blur();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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 === maxKeybindLength) {
|
||||
if (displayKeys.length < maxKeybindLength - 2) {
|
||||
onKeysChange(oldKeys);
|
||||
setLocalKeys(oldKeys);
|
||||
}
|
||||
@@ -73,22 +69,23 @@ export const KeybindRecorder = forwardRef<
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative w-full">
|
||||
{!showError ? (
|
||||
<div className="absolute bottom-">
|
||||
<Typography>{errorText}</Typography>
|
||||
<div className="relative w-full justify-center align-center">
|
||||
{showError ? (
|
||||
<div className="absolute bottom isInvalid keyslot-invalid text-red-600">
|
||||
<Typography color="red-600">{errorText}</Typography>
|
||||
</div>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
<input
|
||||
ref={inputRef}
|
||||
className="opacity-0 absolute inset-0 cursor-pointer"
|
||||
onFocus={handleOnFocus}
|
||||
onBlur={handleOnBlur}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
<div className="flex gap-2 min-h-[42px] items-center">
|
||||
<div className="flex gap-2 my-5 min-h-[60px] w-full items-center bg-background-70 rounded-md">
|
||||
<input
|
||||
autoFocus
|
||||
ref={inputRef}
|
||||
className="opacity-0 absolute inset-0 cursor-pointer"
|
||||
onFocus={handleOnFocus}
|
||||
onBlur={handleOnBlur}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
<div className="flex flex-grow gap-2 justify-center">
|
||||
{Array.from({ length: maxKeybindLength }).map((_, i) => {
|
||||
const key = displayKeys[i];
|
||||
@@ -99,8 +96,8 @@ export const KeybindRecorder = forwardRef<
|
||||
<div
|
||||
key={i}
|
||||
className={`
|
||||
rounded-md min-w-[50px] min-h-[50px] text-lg flex items-center justify-center hover:ring-2 hover:ring-accent
|
||||
${key ? 'bg-background-90' : 'bg-background-80'}
|
||||
rounded-md m-2 min-w-[50px] min-h-[50px] text-lg flex items-center justify-center hover:ring-2 hover:ring-accent
|
||||
${key ? 'bg-background-90 p-2' : 'bg-background-80'}
|
||||
${
|
||||
isInvalid
|
||||
? 'keyslot-invalid ring-2 ring-red-600'
|
||||
@@ -119,14 +116,6 @@ export const KeybindRecorder = forwardRef<
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/*
|
||||
<div className="w-40 flex-shrink-0 text-accent-background-10 text-right text-sm font-medium">
|
||||
{displayKeys.length < maxKeybindLength && isRecording
|
||||
? l10n.getString('settings-keybinds_now-recording')
|
||||
: l10n.getString('settings-keybinds_record-keybind')}
|
||||
</div>
|
||||
*/}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -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<any>;
|
||||
resetField: UseFormResetField<any>;
|
||||
name: string;
|
||||
delay: string;
|
||||
resetField: UseFormResetField<any>;
|
||||
isVisisble: boolean;
|
||||
onClose: () => void;
|
||||
onUnbind: () => void;
|
||||
}) {
|
||||
|
||||
const { l10n } = useLocalization();
|
||||
|
||||
return (
|
||||
<BaseModal
|
||||
isOpen={isVisisble}
|
||||
appendClasses="w-full max-w-xl h-full max-h-48"
|
||||
appendClasses="w-full max-w-xl h-full max-h-60"
|
||||
>
|
||||
<div className="flex-col gap-4 w-full">
|
||||
<div className="flex flex-col w-full">
|
||||
<div className="flex flex-col gap-3 w-full">
|
||||
<Typography variant="section-title">
|
||||
Create keybind for {l10n.getString(`settings-keybinds_${id}`)}
|
||||
Assign keybind for {l10n.getString(`settings-keybinds_${id}`)}
|
||||
</Typography>
|
||||
<Controller
|
||||
control={control}
|
||||
name={name}
|
||||
render={({ field }) => (
|
||||
<KeybindRecorder
|
||||
keys={field.value ?? []}
|
||||
keys={field.value ?? []}
|
||||
onKeysChange={field.onChange}
|
||||
ref={field.ref}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<div className="flex flex-row justify-end gap-4">
|
||||
<Button
|
||||
id="settings-keybinds_reset-button"
|
||||
variant="primary"
|
||||
onClick={() => {
|
||||
resetField(name);
|
||||
resetField(delay);
|
||||
}}
|
||||
/>
|
||||
<Button id="" variant="primary" onClick={onClose}>
|
||||
Done
|
||||
</Button>
|
||||
<div className="flex flex-row justify-between w-full">
|
||||
<div className="flex flex-row justify-start gap-4">
|
||||
<Button
|
||||
id="settings-keybinds_reset-button"
|
||||
variant="primary"
|
||||
onClick={() => {
|
||||
resetField(name)
|
||||
}}
|
||||
/>
|
||||
<Button variant="primary" onClick={onUnbind}>
|
||||
unbind
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-row justify-end">
|
||||
<Button id="" variant="primary" onClick={onClose}>
|
||||
Done
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -55,14 +55,6 @@ export function KeybindRow({
|
||||
delay={delay}
|
||||
isVisisble={true}
|
||||
/>
|
||||
<NumberSelector
|
||||
control={control}
|
||||
name={delay}
|
||||
valueLabelFormat={(value) => secondsFormat.format(value)}
|
||||
min={0}
|
||||
max={10}
|
||||
step={0.2}
|
||||
/>
|
||||
<div className="max-w-[45px]">
|
||||
<Button
|
||||
id="settings-keybinds_reset-button"
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
import { Typography } from './Typography';
|
||||
import './KeybindRow.scss';
|
||||
import { ReactNode } from 'react';
|
||||
import { ReactNode, useEffect, useState } from 'react';
|
||||
import { Control, UseFormGetValues, useWatch } from 'react-hook-form';
|
||||
import { NumberSelector } from './NumberSelector';
|
||||
import { useLocaleConfig } from '@/i18n/config';
|
||||
|
||||
const createKeybindDisplay = (keybind: string[]): ReactNode | null => {
|
||||
console.log(keybind.length);
|
||||
if (keybind.length <= 1) {
|
||||
return (
|
||||
<div className="flex min-h-[50px] text-lg items-center justifiy-center">
|
||||
Click to edit keybind
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return keybind.map((key, i) => {
|
||||
return (
|
||||
<div className="flex flex-row">
|
||||
<div
|
||||
key={i}
|
||||
className="flex rounded-xl min-w-[50px] min-h-[50px] text-lg justify-center items-center bg-background-70"
|
||||
>
|
||||
<div key={i} className="flex flex-row">
|
||||
<div className="flex p-2 rounded-xl min-w-[50px] min-h-[50px] text-lg justify-center items-center bg-background-70">
|
||||
{key ?? ''}
|
||||
</div>
|
||||
<div className="flex justify-center items-center text-lg gap-2 pl-3">
|
||||
@@ -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<any>;
|
||||
index: number;
|
||||
getValue: UseFormGetValues<any>;
|
||||
openKeybindRecorderModal: (index: number) => void;
|
||||
}) {
|
||||
const [keybindDisplay, setKeybindDisplay] = useState<ReactNode>(null);
|
||||
const [binding, setBinding] = useState<string[]>();
|
||||
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 (
|
||||
<div className="keybind-row bg-background-60 rounded-xl hover:ring-2 hover:ring-accent">
|
||||
<label className="text-sm font-medium text-background-10 p-2">
|
||||
<Typography id={`settings-keybinds_${id}`} />
|
||||
</label>
|
||||
<div className="flex gap-2 min-h-[42px] items-center px-3 py-2 rounded-lg bg-background-80">
|
||||
<div
|
||||
className="flex gap-2 min-h-[42px] items-center px-3 py-2 rounded-lg bg-background-80 hover:ring-2 hover:ring-purple-500"
|
||||
onClick={handleOpenModal}
|
||||
>
|
||||
<div className="flex flex-grow gap-2 justify-center">
|
||||
{keybind != null ? createKeybindDisplay(keybind) : ''}
|
||||
{keybindDisplay}
|
||||
</div>
|
||||
</div>
|
||||
<div>{delay}</div>
|
||||
<NumberSelector
|
||||
control={control}
|
||||
name={`keybinds.${index}.delay`}
|
||||
valueLabelFormat={(value) => secondsFormat.format(value)}
|
||||
min={0}
|
||||
max={10}
|
||||
step={0.2}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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<boolean>(false);
|
||||
const [keybinds, setKeybinds] = useState<KeybindT[]>();
|
||||
const [selectedKeybind, setSelectedKeybind] = useState<KeybindT | null>(null);
|
||||
const [selectedIndex, setSelectedIndex] = useState<number | null>(null);
|
||||
const [defaultKeybindsState, setDefaultKeybindsState] = useState<KeybindForm>(
|
||||
{
|
||||
keybinds: [],
|
||||
}
|
||||
);
|
||||
|
||||
const { control, resetField, reset, handleSubmit, watch } =
|
||||
useForm<KeybindForm>({});
|
||||
const { control, resetField, handleSubmit, reset, setValue, getValues } =
|
||||
useForm<KeybindForm>({
|
||||
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 (
|
||||
<div className="keybind-row" onClick={() => handleOpenRecorderModal(i)}>
|
||||
<div className="keybind-row">
|
||||
<NewKeybindsRow
|
||||
key={i}
|
||||
id={typeof key.keybindNameId === 'string' ? key.keybindNameId : ''}
|
||||
keybind={
|
||||
(typeof key.keybindValue === 'string'
|
||||
? key.keybindValue
|
||||
: ''
|
||||
).split('+') || ''
|
||||
}
|
||||
delay={key.keybindDelay}
|
||||
id={typeof field.name === 'string' ? field.name : ''}
|
||||
control={control}
|
||||
index={index}
|
||||
getValue={getValues}
|
||||
openKeybindRecorderModal={handleOpenRecorderModal}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -107,7 +122,7 @@ export function NewKeybindSettings() {
|
||||
|
||||
useEffect(() => {
|
||||
sendRPCPacket(RpcMessage.KeybindRequest, new KeybindRequestT());
|
||||
}, [isOpen]);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<SettingsPageLayout>
|
||||
@@ -122,33 +137,40 @@ export function NewKeybindSettings() {
|
||||
))}
|
||||
</div>
|
||||
<div className="keybind-settings">
|
||||
<Typography id="keybind_config-keybind_name" />
|
||||
<Typography id="keybind_config-keybind_value" />
|
||||
<Typography id="keybind_config-keybind_delay" />
|
||||
<Typography
|
||||
id="keybind_config-keybind_name"
|
||||
variant="section-title"
|
||||
/>
|
||||
<Typography
|
||||
id="keybind_config-keybind_value"
|
||||
variant="section-title"
|
||||
/>
|
||||
<Typography
|
||||
id="keybind_config-keybind_delay"
|
||||
variant="section-title"
|
||||
/>
|
||||
{createKeybindRows()}
|
||||
<Button
|
||||
id="settings-keybinds_reset-all-button"
|
||||
className="justify-self-start"
|
||||
onClick={handleOnClick}
|
||||
onClick={() => reset(defaultKeybindsState)}
|
||||
variant="primary"
|
||||
/>
|
||||
</div>
|
||||
{selectedKeybind && (
|
||||
{selectedIndex != null && (
|
||||
<KeybindRecorderModal
|
||||
id={
|
||||
typeof selectedKeybind.keybindNameId === 'string'
|
||||
? selectedKeybind.keybindNameId
|
||||
: ''
|
||||
}
|
||||
id={fields[selectedIndex].name}
|
||||
control={control}
|
||||
resetField={resetField}
|
||||
name="binding"
|
||||
delay={selectedKeybind.keybindDelay.toString()}
|
||||
name={`keybinds.${selectedIndex}.binding`}
|
||||
isVisisble={isOpen}
|
||||
onClose={() => {
|
||||
console.log('onclose');
|
||||
setIsOpen(false);
|
||||
setSelectedKeybind(null);
|
||||
setSelectedIndex(null);
|
||||
handleSubmit(onSubmit)()
|
||||
}}
|
||||
onUnbind={() => {
|
||||
setValue(`keybinds.${selectedIndex}.binding`, []);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -41,13 +41,6 @@ class KeybindingsConfig {
|
||||
"CTRL+ALT+SHIFT+O",
|
||||
0f
|
||||
)
|
||||
keybinds[KeybindId.TEST] =
|
||||
KeybindData(
|
||||
KeybindId.TEST,
|
||||
"test",
|
||||
"A+B+C+D",
|
||||
2f
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<KeybindListener> = CopyOnWriteArrayList()
|
||||
var keybinds: MutableList<KeybindT> = mutableListOf()
|
||||
var defaultKeybinds: MutableList<KeybindT> = 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()
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ class RPCKeybindHandler(
|
||||
fbb,
|
||||
KeybindResponseT().apply {
|
||||
keybind = api.server.keybindHandler.keybinds.toTypedArray()
|
||||
defaultKeybinds = api.server.keybindHandler.defaultKeybinds.toTypedArray()
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -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: {}
|
||||
|
||||
Submodule solarxr-protocol updated: 7c273070ef...9113fa9576
Reference in New Issue
Block a user