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

发布于 2024-11-08 14:52:11 字数 1007 浏览 6 评论 0原文

我的应用程序中几乎没有“热键”。所有“热键”序列在应用程序范围内都是唯一的(例如 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 我将能够在其中编辑它一个地方而不是搜索和替换工具..

I have few "hotkeys" in my application. All "hotkeys" sequences are unique in application scope (so for example F12 key will always fire the same single task). In few places there are handled like here:

        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();
        }

But I have idea to keep all keyboard shortcuts used in my app in one place.
I was thinking to put them in Constants.cs file:

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

But how to achieve this in case of this sequence:
e.Modifiers == Keys.Shift && e.KeyCode == Keys.Up

All advices how to store all application "hotkeys" definitions in one place are welcome :) So one day if I need to change Keys.F12 to Keys.F10 I will be able to just edit it in one place instead of search&replace tool..

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

想你只要分分秒秒 2024-11-15 14:52:11

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

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() 方法中执行此操作,也可以添加一些代码以从配置文件加载定义。

A complete solution to this would be to use some form of Command Management, where you define application-wide commands and (optionally) assign hot-keys to them.

WPF has support for Command Management built-in, and you can roll out your own without too much effort.

If you don't want to go down that route, you can create an application-wide filter for key messages, and work with those.

Below is code for a KeyStore class. It's a singleton class that acts as a message filter for keys.

/// <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>();
    }
}

To use it, first assign the key filter to the Application class. In your Main() method (probably in the Program.cs file), add the following line before Application.Run():

Application.AddMessageFilter(KeyStore.Instance);

Make sure this line is inserted before Application.Run(). This registers the KeyStore as a key handler.

Then, you can add keys to the KeyStore anywhere you want, for example in the Form_Load of your main form:

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

This registers two combinations: F12 and Control+S.

Then, register an event handler so you can capture the CloseApp and Save key presses.

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

In my example code, I used MessageBox.Show() to prove that the event was fired:

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

You can register or unregister event handlers at will, when forms are opened and closed for example, or have application-wide handlers. It's up to you.

Because the KeyStore is a singleton, you can add the key definitions from anywhere in your application. You can do it in the Main() method, before calling Application.Run(), or you can add some code to load definitions from a configuration file.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文