c# - 用户按键设置热键的简单方法。显示热键文本,保存虚拟键码

标签 c# winforms

不确定我对标题的解释是否足够好,但我想让一个人按任意键,然后我可以存储该键代码供以后使用,但更重要的是,我想直观地显示他们选择的键。有点像游戏中的键盘设置类型。

我想知道是否有任何公共(public)类或其他东西可以减轻为每个键编码的麻烦。

最佳答案

有一个专门为此目的设计的 native Win32 控件,称为 Hot Key控制。您可能已经在 Windows shell 和其他应用程序中看到过它的使用。这就是我建议您使用的方法,而不是尝试自己重新发明轮子。

不幸的是,WinForms 没有提供此控件的包装器。这意味着您要么必须自己编写,要么满足于 someone else's implementation of a similar type of control .

编辑:或者使用这个快速拼凑在一起的 .NET 包装器来实现热键控件。整个公共(public)接口(interface)是 KeyData 属性,其工作方式与 KeyEventArgs 的同名属性类似。类(class)。 Text 属性(通过从 Control 继承而提供)不执行任何操作,但可以重载以返回所选热键的 pretty-print 版本。此外, native 控件的功能 HKM_SETRULES消息未执行;如果您需要该功能,则需要自己添加代码。

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

internal static class NativeMethods
{
   internal const string HOTKEY_CLASS = "msctls_hotkey32";
   internal const int CS_GLOBALCLASS = 0x4000;

   internal const int WS_CHILD = 0x40000000;
   internal const int WS_VISIBLE = 0x10000000;
   internal const int WS_TABSTOP = 0x00010000;
   internal const int WS_EX_NOPARENTNOTIFY = 0x00000004;
   internal const int WS_EX_CLIENTEDGE = 0x00000200;
   internal const int WS_EX_LEFT = 0x00000000;
   internal const int WS_EX_LTRREADING = 0x00000000;
   internal const int WS_EX_RIGHTSCROLLBAR = 0x00000000;
   internal const int WS_EX_RIGHT = 0x00001000;
   internal const int WS_EX_RTLREADING = 0x00002000;
   internal const int WS_EX_LEFTSCROLLBAR = 0x00004000;

   internal const int HOTKEYF_SHIFT = 0x01;
   internal const int HOTKEYF_CONTROL = 0x02;
   internal const int HOTKEYF_ALT = 0x04;
   internal const int HOTKEYF_EXT = 0x08;

   internal const int WM_USER = 0x0400;
   internal const int HKM_SETHOTKEY = (WM_USER + 1);
   internal const int HKM_GETHOTKEY = (WM_USER + 2);
   internal const int HKM_SETRULES = (WM_USER + 3);

   [DllImport("user32.dll", CharSet = CharSet.Auto)]
   internal static extern IntPtr SendMessage(IntPtr hWnd,
                                             int msg,
                                             IntPtr wParam,
                                             IntPtr lParam);
}

class HotKey : Control
{
   public HotKey()
   {
      base.SetStyle(ControlStyles.UserPaint
                     | ControlStyles.StandardClick
                     | ControlStyles.StandardDoubleClick
                     | ControlStyles.UseTextForAccessibility, false);
      base.SetStyle(ControlStyles.FixedHeight, true);
   }

   public Keys KeyData
   {
      get
      {
         IntPtr retVal = NativeMethods.SendMessage(Handle,
                                                   NativeMethods.HKM_GETHOTKEY,
                                                   IntPtr.Zero,
                                                   IntPtr.Zero);

         Keys keyCode = (Keys)(retVal.ToInt32() & 0xFF);

         int modifierFlags = (retVal.ToInt32() >> 8);
         Keys modifiers = Keys.None;
         if ((modifierFlags & NativeMethods.HOTKEYF_ALT) == NativeMethods.HOTKEYF_ALT)
            modifiers |= Keys.Alt;
         if ((modifierFlags & NativeMethods.HOTKEYF_CONTROL) == NativeMethods.HOTKEYF_CONTROL)
            modifiers |= Keys.Control;
         if ((modifierFlags & NativeMethods.HOTKEYF_SHIFT) == NativeMethods.HOTKEYF_SHIFT)
            modifiers |= Keys.Shift;

         return (keyCode | modifiers);
      }
      set
      {
         Keys keyCode = (value & (~Keys.Alt & ~Keys.Control & ~Keys.Shift));

         int modifierFlags = 0;
         if ((value & Keys.Alt) == Keys.Alt)
            modifierFlags |= NativeMethods.HOTKEYF_ALT;
         if ((value & Keys.Control) == Keys.Control)
            modifierFlags |= NativeMethods.HOTKEYF_CONTROL;
         if ((value & Keys.Shift) == Keys.Shift)
            modifierFlags |= NativeMethods.HOTKEYF_SHIFT;

         NativeMethods.SendMessage(Handle,
                                   NativeMethods.HKM_SETHOTKEY,
                                   (IntPtr)((modifierFlags << 8) | ((int)keyCode & 0xffff)),
                                   IntPtr.Zero);
      }
   }

   protected override CreateParams CreateParams
   {
      get
      {
         CreateParams cp = base.CreateParams;
         cp.ClassName = NativeMethods.HOTKEY_CLASS;
         cp.ClassStyle = NativeMethods.CS_GLOBALCLASS;
         cp.Style = NativeMethods.WS_CHILD | NativeMethods.WS_VISIBLE | NativeMethods.WS_TABSTOP;
         cp.ExStyle = NativeMethods.WS_EX_NOPARENTNOTIFY | NativeMethods.WS_EX_CLIENTEDGE;
         if (RightToLeft == RightToLeft.No ||
            (RightToLeft == RightToLeft.Inherit && Parent.RightToLeft == RightToLeft.No))
         {
            cp.ExStyle |= NativeMethods.WS_EX_LEFT
                            | NativeMethods.WS_EX_LTRREADING
                            | NativeMethods.WS_EX_RIGHTSCROLLBAR;
         }
         else
         {
            cp.ExStyle |= NativeMethods.WS_EX_RIGHT
                           | NativeMethods.WS_EX_RTLREADING
                           | NativeMethods.WS_EX_LEFTSCROLLBAR;
         }
         return cp;
      }
   }
}

关于c# - 用户按键设置热键的简单方法。显示热键文本,保存虚拟键码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17497533/

相关文章:

c# - 为什么按下后退按钮时 MvvmCross 创建一个新的 ViewModel

c# - WCF服务Process.Start在网络服务帐户下模拟为其他用户

c# - 如何知道一条线是否与矩形相交

c# - 从新表单实例中显示此表单

c# - 完全迁移到 WPF 项目的好处和麻烦

c# - 如何继承 DataRow 类以便继承的 DataTable 可以具有 DataTable.NewRow()

c# - 上传前如何重命名文件

c# - 在 C# 中模拟 StreamReader 以进行单元测试

c# - 加密 app.config 后无法识别的属性 'configProtectionProvider'

c# - 如何更改代码以检索 datagridview 中的特定列?