检查是不是在 Winforms 中按下热键

Posted

技术标签:

【中文标题】检查是不是在 Winforms 中按下热键【英文标题】:Check if hot key pressed in Winforms检查是否在 Winforms 中按下热键 【发布时间】:2021-02-25 02:14:26 【问题描述】:

要获取热键Ctrl+A,我们可以在Form1_KeyDown中使用以下语句。

if (e.Modifiers == Keys.Control && e.KeyCode == Keys.A)

    MessageBox.Show("Test");

要捕获Ctrl+Alt+A,我们可以使用:

if (e.Control && e.Alt)

    if (e.KeyCode == Keys.A)
    
        // Your code goes here
    

问题是如何捕捉Ctrl+A+B这样的热键?

【问题讨论】:

您的意思是 Ctrl+A, CTRL+BCTRL+A 后跟 B,而 CTRL 键仍被按下 - 或者,CTRL 键尚未释放)。 @Jimi 仍然按下 在 WinForms 中没有简单的方法可以做到这一点。您必须保留布尔字典并跟踪按下的键。或者,您可以导入 WPF 运行时并将Keyboard.IsKeyDownKeyDown 事件结合使用。你也可以求助于 Win32 API 并使用 GetKeyState 这个“热键”是否应该只在您的应用程序中有效? 【参考方案1】:

这里有一些东西可以帮助您开始使用IMessageFilter。

这将在按下 Ctrl-A-B 时触发,而不是在释放时触发。它目前还会在按住这些键时重复触发。这可以通过混合中的另一个布尔变量来改变。这绝对不是完美的……

public partial class Form1 : Form
   

    public Form1()
    
        InitializeComponent();
    

    private MyFilter mf = new MyFilter();

    private void Form1_Load(object sender, EventArgs e)
    
        mf.Ctrl_A_B += Mf_Ctrl_A_B;
        Application.AddMessageFilter(mf);
    

    private void Mf_Ctrl_A_B()
    
        Console.WriteLine("Ctrl-A-B was held down!");
    



public class MyFilter : IMessageFilter


    private bool keyCtrl;
    private bool keyA;
    private bool keyB;

    private const int WM_KEYDOWN = 0x100;
    private const int WM_KEYUP = 0x101;

    public delegate void dlg_Ctrl_A_B();
    public event dlg_Ctrl_A_B Ctrl_A_B;

    public bool PreFilterMessage(ref Message m)
    
        Keys keyData;
        switch (m.Msg)
        
            case WM_KEYDOWN:
                keyData = (Keys)((int)m.WParam);
                switch (keyData)
                
                    case Keys.ControlKey:
                        keyCtrl = true;
                        break;

                    case Keys.A:
                        keyA = true;
                        break;

                    case Keys.B:
                        keyB = true;
                        break;
                
                if (keyCtrl && keyA && keyB)
                
                    Ctrl_A_B?.Invoke();
                
                break;

            case WM_KEYUP:
                keyData = (Keys)((int)m.WParam);
                switch (keyData)
                
                    case Keys.ControlKey:
                        keyCtrl = false;
                        break;

                    case Keys.A:
                        keyA = false;
                        break;

                    case Keys.B:
                        keyB = false;
                        break;
                
                break;
        

        return false;
    


【讨论】:

Ctrl+J+E 或任何其他组合怎么样?我们应该为每个声明一个变量吗? 就是这样,或者创建某种Dictionary<Keys, bool>,以便您可以查找和切换特定值。无论哪种方式都会变得一团糟...... 嗯,我不这么认为,如果你允许的话。只需一个变量就足够了。类似于另一个答案。适用于任何Ctrl+Any+Any。不管投票的事情,试试吧。感谢您的宝贵时间。 @dr.null Dictionary 方法将是最灵活的。如果明天他们要求 Ctrl-A-B-C,即使您的方法也需要修改。【参考方案2】:

您可以将第一个键视为附加或自定义修饰符以扩展快捷键的范围。

声明一个类变量来保存该修饰符:

private Keys KeyModifier = Keys.None;

如下处理KeyDown事件:

private void FormWhatEver_KeyDown(object sender, KeyEventArgs e)

    if (e.Control)
    
        switch (e.KeyCode)
        
            case Keys.B:
                if (KeyModifier == Keys.A)
                
                    // Handle Ctrl+AB
                
                else
                
                    // Handle Ctrl+B
                
                break;
            case Keys.C:
                if (KeyModifier == Keys.A)
                
                    // Handle Ctrl+AC
                
                else
                
                    // Handle Ctrl+C
                
                break;
            default:
                // Otherwise set the pressed key as a key modifier.
                KeyModifier = e.KeyCode;
                break;
        
    

释放Control 键时重置修饰符。这对于使上述工作正常工作很重要。

private void FormWhatEver_KeyUp(object sender, KeyEventArgs e)

    if (!e.Control) KeyModifier = Keys.None;

【讨论】:

以上是关于检查是不是在 Winforms 中按下热键的主要内容,如果未能解决你的问题,请参考以下文章

如何防止在WinForms TextBox中按下alt键引起的哔声?

从 Winforms 应用程序发送全局击键/伪造全局热键

Winforms MenuStrip 带下划线的热键字母

我是不是需要在我的 iphone 应用程序中按下每个按钮时不断检查连接?

如何检查是不是已在 Ruby 和 Windows 控制台中按下箭头键

始终显示热键