From d01fa376bd8121d0d14a242fb073643a93830080 Mon Sep 17 00:00:00 2001
From: Paci <89483951+PaciStardust@users.noreply.github.com>
Date: Fri, 24 Mar 2023 22:16:28 +0100
Subject: [PATCH 1/8] Initial Test Commit
---
OscMultitool/Config.cs | 612 +-----------------
OscMultitool/Hoscy.csproj | 10 +-
OscMultitool/Models/ApiPresetModel.cs | 75 +++
OscMultitool/Models/ConfigModels.cs | 349 ++++++++++
OscMultitool/Models/CounterModel.cs | 46 ++
OscMultitool/Models/OscRoutingFilterModel.cs | 32 +
OscMultitool/Models/RegexModels.cs | 150 +++++
OscMultitool/Services/Api/ApiClient.cs | 7 +-
.../Services/OscControl/OscDataHandler.cs | 1 -
.../Speech/Recognizers/RecognizerBase.cs | 5 +-
OscMultitool/Services/Speech/TextProcessor.cs | 14 +-
OscMultitool/Ui/Pages/PageConfig.xaml.cs | 1 -
OscMultitool/Ui/Pages/PageInput.xaml.cs | 1 -
OscMultitool/Ui/Pages/PageOutput.xaml.cs | 3 +-
OscMultitool/Ui/Pages/PageSpeech.xaml | 2 -
OscMultitool/Ui/Pages/PageSpeech.xaml.cs | 2 +-
.../Ui/Windows/ModifyApiPresetsWindow.xaml.cs | 11 +-
.../Ui/Windows/ModifyCountersWindow.xaml.cs | 11 +-
.../Ui/Windows/ModifyFiltersWindow.xaml | 2 +-
.../Ui/Windows/ModifyFiltersWindow.xaml.cs | 11 +-
.../ModifyOscRoutingFiltersWindow.xaml.cs | 11 +-
.../Ui/Windows/ModifyReplacementsWindow.xaml | 11 +-
.../Windows/ModifyReplacementsWindow.xaml.cs | 17 +-
.../Ui/Windows/ModifyShortcutsWindow.xaml | 57 ++
.../Ui/Windows/ModifyShortcutsWindow.xaml.cs | 95 +++
OscMultitool/Utils.cs | 22 +
26 files changed, 893 insertions(+), 665 deletions(-)
create mode 100644 OscMultitool/Models/ApiPresetModel.cs
create mode 100644 OscMultitool/Models/ConfigModels.cs
create mode 100644 OscMultitool/Models/CounterModel.cs
create mode 100644 OscMultitool/Models/OscRoutingFilterModel.cs
create mode 100644 OscMultitool/Models/RegexModels.cs
create mode 100644 OscMultitool/Ui/Windows/ModifyShortcutsWindow.xaml
create mode 100644 OscMultitool/Ui/Windows/ModifyShortcutsWindow.xaml.cs
diff --git a/OscMultitool/Config.cs b/OscMultitool/Config.cs
index 36c94fe..a6e16e7 100644
--- a/OscMultitool/Config.cs
+++ b/OscMultitool/Config.cs
@@ -1,10 +1,9 @@
-using Newtonsoft.Json;
+using Hoscy.Models;
+using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
-using System.Net.Http.Headers;
using System.Text;
-using System.Text.RegularExpressions;
using System.Windows.Forms;
namespace Hoscy
@@ -88,23 +87,6 @@ private static void TryLoadFolderModels()
#endregion
#region Utility
- ///
- /// A combination of floor and ceil for comparables
- ///
- /// Type to compare
- /// Value to compare
- /// Minimum value
- /// Maximum value
- /// Value, if within bounds. Min, if value smaller than min. Max, if value larger than max. If max is smaller than min, min has priority
- internal static T MinMax(T value, T min, T max) where T : IComparable
- {
- if (value.CompareTo(min) < 0)
- return min;
- if (value.CompareTo(max) > 0)
- return max;
- return value;
- }
-
///
/// This exists as newtonsoft seems to have an issue with my way of creating a default config
///
@@ -213,594 +195,6 @@ private static void UpdateConfig(ConfigModel config)
config.ConfigVersion = 4;
}
- #endregion
-
- #region Models
- ///
- /// Model for storing all config data
- ///
- internal class ConfigModel
- {
- public int ConfigVersion { get; set; } = 0;
-
- public ConfigOscModel Osc { get; init; } = new();
- public ConfigSpeechModel Speech { get; init; } = new();
- public ConfigTextboxModel Textbox { get; init; } = new();
- public ConfigInputModel Input { get; init; } = new();
- public ConfigApiModel Api { get; init; } = new();
- public ConfigLoggerModel Debug { get; init; } = new();
- }
-
- ///
- /// Model for storing all OSC related data (Ports, IPs, Addresses, Filters)
- ///
- internal class ConfigOscModel
- {
- //Routing Related
- public string Ip { get; set; } = "127.0.0.1"; //Target IP for sending
- public int Port //Target port for sending
- {
- get => _port;
- set { _port = MinMax(value, -1, 65535); }
- }
- private int _port = 9000;
- public int PortListen //Port HOSCY listens on
- {
- get => _portListen;
- set { _portListen = MinMax(value, -1, 65535); }
- }
- private int _portListen = 9001;
- public List RoutingFilters { get; set; } = new(); //Routing
-
- //Addresses for OSC Control
- public string AddressManualMute { get; set; } = "/avatar/parameters/ToolMute";
- public string AddressManualSkipSpeech { get; set; } = "/avatar/parameters/ToolSkipSpeech";
- public string AddressManualSkipBox { get; set; } = "/avatar/parameters/ToolSkipBox";
- public string AddressEnableReplacements { get; set; } = "/avatar/parameters/ToolEnableReplacements";
- public string AddressEnableTextbox { get; set; } = "/avatar/parameters/ToolEnableBox";
- public string AddressEnableTts { get; set; } = "/avatar/parameters/ToolEnableTts";
- public string AddressEnableAutoMute { get; set; } = "/avatar/parameters/ToolEnableAutoMute";
- public string AddressListeningIndicator { get; set; } = "/avatar/parameters/MicListening";
- public string AddressGameMute { get; set; } = "/avatar/parameters/MuteSelf";
- public string AddressGameAfk { get; set; } = "/avatar/parameters/AFK";
- public string AddressGameTextbox { get; set; } = "/chatbox/input";
- public string AddressAddTextbox { get; set; } = "/hoscy/message";
- public string AddressAddTts { get; set; } = "/hoscy/tts";
- public string AddressAddNotification { get; set; } = "/hoscy/notification";
- public string AddressMediaPause { get; set; } = "/avatar/parameters/MediaPause";
- public string AddressMediaUnpause { get; set; } = "/avatar/parameters/MediaUnpause";
- public string AddressMediaRewind { get; set; } = "/avatar/parameters/MediaRewind";
- public string AddressMediaSkip { get; set; } = "/avatar/parameters/MediaSkip";
- public string AddressMediaInfo { get; set; } = "/avatar/parameters/MediaInfo";
- public string AddressMediaToggle { get; set; } = "/avatar/parameters/MediaToggle";
-
- //Counter Related
- public bool ShowCounterNotifications { get; set; } = false; //Display in Textbox
- public float CounterDisplayDuration //Duration (in seconds) that counters will be accounted for in display
- {
- get => _counterDisplayDuration;
- set { _counterDisplayDuration = MinMax(value, 0.01f, 30); }
- }
- private float _counterDisplayDuration = 10f;
-
- public float CounterDisplayCooldown //Duration (in seconds) that counters cannot be displayed
- {
- get => _counterDisplayCooldown;
- set { _counterDisplayCooldown = MinMax(value, 0, 300); }
- }
- private float _counterDisplayCooldown = 0f;
-
- public List Counters { get; set; } = new();
-
- //AFK Related
- public bool ShowAfkDuration { get; set; } = false; //Display in Textbox
- public float AfkDuration //Duration (in seconds) between initial AFK notifications
- {
- get => _afkDuration;
- set { _afkDuration = MinMax(value, 5, 300); }
- }
- private float _afkDuration = 15;
-
- public float AfkDoubleDuration //Amount of times the duration gets displayed before duration doubles
- {
- get => _afkDoubleDuration;
- set { _afkDoubleDuration = MinMax(value, 0, 60); }
- }
- private float _afkDoubleDuration = 12;
- }
-
- ///
- /// Model for storing all Speech related data (TTS, Models, Device Options)
- ///
- internal class ConfigSpeechModel
- {
- //Usage
- public bool UseTextbox { get; set; } = true; //Result will be sent through textbox
- public bool UseTts { get; set; } = false; //Result will be sent through TTS
- public string MicId { get; set; } = string.Empty; //Recording microphone
- public bool StartUnmuted { get; set; } = true; //Start recognition unmuted
- public bool PlayMuteSound { get; set; } = false; //Play mute and unmute sounds
- public bool MuteOnVrcMute { get; set; } = true; //Automatically mute when muted in VRC
- public string ModelName { get; set; } = string.Empty; //Name of used model
-
- //TTS
- public string TtsId { get; set; } = string.Empty; //Identifier for Microsoft TTS
- public string SpeakerId { get; set; } = string.Empty; //Speaker for TTS out
- public float SpeakerVolume //TTS volume
- {
- get => _speakerVolume;
- set { _speakerVolume = MinMax(value, 0, 1); }
- }
- private float _speakerVolume = 0.5f;
- public int MaxLenTtsString //Max length of strings that get TTS
- {
- get => _maxLenTtsString;
- set { _maxLenTtsString = MinMax(value, 1, 99999); }
- }
- private int _maxLenTtsString = 500;
- public bool SkipLongerMessages { get; set; } = true; //Skip longer messages instead of cutting off
-
- //Vosk
- public Dictionary VoskModels { get; set; } = new(); //Model identifiers and filepaths
- public string VoskModelCurrent { get; set; } = string.Empty; //Identifier for current model
- public int VoskTimeout //Time (in milliseconds) allowed to pass where no new words are identified before manually cutting off
- {
- get => _voskTimeout;
- set { _voskTimeout = MinMax(value, 500, 30000); }
- }
- private int _voskTimeout = 2500;
-
- //Windows
- public string WinModelId { get; set; } = string.Empty; //Identifier for Microsoft Recognizer
-
- //Replacement
- public List NoiseFilter { get; set; } = new(); //List of words deemed noise
- public bool IgnoreCaps { get; set; } = true; //Ignoring caps when testing for replacements
- public bool RemoveFullStop { get; set; } = true; //Removing the full stop at the end of a sentence if available
- public bool UseReplacements { get; set; } = true; //Are replacements (and shortcuts) even used?
- public List Shortcuts { get; set; } = new();
- public List Replacements { get; set; } = new();
- }
-
- ///
- /// Model for storing all Textbox related data (Timeouts, MaxLength)
- ///
- internal class ConfigTextboxModel
- {
- //Timeout, Maxlen
- public int MaxLength //Max length of string displayed before cutoff
- {
- get => _maxLength;
- set { _maxLength = MinMax(value, 50, 130); }
- }
- private int _maxLength = 130;
- public int TimeoutMultiplier //Add x milliseconds to timeout per 20 characters
- {
- get => _timeoutMultiplier;
- set { _timeoutMultiplier = MinMax(value, 250, 10000); }
- }
- private int _timeoutMultiplier = 1250;
-
- public int MinimumTimeout //Minimum timeout (in milliseconds) that a message stays in the chatbox
- {
- get => _minimumTimeout;
- set { _minimumTimeout = MinMax(value, 1250, 30000); }
- }
- private int _minimumTimeout = 3000;
-
- public int DefaultTimeout //Default timeout (in milliseconds) that a message stays in the chatbox
- {
- get => _defaultTimeout;
- set { _defaultTimeout = MinMax(value, 1250, 30000); }
- }
- private int _defaultTimeout = 5000;
- public bool DynamicTimeout { get; set; } = true; //Enables the dynamic timeout
-
- //Visual
- public bool AutomaticClearNotification { get; set; } = true; //Automatic clearing after notification timeout
- public bool AutomaticClearMessage { get; set; } = false; //Automatic clearing after message timeout
- public bool UseIndicatorWithoutBox { get; set; } = false; //"Typing" indicator when box is disabled
-
- public string NotificationIndicatorLeft //Text to the left of a notification
- {
- get => _notificationIndicatorLeft;
- set
- {
- _notificationIndicatorLeft = value.Length < 4 ? value : value[..3];
- _notificationIndicatorLength = CalcNotificationIndicatorLength();
- }
- }
- private string _notificationIndicatorLeft = "〈";
-
- public string NotificationIndicatorRight //Text to the right of a notification
- {
- get => _notificationIndicatorRight;
- set
- {
- _notificationIndicatorRight = value.Length < 4 ? value : value[..3];
- _notificationIndicatorLength = CalcNotificationIndicatorLength();
- }
- }
- private string _notificationIndicatorRight = "〉";
- private int _notificationIndicatorLength = 2;
-
- //Sound
- public bool SoundOnMessage { get; set; } = true; //Play sound on textbox message
- public bool SoundOnNotification { get; set; } = false; //Play sound on textbox notification
-
- //Notification handling
- public bool UseNotificationPriority { get; set; } = true; //Only allows overwriting notification current not of lower priority
- public bool UseNotificationSkip { get; set; } = true; //Skip notifications if a message is available
-
- //Media
- public bool MediaShowStatus { get; set; } = false; //Display media information in textbox
- public bool MediaAddAlbum { get; set; } = false; //Also add album to media information
-
- public string MediaPlayingVerb //xyz "songname" by "artist" on "album"
- {
- get => _mediaPlayingVerb;
- set { _mediaPlayingVerb = value.Length > 0 ? value : "Playing"; }
- }
- private string _mediaPlayingVerb = "Playing";
-
- public string MediaArtistVerb //Playing "songname" xyz "artist" on "album"
- {
- get => _mediaArtistVerb;
- set { _mediaArtistVerb = value.Length > 0 ? value : "by"; }
- }
- private string _mediaArtistVerb = "by";
-
- public string MediaAlbumVerb //Playing "songname" by "artist" xyz "album"
- {
- get => _mediaAlbumVerb;
- set { _mediaAlbumVerb = value.Length > 0 ? value : "on"; }
- }
- private string _mediaAlbumVerb = "on";
-
- public string MediaExtra { get; set; } = string.Empty;
-
- public List MediaFilters { get; set; } = new(); //Phrases filtered from media
-
- private int CalcNotificationIndicatorLength()
- => _notificationIndicatorRight.Length + _notificationIndicatorLeft.Length;
-
- internal int NotificationIndicatorLength() => _notificationIndicatorLength;
- }
-
- ///
- /// Model for all API related data
- ///
- internal class ConfigApiModel
- {
- //General
- public List Presets { get; set; } = new();
-
- //Recognition
- public string RecognitionPreset { get; set; } = string.Empty; //API preset for recognition
- public int RecognitionMaxRecordingTime //Max time (in seconds) that can be recorded at once
- {
- get => _recognitionMaxRecordingTime;
- set { _recognitionMaxRecordingTime = MinMax(value, 1, 300); }
- }
- private int _recognitionMaxRecordingTime = 30;
-
- //Translation
- public string TranslationPreset { get; set; } = string.Empty; //API preset for translation
- public bool TranslationSkipLongerMessages { get; set; } = true; //Skipping messages that are too long instead of partial translation
- public int TranslationMaxTextLength //Maximum length of translatable text
- {
- get => _translationMaxTextLength;
- set { _translationMaxTextLength = MinMax(value, 1, 60000); }
- }
- private int _translationMaxTextLength = 2000;
-
- //Azure
- public string AzureRegion { get; set; } = string.Empty; //Region for azure
- public string AzureKey { get; set; } = string.Empty; //Cognitive services key
- public string AzureSpeechLanguage { get; set; } = string.Empty; //Language of TTS
- public string AzureCustomEndpointSpeech { get; set; } = string.Empty; //Custom speech endpoint
- public string AzureCustomEndpointRecognition { get; set; } = string.Empty; //Custom recognition endpoint
- public string AzureVoiceCurrent { get; set; } = string.Empty; //Current azure voice
- public List AzurePhrases { get; set; } = new(); //Phrases to set for improved recognition
- public List AzureRecognitionLanguages { get; set; } = new(); //All voices for speech recognition
- public Dictionary AzureVoices { get; set; } = new(); //All voices for TTS
-
- //Usage
- public bool TranslateTts { get; set; } = false; //Automatically translate TTS
- public bool TranslateTextbox { get; set; } = false; //Automatically translate textbox
- public bool TranslationAllowExternal { get; set; } = false; //Translate external
- public bool AddOriginalAfterTranslate { get; set; } = false; //Add original version after translation
- public bool UseAzureTts { get; set; } = false; //Use azure TTS instead of Microsoft
-
- internal int GetIndex(string name)
- {
- for (int i = 0; i < Presets.Count; i++)
- {
- if (Presets[i].Name == name)
- return i;
- }
- return -1;
- }
-
- internal ApiPresetModel? GetPreset(string name)
- {
- var presetIndex = GetIndex(name);
-
- if (presetIndex == -1 || presetIndex >= Presets.Count)
- return null;
-
- return Presets[presetIndex];
- }
- }
-
- ///
- /// Model for all Logging related data, this can currently only be changed in the file
- ///
- internal class ConfigLoggerModel
- {
- public bool OpenLogWindow { get; set; } = false; //Open log window on startup
- public bool CheckUpdates { get; set; } = true; //Automatically check for updates on startup
- public bool Error { get; set; } = true;
- public bool Warning { get; set; } = true;
- public bool Info { get; set; } = true;
- public bool PrioInfo { get; set; } = true;
- public bool Log { get; set; } = true;
- public bool Debug { get; set; } = false;
- public List LogFilters { get; set; } = new(); //Phrases filtered from logs
- }
-
- ///
- /// Model for all Input related data (Presets, Sending Options)
- ///
- internal class ConfigInputModel
- {
- public bool UseTts { get; set; } = false; //Convert input to TTS
- public bool UseTextbox { get; set; } = true; //Convert input to textbox
- public bool TriggerCommands { get; set; } = true; //Input triggers commands
- public bool TriggerReplace { get; set; } = true; //Input triggers replacements
- public bool IgnoreCaps { get;set; } = true; //Ignore caps for commands and replacements
- public bool AllowTranslation { get; set; } = true; //Translate input
- public Dictionary Presets { get; set; } = new(); //Presets for quick access
- }
- #endregion
-
- #region Extra Models
- ///
- /// Model for storing Routing Filter data
- ///
- internal class OscRoutingFilterModel
- {
- public string Name
- {
- get => _name;
- set { _name = string.IsNullOrWhiteSpace(value) ? "Unnamed Filter" : value; }
- }
- private string _name = "Unnamed Filter";
- public int Port
- {
- get => _port;
- set { _port = MinMax(value, -1, 65535); }
- }
- private int _port = -1;
- public string Ip { get; set; } = "127.0.0.1";
- public List Filters { get; set; } = new();
-
- private bool _isValid = true;
- public override string ToString()
- => $"{(_isValid ? "" : "[x]")}{Name} => {Ip}:{Port}";
-
- ///
- /// Sets validity to be displayed in filter window
- ///
- internal void SetValidity(bool state)
- => _isValid = state;
- }
-
- internal class ReplacementModel
- {
- public string Text
- {
- get => _text;
- set {
- _text = string.IsNullOrWhiteSpace(value) ? "New Value" : value;
- _regexPattern = $@"(?<= |\b){Regex.Escape(_text)}(?=$| |\b)";
- _lowercaseText = _text.ToLower();
- }
- }
- private string _text = "New Value";
- private string _regexPattern = $@"(?<= |\b)New\ Value(?= |\b)"; //Pattern for replacing text when used as replacement
- private string _lowercaseText = "new value"; //Lowercase version when checking for shortcuts
-
- public string Replacement { get; set; } = "Example";
- public bool Enabled { get; set; } = true;
-
- public ReplacementModel(string text, string replacement, bool enabled = true)
- {
- Text = text;
- Replacement = replacement;
- Enabled = enabled;
- }
- public ReplacementModel() { }
-
- internal string RegexPattern() => _regexPattern;
- internal string LowercaseText() => _lowercaseText;
-
- public override string ToString()
- => $"{(Enabled ? "" : "[x] ")}{Text} => {Replacement}";
- }
-
- internal class ApiPresetModel
- {
- public string Name
- {
- get => _name;
- set { _name = string.IsNullOrWhiteSpace(value) ? "Unnamed Preset" : value; }
- }
- private string _name = "Unnamed Preset";
- public string SentData { get; set; } = @"{""data"" : ""[T]""}";
- public Dictionary HeaderValues { get; set; } = new();
- public string ContentType { get; set; } = "application/json";
- public string ResultField { get; set; } = "result";
-
- public string TargetUrl
- {
- get => _targetUrl;
- set
- {
- _targetUrl = value;
- _fullTargetUrl = value.StartsWith("h") ? value : "https://" + value;
- }
- }
- private string _targetUrl = string.Empty;
- private string _fullTargetUrl = string.Empty;
-
- public string Authorization
- {
- get => _authorization;
- set
- {
- _authorization = string.Empty;
- _authenticationHeader = null;
-
- if (string.IsNullOrWhiteSpace(value))
- return;
-
- try {
- _authorization = value;
- var authSplit = value.Split(' ');
-
- if (authSplit.Length == 1)
- _authenticationHeader = new(authSplit[0]);
- else if (authSplit.Length > 1)
- _authenticationHeader = new(authSplit[0], string.Join(' ', authSplit[1..]));
- }
- catch { }
- }
- }
- private string _authorization = string.Empty;
- private AuthenticationHeaderValue? _authenticationHeader = null;
-
- public int ConnectionTimeout
- {
- get => _connectionTimeout;
- set { _connectionTimeout = MinMax(value, 25, 60000); }
- }
- private int _connectionTimeout = 3000;
-
- internal string FullTargetUrl() => _fullTargetUrl;
- internal AuthenticationHeaderValue? AuthenticationHeader() => _authenticationHeader;
-
- internal bool IsValid()
- => !string.IsNullOrWhiteSpace(TargetUrl)
- && !string.IsNullOrWhiteSpace(SentData)
- && !string.IsNullOrWhiteSpace(ResultField)
- && !string.IsNullOrWhiteSpace(ContentType);
- }
-
- internal class CounterModel
- {
- public string Name
- {
- get => _name;
- set { _name = string.IsNullOrWhiteSpace(value) ? "Unnamed Counter" : value; }
- }
- private string _name = "Unnamed Counter";
- public uint Count { get; set; } = 0;
- public DateTime LastUsed { get; set; } = DateTime.MinValue;
- public bool Enabled { get; set; } = true;
- public float Cooldown
- {
- get => _cooldown;
- set { _cooldown = MinMax(value, 0, 3600); }
- }
- private float _cooldown = 0;
-
- public string Parameter
- {
- get => _parameter;
- set
- {
- _parameter = value;
- _fullParameter = value.StartsWith("/") ? value : "/avatar/parameters/" + value;
- }
- }
- private string _parameter = "Parameter";
- private string _fullParameter = "/avatar/parameters/Parameter";
-
- internal void Increase()
- {
- Count++;
- LastUsed = DateTime.Now;
- }
-
- internal string FullParameter() => _fullParameter;
-
- public override string ToString()
- => $"{(Enabled ? "" : "[x] ")}{Name}: {Count:N0}";
- }
-
- internal class FilterModel
- {
- public string Name
- {
- get => _name;
- set { _name = string.IsNullOrWhiteSpace(value) ? "Unnamed Filter" : value; }
- }
- private string _name = "Unnamed Filter";
- public string FilterString
- {
- get => _filterString;
- set
- {
- _filterString = string.IsNullOrWhiteSpace(value) ? "Filter Text" : value;
- UpdateRegex();
- }
- }
- private string _filterString = "Filter Text";
- public bool Enabled { get; set; } = true;
- public bool IgnoreCase
- {
- get => _ignoreCase;
- set
- {
- _ignoreCase = value;
- UpdateRegex();
- }
- }
- private bool _ignoreCase = false;
- public bool UseRegex
- {
- get => _useRegex;
- set
- {
- _useRegex = value;
- UpdateRegex();
- }
- }
- private bool _useRegex = false;
- private Regex? _filterRegex;
-
- public FilterModel(string name, string filterString)
- {
- Name = name;
- FilterString = filterString;
- }
- public FilterModel() { }
-
- private void UpdateRegex()
- => _filterRegex = _useRegex ? new(_filterString, _ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None | RegexOptions.CultureInvariant) : null;
-
- internal bool Matches(string compare)
- {
- if (_filterRegex == null)
- return compare.Contains(_filterString, _ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
-
- return _filterRegex.IsMatch(compare);
- }
-
- public override string ToString()
- => $"{(Enabled ? "" : "[x] ")}{_name} ={(_useRegex ? "R" : string.Empty)}{(_ignoreCase ? "C" : string.Empty)}> {_filterString}";
- }
- #endregion
+ #endregion
}
}
diff --git a/OscMultitool/Hoscy.csproj b/OscMultitool/Hoscy.csproj
index 410efc7..abeb04f 100644
--- a/OscMultitool/Hoscy.csproj
+++ b/OscMultitool/Hoscy.csproj
@@ -7,8 +7,8 @@
true
Resources\hoscy_circle.ico
AnyCPU;x64
- 0.6.8
- 0.6.8
+ 0.7
+ 0.7
https://github.com/PaciStardust/HOSCY
https://github.com/PaciStardust/HOSCY
README.md
@@ -78,6 +78,9 @@
Code
+
+ Code
+
Code
@@ -117,6 +120,9 @@
$(DefaultXamlRuntime)
Designer
+
+ $(DefaultXamlRuntime)
+
$(DefaultXamlRuntime)
Designer
diff --git a/OscMultitool/Models/ApiPresetModel.cs b/OscMultitool/Models/ApiPresetModel.cs
new file mode 100644
index 0000000..0710571
--- /dev/null
+++ b/OscMultitool/Models/ApiPresetModel.cs
@@ -0,0 +1,75 @@
+using System.Collections.Generic;
+using System.Net.Http.Headers;
+
+namespace Hoscy.Models
+{
+ internal class ApiPresetModel
+ {
+ public string Name
+ {
+ get => _name;
+ set => _name = string.IsNullOrWhiteSpace(value) ? "Unnamed Preset" : value;
+ }
+ private string _name = "Unnamed Preset";
+
+ public string SentData { get; set; } = @"{""data"" : ""[T]""}";
+ public Dictionary HeaderValues { get; set; } = new();
+ public string ContentType { get; set; } = "application/json";
+ public string ResultField { get; set; } = "result";
+
+ public string TargetUrl
+ {
+ get => _targetUrl;
+ set
+ {
+ _targetUrl = value;
+ _fullTargetUrl = value.StartsWith("h") ? value : "https://" + value;
+ }
+ }
+ private string _targetUrl = string.Empty;
+ private string _fullTargetUrl = string.Empty;
+
+ public string Authorization
+ {
+ get => _authorization;
+ set
+ {
+ _authorization = string.Empty;
+ _authenticationHeader = null;
+
+ if (string.IsNullOrWhiteSpace(value))
+ return;
+
+ try
+ {
+ _authorization = value;
+ var authSplit = value.Split(' ');
+
+ if (authSplit.Length == 1)
+ _authenticationHeader = new(authSplit[0]);
+ else if (authSplit.Length > 1)
+ _authenticationHeader = new(authSplit[0], string.Join(' ', authSplit[1..]));
+ }
+ catch { }
+ }
+ }
+ private string _authorization = string.Empty;
+ private AuthenticationHeaderValue? _authenticationHeader = null;
+
+ public int ConnectionTimeout
+ {
+ get => _connectionTimeout;
+ set => _connectionTimeout = Utils.MinMax(value, 25, 60000);
+ }
+ private int _connectionTimeout = 3000;
+
+ internal string FullTargetUrl() => _fullTargetUrl;
+ internal AuthenticationHeaderValue? AuthenticationHeader() => _authenticationHeader;
+
+ internal bool IsValid()
+ => !string.IsNullOrWhiteSpace(TargetUrl)
+ && !string.IsNullOrWhiteSpace(SentData)
+ && !string.IsNullOrWhiteSpace(ResultField)
+ && !string.IsNullOrWhiteSpace(ContentType);
+ }
+}
diff --git a/OscMultitool/Models/ConfigModels.cs b/OscMultitool/Models/ConfigModels.cs
new file mode 100644
index 0000000..4cc8079
--- /dev/null
+++ b/OscMultitool/Models/ConfigModels.cs
@@ -0,0 +1,349 @@
+using System.Collections.Generic;
+
+namespace Hoscy.Models
+{
+ ///
+ /// Model for storing all config data
+ ///
+ internal class ConfigModel
+ {
+ public int ConfigVersion { get; set; } = 0;
+
+ public ConfigOscModel Osc { get; init; } = new();
+ public ConfigSpeechModel Speech { get; init; } = new();
+ public ConfigTextboxModel Textbox { get; init; } = new();
+ public ConfigInputModel Input { get; init; } = new();
+ public ConfigApiModel Api { get; init; } = new();
+ public ConfigLoggerModel Debug { get; init; } = new();
+ }
+
+ ///
+ /// Model for all API related data
+ ///
+ internal class ConfigApiModel
+ {
+ //General
+ public List Presets { get; set; } = new();
+
+ //Recognition
+ public string RecognitionPreset { get; set; } = string.Empty; //API preset for recognition
+ public int RecognitionMaxRecordingTime //Max time (in seconds) that can be recorded at once
+ {
+ get => _recognitionMaxRecordingTime;
+ set => _recognitionMaxRecordingTime = Utils.MinMax(value, 1, 300);
+ }
+ private int _recognitionMaxRecordingTime = 30;
+
+ //Translation
+ public string TranslationPreset { get; set; } = string.Empty; //API preset for translation
+ public bool TranslationSkipLongerMessages { get; set; } = true; //Skipping messages that are too long instead of partial translation
+ public int TranslationMaxTextLength //Maximum length of translatable text
+ {
+ get => _translationMaxTextLength;
+ set => _translationMaxTextLength = Utils.MinMax(value, 1, 60000);
+ }
+ private int _translationMaxTextLength = 2000;
+
+ //Azure
+ public string AzureRegion { get; set; } = string.Empty; //Region for azure
+ public string AzureKey { get; set; } = string.Empty; //Cognitive services key
+ public string AzureSpeechLanguage { get; set; } = string.Empty; //Language of TTS
+ public string AzureCustomEndpointSpeech { get; set; } = string.Empty; //Custom speech endpoint
+ public string AzureCustomEndpointRecognition { get; set; } = string.Empty; //Custom recognition endpoint
+ public string AzureVoiceCurrent { get; set; } = string.Empty; //Current azure voice
+ public List AzurePhrases { get; set; } = new(); //Phrases to set for improved recognition
+ public List AzureRecognitionLanguages { get; set; } = new(); //All voices for speech recognition
+ public Dictionary AzureVoices { get; set; } = new(); //All voices for TTS
+
+ //Usage
+ public bool TranslateTts { get; set; } = false; //Automatically translate TTS
+ public bool TranslateTextbox { get; set; } = false; //Automatically translate textbox
+ public bool TranslationAllowExternal { get; set; } = false; //Translate external
+ public bool AddOriginalAfterTranslate { get; set; } = false; //Add original version after translation
+ public bool UseAzureTts { get; set; } = false; //Use azure TTS instead of Microsoft
+
+ internal int GetIndex(string name)
+ {
+ for (int i = 0; i < Presets.Count; i++)
+ {
+ if (Presets[i].Name == name)
+ return i;
+ }
+ return -1;
+ }
+
+ internal ApiPresetModel? GetPreset(string name)
+ {
+ var presetIndex = GetIndex(name);
+
+ if (presetIndex == -1 || presetIndex >= Presets.Count)
+ return null;
+
+ return Presets[presetIndex];
+ }
+ }
+
+ ///
+ /// Model for all Input related data (Presets, Sending Options)
+ ///
+ internal class ConfigInputModel
+ {
+ public bool UseTts { get; set; } = false; //Convert input to TTS
+ public bool UseTextbox { get; set; } = true; //Convert input to textbox
+ public bool TriggerCommands { get; set; } = true; //Input triggers commands
+ public bool TriggerReplace { get; set; } = true; //Input triggers replacements
+ public bool AllowTranslation { get; set; } = true; //Translate input
+ public Dictionary Presets { get; set; } = new(); //Presets for quick access
+ }
+
+ ///
+ /// Model for all Logging related data, this can currently only be changed in the file
+ ///
+ internal class ConfigLoggerModel
+ {
+ public bool OpenLogWindow { get; set; } = false; //Open log window on startup
+ public bool CheckUpdates { get; set; } = true; //Automatically check for updates on startup
+ public bool Error { get; set; } = true;
+ public bool Warning { get; set; } = true;
+ public bool Info { get; set; } = true;
+ public bool PrioInfo { get; set; } = true;
+ public bool Log { get; set; } = true;
+ public bool Debug { get; set; } = false;
+ public List LogFilters { get; set; } = new(); //Phrases filtered from logs
+ }
+
+ ///
+ /// Model for storing all OSC related data (Ports, IPs, Addresses, Filters)
+ ///
+ internal class ConfigOscModel
+ {
+ //Routing Related
+ public string Ip { get; set; } = "127.0.0.1"; //Target IP for sending
+ public int Port //Target port for sending
+ {
+ get => _port;
+ set => _port = Utils.MinMax(value, -1, 65535);
+ }
+ private int _port = 9000;
+ public int PortListen //Port HOSCY listens on
+ {
+ get => _portListen;
+ set => _portListen = Utils.MinMax(value, -1, 65535);
+ }
+ private int _portListen = 9001;
+ public List RoutingFilters { get; set; } = new(); //Routing
+
+ //Addresses for OSC Control
+ public string AddressManualMute { get; set; } = "/avatar/parameters/ToolMute";
+ public string AddressManualSkipSpeech { get; set; } = "/avatar/parameters/ToolSkipSpeech";
+ public string AddressManualSkipBox { get; set; } = "/avatar/parameters/ToolSkipBox";
+ public string AddressEnableReplacements { get; set; } = "/avatar/parameters/ToolEnableReplacements";
+ public string AddressEnableTextbox { get; set; } = "/avatar/parameters/ToolEnableBox";
+ public string AddressEnableTts { get; set; } = "/avatar/parameters/ToolEnableTts";
+ public string AddressEnableAutoMute { get; set; } = "/avatar/parameters/ToolEnableAutoMute";
+ public string AddressListeningIndicator { get; set; } = "/avatar/parameters/MicListening";
+ public string AddressGameMute { get; set; } = "/avatar/parameters/MuteSelf";
+ public string AddressGameAfk { get; set; } = "/avatar/parameters/AFK";
+ public string AddressGameTextbox { get; set; } = "/chatbox/input";
+ public string AddressAddTextbox { get; set; } = "/hoscy/message";
+ public string AddressAddTts { get; set; } = "/hoscy/tts";
+ public string AddressAddNotification { get; set; } = "/hoscy/notification";
+ public string AddressMediaPause { get; set; } = "/avatar/parameters/MediaPause";
+ public string AddressMediaUnpause { get; set; } = "/avatar/parameters/MediaUnpause";
+ public string AddressMediaRewind { get; set; } = "/avatar/parameters/MediaRewind";
+ public string AddressMediaSkip { get; set; } = "/avatar/parameters/MediaSkip";
+ public string AddressMediaInfo { get; set; } = "/avatar/parameters/MediaInfo";
+ public string AddressMediaToggle { get; set; } = "/avatar/parameters/MediaToggle";
+
+ //Counter Related
+ public bool ShowCounterNotifications { get; set; } = false; //Display in Textbox
+ public float CounterDisplayDuration //Duration (in seconds) that counters will be accounted for in display
+ {
+ get => _counterDisplayDuration;
+ set => _counterDisplayDuration = Utils.MinMax(value, 0.01f, 30);
+ }
+ private float _counterDisplayDuration = 10f;
+
+ public float CounterDisplayCooldown //Duration (in seconds) that counters cannot be displayed
+ {
+ get => _counterDisplayCooldown;
+ set => _counterDisplayCooldown = Utils.MinMax(value, 0, 300);
+ }
+ private float _counterDisplayCooldown = 0f;
+
+ public List Counters { get; set; } = new();
+
+ //AFK Related
+ public bool ShowAfkDuration { get; set; } = false; //Display in Textbox
+ public float AfkDuration //Duration (in seconds) between initial AFK notifications
+ {
+ get => _afkDuration;
+ set => _afkDuration = Utils.MinMax(value, 5, 300);
+ }
+ private float _afkDuration = 15;
+
+ public float AfkDoubleDuration //Amount of times the duration gets displayed before duration doubles
+ {
+ get => _afkDoubleDuration;
+ set => _afkDoubleDuration = Utils.MinMax(value, 0, 60);
+ }
+ private float _afkDoubleDuration = 12;
+ }
+
+ ///
+ /// Model for storing all Speech related data (TTS, Models, Device Options)
+ ///
+ internal class ConfigSpeechModel
+ {
+ //Usage
+ public bool UseTextbox { get; set; } = true; //Result will be sent through textbox
+ public bool UseTts { get; set; } = false; //Result will be sent through TTS
+ public string MicId { get; set; } = string.Empty; //Recording microphone
+ public bool StartUnmuted { get; set; } = true; //Start recognition unmuted
+ public bool PlayMuteSound { get; set; } = false; //Play mute and unmute sounds
+ public bool MuteOnVrcMute { get; set; } = true; //Automatically mute when muted in VRC
+ public string ModelName { get; set; } = string.Empty; //Name of used model
+
+ //TTS
+ public string TtsId { get; set; } = string.Empty; //Identifier for Microsoft TTS
+ public string SpeakerId { get; set; } = string.Empty; //Speaker for TTS out
+ public float SpeakerVolume //TTS volume
+ {
+ get => _speakerVolume;
+ set => _speakerVolume = Utils.MinMax(value, 0, 1);
+ }
+ private float _speakerVolume = 0.5f;
+ public int MaxLenTtsString //Max length of strings that get TTS
+ {
+ get => _maxLenTtsString;
+ set => _maxLenTtsString = Utils.MinMax(value, 1, 99999);
+ }
+ private int _maxLenTtsString = 500;
+ public bool SkipLongerMessages { get; set; } = true; //Skip longer messages instead of cutting off
+
+ //Vosk
+ public Dictionary VoskModels { get; set; } = new(); //Model identifiers and filepaths
+ public string VoskModelCurrent { get; set; } = string.Empty; //Identifier for current model
+ public int VoskTimeout //Time (in milliseconds) allowed to pass where no new words are identified before manually cutting off
+ {
+ get => _voskTimeout;
+ set => _voskTimeout = Utils.MinMax(value, 500, 30000);
+ }
+ private int _voskTimeout = 2500;
+
+ //Windows
+ public string WinModelId { get; set; } = string.Empty; //Identifier for Microsoft Recognizer
+
+ //Replacement
+ public List NoiseFilter { get; set; } = new(); //List of words deemed noise
+ public bool RemoveFullStop { get; set; } = true; //todo: make default option
+ public bool UseReplacements { get; set; } = true; //Are replacements (and shortcuts) even used?
+ public List Shortcuts { get; set; } = new();
+ public List Replacements { get; set; } = new();
+ }
+
+ ///
+ /// Model for storing all Textbox related data (Timeouts, MaxLength)
+ ///
+ internal class ConfigTextboxModel
+ {
+ //Timeout, Maxlen
+ public int MaxLength //Max length of string displayed before cutoff
+ {
+ get => _maxLength;
+ set => _maxLength = Utils.MinMax(value, 50, 130);
+ }
+ private int _maxLength = 130;
+ public int TimeoutMultiplier //Add x milliseconds to timeout per 20 characters
+ {
+ get => _timeoutMultiplier;
+ set => _timeoutMultiplier = Utils.MinMax(value, 250, 10000);
+ }
+ private int _timeoutMultiplier = 1250;
+
+ public int MinimumTimeout //Minimum timeout (in milliseconds) that a message stays in the chatbox
+ {
+ get => _minimumTimeout;
+ set => _minimumTimeout = Utils.MinMax(value, 1250, 30000);
+ }
+ private int _minimumTimeout = 3000;
+
+ public int DefaultTimeout //Default timeout (in milliseconds) that a message stays in the chatbox
+ {
+ get => _defaultTimeout;
+ set => _defaultTimeout = Utils.MinMax(value, 1250, 30000);
+ }
+ private int _defaultTimeout = 5000;
+ public bool DynamicTimeout { get; set; } = true; //Enables the dynamic timeout
+
+ //Visual
+ public bool AutomaticClearNotification { get; set; } = true; //Automatic clearing after notification timeout
+ public bool AutomaticClearMessage { get; set; } = false; //Automatic clearing after message timeout
+ public bool UseIndicatorWithoutBox { get; set; } = false; //"Typing" indicator when box is disabled
+
+ public string NotificationIndicatorLeft //Text to the left of a notification
+ {
+ get => _notificationIndicatorLeft;
+ set
+ {
+ _notificationIndicatorLeft = value.Length < 4 ? value : value[..3];
+ _notificationIndicatorLength = CalcNotificationIndicatorLength();
+ }
+ }
+ private string _notificationIndicatorLeft = "〈";
+
+ public string NotificationIndicatorRight //Text to the right of a notification
+ {
+ get => _notificationIndicatorRight;
+ set
+ {
+ _notificationIndicatorRight = value.Length < 4 ? value : value[..3];
+ _notificationIndicatorLength = CalcNotificationIndicatorLength();
+ }
+ }
+ private string _notificationIndicatorRight = "〉";
+ private int _notificationIndicatorLength = 2;
+
+ //Sound
+ public bool SoundOnMessage { get; set; } = true; //Play sound on textbox message
+ public bool SoundOnNotification { get; set; } = false; //Play sound on textbox notification
+
+ //Notification handling
+ public bool UseNotificationPriority { get; set; } = true; //Only allows overwriting notification current not of lower priority
+ public bool UseNotificationSkip { get; set; } = true; //Skip notifications if a message is available
+
+ //Media
+ public bool MediaShowStatus { get; set; } = false; //Display media information in textbox
+ public bool MediaAddAlbum { get; set; } = false; //Also add album to media information
+
+ public string MediaPlayingVerb //xyz "songname" by "artist" on "album"
+ {
+ get => _mediaPlayingVerb;
+ set => _mediaPlayingVerb = value.Length > 0 ? value : "Playing";
+ }
+ private string _mediaPlayingVerb = "Playing";
+
+ public string MediaArtistVerb //Playing "songname" xyz "artist" on "album"
+ {
+ get => _mediaArtistVerb;
+ set => _mediaArtistVerb = value.Length > 0 ? value : "by";
+ }
+ private string _mediaArtistVerb = "by";
+
+ public string MediaAlbumVerb //Playing "songname" by "artist" xyz "album"
+ {
+ get => _mediaAlbumVerb;
+ set => _mediaAlbumVerb = value.Length > 0 ? value : "on";
+ }
+ private string _mediaAlbumVerb = "on";
+
+ public string MediaExtra { get; set; } = string.Empty;
+
+ public List MediaFilters { get; set; } = new(); //Phrases filtered from media
+
+ private int CalcNotificationIndicatorLength()
+ => _notificationIndicatorRight.Length + _notificationIndicatorLeft.Length;
+
+ internal int NotificationIndicatorLength() => _notificationIndicatorLength;
+ }
+}
diff --git a/OscMultitool/Models/CounterModel.cs b/OscMultitool/Models/CounterModel.cs
new file mode 100644
index 0000000..cc0d61b
--- /dev/null
+++ b/OscMultitool/Models/CounterModel.cs
@@ -0,0 +1,46 @@
+using System;
+
+namespace Hoscy.Models
+{
+ internal class CounterModel
+ {
+ public string Name
+ {
+ get => _name;
+ set => _name = string.IsNullOrWhiteSpace(value) ? "Unnamed Counter" : value;
+ }
+ private string _name = "Unnamed Counter";
+ public uint Count { get; set; } = 0;
+ public DateTime LastUsed { get; set; } = DateTime.MinValue;
+ public bool Enabled { get; set; } = true;
+ public float Cooldown
+ {
+ get => _cooldown;
+ set => _cooldown = Utils.MinMax(value, 0, 3600);
+ }
+ private float _cooldown = 0;
+
+ public string Parameter
+ {
+ get => _parameter;
+ set
+ {
+ _parameter = value;
+ _fullParameter = value.StartsWith("/") ? value : "/avatar/parameters/" + value;
+ }
+ }
+ private string _parameter = "Parameter";
+ private string _fullParameter = "/avatar/parameters/Parameter";
+
+ internal void Increase()
+ {
+ Count++;
+ LastUsed = DateTime.Now;
+ }
+
+ internal string FullParameter() => _fullParameter;
+
+ public override string ToString()
+ => $"{(Enabled ? "" : "[x] ")}{Name}: {Count:N0}";
+ }
+}
diff --git a/OscMultitool/Models/OscRoutingFilterModel.cs b/OscMultitool/Models/OscRoutingFilterModel.cs
new file mode 100644
index 0000000..7e70f0a
--- /dev/null
+++ b/OscMultitool/Models/OscRoutingFilterModel.cs
@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+
+namespace Hoscy.Models
+{
+ internal class OscRoutingFilterModel
+ {
+ public string Name
+ {
+ get => _name;
+ set => _name = string.IsNullOrWhiteSpace(value) ? "Unnamed Filter" : value;
+ }
+ private string _name = "Unnamed Filter";
+ public int Port
+ {
+ get => _port;
+ set => _port = Utils.MinMax(value, -1, 65535);
+ }
+ private int _port = -1;
+ public string Ip { get; set; } = "127.0.0.1";
+ public List Filters { get; set; } = new();
+
+ private bool _isValid = true;
+ public override string ToString()
+ => $"{(_isValid ? "" : "[x]")}{Name} => {Ip}:{Port}";
+
+ ///
+ /// Sets validity to be displayed in filter window
+ ///
+ internal void SetValidity(bool state)
+ => _isValid = state;
+ }
+}
diff --git a/OscMultitool/Models/RegexModels.cs b/OscMultitool/Models/RegexModels.cs
new file mode 100644
index 0000000..842318f
--- /dev/null
+++ b/OscMultitool/Models/RegexModels.cs
@@ -0,0 +1,150 @@
+using System;
+using System.Text.RegularExpressions;
+
+namespace Hoscy.Models
+{
+ internal abstract class RegexFilteredModelBase
+ {
+ public bool Enabled { get; set; } = true;
+ public bool IgnoreCase
+ {
+ get => _ignoreCase;
+ set
+ {
+ _ignoreCase = value;
+ UpdateRegex();
+ }
+ }
+ protected bool _ignoreCase = true;
+ public bool UseRegex
+ {
+ get => _useRegex;
+ set
+ {
+ _useRegex = value;
+ UpdateRegex();
+ }
+ }
+ protected bool _useRegex = false;
+
+ protected Regex? _regex;
+
+ protected abstract void UpdateRegex();
+ }
+
+ internal class FilterModel : RegexFilteredModelBase
+ {
+ public string Name
+ {
+ get => _name;
+ set => _name = string.IsNullOrWhiteSpace(value) ? "Unnamed Filter" : value;
+ }
+ private string _name = "Unnamed Filter";
+ public string FilterString
+ {
+ get => _filterString;
+ set
+ {
+ _filterString = string.IsNullOrWhiteSpace(value) ? "Filter Text" : value;
+ UpdateRegex();
+ }
+ }
+ private string _filterString = "Filter Text";
+
+ public FilterModel(string name, string filterString)
+ {
+ Name = name;
+ FilterString = filterString;
+ }
+ public FilterModel() { }
+
+ protected override void UpdateRegex()
+ => _regex = _useRegex ? new(_filterString, _ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None | RegexOptions.CultureInvariant) : null;
+
+ internal bool Matches(string compare)
+ {
+ if (_regex == null)
+ return compare.Contains(_filterString, _ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
+
+ return _regex.IsMatch(compare);
+ }
+
+ public override string ToString()
+ => $"{(Enabled ? "" : "[x] ")}{_name} ={(_useRegex ? "[R]" : string.Empty)}{(_ignoreCase ? string.Empty : "[C]")}> {_filterString}";
+ }
+
+ internal abstract class RegexTextChangingModelBase : RegexFilteredModelBase
+ {
+ public string Text
+ {
+ get => _text;
+ set
+ {
+ _text = string.IsNullOrWhiteSpace(value) ? "New Text" : value;
+ UpdateRegex();
+ }
+ }
+ protected string _text = "New Text";
+
+ public string Replacement { get; set; } = "Example";
+
+ public RegexTextChangingModelBase(string text, string replacement) : base()
+ {
+ Text = text;
+ Replacement = replacement;
+ }
+ public RegexTextChangingModelBase()
+ {
+ _ignoreCase = true;
+ }
+
+ public override string ToString()
+ => $"{(Enabled ? "" : "[x] ")}{Text} ={(_useRegex ? "[R]" : string.Empty)}{(_ignoreCase ? string.Empty : "[C]")}> {Replacement}";
+ }
+
+ internal class ReplacementModel : RegexTextChangingModelBase //todo: test
+ {
+ protected override void UpdateRegex()
+ {
+ RegexOptions rexOpt = _ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None | RegexOptions.CultureInvariant;
+ _regex = _useRegex ? new(_text, rexOpt) : new($@"(?<= |\b){Regex.Escape(_text)}(?=$| |\b)", rexOpt);
+ }
+
+ public ReplacementModel(string text, string replacement)
+ {
+ Text = text;
+ Replacement = replacement;
+ }
+ public ReplacementModel() { }
+
+ internal string Replace(string text)
+ => _regex?.Replace(text, Replacement) ?? text;
+ }
+
+ internal class ShortcutModel : RegexTextChangingModelBase //todo: test, unify to one editor window
+ {
+ protected override void UpdateRegex()
+ {
+ if (UseRegex && _text.StartsWith('^') && _text.EndsWith('$'))
+ _text = _text.TrimStart('^').TrimEnd('$');
+
+ RegexOptions rexOpt = _ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None | RegexOptions.CultureInvariant;
+ _regex = UseRegex ? new($"^{_text}$", rexOpt) : null;
+ }
+
+ public ShortcutModel(string text, string replacement)
+ {
+ Text = text;
+ Replacement = replacement;
+ }
+ public ShortcutModel() { }
+
+ internal bool Compare(string text)
+ {
+ if (_regex == null)
+ return Text.Equals(text, IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
+
+ return _regex.IsMatch(text);
+ }
+ }
+}
diff --git a/OscMultitool/Services/Api/ApiClient.cs b/OscMultitool/Services/Api/ApiClient.cs
index de482fb..c78065f 100644
--- a/OscMultitool/Services/Api/ApiClient.cs
+++ b/OscMultitool/Services/Api/ApiClient.cs
@@ -1,4 +1,5 @@
-using System.Net.Http;
+using Hoscy.Models;
+using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
@@ -6,9 +7,9 @@ namespace Hoscy.Services.Api
{
internal class ApiClient
{
- private Config.ApiPresetModel? _preset;
+ private ApiPresetModel? _preset;
- internal bool LoadPreset(Config.ApiPresetModel preset)
+ internal bool LoadPreset(ApiPresetModel preset)
{
if (preset.Equals(_preset))
return true;
diff --git a/OscMultitool/Services/OscControl/OscDataHandler.cs b/OscMultitool/Services/OscControl/OscDataHandler.cs
index b58e8ac..1c4ab46 100644
--- a/OscMultitool/Services/OscControl/OscDataHandler.cs
+++ b/OscMultitool/Services/OscControl/OscDataHandler.cs
@@ -103,7 +103,6 @@ private static void HandleToolDataString(string address, string value)
{
var tProcessor = new TextProcessor()
{
- ReplaceCaseInsensitive = true,
TriggerReplace = true,
TriggerCommands = true,
UseTextbox = useTextbox,
diff --git a/OscMultitool/Services/Speech/Recognizers/RecognizerBase.cs b/OscMultitool/Services/Speech/Recognizers/RecognizerBase.cs
index 8bfd7e2..71c3207 100644
--- a/OscMultitool/Services/Speech/Recognizers/RecognizerBase.cs
+++ b/OscMultitool/Services/Speech/Recognizers/RecognizerBase.cs
@@ -115,7 +115,6 @@ internal static void ProcessMessage(string message)
var processor = new TextProcessor()
{
TriggerReplace = Config.Speech.UseReplacements,
- ReplaceCaseInsensitive = Config.Speech.IgnoreCaps,
TriggerCommands = true,
@@ -152,13 +151,11 @@ protected static string Denoise(string message)
///
internal static void UpdateDenoiseRegex()
{
- RegexOptions opt = Config.Speech.IgnoreCaps ? RegexOptions.IgnoreCase : RegexOptions.None;
-
var filterWords = Config.Speech.NoiseFilter.Select(x => $"(?:{x})");
var filterCombined = string.Join('|', filterWords);
var regString = $"^(?:\\b(?:{filterCombined})\\b)?(.*?)(?:\\b(?:{filterCombined})\\b)?$";
Logger.PInfo($"Updated denoiser ({regString})");
- _denoiseFilter = new Regex(regString, opt | RegexOptions.CultureInvariant);
+ _denoiseFilter = new Regex(regString, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
}
#endregion
}
diff --git a/OscMultitool/Services/Speech/TextProcessor.cs b/OscMultitool/Services/Speech/TextProcessor.cs
index cc6ba29..4860858 100644
--- a/OscMultitool/Services/Speech/TextProcessor.cs
+++ b/OscMultitool/Services/Speech/TextProcessor.cs
@@ -2,7 +2,6 @@
using Hoscy.Services.Api;
using Hoscy.Ui.Pages;
using System;
-using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@@ -15,7 +14,6 @@ internal class TextProcessor
internal bool UseTts { get; init; } = false;
internal bool TriggerCommands { get; init; } = false;
internal bool TriggerReplace { get; init; } = false;
- internal bool ReplaceCaseInsensitive { get; init; } = false;
internal bool AllowTranslate { get; init; } = false;
#region Processing
@@ -74,26 +72,22 @@ private async Task ProcessInternal(string message)
PageInfo.SetMessage(message, UseTextbox, UseTts);
}
- private static readonly List _shortcuts = Config.Speech.Shortcuts;
- private static readonly List _replacements = Config.Speech.Replacements;
///
/// Replaces message or parts of it
///
private string ReplaceMessage(string message)
{
//Splitting and checking for replacements
- var regexOpt = RegexOptions.CultureInvariant | (ReplaceCaseInsensitive ? RegexOptions.IgnoreCase : RegexOptions.None);
- foreach (var r in _replacements)
+ foreach (var r in Config.Speech.Replacements)
{
if (r.Enabled)
- message = Regex.Replace(message, r.RegexPattern(), r.Replacement, regexOpt);
+ message = r.Replace(message);
}
//Checking for shortcuts
- var compareText = ReplaceCaseInsensitive ? message.ToLower() : message;
- foreach (var s in _shortcuts)
+ foreach (var s in Config.Speech.Shortcuts)
{
- if (s.Enabled && compareText == (ReplaceCaseInsensitive ? s.LowercaseText() : s.Text))
+ if (s.Enabled && s.Compare(message))
{
message = s.Replacement;
break;
diff --git a/OscMultitool/Ui/Pages/PageConfig.xaml.cs b/OscMultitool/Ui/Pages/PageConfig.xaml.cs
index 72873cf..a04eead 100644
--- a/OscMultitool/Ui/Pages/PageConfig.xaml.cs
+++ b/OscMultitool/Ui/Pages/PageConfig.xaml.cs
@@ -4,7 +4,6 @@
using Hoscy.Ui.Windows;
using System.Windows;
using System.Windows.Controls;
-using System.Windows.Media.Animation;
namespace Hoscy.Ui.Pages
{
diff --git a/OscMultitool/Ui/Pages/PageInput.xaml.cs b/OscMultitool/Ui/Pages/PageInput.xaml.cs
index f32da28..8296e68 100644
--- a/OscMultitool/Ui/Pages/PageInput.xaml.cs
+++ b/OscMultitool/Ui/Pages/PageInput.xaml.cs
@@ -48,7 +48,6 @@ private void SendMessage()
var tProcessor = new TextProcessor()
{
- ReplaceCaseInsensitive = Config.Input.IgnoreCaps,
TriggerCommands = Config.Input.TriggerCommands,
TriggerReplace = Config.Input.TriggerReplace,
UseTextbox = Config.Input.UseTextbox,
diff --git a/OscMultitool/Ui/Pages/PageOutput.xaml.cs b/OscMultitool/Ui/Pages/PageOutput.xaml.cs
index bcbca09..017bfc1 100644
--- a/OscMultitool/Ui/Pages/PageOutput.xaml.cs
+++ b/OscMultitool/Ui/Pages/PageOutput.xaml.cs
@@ -1,5 +1,4 @@
-using Hoscy.Services.OscControl;
-using Hoscy.Services.Speech;
+using Hoscy.Services.Speech;
using Hoscy.Services.Speech.Utilities;
using Hoscy.Ui.Windows;
using System;
diff --git a/OscMultitool/Ui/Pages/PageSpeech.xaml b/OscMultitool/Ui/Pages/PageSpeech.xaml
index da8abdd..0d5a852 100644
--- a/OscMultitool/Ui/Pages/PageSpeech.xaml
+++ b/OscMultitool/Ui/Pages/PageSpeech.xaml
@@ -44,7 +44,6 @@
-
@@ -109,7 +108,6 @@
-
diff --git a/OscMultitool/Ui/Pages/PageSpeech.xaml.cs b/OscMultitool/Ui/Pages/PageSpeech.xaml.cs
index 17f7234..b60d0f2 100644
--- a/OscMultitool/Ui/Pages/PageSpeech.xaml.cs
+++ b/OscMultitool/Ui/Pages/PageSpeech.xaml.cs
@@ -206,7 +206,7 @@ private void Button_OpenReplacements(object sender, RoutedEventArgs e)
}
private void Button_OpenShortcuts(object sender, RoutedEventArgs e)
{
- var window = new ModifyReplacementsWindow("Edit Shortcuts", Config.Speech.Shortcuts);
+ var window = new ModifyShortcutsWindow("Edit Shortcuts", Config.Speech.Shortcuts);
window.SetDarkMode(true);
window.ShowDialog();
}
diff --git a/OscMultitool/Ui/Windows/ModifyApiPresetsWindow.xaml.cs b/OscMultitool/Ui/Windows/ModifyApiPresetsWindow.xaml.cs
index 31bfb74..cacde12 100644
--- a/OscMultitool/Ui/Windows/ModifyApiPresetsWindow.xaml.cs
+++ b/OscMultitool/Ui/Windows/ModifyApiPresetsWindow.xaml.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using Hoscy.Models;
+using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
@@ -11,9 +12,9 @@ namespace Hoscy.Ui.Windows
///
internal partial class ModifyApiPresetsWindow : Window
{
- private readonly List _list;
+ private readonly List _list;
- public ModifyApiPresetsWindow(string title, List list)
+ public ModifyApiPresetsWindow(string title, List list)
{
InitializeComponent();
@@ -74,9 +75,9 @@ private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e
textAuthHeader.Text = selected.Authorization;
}
- private Config.ApiPresetModel GetNewModel()
+ private ApiPresetModel GetNewModel()
{
- var model = new Config.ApiPresetModel();
+ var model = new ApiPresetModel();
if (!string.IsNullOrWhiteSpace(textName.Text))
model.Name = textName.Text;
diff --git a/OscMultitool/Ui/Windows/ModifyCountersWindow.xaml.cs b/OscMultitool/Ui/Windows/ModifyCountersWindow.xaml.cs
index ce7c824..8ae6024 100644
--- a/OscMultitool/Ui/Windows/ModifyCountersWindow.xaml.cs
+++ b/OscMultitool/Ui/Windows/ModifyCountersWindow.xaml.cs
@@ -1,4 +1,5 @@
-using System;
+using Hoscy.Models;
+using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@@ -13,9 +14,9 @@ namespace Hoscy.Ui.Windows
///
internal partial class ModifyCountersWindow : Window
{
- private readonly List _list;
+ private readonly List _list;
- public ModifyCountersWindow(string title, List list)
+ public ModifyCountersWindow(string title, List list)
{
InitializeComponent();
@@ -74,9 +75,9 @@ private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e
textCooldown.Text = _list[listBox.SelectedIndex].Cooldown.ToString();
}
- private Config.CounterModel GetNewModel()
+ private CounterModel GetNewModel()
{
- var model = new Config.CounterModel()
+ var model = new CounterModel()
{
Enabled = enabledCheckBox.IsChecked ?? false
};
diff --git a/OscMultitool/Ui/Windows/ModifyFiltersWindow.xaml b/OscMultitool/Ui/Windows/ModifyFiltersWindow.xaml
index 228b0eb..20a8b1b 100644
--- a/OscMultitool/Ui/Windows/ModifyFiltersWindow.xaml
+++ b/OscMultitool/Ui/Windows/ModifyFiltersWindow.xaml
@@ -44,7 +44,7 @@
-
+
diff --git a/OscMultitool/Ui/Windows/ModifyFiltersWindow.xaml.cs b/OscMultitool/Ui/Windows/ModifyFiltersWindow.xaml.cs
index 1bf3008..46640d1 100644
--- a/OscMultitool/Ui/Windows/ModifyFiltersWindow.xaml.cs
+++ b/OscMultitool/Ui/Windows/ModifyFiltersWindow.xaml.cs
@@ -1,6 +1,5 @@
-using System;
+using Hoscy.Models;
using System.Collections.Generic;
-using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
@@ -13,9 +12,9 @@ namespace Hoscy.Ui.Windows
///
internal partial class ModifyFiltersWindow : Window
{
- private readonly List _list;
+ private readonly List _list;
- public ModifyFiltersWindow(string title, List list)
+ public ModifyFiltersWindow(string title, List list)
{
InitializeComponent();
@@ -74,9 +73,9 @@ private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e
ignoreCaseCheckBox.IsChecked = _list[listBox.SelectedIndex].IgnoreCase;
}
- private Config.FilterModel GetNewModel()
+ private FilterModel GetNewModel()
{
- var model = new Config.FilterModel()
+ var model = new FilterModel()
{
Enabled = enabledCheckBox.IsChecked ?? false,
UseRegex = regexCheckBox.IsChecked ?? false,
diff --git a/OscMultitool/Ui/Windows/ModifyOscRoutingFiltersWindow.xaml.cs b/OscMultitool/Ui/Windows/ModifyOscRoutingFiltersWindow.xaml.cs
index fe6b4ba..a7e84a9 100644
--- a/OscMultitool/Ui/Windows/ModifyOscRoutingFiltersWindow.xaml.cs
+++ b/OscMultitool/Ui/Windows/ModifyOscRoutingFiltersWindow.xaml.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using Hoscy.Models;
+using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
@@ -11,9 +12,9 @@ namespace Hoscy.Ui.Windows
///
internal partial class ModifyOscRoutingFiltersWindow : Window
{
- private readonly List _list;
+ private readonly List _list;
- public ModifyOscRoutingFiltersWindow(string title, List list)
+ public ModifyOscRoutingFiltersWindow(string title, List list)
{
InitializeComponent();
@@ -70,9 +71,9 @@ private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e
textIp.Text = _list[listBox.SelectedIndex].Ip;
}
- private Config.OscRoutingFilterModel GetNewModel()
+ private OscRoutingFilterModel GetNewModel()
{
- var model = new Config.OscRoutingFilterModel();
+ var model = new OscRoutingFilterModel();
if (!string.IsNullOrWhiteSpace(textName.Text))
model.Name = textName.Text;
diff --git a/OscMultitool/Ui/Windows/ModifyReplacementsWindow.xaml b/OscMultitool/Ui/Windows/ModifyReplacementsWindow.xaml
index cf23679..838c04f 100644
--- a/OscMultitool/Ui/Windows/ModifyReplacementsWindow.xaml
+++ b/OscMultitool/Ui/Windows/ModifyReplacementsWindow.xaml
@@ -22,6 +22,7 @@
+
@@ -38,11 +39,19 @@
-
+
+
+
+
+
+
+
+
+
diff --git a/OscMultitool/Ui/Windows/ModifyReplacementsWindow.xaml.cs b/OscMultitool/Ui/Windows/ModifyReplacementsWindow.xaml.cs
index 1e73c35..fd31059 100644
--- a/OscMultitool/Ui/Windows/ModifyReplacementsWindow.xaml.cs
+++ b/OscMultitool/Ui/Windows/ModifyReplacementsWindow.xaml.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using Hoscy.Models;
+using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
@@ -11,9 +12,9 @@ namespace Hoscy.Ui.Windows
///
internal partial class ModifyReplacementsWindow : Window
{
- private readonly List _list;
+ private readonly List _list;
- public ModifyReplacementsWindow(string title, List list)
+ public ModifyReplacementsWindow(string title, List list)
{
InitializeComponent();
@@ -68,13 +69,17 @@ private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e
textValue.Text = _list[listBox.SelectedIndex].Text;
replacementValue.Text = _list[listBox.SelectedIndex].Replacement;
enabledCheckBox.IsChecked = _list[listBox.SelectedIndex].Enabled;
+ regexCheckBox.IsChecked = _list[listBox.SelectedIndex].UseRegex;
+ ignoreCaseCheckBox.IsChecked = _list[listBox.SelectedIndex].IgnoreCase;
}
- private Config.ReplacementModel GetNewModel()
+ private ReplacementModel GetNewModel()
{
- var model = new Config.ReplacementModel()
+ var model = new ReplacementModel()
{
- Enabled = enabledCheckBox.IsChecked ?? false
+ Enabled = enabledCheckBox.IsChecked ?? false,
+ UseRegex = regexCheckBox.IsChecked ?? false,
+ IgnoreCase = ignoreCaseCheckBox.IsChecked ?? false
};
if (!string.IsNullOrWhiteSpace(textValue.Text))
diff --git a/OscMultitool/Ui/Windows/ModifyShortcutsWindow.xaml b/OscMultitool/Ui/Windows/ModifyShortcutsWindow.xaml
new file mode 100644
index 0000000..1b1b5b2
--- /dev/null
+++ b/OscMultitool/Ui/Windows/ModifyShortcutsWindow.xaml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OscMultitool/Ui/Windows/ModifyShortcutsWindow.xaml.cs b/OscMultitool/Ui/Windows/ModifyShortcutsWindow.xaml.cs
new file mode 100644
index 0000000..143c35c
--- /dev/null
+++ b/OscMultitool/Ui/Windows/ModifyShortcutsWindow.xaml.cs
@@ -0,0 +1,95 @@
+using Hoscy.Models;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+
+namespace Hoscy.Ui.Windows
+{
+ ///
+ /// Interaction logic for ModifyShortcutsWindow.xaml
+ ///
+ internal partial class ModifyShortcutsWindow : Window
+ {
+ private readonly List _list;
+
+ public ModifyShortcutsWindow(string title, List list)
+ {
+ InitializeComponent();
+
+ Closed += (s, a) => Config.SaveConfig();
+
+ _list = list;
+ Title = title;
+ Refresh(-1);
+ }
+
+ private void Refresh(int index)
+ => listBox.Refresh(_list.Select(x => x.ToString()), index);
+
+ #region Modifification
+ private void AddEntry()
+ {
+ _list.Add(GetNewModel());
+ Refresh(_list.Count - 1);
+ }
+
+ private void TextBox_KeyPressed(object sender, KeyEventArgs e)
+ {
+ if (e.Key == Key.Enter)
+ AddEntry();
+ }
+
+ private void Button_AddEntry(object sender, RoutedEventArgs e)
+ => AddEntry();
+
+ private void Button_RemoveEntry(object sender, RoutedEventArgs e)
+ {
+ int index = listBox.SelectedIndex;
+ if (_list.TryRemoveAt(index))
+ Refresh(index - 1);
+ }
+
+ private void Button_ModifyEntry(object sender, RoutedEventArgs e)
+ {
+ int index = listBox.SelectedIndex;
+
+ if (_list.TryModifyAt(GetNewModel(), index))
+ Refresh(index);
+ }
+ #endregion
+
+ #region Other
+ private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ if (!listBox.IsInBounds(_list))
+ return;
+
+ textValue.Text = _list[listBox.SelectedIndex].Text;
+ replacementValue.Text = _list[listBox.SelectedIndex].Replacement;
+ enabledCheckBox.IsChecked = _list[listBox.SelectedIndex].Enabled;
+ regexCheckBox.IsChecked = _list[listBox.SelectedIndex].UseRegex;
+ ignoreCaseCheckBox.IsChecked = _list[listBox.SelectedIndex].IgnoreCase;
+ }
+
+ private ShortcutModel GetNewModel()
+ {
+ var model = new ShortcutModel()
+ {
+ Enabled = enabledCheckBox.IsChecked ?? false,
+ UseRegex = regexCheckBox.IsChecked ?? false,
+ IgnoreCase = ignoreCaseCheckBox.IsChecked ?? false
+ };
+
+ if (!string.IsNullOrWhiteSpace(textValue.Text))
+ model.Text = textValue.Text;
+
+ if (!string.IsNullOrWhiteSpace(replacementValue.Text))
+ model.Replacement = replacementValue.Text;
+
+ return model;
+ }
+ #endregion
+ }
+}
diff --git a/OscMultitool/Utils.cs b/OscMultitool/Utils.cs
index 9369be3..16f94c4 100644
--- a/OscMultitool/Utils.cs
+++ b/OscMultitool/Utils.cs
@@ -78,6 +78,28 @@ internal static string GetActualContentFolder(string folderName)
return folderName;
}
+ ///
+ /// A combination of floor and ceil for comparables
+ ///
+ /// Type to compare
+ /// Value to compare
+ /// Minimum value
+ /// Maximum value
+ /// Value, if within bounds. Min, if value smaller than min. Max, if value larger than max. If max is smaller than min, min has priority
+ internal static T MinMax(T value, T min, T max) where T : IComparable
+ {
+ if (value.CompareTo(min) < 0)
+ return min;
+ if (value.CompareTo(max) > 0)
+ return max;
+ return value;
+ }
+
+ ///
+ /// Gets the emedded ressource stream from the assembly by name
+ ///
+ /// Name of ressource
+ /// Stream of ressource
internal static Stream? GetEmbeddedRessourceStream(string name)
=> Assembly.GetExecutingAssembly().GetManifestResourceStream(name);
}
From 786c9c61801e0aec8127a722c99a9016ec371ebb Mon Sep 17 00:00:00 2001
From: Paci <89483951+PaciStardust@users.noreply.github.com>
Date: Fri, 24 Mar 2023 22:24:33 +0100
Subject: [PATCH 2/8] Display Adjustment
---
OscMultitool/Models/RegexModels.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/OscMultitool/Models/RegexModels.cs b/OscMultitool/Models/RegexModels.cs
index 842318f..61fab9f 100644
--- a/OscMultitool/Models/RegexModels.cs
+++ b/OscMultitool/Models/RegexModels.cs
@@ -70,7 +70,7 @@ internal bool Matches(string compare)
}
public override string ToString()
- => $"{(Enabled ? "" : "[x] ")}{_name} ={(_useRegex ? "[R]" : string.Empty)}{(_ignoreCase ? string.Empty : "[C]")}> {_filterString}";
+ => $"{(Enabled ? "" : "[x] ")}{_name} ={(_useRegex ? "R" : string.Empty)}{(_ignoreCase ? string.Empty : "C")}> {_filterString}";
}
internal abstract class RegexTextChangingModelBase : RegexFilteredModelBase
@@ -99,7 +99,7 @@ public RegexTextChangingModelBase()
}
public override string ToString()
- => $"{(Enabled ? "" : "[x] ")}{Text} ={(_useRegex ? "[R]" : string.Empty)}{(_ignoreCase ? string.Empty : "[C]")}> {Replacement}";
+ => $"{(Enabled ? "" : "[x] ")}{Text} ={(_useRegex ? "R" : string.Empty)}{(_ignoreCase ? string.Empty : "C")}> {Replacement}";
}
internal class ReplacementModel : RegexTextChangingModelBase //todo: test
From 1cd5cf78b9a21d48158d01c2c0f88a0ca9b2f796 Mon Sep 17 00:00:00 2001
From: Paci <89483951+PaciStardust@users.noreply.github.com>
Date: Sat, 25 Mar 2023 19:10:22 +0100
Subject: [PATCH 3/8] Reorganizing replacement handling
---
OscMultitool/Config.cs | 30 ++--
OscMultitool/Hoscy.csproj | 10 +-
OscMultitool/Models/ConfigModels.cs | 4 +-
OscMultitool/Models/FilterModel.cs | 70 ++++++++
OscMultitool/Models/RegexModels.cs | 150 ------------------
OscMultitool/Models/ReplacementDataModel.cs | 32 ++++
OscMultitool/Services/Speech/TextProcessor.cs | 44 ++++-
.../Utilities/ReplacementDataHandlers.cs | 54 +++++++
OscMultitool/Ui/Pages/PageSpeech.xaml.cs | 6 +-
....xaml => ModifyReplacementDataWindow.xaml} | 19 ++-
...cs => ModifyReplacementDataWindow.xaml.cs} | 10 +-
.../Ui/Windows/ModifyShortcutsWindow.xaml | 57 -------
.../Ui/Windows/ModifyShortcutsWindow.xaml.cs | 95 -----------
13 files changed, 233 insertions(+), 348 deletions(-)
create mode 100644 OscMultitool/Models/FilterModel.cs
delete mode 100644 OscMultitool/Models/RegexModels.cs
create mode 100644 OscMultitool/Models/ReplacementDataModel.cs
create mode 100644 OscMultitool/Services/Speech/Utilities/ReplacementDataHandlers.cs
rename OscMultitool/Ui/Windows/{ModifyReplacementsWindow.xaml => ModifyReplacementDataWindow.xaml} (78%)
rename OscMultitool/Ui/Windows/{ModifyReplacementsWindow.xaml.cs => ModifyReplacementDataWindow.xaml.cs} (89%)
delete mode 100644 OscMultitool/Ui/Windows/ModifyShortcutsWindow.xaml
delete mode 100644 OscMultitool/Ui/Windows/ModifyShortcutsWindow.xaml.cs
diff --git a/OscMultitool/Config.cs b/OscMultitool/Config.cs
index a6e16e7..2246c59 100644
--- a/OscMultitool/Config.cs
+++ b/OscMultitool/Config.cs
@@ -106,22 +106,22 @@ private static void UpdateConfig(ConfigModel config)
if (config.Speech.Replacements.Count == 0)
{
- config.Speech.Replacements.AddRange(new List()
+ config.Speech.Replacements.AddRange(new List()
{
- new("exclamation mark", "!"),
- new("question mark", "?"),
- new("colon", ":"),
- new("semicolon", ";"),
- new("open parenthesis", "("),
- new("closed parenthesis", ")"),
- new("open bracket", "("),
- new("closed bracket", ")"),
- new("minus", "-"),
- new("plus", "+"),
- new("slash", "/"),
- new("backslash", "\\"),
- new("hashtag", "#"),
- new("asterisk", "*")
+ new("exclamation mark", "!", false),
+ new("question mark", "?", false),
+ new("colon", ":", false),
+ new("semicolon", ";", false),
+ new("open parenthesis", "(", false),
+ new("closed parenthesis", ")", false),
+ new("open bracket", "(", false),
+ new("closed bracket", ")", false),
+ new("minus", "-", false),
+ new("plus", "+", false),
+ new("slash", "/", false),
+ new("backslash", "\\", false),
+ new("hashtag", "#", false),
+ new("asterisk", "*", false)
});
}
}
diff --git a/OscMultitool/Hoscy.csproj b/OscMultitool/Hoscy.csproj
index abeb04f..2c688fc 100644
--- a/OscMultitool/Hoscy.csproj
+++ b/OscMultitool/Hoscy.csproj
@@ -78,10 +78,7 @@
Code
-
- Code
-
-
+
Code
@@ -120,10 +117,7 @@
$(DefaultXamlRuntime)
Designer
-
- $(DefaultXamlRuntime)
-
-
+
$(DefaultXamlRuntime)
Designer
diff --git a/OscMultitool/Models/ConfigModels.cs b/OscMultitool/Models/ConfigModels.cs
index 4cc8079..587644e 100644
--- a/OscMultitool/Models/ConfigModels.cs
+++ b/OscMultitool/Models/ConfigModels.cs
@@ -238,8 +238,8 @@ public int MaxLenTtsString //Max length of strings that get TTS
public List NoiseFilter { get; set; } = new(); //List of words deemed noise
public bool RemoveFullStop { get; set; } = true; //todo: make default option
public bool UseReplacements { get; set; } = true; //Are replacements (and shortcuts) even used?
- public List Shortcuts { get; set; } = new();
- public List Replacements { get; set; } = new();
+ public List Shortcuts { get; set; } = new();
+ public List Replacements { get; set; } = new();
}
///
diff --git a/OscMultitool/Models/FilterModel.cs b/OscMultitool/Models/FilterModel.cs
new file mode 100644
index 0000000..082ff59
--- /dev/null
+++ b/OscMultitool/Models/FilterModel.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Text.RegularExpressions;
+
+namespace Hoscy.Models
+{
+ internal class FilterModel
+ {
+ public string Name
+ {
+ get => _name;
+ set => _name = string.IsNullOrWhiteSpace(value) ? "Unnamed Filter" : value;
+ }
+ private string _name = "Unnamed Filter";
+ public string FilterString
+ {
+ get => _filterString;
+ set
+ {
+ _filterString = string.IsNullOrWhiteSpace(value) ? "Filter Text" : value;
+ UpdateRegex();
+ }
+ }
+ private string _filterString = "Filter Text";
+
+ public bool Enabled { get; set; } = true;
+ public bool IgnoreCase
+ {
+ get => _ignoreCase;
+ set
+ {
+ _ignoreCase = value;
+ UpdateRegex();
+ }
+ }
+ protected bool _ignoreCase = true;
+ public bool UseRegex
+ {
+ get => _useRegex;
+ set
+ {
+ _useRegex = value;
+ UpdateRegex();
+ }
+ }
+ protected bool _useRegex = false;
+
+ protected Regex? _regex;
+
+ public FilterModel(string name, string filterString)
+ {
+ Name = name;
+ FilterString = filterString;
+ }
+ public FilterModel() { }
+
+ protected void UpdateRegex()
+ => _regex = _useRegex ? new(_filterString, _ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None | RegexOptions.CultureInvariant) : null;
+
+ internal bool Matches(string compare)
+ {
+ if (_regex == null)
+ return compare.Contains(_filterString, _ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
+
+ return _regex.IsMatch(compare);
+ }
+
+ public override string ToString()
+ => $"{(Enabled ? "" : "[x] ")}{_name} ={(_useRegex ? "R" : string.Empty)}{(_ignoreCase ? string.Empty : "C")}> {_filterString}";
+ }
+}
diff --git a/OscMultitool/Models/RegexModels.cs b/OscMultitool/Models/RegexModels.cs
deleted file mode 100644
index 61fab9f..0000000
--- a/OscMultitool/Models/RegexModels.cs
+++ /dev/null
@@ -1,150 +0,0 @@
-using System;
-using System.Text.RegularExpressions;
-
-namespace Hoscy.Models
-{
- internal abstract class RegexFilteredModelBase
- {
- public bool Enabled { get; set; } = true;
- public bool IgnoreCase
- {
- get => _ignoreCase;
- set
- {
- _ignoreCase = value;
- UpdateRegex();
- }
- }
- protected bool _ignoreCase = true;
- public bool UseRegex
- {
- get => _useRegex;
- set
- {
- _useRegex = value;
- UpdateRegex();
- }
- }
- protected bool _useRegex = false;
-
- protected Regex? _regex;
-
- protected abstract void UpdateRegex();
- }
-
- internal class FilterModel : RegexFilteredModelBase
- {
- public string Name
- {
- get => _name;
- set => _name = string.IsNullOrWhiteSpace(value) ? "Unnamed Filter" : value;
- }
- private string _name = "Unnamed Filter";
- public string FilterString
- {
- get => _filterString;
- set
- {
- _filterString = string.IsNullOrWhiteSpace(value) ? "Filter Text" : value;
- UpdateRegex();
- }
- }
- private string _filterString = "Filter Text";
-
- public FilterModel(string name, string filterString)
- {
- Name = name;
- FilterString = filterString;
- }
- public FilterModel() { }
-
- protected override void UpdateRegex()
- => _regex = _useRegex ? new(_filterString, _ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None | RegexOptions.CultureInvariant) : null;
-
- internal bool Matches(string compare)
- {
- if (_regex == null)
- return compare.Contains(_filterString, _ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
-
- return _regex.IsMatch(compare);
- }
-
- public override string ToString()
- => $"{(Enabled ? "" : "[x] ")}{_name} ={(_useRegex ? "R" : string.Empty)}{(_ignoreCase ? string.Empty : "C")}> {_filterString}";
- }
-
- internal abstract class RegexTextChangingModelBase : RegexFilteredModelBase
- {
- public string Text
- {
- get => _text;
- set
- {
- _text = string.IsNullOrWhiteSpace(value) ? "New Text" : value;
- UpdateRegex();
- }
- }
- protected string _text = "New Text";
-
- public string Replacement { get; set; } = "Example";
-
- public RegexTextChangingModelBase(string text, string replacement) : base()
- {
- Text = text;
- Replacement = replacement;
- }
- public RegexTextChangingModelBase()
- {
- _ignoreCase = true;
- }
-
- public override string ToString()
- => $"{(Enabled ? "" : "[x] ")}{Text} ={(_useRegex ? "R" : string.Empty)}{(_ignoreCase ? string.Empty : "C")}> {Replacement}";
- }
-
- internal class ReplacementModel : RegexTextChangingModelBase //todo: test
- {
- protected override void UpdateRegex()
- {
- RegexOptions rexOpt = _ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None | RegexOptions.CultureInvariant;
- _regex = _useRegex ? new(_text, rexOpt) : new($@"(?<= |\b){Regex.Escape(_text)}(?=$| |\b)", rexOpt);
- }
-
- public ReplacementModel(string text, string replacement)
- {
- Text = text;
- Replacement = replacement;
- }
- public ReplacementModel() { }
-
- internal string Replace(string text)
- => _regex?.Replace(text, Replacement) ?? text;
- }
-
- internal class ShortcutModel : RegexTextChangingModelBase //todo: test, unify to one editor window
- {
- protected override void UpdateRegex()
- {
- if (UseRegex && _text.StartsWith('^') && _text.EndsWith('$'))
- _text = _text.TrimStart('^').TrimEnd('$');
-
- RegexOptions rexOpt = _ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None | RegexOptions.CultureInvariant;
- _regex = UseRegex ? new($"^{_text}$", rexOpt) : null;
- }
-
- public ShortcutModel(string text, string replacement)
- {
- Text = text;
- Replacement = replacement;
- }
- public ShortcutModel() { }
-
- internal bool Compare(string text)
- {
- if (_regex == null)
- return Text.Equals(text, IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
-
- return _regex.IsMatch(text);
- }
- }
-}
diff --git a/OscMultitool/Models/ReplacementDataModel.cs b/OscMultitool/Models/ReplacementDataModel.cs
new file mode 100644
index 0000000..802eb18
--- /dev/null
+++ b/OscMultitool/Models/ReplacementDataModel.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Text.RegularExpressions;
+
+namespace Hoscy.Models
+{
+ internal class ReplacementDataModel
+ {
+ public string Text
+ {
+ get => _text;
+ set => _text = string.IsNullOrWhiteSpace(value) ? "New Text" : value;
+ }
+ protected string _text = "New Text";
+
+ public string Replacement { get; set; } = "Example";
+
+ public bool Enabled { get; set; } = true;
+ public bool UseRegex { get; set; } = false;
+ public bool IgnoreCase { get; set; } = true;
+
+ public ReplacementDataModel(string text, string replacement, bool ignoreCase = true)
+ {
+ Text = text;
+ Replacement = replacement;
+ IgnoreCase = ignoreCase;
+ }
+ public ReplacementDataModel() { }
+
+ public override string ToString()
+ => $"{(Enabled ? "" : "[x] ")}{Text} ={(UseRegex ? "R" : string.Empty)}{(IgnoreCase ? string.Empty : "C")}> {Replacement}";
+ }
+}
diff --git a/OscMultitool/Services/Speech/TextProcessor.cs b/OscMultitool/Services/Speech/TextProcessor.cs
index 4860858..f0282a0 100644
--- a/OscMultitool/Services/Speech/TextProcessor.cs
+++ b/OscMultitool/Services/Speech/TextProcessor.cs
@@ -5,11 +5,44 @@
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
+using System.Collections.Generic;
+using Hoscy.Services.Speech.Utilities;
namespace Hoscy.Services.Speech
{
internal class TextProcessor
{
+ #region Static
+ private static List _replacements = new();
+ private static List _shortcuts = new();
+
+ static TextProcessor()
+ {
+ UpdateReplacementDataHandlers();
+ }
+
+ internal static void UpdateReplacementDataHandlers()
+ {
+ var replacements = new List();
+ foreach (var replacementData in Config.Speech.Replacements)
+ {
+ if (replacementData.Enabled)
+ replacements.Add(new(replacementData));
+ }
+
+ var shortcuts = new List();
+ foreach (var replacementData in Config.Speech.Shortcuts)
+ {
+ if (replacementData.Enabled)
+ shortcuts.Add(new(replacementData));
+ }
+
+ _replacements = replacements;
+ _shortcuts = shortcuts;
+ Logger.PInfo($"Reloaded ReplacementDataHandlers ({_replacements.Count} Replacements, {_shortcuts.Count} Shortcuts)");
+ }
+ #endregion
+
internal bool UseTextbox { get; init; } = false;
internal bool UseTts { get; init; } = false;
internal bool TriggerCommands { get; init; } = false;
@@ -78,16 +111,13 @@ private async Task ProcessInternal(string message)
private string ReplaceMessage(string message)
{
//Splitting and checking for replacements
- foreach (var r in Config.Speech.Replacements)
- {
- if (r.Enabled)
- message = r.Replace(message);
- }
+ foreach (var r in _replacements)
+ message = r.Replace(message);
//Checking for shortcuts
- foreach (var s in Config.Speech.Shortcuts)
+ foreach (var s in _shortcuts)
{
- if (s.Enabled && s.Compare(message))
+ if (s.Compare(message))
{
message = s.Replacement;
break;
diff --git a/OscMultitool/Services/Speech/Utilities/ReplacementDataHandlers.cs b/OscMultitool/Services/Speech/Utilities/ReplacementDataHandlers.cs
new file mode 100644
index 0000000..038f0a1
--- /dev/null
+++ b/OscMultitool/Services/Speech/Utilities/ReplacementDataHandlers.cs
@@ -0,0 +1,54 @@
+using Hoscy.Models;
+using System;
+using System.Text.RegularExpressions;
+
+namespace Hoscy.Services.Speech.Utilities
+{
+ internal readonly struct ReplacementHandler
+ {
+ private readonly Regex _regex;
+ private readonly string _replacement;
+
+ internal ReplacementHandler(ReplacementDataModel replacementData)
+ {
+ _replacement = replacementData.Replacement;
+
+ RegexOptions rexOpt = replacementData.IgnoreCase ? RegexOptions.IgnoreCase : RegexOptions.None | RegexOptions.CultureInvariant;
+ _regex = replacementData.UseRegex
+ ? new(replacementData.Text, rexOpt)
+ : new($@"(?<= |\b){Regex.Escape(replacementData.Text)}(?=$| |\b)", rexOpt);
+ }
+
+ internal string Replace(string text)
+ => _regex?.Replace(text, _replacement) ?? text;
+ }
+
+ internal readonly struct ShortcutHandler
+ {
+ private readonly Regex? _regex;
+ private readonly string _text;
+ private readonly bool _ignoreCase;
+ internal readonly string Replacement { get; private init; }
+
+ internal ShortcutHandler(ReplacementDataModel replacementData)
+ {
+ Replacement = replacementData.Replacement;
+ _text = replacementData.Text;
+ _ignoreCase = replacementData.IgnoreCase;
+
+ if (replacementData.UseRegex && _text.StartsWith('^') && _text.EndsWith('$'))
+ _text = _text.TrimStart('^').TrimEnd('$');
+
+ RegexOptions rexOpt = replacementData.UseRegex ? RegexOptions.IgnoreCase : RegexOptions.None | RegexOptions.CultureInvariant;
+ _regex = replacementData.UseRegex ? new($"^{_text}$", rexOpt) : null;
+ }
+
+ internal bool Compare(string text)
+ {
+ if (_regex == null)
+ return _text.Equals(text, _ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
+
+ return _regex.IsMatch(text);
+ }
+ }
+}
diff --git a/OscMultitool/Ui/Pages/PageSpeech.xaml.cs b/OscMultitool/Ui/Pages/PageSpeech.xaml.cs
index b60d0f2..4f9d3f8 100644
--- a/OscMultitool/Ui/Pages/PageSpeech.xaml.cs
+++ b/OscMultitool/Ui/Pages/PageSpeech.xaml.cs
@@ -200,15 +200,17 @@ private void Button_OpenNoiseFilter(object sender, RoutedEventArgs e)
}
private void Button_OpenReplacements(object sender, RoutedEventArgs e)
{
- var window = new ModifyReplacementsWindow("Edit Replacements", Config.Speech.Replacements);
+ var window = new ModifyReplacementDataWindow("Edit Replacements", Config.Speech.Replacements);
window.SetDarkMode(true);
window.ShowDialog();
+ TextProcessor.UpdateReplacementDataHandlers();
}
private void Button_OpenShortcuts(object sender, RoutedEventArgs e)
{
- var window = new ModifyShortcutsWindow("Edit Shortcuts", Config.Speech.Shortcuts);
+ var window = new ModifyReplacementDataWindow("Edit Shortcuts", Config.Speech.Shortcuts);
window.SetDarkMode(true);
window.ShowDialog();
+ TextProcessor.UpdateReplacementDataHandlers();
}
private void Button_EditVoskModels(object sender, RoutedEventArgs e)
diff --git a/OscMultitool/Ui/Windows/ModifyReplacementsWindow.xaml b/OscMultitool/Ui/Windows/ModifyReplacementDataWindow.xaml
similarity index 78%
rename from OscMultitool/Ui/Windows/ModifyReplacementsWindow.xaml
rename to OscMultitool/Ui/Windows/ModifyReplacementDataWindow.xaml
index 838c04f..80caee0 100644
--- a/OscMultitool/Ui/Windows/ModifyReplacementsWindow.xaml
+++ b/OscMultitool/Ui/Windows/ModifyReplacementDataWindow.xaml
@@ -1,4 +1,4 @@
-
+ Title="Modify Replacement Data" Height="400" Width="700" Background="{Binding Source={x:Static ui:UiHelper.ColorBack}}" ResizeMode="CanResize">
@@ -21,7 +21,8 @@
-
+
+
@@ -36,16 +37,20 @@
-
-
+
-
+
+
+
+
+
+
-
+
diff --git a/OscMultitool/Ui/Windows/ModifyReplacementsWindow.xaml.cs b/OscMultitool/Ui/Windows/ModifyReplacementDataWindow.xaml.cs
similarity index 89%
rename from OscMultitool/Ui/Windows/ModifyReplacementsWindow.xaml.cs
rename to OscMultitool/Ui/Windows/ModifyReplacementDataWindow.xaml.cs
index fd31059..79793ed 100644
--- a/OscMultitool/Ui/Windows/ModifyReplacementsWindow.xaml.cs
+++ b/OscMultitool/Ui/Windows/ModifyReplacementDataWindow.xaml.cs
@@ -10,11 +10,11 @@ namespace Hoscy.Ui.Windows
///
/// Interaction logic for ModifyListWindow.xaml
///
- internal partial class ModifyReplacementsWindow : Window
+ internal partial class ModifyReplacementDataWindow : Window
{
- private readonly List _list;
+ private readonly List _list;
- public ModifyReplacementsWindow(string title, List list)
+ public ModifyReplacementDataWindow(string title, List list)
{
InitializeComponent();
@@ -73,9 +73,9 @@ private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e
ignoreCaseCheckBox.IsChecked = _list[listBox.SelectedIndex].IgnoreCase;
}
- private ReplacementModel GetNewModel()
+ private ReplacementDataModel GetNewModel()
{
- var model = new ReplacementModel()
+ var model = new ReplacementDataModel()
{
Enabled = enabledCheckBox.IsChecked ?? false,
UseRegex = regexCheckBox.IsChecked ?? false,
diff --git a/OscMultitool/Ui/Windows/ModifyShortcutsWindow.xaml b/OscMultitool/Ui/Windows/ModifyShortcutsWindow.xaml
deleted file mode 100644
index 1b1b5b2..0000000
--- a/OscMultitool/Ui/Windows/ModifyShortcutsWindow.xaml
+++ /dev/null
@@ -1,57 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/OscMultitool/Ui/Windows/ModifyShortcutsWindow.xaml.cs b/OscMultitool/Ui/Windows/ModifyShortcutsWindow.xaml.cs
deleted file mode 100644
index 143c35c..0000000
--- a/OscMultitool/Ui/Windows/ModifyShortcutsWindow.xaml.cs
+++ /dev/null
@@ -1,95 +0,0 @@
-using Hoscy.Models;
-using System.Collections.Generic;
-using System.Linq;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
-
-namespace Hoscy.Ui.Windows
-{
- ///
- /// Interaction logic for ModifyShortcutsWindow.xaml
- ///
- internal partial class ModifyShortcutsWindow : Window
- {
- private readonly List _list;
-
- public ModifyShortcutsWindow(string title, List list)
- {
- InitializeComponent();
-
- Closed += (s, a) => Config.SaveConfig();
-
- _list = list;
- Title = title;
- Refresh(-1);
- }
-
- private void Refresh(int index)
- => listBox.Refresh(_list.Select(x => x.ToString()), index);
-
- #region Modifification
- private void AddEntry()
- {
- _list.Add(GetNewModel());
- Refresh(_list.Count - 1);
- }
-
- private void TextBox_KeyPressed(object sender, KeyEventArgs e)
- {
- if (e.Key == Key.Enter)
- AddEntry();
- }
-
- private void Button_AddEntry(object sender, RoutedEventArgs e)
- => AddEntry();
-
- private void Button_RemoveEntry(object sender, RoutedEventArgs e)
- {
- int index = listBox.SelectedIndex;
- if (_list.TryRemoveAt(index))
- Refresh(index - 1);
- }
-
- private void Button_ModifyEntry(object sender, RoutedEventArgs e)
- {
- int index = listBox.SelectedIndex;
-
- if (_list.TryModifyAt(GetNewModel(), index))
- Refresh(index);
- }
- #endregion
-
- #region Other
- private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- if (!listBox.IsInBounds(_list))
- return;
-
- textValue.Text = _list[listBox.SelectedIndex].Text;
- replacementValue.Text = _list[listBox.SelectedIndex].Replacement;
- enabledCheckBox.IsChecked = _list[listBox.SelectedIndex].Enabled;
- regexCheckBox.IsChecked = _list[listBox.SelectedIndex].UseRegex;
- ignoreCaseCheckBox.IsChecked = _list[listBox.SelectedIndex].IgnoreCase;
- }
-
- private ShortcutModel GetNewModel()
- {
- var model = new ShortcutModel()
- {
- Enabled = enabledCheckBox.IsChecked ?? false,
- UseRegex = regexCheckBox.IsChecked ?? false,
- IgnoreCase = ignoreCaseCheckBox.IsChecked ?? false
- };
-
- if (!string.IsNullOrWhiteSpace(textValue.Text))
- model.Text = textValue.Text;
-
- if (!string.IsNullOrWhiteSpace(replacementValue.Text))
- model.Replacement = replacementValue.Text;
-
- return model;
- }
- #endregion
- }
-}
From 28a4745acc327c150f62940edbbebc4e4f3559d1 Mon Sep 17 00:00:00 2001
From: Paci <89483951+PaciStardust@users.noreply.github.com>
Date: Sat, 25 Mar 2023 19:14:49 +0100
Subject: [PATCH 4/8] UI Tweaks
---
OscMultitool/Ui/Windows/ModifyFiltersWindow.xaml | 13 ++++++++-----
.../Ui/Windows/ModifyReplacementDataWindow.xaml | 2 --
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/OscMultitool/Ui/Windows/ModifyFiltersWindow.xaml b/OscMultitool/Ui/Windows/ModifyFiltersWindow.xaml
index 20a8b1b..5633621 100644
--- a/OscMultitool/Ui/Windows/ModifyFiltersWindow.xaml
+++ b/OscMultitool/Ui/Windows/ModifyFiltersWindow.xaml
@@ -22,6 +22,7 @@
+
@@ -34,15 +35,17 @@
-
-
-
+
+
-
-
+
+
+
+
+
diff --git a/OscMultitool/Ui/Windows/ModifyReplacementDataWindow.xaml b/OscMultitool/Ui/Windows/ModifyReplacementDataWindow.xaml
index 80caee0..08fcd6f 100644
--- a/OscMultitool/Ui/Windows/ModifyReplacementDataWindow.xaml
+++ b/OscMultitool/Ui/Windows/ModifyReplacementDataWindow.xaml
@@ -36,8 +36,6 @@
-
-
From ea9c2c1d011835addb0fa778fea85d8adbe2f8fd Mon Sep 17 00:00:00 2001
From: Paci <89483951+PaciStardust@users.noreply.github.com>
Date: Sat, 25 Mar 2023 20:01:04 +0100
Subject: [PATCH 5/8] Structure changes, counter decimal fix
---
OscMultitool/Models/CounterModel.cs | 9 ++++++++-
OscMultitool/Services/Speech/TextProcessor.cs | 8 ++++----
.../Speech/Utilities/ReplacementDataHandlers.cs | 11 +++++++----
3 files changed, 19 insertions(+), 9 deletions(-)
diff --git a/OscMultitool/Models/CounterModel.cs b/OscMultitool/Models/CounterModel.cs
index cc0d61b..7e979e6 100644
--- a/OscMultitool/Models/CounterModel.cs
+++ b/OscMultitool/Models/CounterModel.cs
@@ -1,9 +1,16 @@
using System;
+using System.Globalization;
namespace Hoscy.Models
{
internal class CounterModel
{
+ private static readonly NumberFormatInfo _nfi = new()
+ {
+ NumberDecimalDigits = 0,
+ NumberGroupSeparator = "."
+ };
+
public string Name
{
get => _name;
@@ -41,6 +48,6 @@ internal void Increase()
internal string FullParameter() => _fullParameter;
public override string ToString()
- => $"{(Enabled ? "" : "[x] ")}{Name}: {Count:N0}";
+ => $"{(Enabled ? "" : "[x] ")}{Name}: {Count.ToString("N", _nfi)}";
}
}
diff --git a/OscMultitool/Services/Speech/TextProcessor.cs b/OscMultitool/Services/Speech/TextProcessor.cs
index f0282a0..d1118f8 100644
--- a/OscMultitool/Services/Speech/TextProcessor.cs
+++ b/OscMultitool/Services/Speech/TextProcessor.cs
@@ -13,8 +13,8 @@ namespace Hoscy.Services.Speech
internal class TextProcessor
{
#region Static
- private static List _replacements = new();
- private static List _shortcuts = new();
+ private static IReadOnlyList _replacements = new List();
+ private static IReadOnlyList _shortcuts = new List();
static TextProcessor()
{
@@ -108,7 +108,7 @@ private async Task ProcessInternal(string message)
///
/// Replaces message or parts of it
///
- private string ReplaceMessage(string message)
+ private static string ReplaceMessage(string message)
{
//Splitting and checking for replacements
foreach (var r in _replacements)
@@ -119,7 +119,7 @@ private string ReplaceMessage(string message)
{
if (s.Compare(message))
{
- message = s.Replacement;
+ message = s.GetReplacement();
break;
}
}
diff --git a/OscMultitool/Services/Speech/Utilities/ReplacementDataHandlers.cs b/OscMultitool/Services/Speech/Utilities/ReplacementDataHandlers.cs
index 038f0a1..8e29e65 100644
--- a/OscMultitool/Services/Speech/Utilities/ReplacementDataHandlers.cs
+++ b/OscMultitool/Services/Speech/Utilities/ReplacementDataHandlers.cs
@@ -4,7 +4,7 @@
namespace Hoscy.Services.Speech.Utilities
{
- internal readonly struct ReplacementHandler
+ internal class ReplacementHandler
{
private readonly Regex _regex;
private readonly string _replacement;
@@ -23,16 +23,16 @@ internal string Replace(string text)
=> _regex?.Replace(text, _replacement) ?? text;
}
- internal readonly struct ShortcutHandler
+ internal class ShortcutHandler
{
private readonly Regex? _regex;
private readonly string _text;
private readonly bool _ignoreCase;
- internal readonly string Replacement { get; private init; }
+ private readonly string _replacement;
internal ShortcutHandler(ReplacementDataModel replacementData)
{
- Replacement = replacementData.Replacement;
+ _replacement = replacementData.Replacement;
_text = replacementData.Text;
_ignoreCase = replacementData.IgnoreCase;
@@ -50,5 +50,8 @@ internal bool Compare(string text)
return _regex.IsMatch(text);
}
+
+ internal string GetReplacement()
+ => _replacement;
}
}
From 7cce07ab9c3e423f9eeaa6caba204cb0cca7894f Mon Sep 17 00:00:00 2001
From: Paci <89483951+PaciStardust@users.noreply.github.com>
Date: Sun, 26 Mar 2023 01:36:45 +0100
Subject: [PATCH 6/8] Splitting fixes
---
OscMultitool/Services/Speech/Textbox.cs | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/OscMultitool/Services/Speech/Textbox.cs b/OscMultitool/Services/Speech/Textbox.cs
index 6a4b527..96c1f8e 100644
--- a/OscMultitool/Services/Speech/Textbox.cs
+++ b/OscMultitool/Services/Speech/Textbox.cs
@@ -120,6 +120,9 @@ private static void MessageQueueLoop()
private static bool SendMessage(string message, bool notify)
{
+ if (message.Length > 140)
+ message = message[..140];
+
var packet = new OscPacket(Config.Osc.AddressGameTextbox, message, true, notify);
if (!packet.IsValid)
{
@@ -208,7 +211,7 @@ private static List SplitMessage(string message)
currentMessage.Append(" ...");
messages.Add(currentMessage.ToString());
- currentMessage.Clear().Append("... ");
+ currentMessage.Clear().Append($"... {word}"); //todo: word doesnt get added?
}
var messageStringLast = currentMessage.ToString();
From 762b38619206b180fcf87b12c6bddac5a33766fd Mon Sep 17 00:00:00 2001
From: Paci <89483951+PaciStardust@users.noreply.github.com>
Date: Sun, 26 Mar 2023 03:46:08 +0200
Subject: [PATCH 7/8] Supress OSC sending error
---
OscMultitool/Services/OscControl/Osc.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/OscMultitool/Services/OscControl/Osc.cs b/OscMultitool/Services/OscControl/Osc.cs
index 85603aa..f730834 100644
--- a/OscMultitool/Services/OscControl/Osc.cs
+++ b/OscMultitool/Services/OscControl/Osc.cs
@@ -43,7 +43,7 @@ internal static bool Send(OscPacket p)
}
catch (Exception e)
{
- Logger.Error(e, "Failed to send OSC data.");
+ Logger.Error(e, "Failed to send OSC data.", false);
return false;
}
}
From 3310ee51f0b6bf20b40b84d7132a0850af30793f Mon Sep 17 00:00:00 2001
From: Paci <89483951+PaciStardust@users.noreply.github.com>
Date: Sun, 26 Mar 2023 04:19:41 +0200
Subject: [PATCH 8/8] Counter display fix
---
OscMultitool/Models/CounterModel.cs | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/OscMultitool/Models/CounterModel.cs b/OscMultitool/Models/CounterModel.cs
index 7e979e6..f3fdfbc 100644
--- a/OscMultitool/Models/CounterModel.cs
+++ b/OscMultitool/Models/CounterModel.cs
@@ -5,12 +5,6 @@ namespace Hoscy.Models
{
internal class CounterModel
{
- private static readonly NumberFormatInfo _nfi = new()
- {
- NumberDecimalDigits = 0,
- NumberGroupSeparator = "."
- };
-
public string Name
{
get => _name;
@@ -48,6 +42,6 @@ internal void Increase()
internal string FullParameter() => _fullParameter;
public override string ToString()
- => $"{(Enabled ? "" : "[x] ")}{Name}: {Count.ToString("N", _nfi)}";
+ => $"{(Enabled ? "" : "[x] ")}{Name}: {Count:N0}";
}
}