WM_HOTKEY 的文档说LPARAM 包含两个 16 位字段。高位字(高 16 位)有按键的 VK,低位字(低 16 位)有指定的修饰符。
LPARAM & 0xffff 将获得低 16 位,LPARAM >> 16 将获得高 16 位。
LPARAM & 0xffff 有效,因为 32 位 LPARAM 看起来像:
V bit 31 V bit 0
HIGH WORD LOW WORD
0y vvvv vvvv vvvv vvvv mmmm mmmm mmmm mmmm where v is the vk, and m is the modifier
0y 0000 0000 0000 0000 1111 1111 1111 1111 == 0x0000ffff
========================================== Bitwise and
0y 0000 0000 0000 0000 mmmm mmmm mmmm mmmm Just left with the modifier bits
LPARAM >> 16 通过将位向右移动 16 个位置来工作
V bit 31 V bit 0
HIGH WORD LOW WORD
0y vvvv vvvv vvvv vvvv mmmm mmmm mmmm mmmm where v is the vk, and m is the modifier
0y 0vvv vvvv vvvv vvvv vmmm mmmm mmmm mmmm right shifted once (>> 1)
0y 00vv vvvv vvvv vvvv vvmm mmmm mmmm mmmm right shifted twice (>> 2)
...
0y 0000 0000 0000 0000 vvvv vvvv vvvv vvvv right shifted sixteen times (>> 16)
LPARAM 被定义为指针的大小,因此它将映射到托管代码中的IntPtr。由于我们只使用 LPARAM 的低 32 位,我们需要切掉高 32。我们可以强制转换为 int 这样做,但如果您使用 checked 算法运行,它将导致 @987654333 @。相反,我们将IntPtr 转换为long(在32 位机器上将填零),然后转换为int(将截断)。
如果我们不将IntPtr 的大小调整为Int32,如果应用程序发送一条设置为lparam >> 16 的结果的高位消息,您可能会遇到异常。
IntPtr lparam = /* comes from WndProc */;
Int32 lparam32 = unchecked((int)(long)lparam);
Int16 lowWord = lparam32 & 0xffff;
Int16 highWord = lparam32 >> 16;
话虽如此,这里是 C# 中热键侦听器的完整实现,我不记得在哪里找到了。如果有人对此有归属,请告诉我,或编辑此帖子以列出原作者。
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public sealed class KeyboardHook : IDisposable
{
private int _currentId;
private Window _window;
public event EventHandler<KeyPressedEventArgs> KeyPressed;
public KeyboardHook()
{
EventHandler<KeyPressedEventArgs> handler = null;
this._window = new Window();
if (handler == null)
{
handler = delegate (object sender, KeyPressedEventArgs args) {
if (this.KeyPressed != null)
{
this.KeyPressed(this, args);
}
};
}
this._window.KeyPressed += handler;
}
public void Dispose()
{
for (int i = this._currentId; i > 0; i--)
{
UnregisterHotKey(this._window.Handle, i);
}
this._window.Dispose();
}
public void RegisterHotKey(ModifierKeys modifier, Keys key)
{
this._currentId++;
if (!RegisterHotKey(this._window.Handle, this._currentId, (uint) modifier, (uint) key))
{
throw new InvalidOperationException("Couldn’t register the hot key.");
}
}
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
private class Window : NativeWindow, IDisposable
{
private static int WM_HOTKEY = 0x312;
public event EventHandler<KeyPressedEventArgs> KeyPressed;
public Window()
{
this.CreateHandle(new CreateParams());
}
public void Dispose()
{
this.DestroyHandle();
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_HOTKEY)
{
Keys key = ((Keys) (((int) m.LParam) >> 0x10)) & Keys.KeyCode;
ModifierKeys modifier = ((ModifierKeys) ((int) m.LParam)) & ((ModifierKeys) 0xffff);
if (this.KeyPressed != null)
{
this.KeyPressed(this, new KeyPressedEventArgs(modifier, key));
}
}
}
}
}