From 6e3171259ee5c941227b599efd6fd28d1c2f130a Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Thu, 23 May 2019 23:50:07 +0800 Subject: [PATCH 1/2] Completed the main functions --- .../HandyControlDemo_Shared/App.xaml.cs | 3 - .../HandyControlDemo_Shared/MainWindow.xaml | 4 + .../MainWindow.xaml.cs | 3 + .../ViewModel/Main/MainViewModel.cs | 11 +- .../Data/Args/KeyboardHookEventArgs.cs | 5 +- .../HandyControl_Shared.projitems | 1 + .../Tools/GlobalShortcut.cs | 116 ++++++++++++++++++ .../Tools/Hook/KeyboardHook.cs | 55 +++++++-- .../Tools/Hook/MouseHook.cs | 9 +- .../Tools/Interop/NativeMethods.cs | 2 + 10 files changed, 195 insertions(+), 14 deletions(-) create mode 100644 src/Shared/HandyControl_Shared/Tools/GlobalShortcut.cs diff --git a/src/Shared/HandyControlDemo_Shared/App.xaml.cs b/src/Shared/HandyControlDemo_Shared/App.xaml.cs index b597e60c..3f67d7c5 100644 --- a/src/Shared/HandyControlDemo_Shared/App.xaml.cs +++ b/src/Shared/HandyControlDemo_Shared/App.xaml.cs @@ -1,8 +1,5 @@ using System; -using System.Globalization; -using System.Threading; using System.Windows; -using HandyControl.Controls; using HandyControl.Data; using HandyControl.Tools; using HandyControlDemo.Data; diff --git a/src/Shared/HandyControlDemo_Shared/MainWindow.xaml b/src/Shared/HandyControlDemo_Shared/MainWindow.xaml index fabf5ef1..51e33d9b 100644 --- a/src/Shared/HandyControlDemo_Shared/MainWindow.xaml +++ b/src/Shared/HandyControlDemo_Shared/MainWindow.xaml @@ -23,6 +23,10 @@ hc:Dialog.Token="{x:Static data:MessageToken.MainWindow}" d:DesignHeight="800" d:DesignWidth="1400"> + + + + diff --git a/src/Shared/HandyControlDemo_Shared/MainWindow.xaml.cs b/src/Shared/HandyControlDemo_Shared/MainWindow.xaml.cs index ec24646f..5b5db38e 100644 --- a/src/Shared/HandyControlDemo_Shared/MainWindow.xaml.cs +++ b/src/Shared/HandyControlDemo_Shared/MainWindow.xaml.cs @@ -2,6 +2,7 @@ using System.ComponentModel; using GalaSoft.MvvmLight.Messaging; using HandyControl.Controls; +using HandyControl.Tools; using HandyControlDemo.Data; using HandyControlDemo.Tools; @@ -21,6 +22,8 @@ namespace HandyControlDemo Messenger.Default.Send(null, MessageToken.ClearLeftSelected); Messenger.Default.Send(true, MessageToken.FullSwitch); Messenger.Default.Send(AssemblyHelper.CreateInternalInstance($"UserControl.{MessageToken.OverView}"), MessageToken.LoadShowContent); + + GlobalShortcut.Init(this); } protected override void OnClosing(CancelEventArgs e) diff --git a/src/Shared/HandyControlDemo_Shared/ViewModel/Main/MainViewModel.cs b/src/Shared/HandyControlDemo_Shared/ViewModel/Main/MainViewModel.cs index c2d992cb..6382450c 100644 --- a/src/Shared/HandyControlDemo_Shared/ViewModel/Main/MainViewModel.cs +++ b/src/Shared/HandyControlDemo_Shared/ViewModel/Main/MainViewModel.cs @@ -6,6 +6,7 @@ using GalaSoft.MvvmLight.Command; using GalaSoft.MvvmLight.CommandWpf; #endif using GalaSoft.MvvmLight.Messaging; +using HandyControl.Controls; using HandyControlDemo.Data; using HandyControlDemo.Service; using HandyControlDemo.Tools; @@ -98,9 +99,15 @@ namespace HandyControlDemo.ViewModel public RelayCommand OpenOverviewCmd => new Lazy(() => new RelayCommand(OpenOverview)).Value; -#endregion + public RelayCommand GlobalShortcutInfoCmd => new Lazy(() => + new RelayCommand(() => Growl.Info("Global Shortcut Info"))).Value; -#region 方法 + public RelayCommand GlobalShortcutErrorCmd => new Lazy(() => + new RelayCommand(() => Growl.Info("Global Shortcut Error"))).Value; + + #endregion + + #region 方法 /// /// 切换例子 diff --git a/src/Shared/HandyControl_Shared/Data/Args/KeyboardHookEventArgs.cs b/src/Shared/HandyControl_Shared/Data/Args/KeyboardHookEventArgs.cs index 3d3eb0b3..717c6384 100644 --- a/src/Shared/HandyControl_Shared/Data/Args/KeyboardHookEventArgs.cs +++ b/src/Shared/HandyControl_Shared/Data/Args/KeyboardHookEventArgs.cs @@ -5,10 +5,13 @@ namespace HandyControl.Data { internal class KeyboardHookEventArgs : EventArgs { + public bool IsSystemKey { get; } + public Key Key { get; } - public KeyboardHookEventArgs(int virtualKey) + public KeyboardHookEventArgs(int virtualKey, bool isSystemKey) { + IsSystemKey = isSystemKey; Key = KeyInterop.KeyFromVirtualKey(virtualKey); } } diff --git a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems index 0b15d2bc..1c6a298b 100644 --- a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems +++ b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems @@ -19,6 +19,7 @@ + diff --git a/src/Shared/HandyControl_Shared/Tools/GlobalShortcut.cs b/src/Shared/HandyControl_Shared/Tools/GlobalShortcut.cs new file mode 100644 index 00000000..2c51ef61 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Tools/GlobalShortcut.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Input; +using HandyControl.Data; + +namespace HandyControl.Tools +{ + public class GlobalShortcut + { + private static ModifierKeys ModifierKeys; + + private static readonly Dictionary CommandDic = new Dictionary(); + + static GlobalShortcut() + { + KeyboardHook.KeyDown += KeyboardHook_KeyDown; + } + + private static void KeyboardHook_KeyDown(object sender, KeyboardHookEventArgs e) => HitTest(e.Key); + + private static void HitTest(Key key) + { + Console.WriteLine(key.ToString()); + if (IsModifierKey(key)) + { + ModifierKeys |= GetModifierKey(key); + } + else + { + var keyStr = ModifierKeys != ModifierKeys.None ? $"{ModifierKeys.ToString()}, {key.ToString()}" : key.ToString(); + ExecuteCommand(keyStr); + } + } + + private static void ExecuteCommand(string key) + { + if (string.IsNullOrEmpty(key)) return; + if (CommandDic.ContainsKey(key)) + { + var keyBinding = CommandDic[key]; + var command = keyBinding.Command; + if (command != null && command.CanExecute(keyBinding.CommandParameter)) + { + command.Execute(keyBinding.CommandParameter); + } + } + } + + private static ModifierKeys GetModifierKey(Key key) + { + switch (key) + { + case Key.LeftCtrl: + case Key.RightCtrl: + return ModifierKeys.Control; + case Key.LeftAlt: + case Key.RightAlt: + return ModifierKeys.Alt; + case Key.LeftShift: + case Key.RightShift: + return ModifierKeys.Shift; + case Key.LWin: + case Key.RWin: + return ModifierKeys.Windows; + default: + return ModifierKeys.None; + } + } + + private static bool IsModifierKey(Key key) + { + return key == Key.LeftCtrl || key == Key.LeftAlt || key == Key.LeftShift || key == Key.LWin || + key == Key.RightCtrl || key == Key.RightAlt || key == Key.RightShift || key == Key.RWin; + } + + public static void Init(DependencyObject host) + { + CommandDic.Clear(); + + if (host == null) return; + + var keyBindings = GetKeyBindings(host); + if (keyBindings == null || keyBindings.Count == 0) return; + + foreach (KeyBinding item in keyBindings) + { + if (item.Key == Key.None) + { + continue; + } + + if (item.Modifiers == ModifierKeys.None) + { + CommandDic[item.Key.ToString()] = item; + } + else + { + var keyStr = $"{item.Modifiers.ToString()}, {item.Key.ToString()}"; + CommandDic[keyStr] = item; + } + } + + KeyboardHook.Start(); + } + + public static readonly DependencyProperty KeyBindingsProperty = DependencyProperty.RegisterAttached( + "KeyBindings", typeof(InputBindingCollection), typeof(GlobalShortcut), new PropertyMetadata(new InputBindingCollection())); + + public static void SetKeyBindings(DependencyObject element, InputBindingCollection value) + => element.SetValue(KeyBindingsProperty, value); + + public static InputBindingCollection GetKeyBindings(DependencyObject element) + => (InputBindingCollection) element.GetValue(KeyBindingsProperty); + } +} \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Tools/Hook/KeyboardHook.cs b/src/Shared/HandyControl_Shared/Tools/Hook/KeyboardHook.cs index 0bd562fd..9f171d48 100644 --- a/src/Shared/HandyControl_Shared/Tools/Hook/KeyboardHook.cs +++ b/src/Shared/HandyControl_Shared/Tools/Hook/KeyboardHook.cs @@ -16,7 +16,24 @@ namespace HandyControl.Tools private static readonly UnsafeNativeMethods.HookProc Proc = HookCallback; - public static void Start() => HookId = SetHook(Proc); + private static int VirtualKey; + + private static readonly IntPtr KeyDownIntPtr = (IntPtr)NativeMethods.WM_KEYDOWN; + + private static readonly IntPtr KeyUpIntPtr = (IntPtr)NativeMethods.WM_KEYUP; + + private static readonly IntPtr SyskeyDownIntPtr = (IntPtr)NativeMethods.WM_SYSKEYDOWN; + + private static readonly IntPtr SyskeyUpIntPtr = (IntPtr)NativeMethods.WM_SYSKEYUP; + + public static void Start() + { + if (HookId != IntPtr.Zero) + { + Stop(); + } + HookId = SetHook(Proc); + } public static void Stop() => UnsafeNativeMethods.UnhookWindowsHookEx(HookId); @@ -38,17 +55,41 @@ namespace HandyControl.Tools { if (nCode >= 0) { - if (wParam == (IntPtr)NativeMethods.WM_KEYDOWN) + if (wParam == KeyDownIntPtr) { var virtualKey = Marshal.ReadInt32(lParam); - - KeyDown?.Invoke(null, new KeyboardHookEventArgs(virtualKey)); + if (VirtualKey != virtualKey) + { + VirtualKey = virtualKey; + KeyDown?.Invoke(null, new KeyboardHookEventArgs(virtualKey, false)); + } } - else if (wParam == (IntPtr)NativeMethods.WM_KEYUP) + else if (wParam == SyskeyDownIntPtr) { var virtualKey = Marshal.ReadInt32(lParam); - - KeyUp?.Invoke(null, new KeyboardHookEventArgs(virtualKey)); + if (VirtualKey != virtualKey) + { + VirtualKey = virtualKey; + KeyDown?.Invoke(null, new KeyboardHookEventArgs(virtualKey, true)); + } + } + else if (wParam == KeyUpIntPtr) + { + var virtualKey = Marshal.ReadInt32(lParam); + if (VirtualKey != virtualKey) + { + VirtualKey = virtualKey; + KeyUp?.Invoke(null, new KeyboardHookEventArgs(virtualKey, false)); + } + } + else if (wParam == SyskeyUpIntPtr) + { + var virtualKey = Marshal.ReadInt32(lParam); + if (VirtualKey != virtualKey) + { + VirtualKey = virtualKey; + KeyUp?.Invoke(null, new KeyboardHookEventArgs(virtualKey, true)); + } } } return UnsafeNativeMethods.CallNextHookEx(HookId, nCode, wParam, lParam); diff --git a/src/Shared/HandyControl_Shared/Tools/Hook/MouseHook.cs b/src/Shared/HandyControl_Shared/Tools/Hook/MouseHook.cs index e7e2d0d1..5405c6cf 100644 --- a/src/Shared/HandyControl_Shared/Tools/Hook/MouseHook.cs +++ b/src/Shared/HandyControl_Shared/Tools/Hook/MouseHook.cs @@ -14,7 +14,14 @@ namespace HandyControl.Tools private static readonly UnsafeNativeMethods.HookProc Proc = HookCallback; - public static void Start() => HookId = SetHook(Proc); + public static void Start() + { + if (HookId != IntPtr.Zero) + { + Stop(); + } + HookId = SetHook(Proc); + } public static void Stop() => UnsafeNativeMethods.UnhookWindowsHookEx(HookId); diff --git a/src/Shared/HandyControl_Shared/Tools/Interop/NativeMethods.cs b/src/Shared/HandyControl_Shared/Tools/Interop/NativeMethods.cs index 94ae1c3b..66c17772 100644 --- a/src/Shared/HandyControl_Shared/Tools/Interop/NativeMethods.cs +++ b/src/Shared/HandyControl_Shared/Tools/Interop/NativeMethods.cs @@ -33,6 +33,8 @@ namespace HandyControl.Tools.Interop NIIF_ERROR = 0x00000003, WM_KEYDOWN = 0x0100, WM_KEYUP = 0x0101, + WM_SYSKEYDOWN = 0x0104, + WM_SYSKEYUP = 0x0105, WM_MOUSEMOVE = 0x0200, WM_LBUTTONDOWN = 0x0201, WM_LBUTTONUP = 0x0202, From a269739949b2103ffa9f6839afccae594464c88b Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Fri, 24 May 2019 00:27:40 +0800 Subject: [PATCH 2/2] completed the branch --- .../HandyControlDemo_Shared/MainWindow.xaml | 4 +- .../ViewModel/Main/MainViewModel.cs | 4 +- .../Tools/GlobalShortcut.cs | 41 +++---------------- .../Tools/Hook/KeyboardHook.cs | 14 ++----- 4 files changed, 14 insertions(+), 49 deletions(-) diff --git a/src/Shared/HandyControlDemo_Shared/MainWindow.xaml b/src/Shared/HandyControlDemo_Shared/MainWindow.xaml index 51e33d9b..cde47eb6 100644 --- a/src/Shared/HandyControlDemo_Shared/MainWindow.xaml +++ b/src/Shared/HandyControlDemo_Shared/MainWindow.xaml @@ -24,8 +24,8 @@ d:DesignHeight="800" d:DesignWidth="1400"> - - + + diff --git a/src/Shared/HandyControlDemo_Shared/ViewModel/Main/MainViewModel.cs b/src/Shared/HandyControlDemo_Shared/ViewModel/Main/MainViewModel.cs index 6382450c..5b3c1691 100644 --- a/src/Shared/HandyControlDemo_Shared/ViewModel/Main/MainViewModel.cs +++ b/src/Shared/HandyControlDemo_Shared/ViewModel/Main/MainViewModel.cs @@ -102,8 +102,8 @@ namespace HandyControlDemo.ViewModel public RelayCommand GlobalShortcutInfoCmd => new Lazy(() => new RelayCommand(() => Growl.Info("Global Shortcut Info"))).Value; - public RelayCommand GlobalShortcutErrorCmd => new Lazy(() => - new RelayCommand(() => Growl.Info("Global Shortcut Error"))).Value; + public RelayCommand GlobalShortcutWarningCmd => new Lazy(() => + new RelayCommand(() => Growl.Warning("Global Shortcut Warning"))).Value; #endregion diff --git a/src/Shared/HandyControl_Shared/Tools/GlobalShortcut.cs b/src/Shared/HandyControl_Shared/Tools/GlobalShortcut.cs index 2c51ef61..ce248ba5 100644 --- a/src/Shared/HandyControl_Shared/Tools/GlobalShortcut.cs +++ b/src/Shared/HandyControl_Shared/Tools/GlobalShortcut.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Windows; using System.Windows.Input; using HandyControl.Data; @@ -8,8 +7,6 @@ namespace HandyControl.Tools { public class GlobalShortcut { - private static ModifierKeys ModifierKeys; - private static readonly Dictionary CommandDic = new Dictionary(); static GlobalShortcut() @@ -21,16 +18,11 @@ namespace HandyControl.Tools private static void HitTest(Key key) { - Console.WriteLine(key.ToString()); - if (IsModifierKey(key)) - { - ModifierKeys |= GetModifierKey(key); - } - else - { - var keyStr = ModifierKeys != ModifierKeys.None ? $"{ModifierKeys.ToString()}, {key.ToString()}" : key.ToString(); - ExecuteCommand(keyStr); - } + if (IsModifierKey(key)) return; + + var modifierKeys = Keyboard.Modifiers; + var keyStr = modifierKeys != ModifierKeys.None ? $"{modifierKeys.ToString()}, {key.ToString()}" : key.ToString(); + ExecuteCommand(keyStr); } private static void ExecuteCommand(string key) @@ -47,27 +39,6 @@ namespace HandyControl.Tools } } - private static ModifierKeys GetModifierKey(Key key) - { - switch (key) - { - case Key.LeftCtrl: - case Key.RightCtrl: - return ModifierKeys.Control; - case Key.LeftAlt: - case Key.RightAlt: - return ModifierKeys.Alt; - case Key.LeftShift: - case Key.RightShift: - return ModifierKeys.Shift; - case Key.LWin: - case Key.RWin: - return ModifierKeys.Windows; - default: - return ModifierKeys.None; - } - } - private static bool IsModifierKey(Key key) { return key == Key.LeftCtrl || key == Key.LeftAlt || key == Key.LeftShift || key == Key.LWin || diff --git a/src/Shared/HandyControl_Shared/Tools/Hook/KeyboardHook.cs b/src/Shared/HandyControl_Shared/Tools/Hook/KeyboardHook.cs index 9f171d48..32bb8dcf 100644 --- a/src/Shared/HandyControl_Shared/Tools/Hook/KeyboardHook.cs +++ b/src/Shared/HandyControl_Shared/Tools/Hook/KeyboardHook.cs @@ -76,20 +76,14 @@ namespace HandyControl.Tools else if (wParam == KeyUpIntPtr) { var virtualKey = Marshal.ReadInt32(lParam); - if (VirtualKey != virtualKey) - { - VirtualKey = virtualKey; - KeyUp?.Invoke(null, new KeyboardHookEventArgs(virtualKey, false)); - } + VirtualKey = -1; + KeyUp?.Invoke(null, new KeyboardHookEventArgs(virtualKey, false)); } else if (wParam == SyskeyUpIntPtr) { var virtualKey = Marshal.ReadInt32(lParam); - if (VirtualKey != virtualKey) - { - VirtualKey = virtualKey; - KeyUp?.Invoke(null, new KeyboardHookEventArgs(virtualKey, true)); - } + VirtualKey = -1; + KeyUp?.Invoke(null, new KeyboardHookEventArgs(virtualKey, true)); } } return UnsafeNativeMethods.CallNextHookEx(HookId, nCode, wParam, lParam);