From 6079e76be5f9b8944068e5afe6cf07a2d81bdc6b Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Tue, 25 Feb 2025 14:26:12 +0800 Subject: [PATCH] Improved global hotkey setting --- v2rayN/ServiceLib/Handler/ConfigHandler.cs | 1 + .../GlobalHotkeySettingViewModel.cs | 67 ++++++++ v2rayN/v2rayN/Handler/HotkeyHandler.cs | 4 - .../Views/GlobalHotkeySettingWindow.xaml | 9 +- .../Views/GlobalHotkeySettingWindow.xaml.cs | 148 ++++++++---------- 5 files changed, 137 insertions(+), 92 deletions(-) create mode 100644 v2rayN/ServiceLib/ViewModels/GlobalHotkeySettingViewModel.cs diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs index 06934b4b..03f16d48 100644 --- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs @@ -158,6 +158,7 @@ namespace ServiceLib.Handler Length = "100-200", Interval = "10-20" }; + config.GlobalHotkeys ??= new(); if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty()) { diff --git a/v2rayN/ServiceLib/ViewModels/GlobalHotkeySettingViewModel.cs b/v2rayN/ServiceLib/ViewModels/GlobalHotkeySettingViewModel.cs new file mode 100644 index 00000000..41160a16 --- /dev/null +++ b/v2rayN/ServiceLib/ViewModels/GlobalHotkeySettingViewModel.cs @@ -0,0 +1,67 @@ +using System.Reactive; +using System.Text; +using ReactiveUI; +using ReactiveUI.Fody.Helpers; + +namespace ServiceLib.ViewModels +{ + public class GlobalHotkeySettingViewModel : MyReactiveObject + { + private readonly List _globalHotkeys; + + public ReactiveCommand SaveCmd { get; } + + public GlobalHotkeySettingViewModel(Func>? updateView) + { + _config = AppHandler.Instance.Config; + _updateView = updateView; + + _globalHotkeys = JsonUtils.DeepCopy(_config.GlobalHotkeys); + + SaveCmd = ReactiveCommand.CreateFromTask(async () => + { + await SaveSettingAsync(); + }); + } + + public KeyEventItem GetKeyEventItem(EGlobalHotkey eg) + { + var item = _globalHotkeys.FirstOrDefault((it) => it.EGlobalHotkey == eg); + if (item != null) + { + return item; + } + + item = new() + { + EGlobalHotkey = eg, + Control = false, + Alt = false, + Shift = false, + KeyCode = null + }; + _globalHotkeys.Add(item); + + return item; + } + + public void ResetKeyEventItem() + { + _globalHotkeys.Clear(); + } + + private async Task SaveSettingAsync() + { + _config.GlobalHotkeys = _globalHotkeys; + + if (await ConfigHandler.SaveConfig(_config) == 0) + { + _updateView?.Invoke(EViewAction.CloseWindow, null); + } + else + { + NoticeHandler.Instance.Enqueue(ResUI.OperationFailed); + } + } + } +} diff --git a/v2rayN/v2rayN/Handler/HotkeyHandler.cs b/v2rayN/v2rayN/Handler/HotkeyHandler.cs index 57bb8e70..b5b798f2 100644 --- a/v2rayN/v2rayN/Handler/HotkeyHandler.cs +++ b/v2rayN/v2rayN/Handler/HotkeyHandler.cs @@ -29,10 +29,6 @@ namespace v2rayN.Handler private void Init() { _hotkeyTriggerDic.Clear(); - if (AppHandler.Instance.Config.GlobalHotkeys == null) - { - return; - } foreach (var item in AppHandler.Instance.Config.GlobalHotkeys) { if (item.KeyCode != null && (Key)item.KeyCode != Key.None) diff --git a/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml b/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml index 4669ddcb..0e763ca7 100644 --- a/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml +++ b/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml @@ -8,10 +8,10 @@ xmlns:reactiveui="http://reactiveui.net" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib" - Title="{x:Static resx:ResUI.menuSetting}" + Title="{x:Static resx:ResUI.menuGlobalHotkeySetting}" Width="700" Height="500" - x:TypeArguments="vms:SubEditViewModel" + x:TypeArguments="vms:GlobalHotkeySettingViewModel" ShowInTaskbar="False" Style="{StaticResource WindowGlobal}" WindowStartupLocation="CenterScreen" @@ -91,7 +91,6 @@ VerticalAlignment="Center" AcceptsReturn="True" IsReadOnly="True" - PreviewKeyDown="TxtGlobalHotkey_PreviewKeyDown" Style="{StaticResource MyOutlinedTextBox}" /> diff --git a/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml.cs b/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml.cs index e61e6614..197a4465 100644 --- a/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml.cs @@ -1,62 +1,80 @@ +using System.Reactive.Disposables; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Input; +using ReactiveUI; using v2rayN.Handler; namespace v2rayN.Views { public partial class GlobalHotkeySettingWindow { - private static Config? _config; - private Dictionary _textBoxKeyEventItem = new(); + private readonly List _textBoxKeyEventItem = new(); public GlobalHotkeySettingWindow() { InitializeComponent(); this.Owner = Application.Current.MainWindow; - _config = AppHandler.Instance.Config; - _config.GlobalHotkeys ??= new(); + + ViewModel = new GlobalHotkeySettingViewModel(UpdateViewHandler); btnReset.Click += btnReset_Click; - btnSave.Click += btnSave_ClickAsync; - - txtGlobalHotkey0.KeyDown += TxtGlobalHotkey_PreviewKeyDown; - txtGlobalHotkey1.KeyDown += TxtGlobalHotkey_PreviewKeyDown; - txtGlobalHotkey2.KeyDown += TxtGlobalHotkey_PreviewKeyDown; - txtGlobalHotkey3.KeyDown += TxtGlobalHotkey_PreviewKeyDown; - txtGlobalHotkey4.KeyDown += TxtGlobalHotkey_PreviewKeyDown; HotkeyHandler.Instance.IsPause = true; this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false; - WindowsUtils.SetDarkBorder(this, _config.UiItem.CurrentTheme); - InitData(); + + this.WhenActivated(disposables => + { + this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); + }); + WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme); + + Init(); + BindingData(); } - private void InitData() + private async Task UpdateViewHandler(EViewAction action, object? obj) { - _textBoxKeyEventItem = new() + switch (action) { - { txtGlobalHotkey0,GetKeyEventItemByEGlobalHotkey(_config.GlobalHotkeys,EGlobalHotkey.ShowForm) }, - { txtGlobalHotkey1,GetKeyEventItemByEGlobalHotkey(_config.GlobalHotkeys,EGlobalHotkey.SystemProxyClear) }, - { txtGlobalHotkey2,GetKeyEventItemByEGlobalHotkey(_config.GlobalHotkeys,EGlobalHotkey.SystemProxySet) }, - { txtGlobalHotkey3,GetKeyEventItemByEGlobalHotkey(_config.GlobalHotkeys,EGlobalHotkey.SystemProxyUnchanged)}, - { txtGlobalHotkey4,GetKeyEventItemByEGlobalHotkey(_config.GlobalHotkeys,EGlobalHotkey.SystemProxyPac)} - }; + case EViewAction.CloseWindow: + this.DialogResult = true; + break; + } + return await Task.FromResult(true); + } - BindingData(); + private void Init() + { + _textBoxKeyEventItem.Add(txtGlobalHotkey0); + _textBoxKeyEventItem.Add(txtGlobalHotkey1); + _textBoxKeyEventItem.Add(txtGlobalHotkey2); + _textBoxKeyEventItem.Add(txtGlobalHotkey3); + _textBoxKeyEventItem.Add(txtGlobalHotkey4); + + for (var index = 0; index < _textBoxKeyEventItem.Count; index++) + { + var sender = _textBoxKeyEventItem[index]; + if (sender is not TextBox txtBox) + { + continue; + } + txtBox.Tag = (EGlobalHotkey)index; + txtBox.PreviewKeyDown += TxtGlobalHotkey_PreviewKeyDown; + } } private void TxtGlobalHotkey_PreviewKeyDown(object? sender, KeyEventArgs e) { e.Handled = true; - if (sender is null) + if (sender is not TextBox txtBox) { return; } - var item = _textBoxKeyEventItem[sender]; + var item = ViewModel?.GetKeyEventItem((EGlobalHotkey)txtBox.Tag); var modifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift, Key.RightShift, Key.LeftAlt, Key.RightAlt, Key.LWin, Key.RWin }; item.KeyCode = (int)(e.Key == Key.System ? (modifierKeys.Contains(e.SystemKey) ? Key.None : e.SystemKey) : (modifierKeys.Contains(e.Key) ? Key.None : e.Key)); @@ -64,38 +82,50 @@ namespace v2rayN.Views item.Control = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control; item.Shift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift; - (sender as TextBox)!.Text = KeyEventItemToString(item); + txtBox.Text = KeyEventItemToString(item); } - private KeyEventItem GetKeyEventItemByEGlobalHotkey(List lstKey, EGlobalHotkey eg) + private void BindingData() { - return JsonUtils.DeepCopy(lstKey.Find((it) => it.EGlobalHotkey == eg) ?? new() + foreach (var sender in _textBoxKeyEventItem) { - EGlobalHotkey = eg, - Control = false, - Alt = false, - Shift = false, - KeyCode = null - }); + if (sender is not TextBox txtBox) + { + continue; + } + + var item = ViewModel?.GetKeyEventItem((EGlobalHotkey)txtBox.Tag); + txtBox.Text = KeyEventItemToString(item); + } } - private string KeyEventItemToString(KeyEventItem item) + private void btnReset_Click(object sender, RoutedEventArgs e) { + ViewModel?.ResetKeyEventItem(); + BindingData(); + } + + private string KeyEventItemToString(KeyEventItem? item) + { + if (item == null) + { + return string.Empty; + } var res = new StringBuilder(); if (item.Control) { - res.Append($"{ModifierKeys.Control}+"); + res.Append($"{ModifierKeys.Control} +"); } if (item.Shift) { - res.Append($"{ModifierKeys.Shift}+"); + res.Append($"{ModifierKeys.Shift} +"); } if (item.Alt) { - res.Append($"{ModifierKeys.Alt}+"); + res.Append($"{ModifierKeys.Alt} +"); } if (item.KeyCode != null && (Key)item.KeyCode != Key.None) @@ -105,49 +135,5 @@ namespace v2rayN.Views return res.ToString(); } - - private void BindingData() - { - foreach (var item in _textBoxKeyEventItem) - { - if (item.Value.KeyCode != null && (Key)item.Value.KeyCode != Key.None) - { - (item.Key as TextBox)!.Text = KeyEventItemToString(item.Value); - } - else - { - (item.Key as TextBox)!.Text = string.Empty; - } - } - } - - private async void btnSave_ClickAsync(object sender, RoutedEventArgs e) - { - _config.GlobalHotkeys = _textBoxKeyEventItem.Values.ToList(); - - if (await ConfigHandler.SaveConfig(_config) == 0) - { - HotkeyHandler.Instance.ReLoad(); - this.DialogResult = true; - } - else - { - UI.Show(ResUI.OperationFailed); - } - } - - private void btnReset_Click(object sender, RoutedEventArgs e) - { - foreach (var k in _textBoxKeyEventItem.Keys) - { - var item = _textBoxKeyEventItem[k]; - - item.Alt = false; - item.Control = false; - item.Shift = false; - item.KeyCode = (int)Key.None; - } - BindingData(); - } } }