C# - System.Windows.Forms.Keys - 如何将应用程序热键保留在一处

2023-12-02

我的应用程序中几乎没有“热键”。所有“热键”序列在应用程序范围内都是唯一的(例如 F12 键将始终触发相同的单个任务)。在少数地方有这样的处理:

        if (e.Modifiers == Keys.Shift && e.KeyCode == Keys.Delete)
        {
             this.Close();
        }

        if (e.Modifiers == Keys.Shift && e.KeyCode == Keys.Up)
        {
            if (Program.PerformLogin())
            {
                frmConfigurationSetup frmSetup = new frmConfigurationSetup();
                frmSetup.Show();
            }
        }

        if (e.KeyCode == Keys.F12)
        {
            frmAbout formAbout = new frmAbout();
            formAbout.Show();
        }

但我有想法将我的应用程序中使用的所有键盘快捷键保留在一处。 我想将它们放入 Constants.cs 文件中:

    public const System.Windows.Forms.Keys ShowAboutForm = System.Windows.Forms.Keys.F12;

但在这种序列的情况下如何实现这一点: e.Modifiers == Keys.Shift && e.KeyCode == Keys.Up

欢迎所有关于如何将所有应用程序“热键”定义存储在一个地方的建议:) 因此,有一天,如果我需要将 Keys.F12 更改为 Keys.F10,我将能够在一处编辑它,而不是搜索和替换工具。


对此的完整解决方案是使用某种形式的命令管理,您可以在其中定义应用程序范围的命令并(可选)为其分配热键。

WPF 内置了对命令管理的支持,您可以毫不费力地推出自己的命令管理。

如果您不想走这条路,您可以为关键消息创建一个应用程序范围的过滤器,并使用它们。

下面是 KeyStore 类的代码。它是一个单例类,充当键的消息过滤器。

/// <summary>
/// The KeyStoreEventHandler is used by the KeyPress event of the KeyStore
/// class. It notifies listeners of a named key press.
/// </summary>
/// <param name="name">The name of the key.</param>
public delegate void KeyStoreEventHandler(string name);

class KeyStore : IMessageFilter
{
    // Interop
    [DllImport("user32.dll")]
    static extern short GetKeyState(Keys key);

    // Windows message constants
    private const int WM_KEYDOWN = 0x100;
    private const int WM_KEYUP = 0x101;

    // The singleton instance
    private static KeyStore s_instance = null;

    // The modifier keys
    private bool _shift = false;
    private bool _control = false;

    // The definitions
    private Dictionary<Keys, string> _definitions;

    // The KeyPressed Event
    public event KeyStoreEventHandler KeyPress;

    /// <summary>
    /// Adds a key definition to the store.
    /// </summary>
    /// <param name="name">The name of the key.</param>
    /// <param name="key">The key</param>
    /// <param name="modifiers">The modifiers (shift, control)</param>
    public void AddKeyDefinition(string name, Keys key, Keys modifiers)
    {
        Keys combined = key | modifiers;

        _definitions[combined] = name;
    }

    /// <summary>
    /// The filter message.
    /// </summary>
    public bool PreFilterMessage(ref Message m)
    {
        bool handled = false;
        Keys key = Keys.None;

        switch (m.Msg)
        {
            case WM_KEYUP:
                key = (Keys)m.WParam;
                handled = HandleModifier(key, false);
                break;

            case WM_KEYDOWN:
                key = (Keys)m.WParam;
                handled = HandleModifier(key, true);
                if (false == handled)
                {
                    // If one of the defined keys was pressed then we
                    // raise an event.
                    handled = HandleDefinedKey(key);
                }
                break;
        }

        return handled;
    }

    /// <summary>
    /// Compares a key against the definitions, and raises an event
    /// if there is a match.
    /// </summary>
    /// <param name="key">The key</param>
    /// <returns>True if the key was one of the defined key combinations.</returns>
    private bool HandleDefinedKey(Keys key)
    {
        bool handled = false;

        Keys combined = key;
        if (_shift) combined |= Keys.Shift;
        if (_control) combined |= Keys.Control;

        // If we have found a matching combination then we
        // raise an event.
        string name = null;
        if (true == _definitions.TryGetValue(combined, out name))
        {
            OnKeyPress(name);

            handled = true;
        }
        return handled;
    }

    /// <summary>
    /// Attempt to handle a modifier key, and return a boolean indicating if a modifier key was
    /// handled.
    /// </summary>
    /// <param name="key">The key</param>
    /// <param name="isDown">True if the key is pressed; False if it is released.</param>
    /// <returns>True if a modifier key was selected; False otherwise.</returns>
    private bool HandleModifier(Keys key, bool isDown)
    {
        bool handled = false;

        switch (key)
        {
            case Keys.RControlKey:
            case Keys.ControlKey:
                _control = isDown;
                handled = true;
                break;

            case Keys.RShiftKey:
            case Keys.ShiftKey:
                _shift = isDown;
                handled = true;
                break;
        }

        return handled;
    }

    /// <summary>
    /// Raises the KeyPress event.
    /// </summary>
    /// <param name="name">The name of the key.</param>
    private void OnKeyPress(string name)
    {
        // Raise event
        if (null != KeyPress) KeyPress(name);

        // Check if modifier keys were released in the mean time.
        _control =
            -127 == GetKeyState(Keys.ControlKey) ||
            -127 == GetKeyState(Keys.RControlKey);

        _shift =
            -127 == GetKeyState(Keys.ShiftKey) ||
            -127 == GetKeyState(Keys.RShiftKey);

    }

    /// <summary>
    /// Returns the singleton instance.
    /// </summary>
    public static KeyStore Instance
    {
        get
        {
            if (null == s_instance) 
                s_instance = new KeyStore();

            return s_instance;
        }
    }

    // The constructor is private because this is a singleton class.
    private KeyStore()
    {
        _definitions = new Dictionary<Keys, string>();
    }
}

要使用它,首先将关键过滤器分配给 Application 类。在 Main() 方法中(可能在 Program.cs 文件中),在 Application.Run() 之前添加以下行:

Application.AddMessageFilter(KeyStore.Instance);

确保此行插入到 Application.Run() 之前。这会将 KeyStore 注册为密钥处理程序。

然后,您可以将密钥添加到 KeyStore 中任何您想要的位置,例如在主表单的 Form_Load 中:

KeyStore.Instance.AddKeyDefinition("CloseApp", Keys.F12, Keys.None);
KeyStore.Instance.AddKeyDefinition("Save", Keys.S, Keys.Control);

这会注册两个组合:F12 和 Control+S。

然后,注册一个事件处理程序,以便您可以捕获 CloseApp 和 Save 按键。

KeyStore.Instance.KeyPress += new KeyStoreEventHandler(KeyStore_KeyPress);

在我的示例代码中,我使用 MessageBox.Show() 来证明该事件已被触发:

void KeyStore_KeyPress(string name)
{
    MessageBox.Show(String.Format("Key '{0}' was pressed!", name));
}

您可以随意注册或取消注册事件处理程序,例如打开和关闭表单时,或者拥有应用程序范围的处理程序。由你决定。

由于 KeyStore 是单例,因此您可以从应用程序中的任何位置添加密钥定义。您可以在调用 Application.Run() 之前在 Main() 方法中执行此操作,也可以添加一些代码以从配置文件加载定义。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# - System.Windows.Forms.Keys - 如何将应用程序热键保留在一处 的相关文章

  • 如何从 Azure Key Vault KeyBundle 创建 X509Certificate2 对象

    我正在使用 Azure Key Vault 来保护我们的密钥和机密 但我不确定如何使用通过 net SDK 检索到的 KeyBundle 如何创建 X509Certificate2 对象 当您在 KeyVault 中导入 创建证书时 会创建
  • 全球化自定义数字格式 - 可变小数点

    我正在尝试更改公司应用程序中现有的数字格式 以使其对国际用户更具可读性 这是一个股票交易应用程序 因此大多数股票价格的数字精确到小数点后 2 位 例如 gt 17 23 我们还可以得到精确到小数点后 4 位的价格变动 因此细价股票可能是 0
  • InfluxDB 2 介绍性示例不会向存储桶中插入任何数据

    安装 InfluxDB 2 后 它会显示一个网站 其中包含各种语言的示例代码 创建存储桶和具有 RW 权限的令牌并选择它们后 可以使用带有适当魔术字符串的代码片段 把它们放在一起我有这个 using System using System
  • libc++ 中短字符串优化的机制是什么?

    这个答案 https stackoverflow com a 10319672 1805388给出了短字符串优化 SSO 的高级概述 但是 我想更详细地了解它在实践中是如何工作的 特别是在 libc 实现中 字符串必须有多短才能符合 SSO
  • 如何在Windows窗体中平滑地重新绘制Panel

    如何将面板重漆成光滑的 我正在使用一个使面板无效的计时器 panel1 Invalidate 每 300 毫秒一次 然后panel1 Paint如果我向该面板添加图像 问题是它看起来像是在跳跃 我需要尽可能快地移动其上的一张图像 这是截屏问
  • 如何在 C++ 中创建动态整数数组?

    如何使用 C 创建动态整数数组new关键词 int main int size std cin gt gt size int array new int size delete array return 0 别忘了delete你分配的每个数
  • 如何使用现代 GCC 抑制“-fpermissive”错误?

    我正在尝试编译一些不合格的代码C 17 https en wikipedia org wiki C 2B 2B17 但我遇到了以下问题 pragma GCC diagnostic push pragma GCC diagnostic ign
  • 从 Silverlight 中的文件夹加载资源“.resx”

    我有一个多语言应用程序 客户想要按照他的意愿编辑 Resources resx 文件 我创建了 silverlight 项目并添加了一些文件 资源 resx 资源 en US resx1 资源 uk UA resx2 他们都有构建操作 嵌入
  • C 中的结构和联合,确定大小和访问成员

    All 这是一个关于 Unions 的例子 我觉得它令人困惑 struct s1 int a char b union struct char c long d long e var 考虑到char是1个字节 int是 2 个字节并且lon
  • 如何使用 mongo-cxx-driver 设置 Visual Studio 项目设置?

    我已经在 Windows 10 上成功构建了用于 C 的 MongoDB 驱动程序版本 3 0 3 CMAKE INSTALL PREFIX C mongo cxx driver 但我不知道如何在 Visual Studio 2015 中设
  • 上传带有附加信息的文件(Angular 8 到 C# Core 3)

    我终于弄清楚如何将文件从 Angular 8 前端上传到 C Net Core 3 0 后端 API 控制器 但为了获得我完全需要的内容 我还有一个类定义了用户设置的文件内容 例如标题行 列值等 也需要传入 在客户端 我只需创建一个 For
  • 代码契约确保 ReSharperExternalAnnotations

    有谁知道如何在 ReSharperExternalAnnotations 中添加 Code Contracts Ensures 它在最新的 v7 1 3 和最新的 v8 EAP 中都不存在 在任何自定义 xml 中也不存在 具体来说 它应该
  • C++11正则表达式匹配[重复]

    这个问题在这里已经有答案了 我正在尝试在 C 11 中进行相当简单的正则表达式匹配 使用 gcc 4 7 2 但我遇到了很多麻烦 尝试使用构建模式 std regex unquoted R regex s s regex 导致构造函数抛出一
  • IIS7.5 WCF 服务 - HTTP 错误 401.3(即使在添加 IIS_IUSRS 后)

    我们有使用 NT Authority Network Service 的网站 Response Write WindowsIdentity GetCurrent Name 该网站使用托管在 IIS 7 5 中的 WCF 服务 当我们浏览服务
  • 隐式构造函数和默认构造函数有什么区别?

    这是非常微不足道的 但是捷克语 我的母语 不区分隐式和默认 所以我对一些捷克语翻译感到困惑 隐式和默认构造函数或构造函数调用之间有什么区别 struct Test Test int n 0 您能用这些术语描述以下语句的作用吗 Test t1
  • C# 中 PHP 的快速解析

    我需要用 C 解析 PHP 文件 我们本质上要求另一个国家的一些开发人员上传 PHP 文件 上传后我们需要检查 php 文件并获取所有方法和类 函数等的列表 我想过使用正则表达式 但我无法确定一个函数是否属于一个类等 所以我想知道是否已经有
  • 如何在 MVC 中点击链接的主视图中渲染部分视图?

    我有像下面这样的控制器操作方法将从数据库返回所有详细信息 public ActionResult Index BusDataContext db new BusDataContext List
  • 简单的 C# 屏幕共享应用程序

    我希望用 C 创建一个非常基本的屏幕共享应用程序 无需远程控制 我只希望用户能够将他们的屏幕广播到网络服务器 我应该如何实施这个 任何指向正确方向的指针将不胜感激 它不需要很高的 FPS 甚至更新 5 秒左右就足够了 您认为每隔 5 秒上传
  • 在实体框架中对连接字符串进行硬编码

    我知道很多人认为对连接信息进行硬编码是一个坏主意 但我有一个特定的情况需要这样做 请不要贬低我 因为你认为这是一个坏主意 再次 非常具体的情况 使用下面的代码 我在 LINQ 语句上收到以下错误 底层提供程序在打开时失败 我已经独立测试了连
  • 向前声明类模板显式/部分专业化有什么意义?

    C 98 标准规定 temp class spec 部分专业化声明本身不能通过名称查找找到 如果显式专业化也是如此 则这会使类模板显式 部分专业化的前向声明不可见 temp class spec match 当在需要实例化该类的上下文中使用

随机推荐