[Update] Add hotkeys main functions

This commit is contained in:
Sakamoto Shiina
2025-01-17 02:41:27 +09:00
parent 34d221c437
commit bac7bb15d3
11 changed files with 145 additions and 57 deletions

View File

@@ -258,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 Voice2Chatbox
toggle_transcription_receive:
label: Toggle Speaker2Log
advanced_settings: advanced_settings:
osc_ip_address: osc_ip_address:
label: OSC IP Address label: OSC IP Address

View File

@@ -255,6 +255,10 @@ config_page:
label: 受信したメッセージをVRChatに送信する label: 受信したメッセージをVRChatに送信する
desc: スピーカーから聞き取り、文字起こしされたメッセージをVRChatに送信します。 desc: スピーカーから聞き取り、文字起こしされたメッセージをVRChatに送信します。
hotkeys:
toggle_vrct_visibility:
label: VRCTの最小化/アクティブ化の切り替え
advanced_settings: advanced_settings:
osc_ip_address: osc_ip_address:
label: OSC IP Address label: OSC IP Address

View File

@@ -1040,7 +1040,10 @@ class Config:
self._MIC_MAX_PHRASES = 10 self._MIC_MAX_PHRASES = 10
self._MIC_WORD_FILTER = [] self._MIC_WORD_FILTER = []
self._HOTKEYS = { self._HOTKEYS = {
"toggle_active_vrct": None, "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

View File

@@ -3,6 +3,7 @@ import { register, unregisterAll, isRegistered } from "@tauri-apps/api/globalSho
import { useEffect } from "react"; import { useEffect } from "react";
import { store } from "@store"; import { store } from "@store";
import { useHotkeys } from "@logics_configs"; import { useHotkeys } from "@logics_configs";
import { useMainFunction } from "@logics_main";
// 修飾キーのパースを行う関数 // 修飾キーのパースを行う関数
const parseHotkey = (hotkeyString) => { const parseHotkey = (hotkeyString) => {
@@ -22,40 +23,65 @@ const parseHotkey = (hotkeyString) => {
export const GlobalHotKeyController = () => { export const GlobalHotKeyController = () => {
const { currentHotkeys } = useHotkeys(); const { currentHotkeys } = useHotkeys();
const {
toggleTranslation,
toggleTranscriptionSend,
toggleTranscriptionReceive,
} = useMainFunction();
useEffect(() => { useEffect(() => {
const registerShortcuts = async () => { const registerShortcuts = async () => {
const shortcut_raw = currentHotkeys.data.toggle_active_vrct;
console.log(shortcut_raw);
if (!shortcut_raw) {
console.warn("No hotkey defined.");
return;
}
const shortcut = parseHotkey(shortcut_raw);
try { try {
// 既存のショートカットをすべて解除 // 既存のショートカットをすべて解除
await unregisterAll(); await unregisterAll();
// 新しいショートカットを登録 const hotkeyEntries = Object.entries(currentHotkeys.data);
const isAlreadyRegistered = await isRegistered(shortcut);
if (!isAlreadyRegistered) { for (const [actionKey, hotkeyRaw] of hotkeyEntries) {
await register(shortcut, async () => { if (!hotkeyRaw) continue;
console.log(`Shortcut "${shortcut}" triggered, setting focus.`);
const minimized = await appWindow.isMinimized(); const shortcut = parseHotkey(hotkeyRaw);
if (minimized === true) { const isAlreadyRegistered = await isRegistered(shortcut);
appWindow.unminimize();
await appWindow.setFocus(); if (!isAlreadyRegistered) {
store.text_area_ref.current?.focus(); await register(shortcut, async () => {
} else { console.log(`Shortcut for "${actionKey}" triggered.`);
appWindow.minimize();
} switch (actionKey) {
}); case "toggle_vrct_visibility": {
console.log(`Registered global shortcut: ${shortcut}`); 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;
}
}
});
console.log(`Registered global shortcut: ${shortcut} for action: ${actionKey}`);
}
} }
} catch (error) { } catch (error) {
console.error("Failed to register global shortcut:", error); console.error("Failed to register global shortcuts:", error);
} }
}; };
@@ -67,7 +93,7 @@ export const GlobalHotKeyController = () => {
console.error("Failed to unregister shortcuts:", error); console.error("Failed to unregister shortcuts:", error);
}); });
}; };
}, [currentHotkeys.data.toggle_active_vrct]); // 監視対象を明確に指定 }, [currentHotkeys.data]); // 監視対象を全体に変更
return null; return null;
}; };

View File

@@ -17,8 +17,6 @@ export const HotkeysEntry = (props) => {
const init_display_value = props.value[props.hotkey_id] ? props.value[props.hotkey_id].join(" + ") : ""; const init_display_value = props.value[props.hotkey_id] ? props.value[props.hotkey_id].join(" + ") : "";
setDisplayValue(init_display_value); setDisplayValue(init_display_value);
}, []); }, []);
console.log(props.value[props.hotkey_id]);
const updateHotkeys = (keys) => { const updateHotkeys = (keys) => {
entryRef.current.blur(); entryRef.current.blur();
@@ -35,9 +33,10 @@ export const HotkeysEntry = (props) => {
const keys = []; const keys = [];
const nonModifierKeys = []; const nonModifierKeys = [];
["Ctrl", "Shift", "Alt", "Super"].forEach((modKey) => { ["Ctrl", "Shift", "Alt", "Meta"].forEach((modKey) => {
if (event[`${modKey.toLowerCase()}Key`] && !keys.includes(modKey)) { if (event[`${modKey.toLowerCase()}Key`] && !keys.includes(modKey)) {
keys.push(modKey); let register_mod_key = (modKey === "Meta") ? "Super" : modKey;
keys.push(register_mod_key);
} }
}); });
@@ -80,6 +79,9 @@ export const HotkeysEntry = (props) => {
); );
if (hasNonModifierKeys) { if (hasNonModifierKeys) {
updateHotkeys(keysRef.current); updateHotkeys(keysRef.current);
} else {
const display_value = props.value[props.hotkey_id] ? props.value[props.hotkey_id].join(" + ") : "";
setDisplayValue(display_value);
} }
} }
}; };

View File

@@ -1,7 +1,7 @@
import { useHotkeys } from "@logics_configs"; import { useHotkeys } from "@logics_configs";
import styles from "./Hotkeys.module.scss"; import styles from "./Hotkeys.module.scss";
import { HotkeysEntryContainer } from "../_templates/Templates"; import { HotkeysEntryContainer } from "../_templates/Templates";
import { useTranslation } from "react-i18next";
export const Hotkeys = () => { export const Hotkeys = () => {
return ( return (
<div className={styles.container}> <div className={styles.container}>
@@ -11,13 +11,35 @@ export const Hotkeys = () => {
}; };
const HotkeysBoxContainer = () => { const HotkeysBoxContainer = () => {
const { t } = useTranslation();
const { currentHotkeys, setHotkeys } = useHotkeys(); const { currentHotkeys, setHotkeys } = useHotkeys();
return ( return (
<div className={styles.container}> <div className={styles.container}>
<HotkeysEntryContainer <HotkeysEntryContainer
// label={t("config_page.appearance.send_message_button_type.label")} label={t("config_page.hotkeys.toggle_vrct_visibility.label")}
label="Toggle active input box" hotkey_id="toggle_vrct_visibility"
hotkey_id="toggle_active_vrct" value={currentHotkeys.data}
state={currentHotkeys.state}
setHotkeys={setHotkeys}
/>
<HotkeysEntryContainer
label={t("config_page.hotkeys.toggle_translation.label")}
hotkey_id="toggle_translation"
value={currentHotkeys.data}
state={currentHotkeys.state}
setHotkeys={setHotkeys}
/>
<HotkeysEntryContainer
label={t("config_page.hotkeys.toggle_transcription_send.label")}
hotkey_id="toggle_transcription_send"
value={currentHotkeys.data}
state={currentHotkeys.state}
setHotkeys={setHotkeys}
/>
<HotkeysEntryContainer
label={t("config_page.hotkeys.toggle_transcription_receive.label")}
hotkey_id="toggle_transcription_receive"
value={currentHotkeys.data} value={currentHotkeys.data}
state={currentHotkeys.state} state={currentHotkeys.state}
setHotkeys={setHotkeys} setHotkeys={setHotkeys}

View File

@@ -1,5 +1,5 @@
.container { .container {
display: flex; display: flex;
gap: 6.4rem; // gap: 6.4rem;
flex-direction: column; flex-direction: column;
} }

View File

@@ -41,7 +41,7 @@ export const MessageInputBox = () => {
const onSubmitFunction = (e) => { const onSubmitFunction = (e) => {
e.preventDefault(); e.preventDefault();
appWindow.minimize(); // appWindow.minimize();
if (!currentMessageInputValue.data.trim()) return updateMessageInputValue(""); if (!currentMessageInputValue.data.trim()) return updateMessageInputValue("");

View File

@@ -12,7 +12,13 @@ export const useHotkeys = () => {
const setHotkeys = (hotkeys) => { const setHotkeys = (hotkeys) => {
pendingHotkeys(); pendingHotkeys();
asyncStdoutToPython("/set/data/hotkeys", hotkeys); const send_obj = {
...currentHotkeys.data,
...hotkeys,
};
asyncStdoutToPython("/set/data/hotkeys", send_obj);
}; };
return { return {

View File

@@ -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 = () => {

View File

@@ -55,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, };
};
}
}); });
}; };
@@ -266,7 +266,10 @@ export const { atomInstance: Atom_EnableSendReceivedMessageToVrc, useHook: useSt
// Hotkeys // Hotkeys
export const { atomInstance: Atom_Hotkeys, useHook: useStore_Hotkeys } = createAtomWithHook({ export const { atomInstance: Atom_Hotkeys, useHook: useStore_Hotkeys } = createAtomWithHook({
toggle_active_vrct: null, toggle_vrct_visibility: null,
toggle_translation: null,
toggle_transcription_send: null,
toggle_transcription_receive: null,
}, "Hotkeys"); }, "Hotkeys");
// Advanced Settings // Advanced Settings