65.9K
CodeProject 正在变化。 阅读更多。
Home

WinForms 和 WPF 中的全局快捷方式

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.97/5 (42投票s)

2012 年 8 月 17 日

MIT

14分钟阅读

viewsIcon

129605

downloadIcon

8647

允许应用程序处理热键和执行其他键盘操作的库

引言

有时,您的窗体或窗口(取决于您是构建 WinForm 还是 WPF 应用程序)可能需要响应热键或快捷键(本文中可互换使用),而不管应用程序是否处于焦点状态或在后台运行。

此外,如果您想在应用程序内部或外部注册多个热键,事情会变得有点棘手。在本文中,我们将创建一个库,该库将允许应用程序处理热键和执行其他键盘操作。

术语

  • HotKeys:用户在键盘上按下的可能需要您的应用程序处理的按键。
  • LocalHotKeys:一个管理应用程序内常规热键的类;它们具有按键和/或修饰键(LocalHotkeys 的修饰键是可选的),它们仅在应用程序获得焦点时才有效。例如 Control + C(在大多数情况下用于复制)
  • GlobalHotKeys:一个管理应用程序外部热键的类,无论您的窗体或窗口是否有焦点,或者是否在后台运行。它们是常规热键,具有按键和修饰键,并且只要应用程序正在运行(无论它是否有焦点、最小化还是在后台运行)都会被处理。例如 Window + L(用于锁定计算机)
  • ChordHotKeys:一类高级 LocalHotKeys,更像是两个 LocalHotKeys;BASE 和 CHORD。Base 必须具有 BaseKey 和 BaseModifier,它们在按下时启动 Chord,Chord 具有一个按键和一个可选的 Modifier。例如 Control + KControl + D(在 Visual Studio IDE 中用于缩进代码),在这种情况下,Control + K 是 base,而 Control + D 是 chord 的热键。与 LocalHotKeys 一样,它们仅在应用程序获得焦点时才有效。
  • HotKeyManager:此类管理上述类;它跟踪它们的更改并在关联的热键在键盘上被按下时引发事件。此外,HotKeyManager 类可以监听键盘的所有按键,将它们报告给我们的应用程序,还可以模拟按键。
    * 注册 HotKey 意味着将 Hotkey 订阅到 HotKeyManager。
  • HotKeyControl:一个 UserControl,允许用户通过输入设置热键。

    WinForm 的 HotKey 控件

    WPF 的 HotKeyControls
    * HotKeyControl 不将 WindowKey 视为修饰键,而是将其视为 Key 枚举中的一个键。

背景

在我开始使用 .NET 之前,我想禁用键盘上的某些按键,特别是 Control + Alt + Delete,用于我创建的基于计算机的测试应用程序。我查找了以编程方式禁用它们的方法,但一无所获,直到我使用了 ScanCodeMap。(现在不要太兴奋,HotKeyManager 也做不到这一点)唯一的缺点是我必须重新启动 Windows 才能启用或禁用这些键。我还在 .NET 中遇到了实现全局快捷键并使按键可更改的问题。创建此库是为了加快速度,让您可以轻松地对键盘进行操作,并同时管理大量的动态热键,就像在 VLC 播放器 和其他应用程序中一样。

源文件

WPF 的 HotKeyManager 类拥有 WinForm 等效功能中的大部分(如果不是全部)功能,并且虽然可能很容易在同一个项目中为这两个平台创建类,但是,如果您正在 WinForm 中创建一个程序并想引用 DLL,您还需要导入

  • PresentationCore
  • PresentationFramework
  • WindowsBase

它们是 WPF 的核心库,如果您正在 WPF 中创建一个程序,您还需要导入

  • System.Windows.Forms
  • System.Drawing.

版本取决于项目编写时使用的版本,这将使您的项目充斥着不必要的引用,这就是为什么我将库编写在两个单独的项目中,并使代码用法完全相同。源文件(C# 但与 VB 兼容)包含 5 个项目:一个用于 WinForm 的 C# 2.0 库,一个用于 WPF 的 C# 3.0 和 4.0 库(这只是因为我想为 WPF 创建一个更好的控件),以及两个演示项目,每个项目一个用于 WinForm 和 WPF。

* 我正在为 WinForm 创建另一个库,将类转换为组件,以便它们可以在设计时添加和验证,而不是在代码中编写它们。

开始工作

快捷键由一个或多个修饰键和一个单独的按键组成。修饰键是:Shift 键、Alt 键、Control 键和 Window 键(这不完全是修饰键,并且仅在创建 GlobalShortcuts 时使用),请注意,这与左键或右键无关,WinForm 中的右 Alt 键发送“Control + Alt”,WPF 发送 LeftCtrl,但经过一些调整后,发送的按键与 WinForm 相同。

添加了对 Microsoft.VisualBasic 的引用,我们将使用它来执行一些字符串操作和获取一些键盘按键状态。

我们定义了一个修饰键 enum 并用 flags 属性标记它,该属性指定 enum 可以被视为位字段,第二个 enum 定义了我们希望何时引发本地热键事件。

//First, we want to define the Modifier for the GlobalHotkeys and LocalHotKeys.
   
#region **Modifiers and constants.
    /// <summary>Defines the key to use as Modifier.
    /// </summary>
    [Flags]
    public enum Modifiers
    {
        /// <summary>Specifies that the key should be treated as is, without any modifier.
        /// </summary>
        
        NoModifier = 0x0000,
        
        /// <summary>Specifies that the Accelerator key (ALT) is pressed with the key.
        /// </summary>
        Alt = 0x0001,
        /// <summary>Specifies that the Control key is pressed with the key.
        /// </summary>
        Ctrl = 0x0002,
        /// <summary>Specifies that the Shift key is pressed with the associated key.
        /// </summary>
        Shift = 0x0004,
        /// <summary>Specifies that the Window key is pressed with the associated key.
        /// </summary>
        Win = 0x0008
    }
 
    public enum RaiseLocalEvent
    {
        OnKeyDown = 0x100, //Also 256. Same as WM_KEYDOWN.
        OnKeyUp = 0x101 //Also 257, Same as WM_KEYUP.
    }
#endregion 

WPF 已经在 System.Windows.Input 命名空间中拥有自己的修饰键,称为 ModifierKeys,并且还设置了 flags 属性,因此这不需要。

flags 属性允许通过 XOR 组合修饰键,因此您可以在 WinForm 中写一个语句,例如

Modifiers modifier = Modifiers.Control | Modifiers.Shift;
Dim modifier as Modifiers = Modifiers.Control Xor Modifiers.Shift

而在 WPF 中

ModifierKeys modifier = ModifierKeys.Control | ModifierKeys.Shift;
Dim modifier as ModifierKeys = ModifierKeys.Control Xor ModifierKeys.Shift

这意味着修饰键是 ‘Control + Shift’

RaiseLocalEvent enum 将确定何时引发 LocalHotKey 事件,是在按键按下时 (OnKeyDown) 还是在按键释放时 (OnKeyUp)。

public class HotKeyAlreadyRegisteredException : Exception
public class HotKeyUnregistrationFailedException : Exception
public class HotKeyRegistrationFailedException : Exception
public class HotKeyInvalidNameException : Exception

HotKeyAlreadyRegisteredException:顾名思义,当尝试使用 HotKeyManager 重新注册热键(具有相同的名称、按键和/或修饰键)时,会抛出此异常。对于 GlobalHotKeys,当 global hotkey 的按键和修饰键被另一个应用程序使用时,会抛出此异常。例如,尝试注册 Window + L 会引发此异常。使用库时,尝试使用被 LocalHotKey 使用的基键和基修饰键注册 ChordHotKey 会抛出 HotKeyAlreadyRegisteredException,同样,尝试将具有已被注册为 ChordHotKey 的基键和基修饰键的按键和修饰键注册为 LocalHotKey 也会抛出相同的异常。优先顺序由先注册的 HotKey 决定。

HotKeyUnregistrationFailedException:当无法注销 HotKey 时抛出此异常。HotKeyRegistrationFailedException 也是如此,当无法注册 HotKey 时抛出,当您尝试注册 Control + Escape 等热键时也会发生。

HotKeyInvalidNameException:当您尝试注册一个名称无效的 HotKey 时抛出此异常;在此库中,hotkey 更像控件,您需要为每个 hotkey 分配一个名称,就像在 Visual Studio 中一样,有效的 HotKey 名称不能以数字开头或包含空格。名称在函数中进行检查。

        public static bool IsValidHotkeyName(string text)
        {
            //If the name starts with a number, contains space or is null, return false.
            if (string.IsNullOrEmpty(text)) return false;

            if (text.Contains(" ") || char.IsDigit((char)text.ToCharArray().GetValue(0)))
                return false;

            return true;
        }

当然,您可以根据需要更改此设置。

HotKey 共享类

这是一个 static 类,它有助于执行一些函数,例如检查 HotKey 控件的名称(如前所述),将 string 分割成相应的按键和修饰键(对我们的 HotKeyControl 有用)以及反向操作。它还包含一个用于枚举 ModifiersstructHotKeyControl 将接受字符串形式的热键,除非我们将其分割成相应的按键和修饰键,否则使用起来并不方便,ParseShortcut 函数允许我们实现这一点。

该类具有 static 函数 ParseShortcutCombineShortcut。前者允许您将快捷键,例如“Control + Alt + T”剥离成相应的修饰键(Control,Alt)和按键(T),而后者则执行相反的操作。

ParseShortcut 函数是一个对象数组,它在下边界返回 Hotkey string 的 Modifier,在上边界返回 Key

函数 public static object[] ParseShortcut(string text) 有一个重载。

        public static object[] ParseShortcut(string text, string separator)
        {
            bool HasAlt = false; bool HasControl = false; bool HasShift = false; 
                                 bool HasWin = false;

            Modifiers Modifier = Modifiers.None;		//Variable to contain modifier.
            Keys key = 0;                               //The key to register.

            string[] result;
            string[] separators = new string[] { separator };
            result = text.Split(separators, StringSplitOptions.RemoveEmptyEntries);

            //Iterate through the keys and find the modifier.
            foreach (string entry in result)
            {
                //Find the Control Key.
                if (entry.Trim() == Keys.Control.ToString())
                {
                    HasControl = true;
                }
                //Find the Alt key.
                if (entry.Trim() == Keys.Alt.ToString())
                {
                    HasAlt = true;
                }
                //Find the Shift key.
                if (entry.Trim() == Keys.Shift.ToString())
                {
                    HasShift = true;
                }
                //Find the Window key.
                if (entry.Trim() == Keys.LWin.ToString())
                {
                    HasWin = true;
                }
            }

            if (HasControl) { Modifier |= Modifiers.Control; }
            if (HasAlt) { Modifier |= Modifiers.Alt; }
            if (HasShift) { Modifier |= Modifiers.Shift; }
            if (HasWin) { Modifier |= Modifiers.Win; }

            KeysConverter keyconverter = new KeysConverter();
            key = (Keys)keyconverter.ConvertFrom(result.GetValue(result.Length - 1));

            return new object[] { Modifier, key };
        }

请注意,该函数使用 KeysConverter 类,它是 System.Windows.Forms.Keys enumTypeConverter,用于将 string 转换为其 Key enum 表示。

用法

object[] Result = ParseShortcut(“Control + Shift + A”, “ + ”);
Modifiers modifier = (Modifiers)Result[0];                          //Control | Shift
Keys key = (Keys)Result[1];                                        //Keys.A
在VB中
Dim Result() as Object = ParseShortcut(“Control + Shift + A”, “ + “)
Dim modifier as Modifiers = CType(Result(0), Modifiers)           'Control Xor Shift
Dim key as Keys = CType(Result(0), Keys)                          'Keys.A

为了反转这个过程,我们使用 CombineShortcut 函数

public static string CombineShortcut(Modifiers mod, Keys key)
{
    string hotkey = "";
    foreach (Modifiers a in new HotKeyShared.ParseModifier((int)mod))
    {
        hotkey += a.ToString() + " + ";
    }

    if (hotkey.Contains(Modifiers.None.ToString())) hotkey = "";
    hotkey += key.ToString();
    return hotkey;
}

用法

Modifiers modifier = Modifiers.Control | Modifiers.Shift;
CombineShortcut(modifier, Keys.A);                         //Control + Shift + A
Dim modifier as Modifiers = Modifiers.Control Xor Modifiers.Shift
CombineShortcut(modifier, Keys.A)                          'Control + Shift + A

HotKey 控件

HotKeyControl 是一个 UserControl,它扩展了 TextBox 控件以捕获用户在激活时按下的按键。它添加了 HotKeyIsSet 事件,当用户设置了 HotKey 时会引发该事件,并添加了 UserKeyUserModifer 属性(在设计视图中不可见),它们返回用户设置的按键和修饰键,以及一个 ForceModifiers 属性(在设计视图中可见),该属性指定当 hotkey 设置为 true 时应强制用户输入修饰键,否则接受所有 hotkey

对于 WinForm

HotKey 控件利用 textboxKeyDownKeyUp 事件来获取用户按下的按键。并使用重置按钮清除输入的 HotKey

void HotKeyControl_KeyDown(object sender, KeyEventArgs e)
{
    e.SuppressKeyPress = true; //Suppress the key from being processed 
                               //by the underlying control.
    this.Text = string.Empty;  //Empty the content of the textbox
    KeyisSet = false; //At this point the user has not specified a shortcut.

    //Make the user specify a modifier. Control, Alt or Shift.
    //If a modifier is not present then clear the textbox.
    if (e.Modifiers == Keys.None && forcemodifier)
    {
        MessageBox.Show("You have to specify a modifier like 'Control', 'Alt' or 'Shift'");
        this.Text = Keys.None.ToString();
        return;
    }

    //A modifier is present. Process each modifier.
    //Modifiers are separated by a ",". So we'll split them and write each one to the textbox.
    foreach (string modifier in e.Modifiers.ToString().Split(new Char[] { ',' }))
    {
        if (modifier != Keys.None.ToString())
            this.Text += modifier + " + ";
    }

    //KEYCODE contains the last key pressed by the user.
    //If KEYCODE contains a modifier, then the user has not entered a shortcut. 
    //Hence, KeyisSet is false
    //But if not, KeyisSet is true.
    if (e.KeyCode == Keys.ShiftKey | e.KeyCode == Keys.ControlKey | e.KeyCode == Keys.Menu)
    {
        KeyisSet = false;
    }
    else
    {
        this.Text += e.KeyCode.ToString();
        KeyisSet = true;
    }
}

KeyUp 事件通过检查变量 KeyisSet 来确定是否已设置 HotKey,如果为 true,则引发 HotKeyIsSet 事件或清除控件。

void HotKeyControl_KeyUp(object sender, KeyEventArgs e)
{
    //On KeyUp if KeyisSet is False then clear the textbox.
    if (KeyisSet == false)
    {
        this.Text = Keys.None.ToString();
    }
    else
    {
        if (HotKeyIsSet != null)
        {
            var ex = new HotKeyIsSetEventArgs(UserKey, UserModifier);
            HotKeyIsSet(this, ex);
            if (ex.Cancel)
            {
                KeyisSet = false;
                this.Text = Keys.None.ToString();
            }
        }
    }
}

对于 WPF

源文件包含两个 HotKey 控件,一个构建在 .NET Framework 3.0 中,另一个构建在 .NET Framework 4.0 中。

HotKeyControl 使用 PreviewKeyDown 事件和挂钩来获取用户按下的按键。

public HotKeyControl()
{
    this.GotFocus += new RoutedEventHandler(HotKeyControl_GotFocus);   //Attach the hook here.
    this.hook = new HwndSourceHook(WndProc);                    //Hook to to Windows messages.
    this.LostFocus += new RoutedEventHandler(HotKeyControl_LostFocus); //Remove the hook here.
    this.ContextMenu = null;                                           //Disable shortcuts.
    Text = Keys.None.ToString();
    this.IsReadOnly = true;
    this.PreviewKeyDown += new KeyEventHandler(HotKeyControl_PreviewKeyDown);
}
* HotKeyControl 不将 Window 键视为修饰键,而是将其视为一个键。

HotKeys

GlobalHotkey 类实现了 INotifyPropertyChanged,它会在 Key、ModifierEnabled 属性更改时通知 HotKeyManager

它还与 LocalHotKeyChordHotKey 类类似,实现了 IEquatableISerializable

当按键在键盘上被按下时,HotKeys 会引发 HotKeyPressed 事件。当 GlobalHotKeys 被注册时,它们会被赋予一个 id,在按下时会返回该 id

    [Serializable]
    public class GlobalHotKey : INotifyPropertyChanged, ISerializable, 
                                IEquatable<GlobalHotKey> { }

    [Serializable]
    public class LocalHotKey : ISerializable, IEquatable<LocalHotKey>, 
                               IEquatable<ChordHotKey> { }

    [Serializable]
    public class ChordHotKey : ISerializable, IEquatable<ChordHotKey><chordhotkey>, 
              IEquatable<LocalHotKey><localhotkey> { }</localhotkey></chordhotkey>
* HotKeys 必须先与 HotKeyManager 注册才能工作(引发事件)。

HotKeyManager

WinForm 中的 HotKeyManager 类将管理 GlobalHotKeyLocalHotKeyChordHotKey 类,实现

  • IMessageFilter:允许类接收 Windows 消息回调
  • IDisposable:将释放所有资源,并注销所有 HotKeys

该类将通过添加

Application.AddMessageFilter(this);

在构造函数中,并通过添加

Application.RemoveMessageFilter(this);

在析构函数中接收 Windows 消息。

然后该类将通过添加函数接收消息,这是实现 IMessageFilter 的结果。

public bool PreFilterMessage(ref Message m) { }

对于 **WPF**,会向该类添加一个 Hook,以允许它接收 Windows 消息。

我将 WinForm 的 Keys enum 复制到了 WPF 类中,以便支持 LocalChordHotKeys,因为 Windows 仍然向 WPF 应用程序发送与 WinForm 相同的按键消息。

this.hook = new HwndSourceHook(WndProc);                     //Hook to Windows messages.
this.hwndSource = (HwndSource)HwndSource.FromVisual(window); // new WindowInteropHelper
                                                             // (window).Handle 
                                                             // If the InPtr is needed.
this.hwndSource.AddHook(hook);

然后该类将通过函数接收 Windows 消息。

private IntPtr WndProc
    (IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { }
在源文件中,HotKeyManager 没有空构造函数,因为我希望您提供一个窗体或窗口(根据情况),因为 Windows 需要注册或注销 GlobalHotKeys 所属的窗体或窗口的句柄。如果您想在服务中使用此库,或者您不打算使用 GlobalHotKeys,您可以添加一个空构造函数并进行必要的更改,该库仍然可以正常工作。

HotKeyManager 会在其注册的窗体或窗口关闭时自动处置自身,您无需在您的应用程序中重新处置,如果您这样做也不会抛出异常。它也可以被禁用,它仍然接收消息,只是不对它们做任何事情,在 WinForm 中,您可以将 HotKeyManager 设置为在显示另一个窗体(可能是对话框)时暂时禁用自己,因为它仍然会引发事件,将 DisableOnManagerFormInactive 设置为 true

现在,当您的应用程序中的某个按键被按下时,Windows 会将包含有关被按下按键和状态(是按住还是已释放)的信息的消息发送到我们的类,因为我们已经订阅了它们。

然而,为了获取按键按下时的修饰键,我引用了 Microsoft.VisualBasic 以加快速度。您可以随时按如下方式获取键盘上按下的修饰键

Microsoft.VisualBasic.Devices.Keyboard UserKeyBoard = 
                                 new Microsoft.VisualBasic.Devices.Keyboard();
bool AltPressed = UserKeyBoard.AltKeyDown;
bool ControlPressed = UserKeyBoard.CtrlKeyDown;
bool ShiftPressed = UserKeyBoard.ShiftKeyDown;
您可以看到,Window 键不被视为修饰键,而是被视为 Key,要获取 Window 键的状态,您可以使用
            short ret = Win32.GetKeyState(0x5b); //Get the state of the Window key.
            if ((ret & 0x8000) == 0x8000) LocalModifier |= Modifiers.Window;

当键盘上的任何按键被按下时,HotKeyManager 会遍历所有注册到它的 LocalHotKeysChordHotKeys,并为找到的那些引发事件。

查找 LocalHotKeys

     Keys keydownCode = (Keys)(int)m.WParam & Keys.KeyCode; //Get the key that was pressed.
      LocalHotKey KeyDownHotkey = LocalHotKeyContainer.Find
      (
          delegate(LocalHotKey d)
          {
           return ((d.Key == keydownCode) && (d.Modifier == LocalModifier) 
                  && (d.WhenToRaise == RaiseLocalEvent.OnKeyDown));
          }
      );
LocalHotKey KeyDownHotkey = (from items in LocalHotKeyContainer
                where items.Key == keydownCode && items.Modifier == LocalModifier
                where items.WhenToRaise == RaiseLocalEvent.OnKeyDown
                select items).FirstOrDefault();

* 此搜索在未找到任何内容时返回 null

查找 ChordHotKeys

当找不到 LocalHotKey 时,Manager 会检查任何已注册 ChordHotKey 的基键和修饰键是否与按下的 Key 匹配,这就是为什么您不能为任何其他 localhotkey 设置相同的基键和修饰键。如果找到一个,它会进入 ChordMode,并等待另一个按键按下,忽略修饰键,如果第二个按下的按键与任何 chord 的 chordkey 和修饰键匹配,它会为该 chord 引发事件,否则会离开 ChordMode 并发出类似 Visual Studio 的声音。

查找 GlobalHotKeys

要注册 GlobalHotKeys,没有内置功能允许这样做,但它内置于 Win32 API 中,.NET 提供 一种调用非本机库的方法。我们感兴趣的方法定义在 User32.dll 中,即 RegisterHotKeyUnRegisterHotKey

RegisterHotKey 和 UnRegisterHotKey

现在,定义重要的方法:允许我们注册快捷键的 static 函数。

[DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int RegisterHotKey(IntPtr hwnd, int id, int modifiers, int key);
 
[DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int UnregisterHotKey(IntPtr hwnd, int id);

请注意,我们没有提供方法体。该方法定义在 user32.dll 中,我们只是为我们的应用程序提供了一种直接调用该方法的方式。

  • hWnd 指的是窗体或窗口句柄
  • idhotkey 的唯一标识符
  • modifiers 是您希望与按键一起按下的修饰键(shift/alt/ctrl/win)的整数表示
  • keyhotkey 的虚拟键码

当按下 GlobalHotKey 时,Windows 会在 wParam 中发送注册时分配给 GlobalHotKey 的 ID,然后可以使用此 ID 来搜索所有 GlobalHotKeys,就像我们为 LocalHotKeys 所做的那样。

其他函数

HotKeyManager 还支持枚举,您可以像这样迭代特定的热键;全局、本地或 chord

string message = "Global HotKeys.\n";

foreach (GlobalHotKey gh in MyHotKeyManager.EnumerateGlobalHotKeys)
{
     message += string.Format("{0}{1}", Environment.NewLine, gh.FullInfo());
}

message += "\n\nLocal HotKeys.\n";

foreach (LocalHotKey lh in MyHotKeyManager.EnumerateLocalHotKeys)
{
     message += string.Format("{0}{1}", Environment.NewLine, lh.FullInfo());
}

message += "\n\nChord HotKeys.\n";

foreach (ChordHotKey ch in MyHotKeyManager.EnumerateChordHotKeys)
{
      message += string.Format("{0}{1}", Environment.NewLine, ch.FullInfo());
}

MessageBox.Show(message, "All HotKeys registered by this app.", 
                MessageBoxButtons.OK, MessageBoxIcon.Information);

这将使迭代更容易,因为我们可以像这样直接迭代所有 ChordHotKeys

而不是实现 IEnumerable<ChordHotKey> 并像这样进行迭代,这将需要使用命名空间 System.Collections.Generic

foreach (ChordHotKey ch in (IEnumerable<ChordHotKey>)MyHotKeyManager)
{
      message += string.Format("{0}{1}", Environment.NewLine, gh.FullInfo());
}

HotKeyManager 还利用 Win32 API 来获取所有键盘按键,即使您的应用程序没有获得焦点,并且可以禁用它们。

KeyboardHookEventHandler keyboardhandler = (sender, handler) =>
        {
            if (handler.Modifier == KeyboardHookEventArgs.modifiers.Shift)
                { handler.Handled = true; }
            switch (handler.Key)
            {
                case Keys.A:
                case Keys.E:
                case Keys.I:
                case Keys.O:
                case Keys.U:
                    handler.Handled = true;
                    return;
            }
        };

上面的代码禁用了键盘上的元音键,但在按下 Shift 键时禁用了所有键。

HotKeyManager,使用 Win32API,还可以模拟按键,这里,我们模拟按下 Control + A

            MyHotKeyManager.SimulateKeyDown(Keys.Control);           //Hold down the Control Key
            MyHotKeyManager.SimulateKeyPress(Keys.A);                //Press the A key
            MyHotKeyManager.SimulateKeyUp(Keys.Control);             //Release the Control Key

HotKey 管理器通过注销类注册的所有 GlobalHotKeys,从所有键盘消息中取消挂钩该类,通过方法 HotKeyManager.Dispose 进行处置。

for (int i = GlobalHotKeyContainer.Count - 1; i >= 0; i--)
{
     RemoveGlobalHotKey(GlobalHotKeyContainer[i]);
}

LocalHotKeyContainer.Clear();
ChordHotKeyContainer.Clear();
KeyBoardUnHook();

Using the Code

现在,我们像这样向 HotKeyManager 添加 HotKey

 GlobalHotKey ghkNotepad = new GlobalHotKey("ghkNotepad", Keys.N, 
                                             Modifiers.Control | Modifiers.Shift);
 LocalHotKey lhkNewHotkey = new LocalHotKey("lhkNewHotKey", Keys.A);
 ChordHotKey chotCmd = new ChordHotKey("chotCmd", Keys.C, 
                                        Modifiers.Alt, Keys.P, Modifiers.Alt);
 
 MyHotKeyManager.AddGlobalHotKey(ghkNotepad);
 MyHotKeyManager.AddLocalHotKey(lhkNewHotkey);
 MyHotKeyManager.AddChordHotKey(chotCmd);
Dim ghkNotepad as new GlobalHotKey("ghkNotepad", Keys.N, Modifiers.Control Xor Modifiers.Shift)
Dim lhkNewHotkey as new LocalHotKey("lhkNewHotKey", Keys.A)
Dim chotCmd as new ChordHotKey("chotCmd", Keys.C, Modifiers.Alt, Keys.P, Modifiers.Alt)

MyHotKeyManager.AddGlobalHotKey(ghkNotepad)
MyHotKeyManager.AddLocalHotKey(lhkNewHotKey)
MyHotKeyManager.AddChordHotKey(chotCmd)

对于 HotKeyControl,用户可以使用该控件设置快捷键,然后您可以从 HotKeyControl.UserKeyHotKeyControl.UserModifier 获取关联的按键和修饰键。

HotKeyManager 还可以模拟按键并向 Keyboard 添加挂钩。

您可以通过将按键的 Handled 属性设置为 true 来禁用键盘按键,唯一似乎遗漏的按键组合是 Control + Alt + Delete

下载源文件以访问完整代码。

关注点

  • 当您尝试在 InitializeComponent 方法中使用 WPF 创建新的 HotKeyManager 时,可能会导致您的窗口崩溃,最好在窗口已加载时进行此操作。

  • Library 还可以扩展为组件,以便可以在设计时和运行时添加和验证 HotKeys,这将为您节省大量代码。我会尝试上传我拥有的示例。

如果您有任何疑问,请留下评论。源文件中的示例如下所示

历史

  • 2012 年 8 月 17 日:初始版本
© . All rights reserved.