diff --git a/.gitignore b/.gitignore index 42698ddd..4f3e075c 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ /v2rayN/v2rayUpgrade/bin/Release /v2rayN/v2rayUpgrade/obj/ *.user +/.vs/v2rayN diff --git a/v2rayN/v2rayN/Handler/HotkeyHandler.cs b/v2rayN/v2rayN/Handler/HotkeyHandler.cs new file mode 100644 index 00000000..5b5a4e0f --- /dev/null +++ b/v2rayN/v2rayN/Handler/HotkeyHandler.cs @@ -0,0 +1,137 @@ +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows; +using System.Windows.Input; +using System.Windows.Interop; +using v2rayN.Mode; +using v2rayN.Resx; + +namespace v2rayN.Handler +{ + public sealed class HotkeyHandler + { + private static readonly Lazy _instance = new(() => new()); + public static HotkeyHandler Instance = _instance.Value; + + private const int WmHotkey = 0x0312; + private Config _config + { + get => LazyConfig.Instance.GetConfig(); + } + private Dictionary> _hotkeyTriggerDic; + + public bool IsPause { get; private set; } = false; + public event Action? UpdateViewEvent; + public event Action? HotkeyTriggerEvent; + public HotkeyHandler() + { + _hotkeyTriggerDic = new(); + ComponentDispatcher.ThreadPreprocessMessage += OnThreadPreProcessMessage; + Init(); + } + + private void Init() + { + _hotkeyTriggerDic.Clear(); + if (_config.globalHotkeys == null) return; + foreach(var item in _config.globalHotkeys) + { + if (item.KeyCode != null && item.KeyCode != Key.None) + { + int key = KeyInterop.VirtualKeyFromKey((Key)item.KeyCode); + KeyModifiers modifiers = KeyModifiers.None; + if (item.Control) modifiers |= KeyModifiers.Ctrl; + if (item.Shift) modifiers |= KeyModifiers.Shift; + if (item.Alt) modifiers |= KeyModifiers.Alt; + key = (key << 16) | (int)modifiers; + if (!_hotkeyTriggerDic.ContainsKey(key)) + { + _hotkeyTriggerDic.Add(key, new() { item.eGlobalHotkey }); + } + else + { + if (!_hotkeyTriggerDic[key].Contains(item.eGlobalHotkey)) + _hotkeyTriggerDic[key].Add(item.eGlobalHotkey); + } + } + } + } + public void Load() + { + foreach(var hotkey in _hotkeyTriggerDic.Keys) + { + var _fsModifiers = hotkey & 0xffff; + var _vkey = (hotkey >> 16) & 0xffff; + var hotkeyStr = HotkeyToString(_fsModifiers, _vkey); + bool isSuccess = false; + string msg; + + Application.Current.Dispatcher.Invoke(() => + { + isSuccess = RegisterHotKey(IntPtr.Zero, hotkey, _fsModifiers, _vkey); + }); + if (isSuccess) + { + msg = string.Format(ResUI.RegisterGlobalHotkeySuccessfully, $"{hotkeyStr}"); + } + else + { + var errInfo = new Win32Exception(Marshal.GetLastWin32Error()).Message; + msg = string.Format(ResUI.RegisterGlobalHotkeyFailed, $"{hotkeyStr}", errInfo); + } + UpdateViewEvent?.Invoke(false, msg); + } + } + + public void ReLoad() + { + foreach(var hotkey in _hotkeyTriggerDic.Keys) + { + Application.Current.Dispatcher.Invoke(() => + { + UnregisterHotKey(IntPtr.Zero, hotkey); + }); + } + Init(); + Load(); + } + + private void OnThreadPreProcessMessage(ref MSG msg, ref bool handled) + { + if (msg.message != WmHotkey || IsPause || !_hotkeyTriggerDic.Keys.Contains((int)msg.lParam)) + return; + handled = true; + foreach (var keyEvent in _hotkeyTriggerDic[(int)msg.lParam]) + { + HotkeyTriggerEvent?.Invoke(keyEvent); + } + } + [DllImport("user32.dll", SetLastError = true)] + private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc); + + [DllImport("user32.dll", SetLastError = true)] + private static extern bool UnregisterHotKey(IntPtr hWnd, int id); + private static string HotkeyToString(int fsModifiers,int vk) + { + var sb = new StringBuilder(); + var mdif = (KeyModifiers)fsModifiers; + var key = KeyInterop.KeyFromVirtualKey(vk); + if ((mdif | KeyModifiers.Ctrl) == KeyModifiers.Ctrl) sb.Append($"{KeyModifiers.Ctrl}+"); + if ((mdif | KeyModifiers.Alt) == KeyModifiers.Alt) sb.Append($"{KeyModifiers.Alt}+"); + if ((mdif | KeyModifiers.Shift) == KeyModifiers.Shift) sb.Append($"{KeyModifiers.Shift}+"); + sb.Append(key.ToString()); + return sb.ToString(); + } + [Flags] + private enum KeyModifiers + { + None = 0x0000, + Alt = 0x0001, + Ctrl = 0x0002, + Shift = 0x0004, + Win = 0x0008, + NoRepeat = 0x4000 + } + } +} diff --git a/v2rayN/v2rayN/Handler/MainFormHandler.cs b/v2rayN/v2rayN/Handler/MainFormHandler.cs index cdf7215c..e04d9466 100644 --- a/v2rayN/v2rayN/Handler/MainFormHandler.cs +++ b/v2rayN/v2rayN/Handler/MainFormHandler.cs @@ -343,48 +343,11 @@ namespace v2rayN.Handler } } - public void RegisterGlobalHotkey(Config config, EventHandler handler, Action update) + public void RegisterGlobalHotkey(Config config, Action handler, Action update) { - if (config.globalHotkeys == null) - { - return; - } - - foreach (var item in config.globalHotkeys) - { - if (item.KeyCode == null) - { - continue; - } - - var modifiers = ModifierKeys.None; - if (item.Control) - { - modifiers |= ModifierKeys.Control; - } - if (item.Alt) - { - modifiers |= ModifierKeys.Alt; - } - if (item.Shift) - { - modifiers |= ModifierKeys.Shift; - } - - var gesture = new KeyGesture(KeyInterop.KeyFromVirtualKey((int)item.KeyCode), modifiers); - try - { - HotkeyManager.Current.AddOrReplace(((int)item.eGlobalHotkey).ToString(), gesture, handler); - var msg = string.Format(ResUI.RegisterGlobalHotkeySuccessfully, $"{item.eGlobalHotkey}"); - update(false, msg); - } - catch (Exception ex) - { - var msg = string.Format(ResUI.RegisterGlobalHotkeyFailed, $"{item.eGlobalHotkey}", ex.Message); - update(false, msg); - Utils.SaveLog(msg); - } - } + HotkeyHandler.Instance.UpdateViewEvent += update; + HotkeyHandler.Instance.HotkeyTriggerEvent += handler; + HotkeyHandler.Instance.Load(); } } diff --git a/v2rayN/v2rayN/Mode/ConfigItems.cs b/v2rayN/v2rayN/Mode/ConfigItems.cs index 3f9e9eac..198d3dd9 100644 --- a/v2rayN/v2rayN/Mode/ConfigItems.cs +++ b/v2rayN/v2rayN/Mode/ConfigItems.cs @@ -1,5 +1,4 @@ -using System.Windows.Forms; - +using System.Windows.Input; namespace v2rayN.Mode { [Serializable] @@ -144,7 +143,7 @@ namespace v2rayN.Mode public bool Shift { get; set; } - public Keys? KeyCode { get; set; } + public Key? KeyCode { get; set; } } diff --git a/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs b/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs index e50dc36a..c670f83d 100644 --- a/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs @@ -630,27 +630,26 @@ namespace v2rayN.ViewModels } } - private void OnHotkeyHandler(object sender, HotkeyEventArgs e) + private void OnHotkeyHandler(EGlobalHotkey e) { - switch (Utils.ToInt(e.Name)) + switch (e) { - case (int)EGlobalHotkey.ShowForm: + case EGlobalHotkey.ShowForm: ShowHideWindow(null); break; - case (int)EGlobalHotkey.SystemProxyClear: + case EGlobalHotkey.SystemProxyClear: SetListenerType(ESysProxyType.ForcedClear); break; - case (int)EGlobalHotkey.SystemProxySet: + case EGlobalHotkey.SystemProxySet: SetListenerType(ESysProxyType.ForcedChange); break; - case (int)EGlobalHotkey.SystemProxyUnchanged: + case EGlobalHotkey.SystemProxyUnchanged: SetListenerType(ESysProxyType.Unchanged); break; - case (int)EGlobalHotkey.SystemProxyPac: + case EGlobalHotkey.SystemProxyPac: SetListenerType(ESysProxyType.Pac); break; } - e.Handled = true; } public void MyAppExit(bool blWindowsShutDown) { diff --git a/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml.cs b/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml.cs index 16cc7fce..54b48283 100644 --- a/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml.cs @@ -1,4 +1,5 @@ -using System.Windows; +using Microsoft.Win32.TaskScheduler; +using System.Windows; using System.Windows.Controls; using System.Windows.Input; using v2rayN.Handler; @@ -12,37 +13,23 @@ namespace v2rayN.Views { private static Config _config; List lstKey; + private Dictionary _TextBoxKeyEventItem; public GlobalHotkeySettingWindow() { InitializeComponent(); this.Owner = Application.Current.MainWindow; _config = LazyConfig.Instance.GetConfig(); + _config.globalHotkeys ??= new List(); - if (_config.globalHotkeys == null) + _TextBoxKeyEventItem = new() { - _config.globalHotkeys = new List(); - } - - foreach (EGlobalHotkey it in Enum.GetValues(typeof(EGlobalHotkey))) - { - if (_config.globalHotkeys.FindIndex(t => t.eGlobalHotkey == it) >= 0) - { - continue; - } - - _config.globalHotkeys.Add(new KeyEventItem() - { - eGlobalHotkey = it, - Alt = false, - Control = false, - Shift = false, - KeyCode = null - }); - } - - lstKey = Utils.DeepCopy(_config.globalHotkeys); - + { 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)} + }; txtGlobalHotkey0.KeyDown += TxtGlobalHotkey_KeyDown; txtGlobalHotkey1.KeyDown += TxtGlobalHotkey_KeyDown; txtGlobalHotkey2.KeyDown += TxtGlobalHotkey_KeyDown; @@ -63,7 +50,7 @@ namespace v2rayN.Views { var txt = ((TextBox)sender); var index = Utils.ToInt(txt.Name.Substring(txt.Name.Length - 1, 1)); - var formsKey = (Forms.Keys)KeyInterop.VirtualKeyFromKey(e.Key == Key.System ? e.SystemKey : e.Key); + var formsKey = e.Key == Key.System ? e.SystemKey : e.Key; lstKey[index].KeyCode = formsKey; lstKey[index].Alt = (Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt; @@ -74,6 +61,18 @@ namespace v2rayN.Views } } + private KeyEventItem GetKeyEventItemByEGlobalHotkey(List KELsit,EGlobalHotkey eg) + { + return Utils.DeepCopy(KELsit.Find((it) => it.eGlobalHotkey == eg) ?? new() + { + eGlobalHotkey = eg, + Control = false, + Alt = false, + Shift = false, + KeyCode = null + }); + + } private void BindingData(int index) { for (int k = 0; k < lstKey.Count; k++)