如何在WPF和.NET 3.5中注册全局热键以使用CTRL+SHIFT+(LETTER)?
问题的原因是作者想要在WPF和.NET 3.5中注册一个全局热键,使用Ctrl + Shift + (字母)触发。解决方法是通过以下步骤实现:
1. 绑定所选UI元素(例如顶级窗口)与命令,使用InputBinding。
2. 将命令与处理程序绑定,使用CommandBinding。
以下是示例代码:
public WindowMain() { InitializeComponent(); // 绑定热键 var ib = new InputBinding( MyAppCommands.SaveAll, new KeyGesture(Key.S, ModifierKeys.Shift | ModifierKeys.Control)); this.InputBindings.Add(ib); // 绑定处理程序 var cb = new CommandBinding( MyAppCommands.SaveAll); cb.Executed += new ExecutedRoutedEventHandler( HandlerThatSavesEverthing ); this.CommandBindings.Add (cb ); } private void HandlerThatSavesEverthing (object obSender, ExecutedRoutedEventArgs e) { // 在这里执行保存所有操作 }
需要注意的是,这种方法并不是真正的全局热键,只有当应用程序处于焦点状态时才起作用。如果打开了新窗口并在那里按下热键,它不起作用。此外,如果应用程序失去焦点,也无法触发热键。
问题的出现原因:用户想要在WPF和.NET 3.5中注册一个全局快捷键,但不清楚如何实现。
解决方法:提供了一个完整的工作解决方案,包括一个HotKey类和示例用法。用户可以使用该类来注册全局快捷键,并定义相应的操作。
具体代码如下:
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net.Mime; using System.Runtime.InteropServices; using System.Text; using System.Windows; using System.Windows.Input; using System.Windows.Interop; namespace UnManaged { public class HotKey : IDisposable { private static Dictionary_dictHotKeyToCalBackProc; [DllImport("user32.dll")] private static extern bool RegisterHotKey(IntPtr hWnd, int id, UInt32 fsModifiers, UInt32 vlc); [DllImport("user32.dll")] private static extern bool UnregisterHotKey(IntPtr hWnd, int id); public const int WmHotKey = 0x0312; private bool _disposed = false; public Key Key { get; private set; } public KeyModifier KeyModifiers { get; private set; } public Action Action { get; private set; } public int Id { get; set; } public HotKey(Key k, KeyModifier keyModifiers, Action action, bool register = true) { Key = k; KeyModifiers = keyModifiers; Action = action; if (register) { Register(); } } public bool Register() { int virtualKeyCode = KeyInterop.VirtualKeyFromKey(Key); Id = virtualKeyCode + ((int)KeyModifiers * 0x10000); bool result = RegisterHotKey(IntPtr.Zero, Id, (UInt32)KeyModifiers, (UInt32)virtualKeyCode); if (_dictHotKeyToCalBackProc == null) { _dictHotKeyToCalBackProc = new Dictionary (); ComponentDispatcher.ThreadFilterMessage += new ThreadMessageEventHandler(ComponentDispatcherThreadFilterMessage); } _dictHotKeyToCalBackProc.Add(Id, this); Debug.Print(result.ToString() + ", " + Id + ", " + virtualKeyCode); return result; } public void Unregister() { HotKey hotKey; if (_dictHotKeyToCalBackProc.TryGetValue(Id, out hotKey)) { UnregisterHotKey(IntPtr.Zero, Id); } } private static void ComponentDispatcherThreadFilterMessage(ref MSG msg, ref bool handled) { if (!handled) { if (msg.message == WmHotKey) { HotKey hotKey; if (_dictHotKeyToCalBackProc.TryGetValue((int)msg.wParam, out hotKey)) { if (hotKey.Action != null) { hotKey.Action.Invoke(hotKey); } handled = true; } } } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!this._disposed) { if (disposing) { Unregister(); } _disposed = true; } } } [Flags] public enum KeyModifier { None = 0x0000, Alt = 0x0001, Ctrl = 0x0002, NoRepeat = 0x4000, Shift = 0x0004, Win = 0x0008 } }
使用示例:
_hotKey = new HotKey(Key.F9, KeyModifier.Shift | KeyModifier.Win, OnHotKeyHandler); private void OnHotKeyHandler(HotKey hotKey) { SystemHelper.SetScreenSaverRunning(); }
这个解决方案提供了一个HotKey类,用户可以使用该类来注册全局快捷键,并定义相应的操作。用户可以根据自己的需求修改和扩展该类。
问题的出现原因:
- 注册全局热键可以干扰用户的操作系统,用户不希望应用程序干扰他们的操作系统。
解决方法:
- 在App.xaml.cs文件中,重写OnStartup方法,并通过EventManager.RegisterClassHandler方法注册一个PreviewKeyUpEvent事件处理程序。
- 在OnWindowKeyUp方法中,可以使用e.Key和Keyboard.Modifiers来处理按键事件。
- 这种方法只在应用程序中有效,并且在应用程序关闭时会自动移除注册。
代码示例:
protected override void OnStartup(StartupEventArgs e) { EventManager.RegisterClassHandler(typeof(Window), Window.PreviewKeyUpEvent, new KeyEventHandler(OnWindowKeyUp)); } private void OnWindowKeyUp(object source, KeyEventArgs e) { //Do whatever you like with e.Key and Keyboard.Modifiers }
以上方法简单易行,并且提供了用户友好的方式来注册热键。同时,还指出了注册操作系统级别快捷键的不好之处。