From 6e3da6e71342f2332940c9ef76c06342a78cce07 Mon Sep 17 00:00:00 2001 From: Saya <117558001+fuwako@users.noreply.github.com> Date: Wed, 24 Apr 2024 16:54:20 -0400 Subject: [PATCH] update osc params (#35) * fix values sent via OSC being evaluated as 0 by VRChat * implement editing for VRChat parameter drivers * redesign the title to match other components * validate the assign value field on assign value type change and user-input * fix being only able to use the last declared trigger phrase * modify validation and display * proofread trigger phrase field for consistency * draft behaviors * implement resetting for the osc store * prevent the add param trigger button from leaving the scroll view * implement profiles * remove the attribute persistent from trivial dialogs * reset the add new profile dialog's input field when opening it * implement pulse delay (timeout delay) as a setting * remove item interactivity in the custom params overview * reset pulse by an opposite value instead of zero/false * localize * implement profile renaming * fix display, handle click-outside, fix states * replace deprecated element * refactor * improve display * make behaviors per-assign instead of per-trigger * prevent accidental parameter deletion * handle click-outside * localize warning * improve display for lower resolutions * collapse all expansion panels when switching profiles * lint check --------- Co-authored-by: nae --- src/components/Footer.vue | 59 +- src/components/settings/General.vue | 5 + src/components/settings/OSCParams.vue | 643 ++++++++++++------ .../oscparams/dialogs/ParameterTrigger.vue | 447 ++++++++++++ src/plugins/localization/en.ts | 59 +- src/plugins/localization/ja.ts | 59 +- src/stores/osc.ts | 14 +- 7 files changed, 1075 insertions(+), 211 deletions(-) create mode 100644 src/components/settings/oscparams/dialogs/ParameterTrigger.vue diff --git a/src/components/Footer.vue b/src/components/Footer.vue index 137e2d89..ea8bdb56 100644 --- a/src/components/Footer.vue +++ b/src/components/Footer.vue @@ -209,11 +209,14 @@ export default { // use https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/search // to see which assign is the closest to the keyword found // unless switch to nlp first..... - if (this.oscStore.osc_params.length) { - this.oscStore.osc_params.forEach((custom_param) => { - let matchesKey = null + if (this.oscStore.osc_profiles[this.oscStore.current_profile].length) { + this.oscStore.osc_profiles[this.oscStore.current_profile].forEach((custom_param) => { + let matchesKey: RegExpExecArray | null = null custom_param.keywords.forEach((keyword) => { + if (matchesKey) + return + const key_check = `(^|\\s)(${keyword.text})($|[^a-zA-Z\\d])` const reKey = new RegExp(key_check, 'ig') matchesKey = reKey.exec(input) @@ -225,8 +228,54 @@ export default { const reAssign = new RegExp(assign_check, 'ig') const matchesAssign = reAssign.exec(input) if (matchesAssign) { - this.show_snackbar('secondary', `${custom_param.route} = ${assign.set}`) - window.ipcRenderer.send('send-param-event', { ip: custom_param.ip, port: custom_param.port, route: custom_param.route, value: assign.set }) + this.show_snackbar('secondary', `${custom_param.route} = ${assign.set1}`) + + let newValue: number | boolean | null = null + + switch (assign.type) { + case 'int': + case 'float': + newValue = Number(assign.set1) + + break + case 'bool': + if (assign.set1 === 'true') + newValue = true + else if (assign.set1 === 'false') + newValue = false + else + newValue = Boolean(assign.set1) + + break + } + + window.ipcRenderer.send('send-param-event', { ip: custom_param.ip, port: custom_param.port, route: custom_param.route, value: newValue }) + + if (assign.activation === 'pulse') { + // The value should reset after some time. + setTimeout(() => { + this.show_snackbar('secondary', `${custom_param.route} = ${assign.set2}`) + + switch (assign.type) { + case 'int': + case 'float': + newValue = Number(assign.set2) + + break + case 'bool': + if (assign.set2 === 'true') + newValue = true + else if (assign.set2 === 'false') + newValue = false + else + newValue = Boolean(assign.set2) + + break + } + + window.ipcRenderer.send('send-param-event', { ip: custom_param.ip, port: custom_param.port, route: custom_param.route, value: newValue }) + }, assign.pulse_duration) + } } }) } diff --git a/src/components/settings/General.vue b/src/components/settings/General.vue index b16ca880..376e3b25 100644 --- a/src/components/settings/General.vue +++ b/src/components/settings/General.vue @@ -81,6 +81,7 @@ import { useSpeechStore } from '@/stores/speech' import { useConnectionStore } from '@/stores/connections' import { useLogStore } from '@/stores/logs' import { useTranslationStore } from '@/stores/translation' +import { useOSCStore } from '@/stores/osc' export default { name: 'SettingsGeneral', @@ -92,6 +93,7 @@ export default { const connectionStore = useConnectionStore() const logStore = useLogStore() const translationStore = useTranslationStore() + const oscStore = useOSCStore() return { appearanceStore, @@ -101,6 +103,7 @@ export default { connectionStore, logStore, translationStore, + oscStore, } }, data: () => ({ @@ -146,6 +149,8 @@ export default { this.connectionStore.$reset() if (this.translationStore) this.translationStore.$reset() + if (this.oscStore) + this.oscStore.$reset() this.reset_dialog = false this.snackbar_text = this.$t('settings.general.reset.snackbar.title') this.snackbar = true diff --git a/src/components/settings/OSCParams.vue b/src/components/settings/OSCParams.vue index 92cbd638..e2371efd 100644 --- a/src/components/settings/OSCParams.vue +++ b/src/components/settings/OSCParams.vue @@ -1,175 +1,313 @@ + + diff --git a/src/components/settings/oscparams/dialogs/ParameterTrigger.vue b/src/components/settings/oscparams/dialogs/ParameterTrigger.vue new file mode 100644 index 00000000..7353a04f --- /dev/null +++ b/src/components/settings/oscparams/dialogs/ParameterTrigger.vue @@ -0,0 +1,447 @@ + + + diff --git a/src/plugins/localization/en.ts b/src/plugins/localization/en.ts index 8bab2d38..bba58d8f 100644 --- a/src/plugins/localization/en.ts +++ b/src/plugins/localization/en.ts @@ -18,6 +18,7 @@ export default { type_message: 'Type a message', beta: 'BETA', update: 'Update', + subject_to_change: 'Subject to change', }, alerts: { no_speech: 'Your browser does not support Web Speech API (Speech-to-text).', @@ -172,8 +173,8 @@ export default { general: { title: 'General', description: 'Settings for customizing OSC connection', - osc_ip: 'Default OSC IP', - osc_port: 'Default OSC Port', + osc_ip: 'OSC IP', + osc_port: 'OSC Port', enabled: 'Send all text with OSC (when broadcasting)', typing_indicator: 'Enable typing indicator when typing', speech_indicator: 'Enable typing indicator for speech-to-text', @@ -186,7 +187,59 @@ export default { }, }, params: { - title: 'Custom Params', + title: 'Parameter Triggers', + description: 'Add parameter triggers', + button: { + cancel: 'CANCEL', + confirm: 'CONFIRM', + add: 'ADD', + delete: 'DELETE', + }, + profile: { + label: 'Select a profile', + dialog: { + title: { + add: 'Add new profile', + edit: 'Rename profile', + }, + field_label: 'Profile name', + }, + delete_dialog: { + title: 'Delete profile', + text: 'Are you sure that you want to delete this profile?', + }, + }, + param: { + button: { + edit: 'EDIT', + delete: 'DELETE', + }, + dialog_title: { + add: 'Add parameter trigger', + edit: 'Edit parameter trigger', + }, + address: 'Parameter address', + empty: 'none :c', + trigger_phrases: 'Trigger phrases:', + trigger_phrases_add: 'Add trigger word/phrase', + assign: { + phrases: 'Assign phrases:', + phrases_type: 'Value type', + phrases_value: 'Value ', // This leading space is for displaying "Value 1" and "Value 2". + phrases_add: 'Add assign word/phrase (e.g., on)', + behavior: 'Behavior', + behavior_options: { + default: 'Default', + pulse: 'Pulse', + pulse_wait: 'Wait', + }, + }, + delete_dialog: { + title: 'Delete parameter', + text: 'Are you sure that you want to delete this parameter?', + }, + }, + empty: 'Use the + button to add a new custom parameter trigger!', }, }, }, diff --git a/src/plugins/localization/ja.ts b/src/plugins/localization/ja.ts index fecd6083..5d956db8 100644 --- a/src/plugins/localization/ja.ts +++ b/src/plugins/localization/ja.ts @@ -18,6 +18,7 @@ export default { type_message: 'メッセージを送信', beta: 'ベータ', update: 'アップデート', + subject_to_change: '変更の可能性があります', }, alerts: { no_speech: 'このブラウザはWeb Speech APIをサポートしていません(Speech-to-text)', @@ -172,8 +173,8 @@ export default { general: { title: 'OSC設定', description: 'OSC接続の設定', - osc_ip: 'デフォルトのOSC IP', - osc_port: 'デフォルトのOSC Port', + osc_ip: 'OSC IP', + osc_port: 'OSC Port', enabled: 'OSCで全文送信(ブロードキャスト中)', typing_indicator: 'タイピング時にタイピングインジケーターを有効', speech_indicator: 'Speech-to-text時のタイピングインジケーターを有効', @@ -186,7 +187,59 @@ export default { }, }, params: { - title: 'カスタムパラメータ', + title: 'パラメータトリガー', + description: 'カスタムパラメータトリガーを追加', + button: { + cancel: 'キャンセル', + confirm: 'OK', + add: '追加', + delete: '削除', + }, + profile: { + label: 'プロファイル選択', + dialog: { + title: { + add: 'プロファイルを追加', + edit: 'プロファイル名を変更', + }, + field_label: 'プロファイル名', + }, + delete_dialog: { + title: 'プロファイルを削除', + text: 'このプロファイルを削除してもよろしいですか?', + }, + }, + param: { + button: { + edit: '編集', + delete: '削除', + }, + dialog_title: { + add: 'パラメータトリガーを追加', + edit: 'パラメータトリガーを編集', + }, + address: 'パラメータアドレス', + empty: '無し (;ω;)', + trigger_phrases: 'トリガーフレーズ:', + trigger_phrases_add: 'トリガーフレーズを追加', + assign: { + phrases: '代入フレーズ:', + phrases_type: '型', + phrases_value: '値', + phrases_add: '代入フレーズを追加', + behavior: '挙動', + behavior_options: { + default: 'デフォルト', + pulse: 'パルス', + pulse_wait: '待機時間', + }, + }, + delete_dialog: { + title: 'パラメータを削除', + text: 'このパラメータを削除してもよろしいですか?', + }, + }, + empty: 'カスタムパラメータトリガーを追加するには+ボタンを使用してください!', }, }, }, diff --git a/src/stores/osc.ts b/src/stores/osc.ts index 2178ed9c..066f6542 100644 --- a/src/stores/osc.ts +++ b/src/stores/osc.ts @@ -1,5 +1,8 @@ import { defineStore } from 'pinia' +interface Profile { + [name: string]: Param[] +} interface Param { ip: string port: string @@ -14,7 +17,10 @@ interface Keyword { interface Assign { keyword: string type: string - set: boolean | number | string + set1: string + set2: string + activation: string + pulse_duration: number } export const useOSCStore = defineStore('osc', { @@ -32,7 +38,11 @@ export const useOSCStore = defineStore('osc', { sfx: true, // vrchat sfx indicator show_keyboard: false, - osc_params: [] as Param[], + osc_profiles: { + Default: [], + } as Profile, + + current_profile: 'Default', }), getters: {