5

我有一个应用程序,它总是检查是否按下了类似F12的键。它不需要集中在我的应用程序的主窗口中。我试过这段代码:

public int a = 1;
    // DLL libraries used to manage hotkeys
    [DllImport("user32.dll")]
    public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
    [DllImport("user32.dll")]
    public static extern bool UnregisterHotKey(IntPtr hWnd, int id);

    const int MYACTION_HOTKEY_ID = 1;

    public Form1()
    {
        InitializeComponent();
        // Modifier keys codes: Alt = 1, Ctrl = 2, Shift = 4, Win = 8
        // Compute the addition of each combination of the keys you want to be pressed
        // ALT+CTRL = 1 + 2 = 3 , CTRL+SHIFT = 2 + 4 = 6...
        RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, 0, (int) Keys.F12);
    }

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID)
        {

            a++;
            MessageBox.Show(a.ToString());
        }
        base.WndProc(ref m);
    }

我把 0 放到这一行RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, 0, (int) Keys.F12);,这样只有F12按下它才会捕获。

但它没有用。我该如何解决这个问题?

在这里,我无法理解一些行,例如:

const int MYACTION_HOTKEY_ID = 1;
m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID
base.WndProc(ref m);

谁能帮我理解这些线?

4

4 回答 4

2

但它没有用。我该如何解决这个问题?

你是什​​么意思“它没有工作”?您问题中的代码对我来说看起来是正确的。

它可能不起作用的唯一原因是该RegisterHotKey函数返回错误并且您没有检查它。要使其工作,您需要将该SetLastError属性添加到其声明中,这会导致运行时缓存它设置的 Win32 错误代码。false完成此操作后,您可以通过调用GetLastWin32Error函数来检查错误代码(如果函数返回) 。我建议使用此函数的结果来生成并抛出Win32Exception.

修改您的声明RegisterHotKey如下:

[DllImport("user32.dll", PreserveSig = false)]
public static extern bool RegisterHotKey(IntPtr hWnd,
                                         int id,
                                         uint fsModifiers,
                                         Keys key);

您对函数的调用如下:

if (!RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, 0, Keys.F12))
{
   throw new Win32Exception(Marshal.GetLastWin32Error());
}

完成后,我怀疑您会看到抛出异常并显示错误消息:

热键已注册

好吧,这使得调试问题变得更加简单,不是吗!您可能需要选择不同的热键,因为RegisterHotKey函数文档明确告诉我们:

F12键始终保留供调试器使用,因此不应将其注册为热键。即使您不调试应用程序,F12它也会保留,以防内核模式调试器或即时调试器驻留。

当我运行代码并注册F11为热键时,它对我来说效果很好。


在这里,我无法理解一些行,例如:

const int MYACTION_HOTKEY_ID = 1;
m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID
base.WndProc(ref m);

谁能帮我理解这些线?

当然:

  1. 第一行声明一个常量值,它唯一地标识您使用该RegisterHotKey函数安装的热键。更具体地说,它对应于id函数的参数。您在初次通话时将其传递给了它。

  2. 这将检查窗口过程 ( WndProc) 以查看Msg正在处理的消息 () 是否是WM_HOTKEY消息。每当按下您使用该功能WM_HOTKEY注册的热键时,该消息就会自动发布到您的窗口。RegisterHotKey

    但是,您实际上不应该0x0312直接使用幻数,因为您不是唯一一个不确定它的含义的人。相反,定义一个常量并使用它来代替:

    const int WM_HOTKEY = 0x0312;
    m.Msg == WM_HOTKEY
    

    该条件测试的第二部分( 之后的部分&&)检查wParam消息的字段以查看按下的热键是否是您注册的热键。请记住,这MYACTION_HOTKEY_ID是您的热键的唯一 ID。消息文档告诉我们,WM_HOTKEY检查wParam是我们如何确定按下了哪个热键。

  3. 这将调用基类的窗口过程。换句话说,您所做的是覆盖了虚拟WndProc方法,允许您添加一些额外的代码(您对 的处理WM_HOTKEY)。完成附加逻辑后,您希望继续处理基类的逻辑,因此您继续转发消息。

于 2013-03-15T10:21:56.933 回答
1

为了做类似的事情,我使用SetWindowsHookEx. 这将捕获通过 Windows 的所有键盘消息,并允许您检查它们,并在必要时阻止它们进一步传播。

在我的RocketLauncher GitHub 爱好项目中查看我的 KeyboardHandling项目。你可以直接从中获取你需要的东西。我也将很快将它变成一个 nuget 包。

于 2013-03-15T09:25:26.850 回答
1

我不知道为什么,但我觉得这与这个问题有关......所以我将尝试再次解释一下:

const int MYACTION_HOTKEY_ID = 1;

是您保存用于标识热键的整数的位置。如果您需要注册的不仅仅是热键,则必须声明其他整数字段来标识其他热键:

const int ANOTHER_ACTION_HOTKEY_ID = 2;
const int AND_ANOTHER_ACTION_HOTKEY_ID = 3;

然后,

m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID

是使您能够知道用户键入了哪个热键的条件。

0x0312(例如WM_HOTKEY,您可以在此处找到的文档中声明)是要知道是否已按下注册的热键:

按下某个键时,系统会查找所有热键的匹配项。找到匹配项后,系统会将 WM_HOTKEY 消息发布到与热键关联的窗口的消息队列中。如果热键没有与窗口相关联,则 WM_HOTKEY 消息被发送到与热键相关联的线程。


根据文档,您不能使用F12热键:

F12 键一直保留供调试器使用,因此不应将其注册为热键。即使您不调试应用程序,F12 也会保留,以防内核模式调试器或即时调试器驻留。

于 2013-03-15T09:31:23.513 回答
1

Your code has no wrong . But it doesn't work here because the F12 key is reserved you may try with another key like F10, F11 etc .

于 2013-03-16T04:37:31.550 回答