Merge branch 'feature_hotkey' into develop
This commit is contained in:
@@ -94,6 +94,7 @@ config_page:
|
|||||||
transcription: Transcription
|
transcription: Transcription
|
||||||
vr: VR
|
vr: VR
|
||||||
others: Others
|
others: Others
|
||||||
|
hotkeys: Hotkeys
|
||||||
advanced_settings: Advanced Settings
|
advanced_settings: Advanced Settings
|
||||||
supporters: Supporters
|
supporters: Supporters
|
||||||
about_vrct: About VRCT
|
about_vrct: About VRCT
|
||||||
@@ -257,6 +258,16 @@ config_page:
|
|||||||
label: Send Received Message To VRChat
|
label: Send Received Message To VRChat
|
||||||
desc: Send the message you received from the speaker's sound to VRChat's chatbox.
|
desc: Send the message you received from the speaker's sound to VRChat's chatbox.
|
||||||
|
|
||||||
|
hotkeys:
|
||||||
|
toggle_vrct_visibility:
|
||||||
|
label: Toggle VRCT Visibility
|
||||||
|
toggle_translation:
|
||||||
|
label: Toggle {{translation}}
|
||||||
|
toggle_transcription_send:
|
||||||
|
label: Toggle {{transcription_send}}
|
||||||
|
toggle_transcription_receive:
|
||||||
|
label: Toggle {{transcription_receive}}
|
||||||
|
|
||||||
advanced_settings:
|
advanced_settings:
|
||||||
osc_ip_address:
|
osc_ip_address:
|
||||||
label: OSC IP Address
|
label: OSC IP Address
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ config_page:
|
|||||||
translation: 翻訳
|
translation: 翻訳
|
||||||
transcription: 音声認識
|
transcription: 音声認識
|
||||||
others: その他
|
others: その他
|
||||||
|
hotkeys: ホットキー
|
||||||
advanced_settings: 高度な設定
|
advanced_settings: 高度な設定
|
||||||
|
|
||||||
device:
|
device:
|
||||||
@@ -255,6 +256,16 @@ config_page:
|
|||||||
label: 受信したメッセージをVRChatに送信する
|
label: 受信したメッセージをVRChatに送信する
|
||||||
desc: スピーカーから聞き取り、文字起こしされたメッセージをVRChatに送信します。
|
desc: スピーカーから聞き取り、文字起こしされたメッセージをVRChatに送信します。
|
||||||
|
|
||||||
|
hotkeys:
|
||||||
|
toggle_vrct_visibility:
|
||||||
|
label: VRCTの最小化/アクティブ化の切り替え
|
||||||
|
toggle_translation:
|
||||||
|
label: '{{translation}}機能切り替え'
|
||||||
|
toggle_transcription_send:
|
||||||
|
label: '{{transcription_send}}機能切り替え'
|
||||||
|
toggle_transcription_receive:
|
||||||
|
label: '{{transcription_receive}}機能切り替え'
|
||||||
|
|
||||||
advanced_settings:
|
advanced_settings:
|
||||||
osc_ip_address:
|
osc_ip_address:
|
||||||
label: OSC IP Address
|
label: OSC IP Address
|
||||||
|
|||||||
@@ -533,6 +533,19 @@ class Config:
|
|||||||
self._MIC_WORD_FILTER = sorted(set(value), key=value.index)
|
self._MIC_WORD_FILTER = sorted(set(value), key=value.index)
|
||||||
self.saveConfig(inspect.currentframe().f_code.co_name, value)
|
self.saveConfig(inspect.currentframe().f_code.co_name, value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
@json_serializable('HOTKEYS')
|
||||||
|
def HOTKEYS(self):
|
||||||
|
return self._HOTKEYS
|
||||||
|
|
||||||
|
@HOTKEYS.setter
|
||||||
|
def HOTKEYS(self, value):
|
||||||
|
if isinstance(value, dict) and set(value.keys()) == set(self.HOTKEYS.keys()):
|
||||||
|
for key, value in value.items():
|
||||||
|
if isinstance(value, list) or value is None:
|
||||||
|
self._HOTKEYS[key] = value
|
||||||
|
self.saveConfig(inspect.currentframe().f_code.co_name, self.HOTKEYS, immediate_save=True)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@json_serializable('MIC_AVG_LOGPROB')
|
@json_serializable('MIC_AVG_LOGPROB')
|
||||||
def MIC_AVG_LOGPROB(self):
|
def MIC_AVG_LOGPROB(self):
|
||||||
@@ -1026,6 +1039,12 @@ class Config:
|
|||||||
self._MIC_PHRASE_TIMEOUT = 3
|
self._MIC_PHRASE_TIMEOUT = 3
|
||||||
self._MIC_MAX_PHRASES = 10
|
self._MIC_MAX_PHRASES = 10
|
||||||
self._MIC_WORD_FILTER = []
|
self._MIC_WORD_FILTER = []
|
||||||
|
self._HOTKEYS = {
|
||||||
|
"toggle_vrct_visibility": None,
|
||||||
|
"toggle_translation": None,
|
||||||
|
"toggle_transcription_send": None,
|
||||||
|
"toggle_transcription_receive": None,
|
||||||
|
}
|
||||||
self._MIC_AVG_LOGPROB = -0.8
|
self._MIC_AVG_LOGPROB = -0.8
|
||||||
self._MIC_NO_SPEECH_PROB = 0.6
|
self._MIC_NO_SPEECH_PROB = 0.6
|
||||||
self._AUTO_SPEAKER_SELECT = True
|
self._AUTO_SPEAKER_SELECT = True
|
||||||
|
|||||||
@@ -996,6 +996,15 @@ class Controller:
|
|||||||
response = {"status":200, "result":config.SPEAKER_MAX_PHRASES}
|
response = {"status":200, "result":config.SPEAKER_MAX_PHRASES}
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def getHotkeys(*args, **kwargs) -> dict:
|
||||||
|
return {"status":200, "result":config.HOTKEYS}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def setHotkeys(data, *args, **kwargs) -> dict:
|
||||||
|
config.HOTKEYS = data
|
||||||
|
return {"status":200, "result":config.HOTKEYS}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getSpeakerAvgLogprob(*args, **kwargs) -> dict:
|
def getSpeakerAvgLogprob(*args, **kwargs) -> dict:
|
||||||
return {"status":200, "result":config.SPEAKER_AVG_LOGPROB}
|
return {"status":200, "result":config.SPEAKER_AVG_LOGPROB}
|
||||||
|
|||||||
@@ -183,6 +183,9 @@ mapping = {
|
|||||||
"/get/data/mic_max_phrases": {"status": True, "variable":controller.getMicMaxPhrases},
|
"/get/data/mic_max_phrases": {"status": True, "variable":controller.getMicMaxPhrases},
|
||||||
"/set/data/mic_max_phrases": {"status": True, "variable":controller.setMicMaxPhrases},
|
"/set/data/mic_max_phrases": {"status": True, "variable":controller.setMicMaxPhrases},
|
||||||
|
|
||||||
|
"/get/data/hotkeys": {"status": True, "variable":controller.getHotkeys},
|
||||||
|
"/set/data/hotkeys": {"status": True, "variable":controller.setHotkeys},
|
||||||
|
|
||||||
"/get/data/mic_avg_logprob": {"status": True, "variable":controller.getMicAvgLogprob},
|
"/get/data/mic_avg_logprob": {"status": True, "variable":controller.getMicAvgLogprob},
|
||||||
"/set/data/mic_avg_logprob": {"status": True, "variable":controller.setMicAvgLogprob},
|
"/set/data/mic_avg_logprob": {"status": True, "variable":controller.setMicAvgLogprob},
|
||||||
|
|
||||||
|
|||||||
1070
src-tauri/Cargo.lock
generated
1070
src-tauri/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -11,12 +11,13 @@ edition = "2021"
|
|||||||
tauri-build = { version = "1", features = [] }
|
tauri-build = { version = "1", features = [] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tauri = { version = "1", features = [ "window-set-size", "window-set-position", "window-unmaximize", "window-close", "window-maximize", "window-minimize", "window-unminimize", "window-start-dragging", "window-set-decorations", "window-set-always-on-top", "shell-sidecar", "shell-open", "devtools"] }
|
tauri = { version = "1", features = [ "window-hide", "window-set-focus", "global-shortcut-all", "window-set-size", "window-set-position", "window-unmaximize", "window-close", "window-maximize", "window-minimize", "window-unminimize", "window-start-dragging", "window-set-decorations", "window-set-always-on-top", "shell-sidecar", "shell-open", "devtools"] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
font-kit = "0.14.2"
|
font-kit = "0.14.2"
|
||||||
window-shadows = { git = "https://github.com/tauri-apps/window-shadows.git" }
|
window-shadows = { git = "https://github.com/tauri-apps/window-shadows.git" }
|
||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# This feature is used for production builds or when a dev server is not specified, DO NOT REMOVE!!
|
# This feature is used for production builds or when a dev server is not specified, DO NOT REMOVE!!
|
||||||
custom-protocol = ["tauri/custom-protocol"]
|
custom-protocol = ["tauri/custom-protocol"]
|
||||||
|
|||||||
@@ -15,8 +15,10 @@
|
|||||||
"window": {
|
"window": {
|
||||||
"all": false,
|
"all": false,
|
||||||
"setAlwaysOnTop": true,
|
"setAlwaysOnTop": true,
|
||||||
|
"setFocus": true,
|
||||||
"setDecorations": true,
|
"setDecorations": true,
|
||||||
"close": true,
|
"close": true,
|
||||||
|
"hide": true,
|
||||||
"setPosition": true,
|
"setPosition": true,
|
||||||
"setSize": true,
|
"setSize": true,
|
||||||
"maximize": true,
|
"maximize": true,
|
||||||
@@ -24,7 +26,10 @@
|
|||||||
"unmaximize": true,
|
"unmaximize": true,
|
||||||
"unminimize": true,
|
"unminimize": true,
|
||||||
"startDragging": true
|
"startDragging": true
|
||||||
},
|
},
|
||||||
|
"globalShortcut": {
|
||||||
|
"all": true
|
||||||
|
},
|
||||||
"shell": {
|
"shell": {
|
||||||
"all": false,
|
"all": false,
|
||||||
"open": true,
|
"open": true,
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import {
|
|||||||
useWindow,
|
useWindow,
|
||||||
} from "@logics_common";
|
} from "@logics_common";
|
||||||
|
|
||||||
// import React from "react";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
KeyEventController,
|
KeyEventController,
|
||||||
StartPythonController,
|
StartPythonController,
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import {
|
|||||||
useMainFunction,
|
useMainFunction,
|
||||||
} from "@logics_main";
|
} from "@logics_main";
|
||||||
|
|
||||||
|
import { useHotkeys } from "@logics_configs";
|
||||||
|
|
||||||
import { useStore_MainFunctionsStateMemory } from "@store";
|
import { useStore_MainFunctionsStateMemory } from "@store";
|
||||||
|
|
||||||
export const ConfigPageCloseTriggerController = () => {
|
export const ConfigPageCloseTriggerController = () => {
|
||||||
@@ -27,6 +29,8 @@ export const ConfigPageCloseTriggerController = () => {
|
|||||||
volumeCheckStop_Speaker,
|
volumeCheckStop_Speaker,
|
||||||
} = useVolume();
|
} = useVolume();
|
||||||
|
|
||||||
|
const { registerShortcuts, unregisterAll } = useHotkeys();
|
||||||
|
|
||||||
|
|
||||||
const memorizeLatestMainFunctionsState = () => {
|
const memorizeLatestMainFunctionsState = () => {
|
||||||
updateMainFunctionsStateMemory({
|
updateMainFunctionsStateMemory({
|
||||||
@@ -43,9 +47,11 @@ export const ConfigPageCloseTriggerController = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentIsOpenedConfigPage.data === true) { // When config page is opened.
|
if (currentIsOpenedConfigPage.data === true) { // When config page is opened.
|
||||||
memorizeLatestMainFunctionsState();
|
memorizeLatestMainFunctionsState();
|
||||||
|
unregisterAll();
|
||||||
if (currentTranscriptionSendStatus.data === true) setTranscriptionSend(false);
|
if (currentTranscriptionSendStatus.data === true) setTranscriptionSend(false);
|
||||||
if (currentTranscriptionReceiveStatus.data === true) setTranscriptionReceive(false);
|
if (currentTranscriptionReceiveStatus.data === true) setTranscriptionReceive(false);
|
||||||
} else if (currentIsOpenedConfigPage.data === false) { // When config page is closed.
|
} else if (currentIsOpenedConfigPage.data === false) { // When config page is closed.
|
||||||
|
registerShortcuts();
|
||||||
if (currentMicThresholdCheckStatus.data === true) volumeCheckStop_Mic();
|
if (currentMicThresholdCheckStatus.data === true) volumeCheckStop_Mic();
|
||||||
if (currentSpeakerThresholdCheckStatus.data === true) volumeCheckStop_Speaker();
|
if (currentSpeakerThresholdCheckStatus.data === true) volumeCheckStop_Speaker();
|
||||||
restoreMainFunctionState();
|
restoreMainFunctionState();
|
||||||
|
|||||||
@@ -2,24 +2,27 @@ import { useEffect } from "react";
|
|||||||
|
|
||||||
export const KeyEventController = () => {
|
export const KeyEventController = () => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleKeydown = (event) => {
|
const handleKeydown = (event) => {
|
||||||
if (event.key === "F5" || (event.ctrlKey && event.key === "r") ||
|
if (
|
||||||
(event.metaKey && event.key === "r")) {
|
event.key === "F5" ||
|
||||||
|
(event.ctrlKey && event.key === "r") ||
|
||||||
|
(event.metaKey && event.key === "r")
|
||||||
|
) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleContextmenu = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
const handleContextmenu = (event) => {
|
document.addEventListener("keydown", handleKeydown);
|
||||||
event.preventDefault();
|
document.addEventListener("contextmenu", handleContextmenu);
|
||||||
};
|
|
||||||
|
|
||||||
document.addEventListener("keydown", handleKeydown);
|
return () => {
|
||||||
document.addEventListener("contextmenu", handleContextmenu);
|
document.removeEventListener("keydown", handleKeydown);
|
||||||
|
document.removeEventListener("contextmenu", handleContextmenu);
|
||||||
return () => {
|
};
|
||||||
document.removeEventListener("keydown", handleKeydown);
|
|
||||||
document.removeEventListener("contextmenu", handleContextmenu);
|
|
||||||
};
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
Others,
|
Others,
|
||||||
AdvancedSettings,
|
AdvancedSettings,
|
||||||
Vr,
|
Vr,
|
||||||
|
Hotkeys,
|
||||||
Supporters,
|
Supporters,
|
||||||
AboutVrct,
|
AboutVrct,
|
||||||
} from "@setting_box";
|
} from "@setting_box";
|
||||||
@@ -27,6 +28,8 @@ export const SettingBox = () => {
|
|||||||
return <Others />;
|
return <Others />;
|
||||||
case "vr":
|
case "vr":
|
||||||
return <Vr />;
|
return <Vr />;
|
||||||
|
case "hotkeys":
|
||||||
|
return <Hotkeys />;
|
||||||
case "advanced_settings":
|
case "advanced_settings":
|
||||||
return <AdvancedSettings />;
|
return <AdvancedSettings />;
|
||||||
case "supporters":
|
case "supporters":
|
||||||
|
|||||||
@@ -8,23 +8,36 @@ const _Entry = forwardRef((props, ref) => {
|
|||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
focus: () => {
|
focus: () => {
|
||||||
inputRef.current.focus();
|
inputRef.current.focus();
|
||||||
|
},
|
||||||
|
blur: () => {
|
||||||
|
inputRef.current.blur();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
const input_class_names = clsx(styles.entry_input_area, {
|
const input_class_names = clsx(styles.entry_input_area, {
|
||||||
[styles.is_disabled]: props.is_disabled
|
[styles.is_disabled]: props.is_disabled,
|
||||||
|
});
|
||||||
|
const input_wrapper_class_names = clsx(styles.entry_wrapper, {
|
||||||
|
[styles.is_activated]: props.is_activated,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.entry_container}>
|
<div className={styles.entry_container}>
|
||||||
<div
|
<div
|
||||||
className={styles.entry_wrapper}
|
className={input_wrapper_class_names}
|
||||||
style={{width: props.width }}
|
style={{width: props.width }}
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
|
text={props.text ? props.text : "text"}
|
||||||
|
placeholder={props.placeholder ? props.placeholder : ""}
|
||||||
className={input_class_names}
|
className={input_class_names}
|
||||||
value={props.ui_variable === null ? "" : props.ui_variable}
|
value={props.ui_variable === null ? "" : props.ui_variable}
|
||||||
onChange={(e) => props.onChange(e)}
|
onChange={(e) => props.onChange?.(e)}
|
||||||
|
onFocus={(e) => props.onFocus?.(e)}
|
||||||
|
onBlur={(e) => props.onBlur?.(e)}
|
||||||
|
onKeyDown={(e) => props.onKeyDown?.(e)}
|
||||||
|
onKeyUp={(e) => props.onKeyUp?.(e)}
|
||||||
|
readOnly={props.readOnly === true ? true : false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
background-color: var(--dark_875_color);
|
background-color: var(--dark_875_color);
|
||||||
border: 0.1rem solid var(--dark_750_color);
|
border: 0.1rem solid var(--dark_750_color);
|
||||||
border-radius: 0.4rem;
|
border-radius: 0.4rem;
|
||||||
|
&.is_activated {
|
||||||
|
border: 0.1rem solid var(--primary_400_color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.entry_input_area {
|
.entry_input_area {
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
import styles from "./HotkeysEntry.module.scss";
|
||||||
|
import { _Entry } from "../_atoms/_entry/_Entry";
|
||||||
|
import { useState, useRef, useEffect } from "react";
|
||||||
|
import DeleteSvg from "@images/cancel.svg?react";
|
||||||
|
import { clsx } from "clsx";
|
||||||
|
|
||||||
|
export const HotkeysEntry = (props) => {
|
||||||
|
const [isAcceptingInput, setIsAcceptingInput] = useState(false);
|
||||||
|
const [displayValue, setDisplayValue] = useState("");
|
||||||
|
const lastKeyRef = useRef(null);
|
||||||
|
const isModifierOnlyRef = useRef(false);
|
||||||
|
const entryRef = useRef(null);
|
||||||
|
const pressedKeys = useRef(new Set());
|
||||||
|
const keysRef = useRef([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const init_display_value = props.value[props.hotkey_id] ? props.value[props.hotkey_id].join(" + ") : "";
|
||||||
|
setDisplayValue(init_display_value);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const updateHotkeys = (keys) => {
|
||||||
|
entryRef.current.blur();
|
||||||
|
const result = props.setHotkeys({ [props.hotkey_id]: keys });
|
||||||
|
if (result === false) setDisplayValue("");
|
||||||
|
};
|
||||||
|
|
||||||
|
const processKey = (key) => {
|
||||||
|
if (/^[a-zA-Z]$/.test(key)) return key.toUpperCase();
|
||||||
|
if (key === "Meta") return "Super";
|
||||||
|
return key;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyInput = (event) => {
|
||||||
|
const keys = [];
|
||||||
|
const nonModifierKeys = [];
|
||||||
|
|
||||||
|
["Ctrl", "Shift", "Alt", "Meta"].forEach((modKey) => {
|
||||||
|
if (event[`${modKey.toLowerCase()}Key`] && !keys.includes(modKey)) {
|
||||||
|
let register_mod_key = (modKey === "Meta") ? "Super" : modKey;
|
||||||
|
keys.push(register_mod_key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const key = processKey(event.key);
|
||||||
|
if (!["Control", "Shift", "Alt", "Meta"].includes(event.key)) {
|
||||||
|
keys.push(key);
|
||||||
|
nonModifierKeys.push(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pressedKeys.current.has(key)) {
|
||||||
|
pressedKeys.current.add(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
keysRef.current = keys;
|
||||||
|
setDisplayValue(keys.join(" + "));
|
||||||
|
isModifierOnlyRef.current = nonModifierKeys.length === 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyDown = (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (lastKeyRef.current === event.key) return;
|
||||||
|
|
||||||
|
lastKeyRef.current = event.key;
|
||||||
|
handleKeyInput(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyUp = (event) => {
|
||||||
|
lastKeyRef.current = null;
|
||||||
|
|
||||||
|
const key = processKey(event.key);
|
||||||
|
pressedKeys.current.delete(key);
|
||||||
|
|
||||||
|
if (isModifierOnlyRef.current) {
|
||||||
|
setDisplayValue("");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pressedKeys.current.size === 0) {
|
||||||
|
const hasNonModifierKeys = keysRef.current.some(
|
||||||
|
(key) => !["Ctrl", "Shift", "Alt", "Super"].includes(key)
|
||||||
|
);
|
||||||
|
if (hasNonModifierKeys) {
|
||||||
|
updateHotkeys(keysRef.current);
|
||||||
|
} else {
|
||||||
|
const display_value = props.value[props.hotkey_id] ? props.value[props.hotkey_id].join(" + ") : "";
|
||||||
|
setDisplayValue(display_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBlur = () => {
|
||||||
|
setIsAcceptingInput(false);
|
||||||
|
pressedKeys.current.clear();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = () => {
|
||||||
|
updateHotkeys(null);
|
||||||
|
setDisplayValue("");
|
||||||
|
};
|
||||||
|
|
||||||
|
const is_pending = props.state === "pending";
|
||||||
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
{is_pending && <span className={styles.loader}></span>}
|
||||||
|
<_Entry
|
||||||
|
ref={entryRef}
|
||||||
|
type="text"
|
||||||
|
onFocus={() => setIsAcceptingInput(true)}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
onKeyUp={handleKeyUp}
|
||||||
|
ui_variable={displayValue}
|
||||||
|
width="20rem"
|
||||||
|
is_activated={isAcceptingInput}
|
||||||
|
is_disabled={is_pending}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
<button className={clsx(styles.delete_button, { [styles.is_pending]: is_pending })} onClick={handleDelete}>
|
||||||
|
<DeleteSvg className={styles.delete_svg}/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
@import "@scss_mixins";
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete_button {
|
||||||
|
padding: 0.4rem;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
// background-color: var(--dark_800_color);
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 0.2rem;
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--dark_850_color);
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background-color: var(--dark_900_color);
|
||||||
|
}
|
||||||
|
&.is_pending {
|
||||||
|
pointer-events: none;
|
||||||
|
& .delete_svg {
|
||||||
|
color: var(--dark_600_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete_svg {
|
||||||
|
width: 2.2rem;
|
||||||
|
color: var(--error_bc_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader {
|
||||||
|
@include loader(2rem, 0.2rem, left, -2.2rem);
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ export { ComputeDevice } from "./compute_device/ComputeDevice";
|
|||||||
export { DeeplAuthKey, OpenWebpage_DeeplAuthKey } from "./deepl_auth_key/DeeplAuthKey";
|
export { DeeplAuthKey, OpenWebpage_DeeplAuthKey } from "./deepl_auth_key/DeeplAuthKey";
|
||||||
export { DropdownMenu } from "./dropdown_menu/DropdownMenu";
|
export { DropdownMenu } from "./dropdown_menu/DropdownMenu";
|
||||||
export { Entry } from "./entry/Entry";
|
export { Entry } from "./entry/Entry";
|
||||||
|
export { HotkeysEntry } from "./hotkeys_entry/HotkeysEntry";
|
||||||
export { LabelComponent } from "./label_component/LabelComponent";
|
export { LabelComponent } from "./label_component/LabelComponent";
|
||||||
export { RadioButton } from "./radio_button/RadioButton";
|
export { RadioButton } from "./radio_button/RadioButton";
|
||||||
export { SectionLabelComponent } from "./section_label_component/SectionLabelComponent";
|
export { SectionLabelComponent } from "./section_label_component/SectionLabelComponent";
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
Slider,
|
Slider,
|
||||||
SwitchBox,
|
SwitchBox,
|
||||||
Entry,
|
Entry,
|
||||||
|
HotkeysEntry,
|
||||||
RadioButton,
|
RadioButton,
|
||||||
OpenWebpage_DeeplAuthKey,
|
OpenWebpage_DeeplAuthKey,
|
||||||
DeeplAuthKey,
|
DeeplAuthKey,
|
||||||
@@ -75,6 +76,10 @@ export const EntryContainer = (props) => (
|
|||||||
<CommonContainer Component={Entry} {...props} add_break_point={false} />
|
<CommonContainer Component={Entry} {...props} add_break_point={false} />
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const HotkeysEntryContainer = (props) => (
|
||||||
|
<CommonContainer Component={HotkeysEntry} {...props} />
|
||||||
|
);
|
||||||
|
|
||||||
export const RadioButtonContainer = (props) => (
|
export const RadioButtonContainer = (props) => (
|
||||||
<CommonContainer Component={RadioButton} {...props} />
|
<CommonContainer Component={RadioButton} {...props} />
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { useHotkeys } from "@logics_configs";
|
||||||
|
import styles from "./Hotkeys.module.scss";
|
||||||
|
import { HotkeysEntryContainer } from "../_templates/Templates";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
export const Hotkeys = () => {
|
||||||
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
<HotkeysBoxContainer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const HotkeysBoxContainer = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { currentHotkeys, setHotkeys } = useHotkeys();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
<HotkeysEntryContainer
|
||||||
|
label={t("config_page.hotkeys.toggle_vrct_visibility.label")}
|
||||||
|
hotkey_id="toggle_vrct_visibility"
|
||||||
|
value={currentHotkeys.data}
|
||||||
|
state={currentHotkeys.state}
|
||||||
|
setHotkeys={setHotkeys}
|
||||||
|
/>
|
||||||
|
<HotkeysEntryContainer
|
||||||
|
label={t("config_page.hotkeys.toggle_translation.label", {translation: t("main_page.translation")})}
|
||||||
|
hotkey_id="toggle_translation"
|
||||||
|
value={currentHotkeys.data}
|
||||||
|
state={currentHotkeys.state}
|
||||||
|
setHotkeys={setHotkeys}
|
||||||
|
/>
|
||||||
|
<HotkeysEntryContainer
|
||||||
|
label={t("config_page.hotkeys.toggle_transcription_send.label", {transcription_send: t("main_page.transcription_send")})}
|
||||||
|
hotkey_id="toggle_transcription_send"
|
||||||
|
value={currentHotkeys.data}
|
||||||
|
state={currentHotkeys.state}
|
||||||
|
setHotkeys={setHotkeys}
|
||||||
|
/>
|
||||||
|
<HotkeysEntryContainer
|
||||||
|
label={t("config_page.hotkeys.toggle_transcription_receive.label", {transcription_receive: t("main_page.transcription_receive")})}
|
||||||
|
hotkey_id="toggle_transcription_receive"
|
||||||
|
value={currentHotkeys.data}
|
||||||
|
state={currentHotkeys.state}
|
||||||
|
setHotkeys={setHotkeys}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
// gap: 6.4rem;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
@@ -5,5 +5,6 @@ export { Transcription } from "./transcription/Transcription";
|
|||||||
export { Others, VrcMicMuteSyncContainer } from "./others/Others";
|
export { Others, VrcMicMuteSyncContainer } from "./others/Others";
|
||||||
export { AdvancedSettings } from "./advanced_settings/AdvancedSettings";
|
export { AdvancedSettings } from "./advanced_settings/AdvancedSettings";
|
||||||
export { Vr } from "./vr/Vr";
|
export { Vr } from "./vr/Vr";
|
||||||
|
export { Hotkeys } from "./hotkeys/Hotkeys";
|
||||||
export { AboutVrct } from "./about_vrct/AboutVrct";
|
export { AboutVrct } from "./about_vrct/AboutVrct";
|
||||||
export { Supporters } from "./supporters/Supporters";
|
export { Supporters } from "./supporters/Supporters";
|
||||||
@@ -10,6 +10,7 @@ export const SidebarSection = () => {
|
|||||||
<Tab tab_id="transcription" />
|
<Tab tab_id="transcription" />
|
||||||
<Tab tab_id="vr" />
|
<Tab tab_id="vr" />
|
||||||
<Tab tab_id="others" />
|
<Tab tab_id="others" />
|
||||||
|
<Tab tab_id="hotkeys" />
|
||||||
<Tab tab_id="advanced_settings" />
|
<Tab tab_id="advanced_settings" />
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.separated_tabs_wrapper}>
|
<div className={styles.separated_tabs_wrapper}>
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect, useLayoutEffect, useRef } from "react";
|
||||||
import styles from "./MessageInputBox.module.scss";
|
import styles from "./MessageInputBox.module.scss";
|
||||||
import SendMessageSvg from "@images/send_message.svg?react";
|
import SendMessageSvg from "@images/send_message.svg?react";
|
||||||
import { useMessage } from "@logics_common";
|
import { useMessage } from "@logics_common";
|
||||||
import { useSendMessageButtonType, useEnableAutoClearMessageInputBox } from "@logics_configs";
|
import { useSendMessageButtonType, useEnableAutoClearMessageInputBox } from "@logics_configs";
|
||||||
import { useMessageLogScroll } from "@logics_main";
|
import { useMessageLogScroll } from "@logics_main";
|
||||||
|
import { store } from "@store";
|
||||||
|
import { appWindow } from "@tauri-apps/api/window";
|
||||||
|
|
||||||
export const MessageInputBox = () => {
|
export const MessageInputBox = () => {
|
||||||
const [message_history, setMessageHistory] = useState([]);
|
const [message_history, setMessageHistory] = useState([]);
|
||||||
@@ -22,6 +24,12 @@ export const MessageInputBox = () => {
|
|||||||
|
|
||||||
const { scrollToBottom } = useMessageLogScroll();
|
const { scrollToBottom } = useMessageLogScroll();
|
||||||
|
|
||||||
|
const log_box_ref = useRef(null);
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
store.text_area_ref = log_box_ref;
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentMessageLogs.data) {
|
if (currentMessageLogs.data) {
|
||||||
const sentMessages = currentMessageLogs.data
|
const sentMessages = currentMessageLogs.data
|
||||||
@@ -33,6 +41,7 @@ export const MessageInputBox = () => {
|
|||||||
|
|
||||||
const onSubmitFunction = (e) => {
|
const onSubmitFunction = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
// appWindow.minimize();
|
||||||
|
|
||||||
if (!currentMessageInputValue.data.trim()) return updateMessageInputValue("");
|
if (!currentMessageInputValue.data.trim()) return updateMessageInputValue("");
|
||||||
|
|
||||||
@@ -90,6 +99,7 @@ export const MessageInputBox = () => {
|
|||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className={styles.message_box_wrapper}>
|
<div className={styles.message_box_wrapper}>
|
||||||
<textarea
|
<textarea
|
||||||
|
ref={log_box_ref}
|
||||||
className={styles.message_box_input_area}
|
className={styles.message_box_input_area}
|
||||||
onChange={onChangeFunction}
|
onChange={onChangeFunction}
|
||||||
onBlur={stopTyping}
|
onBlur={stopTyping}
|
||||||
|
|||||||
131
src-ui/logics/configs/hotkeys/useHotkeys.js
Normal file
131
src-ui/logics/configs/hotkeys/useHotkeys.js
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
import { appWindow } from "@tauri-apps/api/window";
|
||||||
|
|
||||||
|
import { store, useStore_Hotkeys } from "@store";
|
||||||
|
import { useStdoutToPython } from "@logics/useStdoutToPython";
|
||||||
|
import { useNotificationStatus } from "@logics_common";
|
||||||
|
import { useMainFunction } from "@logics_main";
|
||||||
|
import { register, unregisterAll, isRegistered } from "@tauri-apps/api/globalShortcut";
|
||||||
|
|
||||||
|
export const useHotkeys = () => {
|
||||||
|
const { asyncStdoutToPython } = useStdoutToPython();
|
||||||
|
const { currentHotkeys, updateHotkeys, pendingHotkeys } = useStore_Hotkeys();
|
||||||
|
const {
|
||||||
|
toggleTranslation,
|
||||||
|
toggleTranscriptionSend,
|
||||||
|
toggleTranscriptionReceive,
|
||||||
|
} = useMainFunction();
|
||||||
|
|
||||||
|
|
||||||
|
const getHotkeys = () => {
|
||||||
|
pendingHotkeys();
|
||||||
|
asyncStdoutToPython("/get/data/hotkeys");
|
||||||
|
};
|
||||||
|
const { showNotification_Success, showNotification_Error, closeNotification } = useNotificationStatus();
|
||||||
|
|
||||||
|
const setHotkeys = (hotkeys) => {
|
||||||
|
pendingHotkeys();
|
||||||
|
|
||||||
|
const updatedHotkeys = { ...currentHotkeys.data, ...hotkeys };
|
||||||
|
const usedShortcuts = new Set();
|
||||||
|
const conflictingKeys = [];
|
||||||
|
|
||||||
|
for (const [actionKey, hotkey] of Object.entries(updatedHotkeys)) {
|
||||||
|
if (!hotkey) continue;
|
||||||
|
|
||||||
|
const shortcut = parseHotkey(hotkey);
|
||||||
|
if (usedShortcuts.has(shortcut)) {
|
||||||
|
showNotification_Error(`The hotkey ${shortcut} is already in use.`);
|
||||||
|
updatedHotkeys[actionKey] = null;
|
||||||
|
conflictingKeys.push(actionKey);
|
||||||
|
} else {
|
||||||
|
usedShortcuts.add(shortcut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHotkeys(updatedHotkeys);
|
||||||
|
|
||||||
|
if (conflictingKeys.length === 0) {
|
||||||
|
asyncStdoutToPython("/set/data/hotkeys", updatedHotkeys);
|
||||||
|
closeNotification();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const registerShortcuts = async () => {
|
||||||
|
try {
|
||||||
|
await unregisterAll();
|
||||||
|
|
||||||
|
const hotkeyEntries = Object.entries(currentHotkeys.data);
|
||||||
|
|
||||||
|
for (const [actionKey, hotkeyRaw] of hotkeyEntries) {
|
||||||
|
if (!hotkeyRaw) continue;
|
||||||
|
|
||||||
|
const shortcut = parseHotkey(hotkeyRaw);
|
||||||
|
const isAlreadyRegistered = await isRegistered(shortcut);
|
||||||
|
|
||||||
|
if (!isAlreadyRegistered) {
|
||||||
|
await register(shortcut, async () => {
|
||||||
|
switch (actionKey) {
|
||||||
|
case "toggle_vrct_visibility": {
|
||||||
|
const minimized = await appWindow.isMinimized();
|
||||||
|
if (minimized) {
|
||||||
|
appWindow.unminimize();
|
||||||
|
await appWindow.setFocus();
|
||||||
|
store.text_area_ref.current?.focus();
|
||||||
|
} else {
|
||||||
|
appWindow.minimize();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "toggle_translation": {
|
||||||
|
toggleTranslation();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "toggle_transcription_send": {
|
||||||
|
toggleTranscriptionSend();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "toggle_transcription_receive": {
|
||||||
|
toggleTranscriptionReceive();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
console.warn(`No handler defined for action: ${actionKey}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to register global shortcuts:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
currentHotkeys,
|
||||||
|
getHotkeys,
|
||||||
|
updateHotkeys,
|
||||||
|
setHotkeys,
|
||||||
|
registerShortcuts,
|
||||||
|
unregisterAll,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 修飾キーのパースを行う関数
|
||||||
|
const parseHotkey = (hotkeyString) => {
|
||||||
|
const keyMap = {
|
||||||
|
Ctrl: "Control",
|
||||||
|
Alt: "Alt",
|
||||||
|
Shift: "Shift",
|
||||||
|
Meta: "Super",
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return hotkeyString
|
||||||
|
.map((key) => keyMap[key] || key)
|
||||||
|
.join("+");
|
||||||
|
};
|
||||||
@@ -51,6 +51,8 @@ export { useOverlayShowOnlyTranslatedMessages } from "./vr/useOverlayShowOnlyTra
|
|||||||
export { useOverlayLargeLogSettings } from "./vr/useOverlayLargeLogSettings";
|
export { useOverlayLargeLogSettings } from "./vr/useOverlayLargeLogSettings";
|
||||||
export { useSendTextToOverlay } from "./vr/useSendTextToOverlay";
|
export { useSendTextToOverlay } from "./vr/useSendTextToOverlay";
|
||||||
|
|
||||||
|
export { useHotkeys } from "./hotkeys/useHotkeys";
|
||||||
|
|
||||||
export { useOscIpAddress } from "./advanced_settings/useOscIpAddress";
|
export { useOscIpAddress } from "./advanced_settings/useOscIpAddress";
|
||||||
export { useOscPort } from "./advanced_settings/useOscPort";
|
export { useOscPort } from "./advanced_settings/useOscPort";
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
useStore_TranscriptionReceiveStatus,
|
useStore_TranscriptionReceiveStatus,
|
||||||
useStore_ForegroundStatus,
|
useStore_ForegroundStatus,
|
||||||
} from "@store";
|
} from "@store";
|
||||||
|
import { useCallback } from "react";
|
||||||
import { useStdoutToPython } from "@logics/useStdoutToPython";
|
import { useStdoutToPython } from "@logics/useStdoutToPython";
|
||||||
|
|
||||||
export const useMainFunction = () => {
|
export const useMainFunction = () => {
|
||||||
@@ -40,7 +40,11 @@ export const useMainFunction = () => {
|
|||||||
asyncStdoutToPython("/set/disable/translation");
|
asyncStdoutToPython("/set/disable/translation");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const toggleTranslation = () => setTranslation(!currentTranslationStatus.data);
|
const toggleTranslation = () => {
|
||||||
|
updateTranslationStatus(prev_state => {
|
||||||
|
if (prev_state.state === "ok") setTranslation(!prev_state.data);
|
||||||
|
}, { set_state: "pending" });
|
||||||
|
};
|
||||||
|
|
||||||
const setTranscriptionSend = (to_enable) => {
|
const setTranscriptionSend = (to_enable) => {
|
||||||
pendingTranscriptionSendStatus();
|
pendingTranscriptionSendStatus();
|
||||||
@@ -50,7 +54,11 @@ export const useMainFunction = () => {
|
|||||||
asyncStdoutToPython("/set/disable/transcription_send");
|
asyncStdoutToPython("/set/disable/transcription_send");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const toggleTranscriptionSend = () => setTranscriptionSend(!currentTranscriptionSendStatus.data);
|
const toggleTranscriptionSend = () => {
|
||||||
|
updateTranscriptionSendStatus(prev_state => {
|
||||||
|
if (prev_state.state === "ok") setTranscriptionSend(!prev_state.data);
|
||||||
|
}, { set_state: "pending" });
|
||||||
|
};
|
||||||
|
|
||||||
const setTranscriptionReceive = (to_enable) => {
|
const setTranscriptionReceive = (to_enable) => {
|
||||||
pendingTranscriptionReceiveStatus();
|
pendingTranscriptionReceiveStatus();
|
||||||
@@ -60,7 +68,11 @@ export const useMainFunction = () => {
|
|||||||
asyncStdoutToPython("/set/disable/transcription_receive");
|
asyncStdoutToPython("/set/disable/transcription_receive");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const toggleTranscriptionReceive = () => setTranscriptionReceive(!currentTranscriptionReceiveStatus.data);
|
const toggleTranscriptionReceive = () => {
|
||||||
|
updateTranscriptionReceiveStatus(prev_state => {
|
||||||
|
if (prev_state.state === "ok") setTranscriptionReceive(!prev_state.data);
|
||||||
|
}, { set_state: "pending" });
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const toggleForeground = () => {
|
const toggleForeground = () => {
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ import {
|
|||||||
useIsEnabledOverlayLargeLog,
|
useIsEnabledOverlayLargeLog,
|
||||||
useOverlayLargeLogSettings,
|
useOverlayLargeLogSettings,
|
||||||
useOverlayShowOnlyTranslatedMessages,
|
useOverlayShowOnlyTranslatedMessages,
|
||||||
|
useHotkeys,
|
||||||
useOscIpAddress,
|
useOscIpAddress,
|
||||||
useOscPort,
|
useOscPort,
|
||||||
} from "@logics_configs";
|
} from "@logics_configs";
|
||||||
@@ -168,6 +169,8 @@ export const useReceiveRoutes = () => {
|
|||||||
const { updateIsEnabledOverlayLargeLog } = useIsEnabledOverlayLargeLog();
|
const { updateIsEnabledOverlayLargeLog } = useIsEnabledOverlayLargeLog();
|
||||||
const { updateOverlayShowOnlyTranslatedMessages } = useOverlayShowOnlyTranslatedMessages();
|
const { updateOverlayShowOnlyTranslatedMessages } = useOverlayShowOnlyTranslatedMessages();
|
||||||
|
|
||||||
|
const { updateHotkeys } = useHotkeys();
|
||||||
|
|
||||||
const { updateOscIpAddress } = useOscIpAddress();
|
const { updateOscIpAddress } = useOscIpAddress();
|
||||||
const { updateOscPort } = useOscPort();
|
const { updateOscPort } = useOscPort();
|
||||||
|
|
||||||
@@ -458,6 +461,10 @@ export const useReceiveRoutes = () => {
|
|||||||
"/set/enable/send_received_message_to_vrc": updateEnableSendReceivedMessageToVrc,
|
"/set/enable/send_received_message_to_vrc": updateEnableSendReceivedMessageToVrc,
|
||||||
"/set/disable/send_received_message_to_vrc": updateEnableSendReceivedMessageToVrc,
|
"/set/disable/send_received_message_to_vrc": updateEnableSendReceivedMessageToVrc,
|
||||||
|
|
||||||
|
// Hotkeys
|
||||||
|
"/get/data/hotkeys": updateHotkeys,
|
||||||
|
"/set/data/hotkeys": updateHotkeys,
|
||||||
|
|
||||||
// Advanced Settings
|
// Advanced Settings
|
||||||
"/get/data/osc_ip_address": updateOscIpAddress,
|
"/get/data/osc_ip_address": updateOscIpAddress,
|
||||||
"/set/data/osc_ip_address": updateOscIpAddress,
|
"/set/data/osc_ip_address": updateOscIpAddress,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export const store = {
|
|||||||
config_page: null,
|
config_page: null,
|
||||||
setting_box_scroll_container: null,
|
setting_box_scroll_container: null,
|
||||||
log_box_ref: null,
|
log_box_ref: null,
|
||||||
|
text_area_ref: null,
|
||||||
is_applied_init_message_box_height: false,
|
is_applied_init_message_box_height: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -54,20 +55,20 @@ const createAtomWithHook = (initialValue, base_name, options) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateAtom = (payload) => {
|
const updateAtom = (payload, options = {}) => {
|
||||||
|
const { remain_state = false, set_state } = options;
|
||||||
|
|
||||||
setAtom((currentValue) => {
|
setAtom((currentValue) => {
|
||||||
if (typeof payload === "function") {
|
const new_state = set_state ?? (remain_state ? currentValue.state : "ok");
|
||||||
const updated_data = payload(currentValue);
|
|
||||||
return {
|
const updated_data = typeof payload === "function"
|
||||||
state: "ok",
|
? payload(currentValue)
|
||||||
data: updated_data,
|
: payload;
|
||||||
};
|
|
||||||
} else {
|
return {
|
||||||
return {
|
state: new_state,
|
||||||
state: "ok",
|
data: updated_data,
|
||||||
data: payload,
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -263,6 +264,14 @@ export const { atomInstance: Atom_EnableVrcMicMuteSync, useHook: useStore_Enable
|
|||||||
export const { atomInstance: Atom_EnableSendMessageToVrc, useHook: useStore_EnableSendMessageToVrc } = createAtomWithHook(true, "EnableSendMessageToVrc");
|
export const { atomInstance: Atom_EnableSendMessageToVrc, useHook: useStore_EnableSendMessageToVrc } = createAtomWithHook(true, "EnableSendMessageToVrc");
|
||||||
export const { atomInstance: Atom_EnableSendReceivedMessageToVrc, useHook: useStore_EnableSendReceivedMessageToVrc } = createAtomWithHook(false, "EnableSendReceivedMessageToVrc");
|
export const { atomInstance: Atom_EnableSendReceivedMessageToVrc, useHook: useStore_EnableSendReceivedMessageToVrc } = createAtomWithHook(false, "EnableSendReceivedMessageToVrc");
|
||||||
|
|
||||||
|
// Hotkeys
|
||||||
|
export const { atomInstance: Atom_Hotkeys, useHook: useStore_Hotkeys } = createAtomWithHook({
|
||||||
|
toggle_vrct_visibility: null,
|
||||||
|
toggle_translation: null,
|
||||||
|
toggle_transcription_send: null,
|
||||||
|
toggle_transcription_receive: null,
|
||||||
|
}, "Hotkeys");
|
||||||
|
|
||||||
// Advanced Settings
|
// Advanced Settings
|
||||||
export const { atomInstance: Atom_OscIpAddress, useHook: useStore_OscIpAddress } = createAtomWithHook("127.0.0.1", "OscIpAddress");
|
export const { atomInstance: Atom_OscIpAddress, useHook: useStore_OscIpAddress } = createAtomWithHook("127.0.0.1", "OscIpAddress");
|
||||||
export const { atomInstance: Atom_OscPort, useHook: useStore_OscPort } = createAtomWithHook("9000", "OscPort");
|
export const { atomInstance: Atom_OscPort, useHook: useStore_OscPort } = createAtomWithHook("9000", "OscPort");
|
||||||
|
|||||||
Reference in New Issue
Block a user