WH_MOUSE_LL 钩子不会因注入事件(mouse_event、SendInput)而被调用
我的代码使用 WH_MOUSE_LL 挂钩来最初抑制所有鼠标输入,除非 dwExtraInfo 属性设置为某个值。该程序还注册了鼠标设备的原始输入,以便我可以识别哪个设备负责输入。当我收到 WM_INPUT 消息并确定源时,根据设备,我可能只想让事件生效,在这种情况下,我使用 SendInput 重新创建它(尝试了 mouse_event,它也已被取代),提供数据在 dwExtraInfo 属性中。这个想法是,钩子应该看到这个新的注入事件,看到额外的信息而不是抑制它。不幸的是,注入的事件永远不会被钩子看到。不过,窗口过程会看到相应的 WM_INPUT 消息,并且 SendInput 返回 1,因此似乎正在生成该事件。我读到上下文切换到安装钩子的线程,并且它必须有一个消息循环。我相信我的代码符合该资格(因为 Application.Run() 在线程上启动消息循环 - 我还尝试了手写的 Win32 风格的消息循环来代替它)。任何人都知道为什么会发生这种情况和/或如何解决这个问题?
下面的代码展示了这个问题。它应该在引用 System 和 System.Windows.Forms 的情况下运行。
主类:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Win32;
public class LLMH : Form
{
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
private InputProcessor inputProcessor;
private static IntPtr extraInfoPointer;
private const int EXTRA_INFO = 1000;
public static void Main()
{
_hookID = SetHook(_proc);
LLMH app = new LLMH();
app.inputProcessor = new InputProcessor();
app.RegisterDevice(0x01, 0x02, (int)RawInputDeviceFlag.RIDEV_INPUTSINK);
int extraInfo = EXTRA_INFO;
LLMH.extraInfoPointer = new IntPtr(extraInfo);
Application.Run();
UnhookWindowsHookEx(_hookID);
}
public void RegisterDevice(ushort usagePage, ushort usage, int flags)
{
inputProcessor.RegisterDevice(usagePage, usage, flags, this.Handle);
}
protected override void WndProc(ref Message message)
{
switch (message.Msg)
{
case (int)WindowsMessage.WM_INPUT:
Console.WriteLine("Received WM_INPUT.");
RawInput rawInput = inputProcessor.GetRawInput(ref message);
String name = inputProcessor.GetRawInputDeviceName(rawInput);
Console.WriteLine("rawInput.extraInfo: {0}", rawInput.mouse.extraInformation);
if (rawInput.mouse.extraInformation != EXTRA_INFO)
{
Console.WriteLine("Creating local mouse event.");
//mouse_event(
// (int)rawInput.mouse.flags,
// rawInput.mouse.lastX,
// rawInput.mouse.lastY,
// rawInput.mouse.buttonData,
// extraInfoPointer);
INPUT input = new INPUT();
input.type = (int)RawInputType.MOUSE;
input.mkhi.mi.dwFlags = (uint)rawInput.mouse.flags;
input.mkhi.mi.dx = rawInput.mouse.lastX;
input.mkhi.mi.dy = rawInput.mouse.lastY;
input.mkhi.mi.mouseData = rawInput.mouse.buttonData;
input.mkhi.mi.dwExtraInfo = extraInfoPointer;
Console.WriteLine("Return value of SendInput: {0}", SendInput(1, ref input, Marshal.SizeOf(input)));
}
base.WndProc(ref message);
break;
default:
base.WndProc(ref message);
break;
}
}
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx((int)WindowsHook.WH_MOUSE_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
Console.WriteLine("\nIn hook.");
if (nCode >= 0)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
if (hookStruct.dwExtraInfo == LLMH.extraInfoPointer)
{
Console.WriteLine("Extra info matches. hookStruct.dwExtraInfo: {0}", hookStruct.dwExtraInfo);
}
else
{
Console.WriteLine("Extra info doesn't match. hookStruct.dwExtraInfo: {0}", hookStruct.dwExtraInfo);
return new IntPtr(-1);
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll", SetLastError = true)]
public static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);
[DllImport("user32.dll")]
public static extern void mouse_event(Int32 dwFlags, Int32 dx, Int32 dy, Int32 dwData, IntPtr dwExtraInfo);
}
InputProcessor 类:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Win32;
public class InputProcessor
{
public RawInput GetRawInput(ref Message message)
{
uint size = 0;
// Call with null pointer to get amount of memory required for buffer.
GetRawInputData(
message.LParam,
(uint)RawInputDeviceCommand.RID_INPUT,
IntPtr.Zero,
ref size,
(uint)Marshal.SizeOf(typeof(RawInputHeader)));
IntPtr buffer = Marshal.AllocHGlobal((int)size);
if (GetRawInputData(
message.LParam,
(uint)RawInputDeviceCommand.RID_INPUT,
buffer,
ref size,
(uint)Marshal.SizeOf(typeof(RawInputHeader))) == size)
{
RawInput input = (RawInput)Marshal.PtrToStructure(buffer, typeof(RawInput));
Marshal.FreeHGlobal(buffer);
return input;
}
else
{
throw new ApplicationException("Failed to return Raw Input");
}
}
public String GetRawInputDeviceName(RawInput rawInput)
{
uint length = 0;
// Determine amount of memory to allocate for device name.
GetRawInputDeviceInfo(
rawInput.header.device,
(uint)RawInputDeviceCommand.RIDI_DEVICENAME,
IntPtr.Zero,
ref length);
String deviceName = String.Empty;
if (length > 0)
{
IntPtr data = Marshal.AllocHGlobal((int)length);
GetRawInputDeviceInfo(rawInput.header.device, (uint)RawInputDeviceCommand.RIDI_DEVICENAME, data, ref length);
deviceName = (String)Marshal.PtrToStringAnsi(data);
Marshal.FreeHGlobal(data);
}
return deviceName;
}
public void RegisterDevice(ushort usagePage, ushort usage, int flags, IntPtr windowHandle)
{
RawInputDevice[] inputDevices = new RawInputDevice[1];
inputDevices[0].usagePage = usagePage;
inputDevices[0].usage = usage;
inputDevices[0].flags = flags;
inputDevices[0].windowHandle = windowHandle;
if (!RegisterRawInputDevices(inputDevices, (uint)inputDevices.Length, (uint)Marshal.SizeOf(inputDevices[0])))
{
throw new ApplicationException("Failed to register raw input devices.");
}
}
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetRawInputDeviceInfo(
IntPtr deviceHandle,
uint command,
IntPtr data,
ref uint size);
[DllImport("User32.dll")]
public static extern bool RegisterRawInputDevices(
RawInputDevice[] rawInputDevice,
uint numDevices,
uint size);
[DllImport("User32.dll")]
public static extern int GetRawInputData(
IntPtr rawInput,
uint command,
IntPtr data,
ref uint size,
uint headerSize);
[DllImport("user32.dll")]
public static extern uint GetRawInputDeviceList(
IntPtr rawInputDeviceList,
ref uint numDevices,
uint size);
}
附加 P/Invoke 结构、枚举等。
using System;
using System.Runtime.InteropServices;
namespace Win32
{
public enum WindowsMessage
{
WM_NULL = 0x0000,
WM_CREATE = 0x0001,
WM_DESTROY = 0x0002,
WM_MOVE = 0x0003,
WM_SIZE = 0x0005,
WM_ACTIVATE = 0x0006,
WM_SETFOCUS = 0x0007,
WM_KILLFOCUS = 0x0008,
WM_QUIT = 0x0012,
WM_INPUT = 0x00FF,
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205
}
public enum WindowsHook
{
WH_MOUSE_LL = 14
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
public struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
// Raw Input section.
[StructLayout(LayoutKind.Sequential)]
public struct RawInput
{
public RawInputHeader header;
public RawInputMouse mouse;
public RawInputKeyboard keyboard;
public RawInputHID hid;
}
[StructLayout(LayoutKind.Sequential)]
public struct RawInputHeader
{
public RawInputType type;
public int size;
public IntPtr device;
public IntPtr wParam;
}
[StructLayout(LayoutKind.Sequential)]
public struct RawInputMouse
{
public RawMouseFlags flags;
public ushort buttonData;
public RawMouseButtons buttonflags;
public uint rawButtons;
public int lastX;
public int lastY;
public uint extraInformation;
}
[StructLayout(LayoutKind.Sequential)]
public struct RawInputKeyboard
{
public ushort makeCode;
public ushort flags;
public ushort reserved;
public ushort virtualKeyCode;
public uint message;
public ulong extraInformation;
}
[StructLayout(LayoutKind.Sequential)]
public struct RawInputHID
{
public int size;
public int count;
public IntPtr data;
}
public enum RawInputType
{
MOUSE = 0,
KEYBOARD = 1,
HID = 2
}
[Flags()]
public enum RawMouseFlags : ushort
{
MOVE_RELATIVE = 0,
MOVE_ABSOLUTE = 1,
VIRTUAL_DESKTOP = 2,
ATTRIBUTES_CHANGED = 4
}
[Flags()]
public enum RawMouseButtons : ushort
{
None = 0,
LeftDown = 0x0001,
LeftUp = 0x0002,
RightDown = 0x0004,
RightUp = 0x0008,
MiddleDown = 0x0010,
MiddleUp = 0x0020,
Button4Down = 0x0040,
Button4Up = 0x0080,
Button5Down = 0x0100,
Button5Up = 0x0200,
MouseWheel = 0x0400
}
[StructLayout(LayoutKind.Sequential)]
public struct RawInputDeviceList
{
public IntPtr device;
public uint type;
}
[StructLayout(LayoutKind.Sequential)]
public struct RawInputDevice
{
[MarshalAs(UnmanagedType.U2)]
public ushort usagePage;
[MarshalAs(UnmanagedType.U2)]
public ushort usage;
[MarshalAs(UnmanagedType.U4)]
public int flags;
public IntPtr windowHandle;
}
public enum RawInputDeviceFlag : int
{
RIDEV_REMOVE = 0x00000001,
RIDEV_EXCLUDE = 0x00000010,
RIDEV_PAGEONLY = 0x00000020,
RIDEV_NOLEGACY = 0x00000030,
RIDEV_INPUTSINK = 0x00000100,
RIDEV_CAPTUREMOUSE = 0x00000200,
RIDEV_NOHOTKEYS = 0x00000200,
RIDEV_APPKEYS = 0x00000400,
RIDEV_EXMODEMASK = 0x00000F0
}
public enum RawInputDeviceCommand : int
{
RID_INPUT = 0x10000003,
RIDI_DEVICENAME = 0x20000007,
RIDI_DEVICEINFO = 0x2000000b
}
public enum HIDUsage : ushort
{
Pointer = 0x01,
Mouse = 0x02,
Joystick = 0x04,
Gamepad = 0x05,
Keyboard = 0x06,
Keypad = 0x07,
SystemControl = 0x80,
X = 0x30,
Y = 0x31,
Z = 0x32,
RelativeX = 0x33,
RelativeY = 0x34,
RelativeZ = 0x35,
Slider = 0x36,
Dial = 0x37,
Wheel = 0x38,
HatSwitch = 0x39,
CountedBuffer = 0x3A,
ByteCount = 0x3B,
MotionWakeup = 0x3C,
VX = 0x40,
VY = 0x41,
VZ = 0x42,
VBRX = 0x43,
VBRY = 0x44,
VBRZ = 0x45,
VNO = 0x46,
SystemControlPower = 0x81,
SystemControlSleep = 0x82,
SystemControlWake = 0x83,
SystemControlContextMenu = 0x84,
SystemControlMainMenu = 0x85,
SystemControlApplicationMenu = 0x86,
SystemControlHelpMenu = 0x87,
SystemControlMenuExit = 0x88,
SystemControlMenuSelect = 0x89,
SystemControlMenuRight = 0x8A,
SystemControlMenuLeft = 0x8B,
SystemControlMenuUp = 0x8C,
SystemControlMenuDown = 0x8D,
KeyboardNoEvent = 0x00,
KeyboardRollover = 0x01,
KeyboardPostFail = 0x02,
KeyboardUndefined = 0x03,
KeyboardaA = 0x04,
KeyboardzZ = 0x1D,
Keyboard1 = 0x1E,
Keyboard0 = 0x27,
KeyboardLeftControl = 0xE0,
KeyboardLeftShift = 0xE1,
KeyboardLeftALT = 0xE2,
KeyboardLeftGUI = 0xE3,
KeyboardRightControl = 0xE4,
KeyboardRightShift = 0xE5,
KeyboardRightALT = 0xE6,
KeyboardRightGUI = 0xE7,
KeyboardScrollLock = 0x47,
KeyboardNumLock = 0x53,
KeyboardCapsLock = 0x39,
KeyboardF1 = 0x3A,
KeyboardF12 = 0x45,
KeyboardReturn = 0x28,
KeyboardEscape = 0x29,
KeyboardDelete = 0x2A,
KeyboardPrintScreen = 0x46,
LEDNumLock = 0x01,
LEDCapsLock = 0x02,
LEDScrollLock = 0x03,
LEDCompose = 0x04,
LEDKana = 0x05,
LEDPower = 0x06,
LEDShift = 0x07,
LEDDoNotDisturb = 0x08,
LEDMute = 0x09,
LEDToneEnable = 0x0A,
LEDHighCutFilter = 0x0B,
LEDLowCutFilter = 0x0C,
LEDEqualizerEnable = 0x0D,
LEDSoundFieldOn = 0x0E,
LEDSurroundFieldOn = 0x0F,
LEDRepeat = 0x10,
LEDStereo = 0x11,
LEDSamplingRateDirect = 0x12,
LEDSpinning = 0x13,
LEDCAV = 0x14,
LEDCLV = 0x15,
LEDRecordingFormatDet = 0x16,
LEDOffHook = 0x17,
LEDRing = 0x18,
LEDMessageWaiting = 0x19,
LEDDataMode = 0x1A,
LEDBatteryOperation = 0x1B,
LEDBatteryOK = 0x1C,
LEDBatteryLow = 0x1D,
LEDSpeaker = 0x1E,
LEDHeadset = 0x1F,
LEDHold = 0x20,
LEDMicrophone = 0x21,
LEDCoverage = 0x22,
LEDNightMode = 0x23,
LEDSendCalls = 0x24,
LEDCallPickup = 0x25,
LEDConference = 0x26,
LEDStandBy = 0x27,
LEDCameraOn = 0x28,
LEDCameraOff = 0x29,
LEDOnLine = 0x2A,
LEDOffLine = 0x2B,
LEDBusy = 0x2C,
LEDReady = 0x2D,
LEDPaperOut = 0x2E,
LEDPaperJam = 0x2F,
LEDRemote = 0x30,
LEDForward = 0x31,
LEDReverse = 0x32,
LEDStop = 0x33,
LEDRewind = 0x34,
LEDFastForward = 0x35,
LEDPlay = 0x36,
LEDPause = 0x37,
LEDRecord = 0x38,
LEDError = 0x39,
LEDSelectedIndicator = 0x3A,
LEDInUseIndicator = 0x3B,
LEDMultiModeIndicator = 0x3C,
LEDIndicatorOn = 0x3D,
LEDIndicatorFlash = 0x3E,
LEDIndicatorSlowBlink = 0x3F,
LEDIndicatorFastBlink = 0x40,
LEDIndicatorOff = 0x41,
LEDFlashOnTime = 0x42,
LEDSlowBlinkOnTime = 0x43,
LEDSlowBlinkOffTime = 0x44,
LEDFastBlinkOnTime = 0x45,
LEDFastBlinkOffTime = 0x46,
LEDIndicatorColor = 0x47,
LEDRed = 0x48,
LEDGreen = 0x49,
LEDAmber = 0x4A,
LEDGenericIndicator = 0x3B,
TelephonyPhone = 0x01,
TelephonyAnsweringMachine = 0x02,
TelephonyMessageControls = 0x03,
TelephonyHandset = 0x04,
TelephonyHeadset = 0x05,
TelephonyKeypad = 0x06,
TelephonyProgrammableButton = 0x07,
SimulationRudder = 0xBA,
SimulationThrottle = 0xBB
}
public enum HIDUsagePage : ushort
{
Undefined = 0x00,
Generic = 0x01,
Simulation = 0x02,
VR = 0x03,
Sport = 0x04,
Game = 0x05,
Keyboard = 0x07,
LED = 0x08,
Button = 0x09,
Ordinal = 0x0A,
Telephony = 0x0B,
Consumer = 0x0C,
Digitizer = 0x0D,
PID = 0x0F,
Unicode = 0x10,
AlphaNumeric = 0x14,
Medical = 0x40,
MonitorPage0 = 0x80,
MonitorPage1 = 0x81,
MonitorPage2 = 0x82,
MonitorPage3 = 0x83,
PowerPage0 = 0x84,
PowerPage1 = 0x85,
PowerPage2 = 0x86,
PowerPage3 = 0x87,
BarCode = 0x8C,
Scale = 0x8D,
MSR = 0x8E
}
// SendInput section.
[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
public int dx;
public int dy;
public uint mouseData;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
}
[StructLayout(LayoutKind.Explicit)]
public struct MOUSEKEYBDHARDWAREINPUT
{
[FieldOffset(0)]
public MOUSEINPUT mi;
[FieldOffset(0)]
public KEYBDINPUT ki;
[FieldOffset(0)]
public HARDWAREINPUT hi;
}
[StructLayout(LayoutKind.Sequential)]
public struct INPUT
{
public int type;
public MOUSEKEYBDHARDWAREINPUT mkhi;
}
}
一个 WM_LBUTTONDOWN 事件后的程序输出:
In hook.
Extra info doesn't match. hookStruct.dwExtraInfo: 0
Received WM_INPUT.
rawInput.extraInfo: 0
Creating local mouse event.
Return value of SendInput: 1
Received WM_INPUT.
rawInput.extraInfo: 1000
My code uses a WH_MOUSE_LL hook to initially suppress all mouse input, unless the dwExtraInfo property is set to a certain value. The program is also registered for raw input for mouse devices, so that I can identify which device is responsible for the input. When I get a WM_INPUT message and determine the source, depending on the device I might just want to allow the event to take effect, in which case I recreate it with SendInput (tried mouse_event, which has been superseded, as well), providing data in the dwExtraInfo property. The idea is that the hook should then see this new injected event, see the extra info and not suppress it. Unfortunately, the injected event is never seen by the hook. The corresponding WM_INPUT message is seen by the window procedure though and SendInput returns 1, so it seems that the event is being generated. I have read that the context switches to the thread that installed the hook and that it must have a message loop. I believe my code meets that qualification (Since Application.Run() starts a message loop on the thread - I've also tried a handwritten Win32-style message loop in its place). Anyone have any ideas why this is happening and/or how to fix this?
The following code exhibits the problem. It should run with references to System and System.Windows.Forms.
Main class:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Win32;
public class LLMH : Form
{
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
private InputProcessor inputProcessor;
private static IntPtr extraInfoPointer;
private const int EXTRA_INFO = 1000;
public static void Main()
{
_hookID = SetHook(_proc);
LLMH app = new LLMH();
app.inputProcessor = new InputProcessor();
app.RegisterDevice(0x01, 0x02, (int)RawInputDeviceFlag.RIDEV_INPUTSINK);
int extraInfo = EXTRA_INFO;
LLMH.extraInfoPointer = new IntPtr(extraInfo);
Application.Run();
UnhookWindowsHookEx(_hookID);
}
public void RegisterDevice(ushort usagePage, ushort usage, int flags)
{
inputProcessor.RegisterDevice(usagePage, usage, flags, this.Handle);
}
protected override void WndProc(ref Message message)
{
switch (message.Msg)
{
case (int)WindowsMessage.WM_INPUT:
Console.WriteLine("Received WM_INPUT.");
RawInput rawInput = inputProcessor.GetRawInput(ref message);
String name = inputProcessor.GetRawInputDeviceName(rawInput);
Console.WriteLine("rawInput.extraInfo: {0}", rawInput.mouse.extraInformation);
if (rawInput.mouse.extraInformation != EXTRA_INFO)
{
Console.WriteLine("Creating local mouse event.");
//mouse_event(
// (int)rawInput.mouse.flags,
// rawInput.mouse.lastX,
// rawInput.mouse.lastY,
// rawInput.mouse.buttonData,
// extraInfoPointer);
INPUT input = new INPUT();
input.type = (int)RawInputType.MOUSE;
input.mkhi.mi.dwFlags = (uint)rawInput.mouse.flags;
input.mkhi.mi.dx = rawInput.mouse.lastX;
input.mkhi.mi.dy = rawInput.mouse.lastY;
input.mkhi.mi.mouseData = rawInput.mouse.buttonData;
input.mkhi.mi.dwExtraInfo = extraInfoPointer;
Console.WriteLine("Return value of SendInput: {0}", SendInput(1, ref input, Marshal.SizeOf(input)));
}
base.WndProc(ref message);
break;
default:
base.WndProc(ref message);
break;
}
}
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx((int)WindowsHook.WH_MOUSE_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
Console.WriteLine("\nIn hook.");
if (nCode >= 0)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
if (hookStruct.dwExtraInfo == LLMH.extraInfoPointer)
{
Console.WriteLine("Extra info matches. hookStruct.dwExtraInfo: {0}", hookStruct.dwExtraInfo);
}
else
{
Console.WriteLine("Extra info doesn't match. hookStruct.dwExtraInfo: {0}", hookStruct.dwExtraInfo);
return new IntPtr(-1);
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll", SetLastError = true)]
public static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);
[DllImport("user32.dll")]
public static extern void mouse_event(Int32 dwFlags, Int32 dx, Int32 dy, Int32 dwData, IntPtr dwExtraInfo);
}
InputProcessor class:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Win32;
public class InputProcessor
{
public RawInput GetRawInput(ref Message message)
{
uint size = 0;
// Call with null pointer to get amount of memory required for buffer.
GetRawInputData(
message.LParam,
(uint)RawInputDeviceCommand.RID_INPUT,
IntPtr.Zero,
ref size,
(uint)Marshal.SizeOf(typeof(RawInputHeader)));
IntPtr buffer = Marshal.AllocHGlobal((int)size);
if (GetRawInputData(
message.LParam,
(uint)RawInputDeviceCommand.RID_INPUT,
buffer,
ref size,
(uint)Marshal.SizeOf(typeof(RawInputHeader))) == size)
{
RawInput input = (RawInput)Marshal.PtrToStructure(buffer, typeof(RawInput));
Marshal.FreeHGlobal(buffer);
return input;
}
else
{
throw new ApplicationException("Failed to return Raw Input");
}
}
public String GetRawInputDeviceName(RawInput rawInput)
{
uint length = 0;
// Determine amount of memory to allocate for device name.
GetRawInputDeviceInfo(
rawInput.header.device,
(uint)RawInputDeviceCommand.RIDI_DEVICENAME,
IntPtr.Zero,
ref length);
String deviceName = String.Empty;
if (length > 0)
{
IntPtr data = Marshal.AllocHGlobal((int)length);
GetRawInputDeviceInfo(rawInput.header.device, (uint)RawInputDeviceCommand.RIDI_DEVICENAME, data, ref length);
deviceName = (String)Marshal.PtrToStringAnsi(data);
Marshal.FreeHGlobal(data);
}
return deviceName;
}
public void RegisterDevice(ushort usagePage, ushort usage, int flags, IntPtr windowHandle)
{
RawInputDevice[] inputDevices = new RawInputDevice[1];
inputDevices[0].usagePage = usagePage;
inputDevices[0].usage = usage;
inputDevices[0].flags = flags;
inputDevices[0].windowHandle = windowHandle;
if (!RegisterRawInputDevices(inputDevices, (uint)inputDevices.Length, (uint)Marshal.SizeOf(inputDevices[0])))
{
throw new ApplicationException("Failed to register raw input devices.");
}
}
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetRawInputDeviceInfo(
IntPtr deviceHandle,
uint command,
IntPtr data,
ref uint size);
[DllImport("User32.dll")]
public static extern bool RegisterRawInputDevices(
RawInputDevice[] rawInputDevice,
uint numDevices,
uint size);
[DllImport("User32.dll")]
public static extern int GetRawInputData(
IntPtr rawInput,
uint command,
IntPtr data,
ref uint size,
uint headerSize);
[DllImport("user32.dll")]
public static extern uint GetRawInputDeviceList(
IntPtr rawInputDeviceList,
ref uint numDevices,
uint size);
}
Additional P/Invoke structs, enums, etc.
using System;
using System.Runtime.InteropServices;
namespace Win32
{
public enum WindowsMessage
{
WM_NULL = 0x0000,
WM_CREATE = 0x0001,
WM_DESTROY = 0x0002,
WM_MOVE = 0x0003,
WM_SIZE = 0x0005,
WM_ACTIVATE = 0x0006,
WM_SETFOCUS = 0x0007,
WM_KILLFOCUS = 0x0008,
WM_QUIT = 0x0012,
WM_INPUT = 0x00FF,
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205
}
public enum WindowsHook
{
WH_MOUSE_LL = 14
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
public struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
// Raw Input section.
[StructLayout(LayoutKind.Sequential)]
public struct RawInput
{
public RawInputHeader header;
public RawInputMouse mouse;
public RawInputKeyboard keyboard;
public RawInputHID hid;
}
[StructLayout(LayoutKind.Sequential)]
public struct RawInputHeader
{
public RawInputType type;
public int size;
public IntPtr device;
public IntPtr wParam;
}
[StructLayout(LayoutKind.Sequential)]
public struct RawInputMouse
{
public RawMouseFlags flags;
public ushort buttonData;
public RawMouseButtons buttonflags;
public uint rawButtons;
public int lastX;
public int lastY;
public uint extraInformation;
}
[StructLayout(LayoutKind.Sequential)]
public struct RawInputKeyboard
{
public ushort makeCode;
public ushort flags;
public ushort reserved;
public ushort virtualKeyCode;
public uint message;
public ulong extraInformation;
}
[StructLayout(LayoutKind.Sequential)]
public struct RawInputHID
{
public int size;
public int count;
public IntPtr data;
}
public enum RawInputType
{
MOUSE = 0,
KEYBOARD = 1,
HID = 2
}
[Flags()]
public enum RawMouseFlags : ushort
{
MOVE_RELATIVE = 0,
MOVE_ABSOLUTE = 1,
VIRTUAL_DESKTOP = 2,
ATTRIBUTES_CHANGED = 4
}
[Flags()]
public enum RawMouseButtons : ushort
{
None = 0,
LeftDown = 0x0001,
LeftUp = 0x0002,
RightDown = 0x0004,
RightUp = 0x0008,
MiddleDown = 0x0010,
MiddleUp = 0x0020,
Button4Down = 0x0040,
Button4Up = 0x0080,
Button5Down = 0x0100,
Button5Up = 0x0200,
MouseWheel = 0x0400
}
[StructLayout(LayoutKind.Sequential)]
public struct RawInputDeviceList
{
public IntPtr device;
public uint type;
}
[StructLayout(LayoutKind.Sequential)]
public struct RawInputDevice
{
[MarshalAs(UnmanagedType.U2)]
public ushort usagePage;
[MarshalAs(UnmanagedType.U2)]
public ushort usage;
[MarshalAs(UnmanagedType.U4)]
public int flags;
public IntPtr windowHandle;
}
public enum RawInputDeviceFlag : int
{
RIDEV_REMOVE = 0x00000001,
RIDEV_EXCLUDE = 0x00000010,
RIDEV_PAGEONLY = 0x00000020,
RIDEV_NOLEGACY = 0x00000030,
RIDEV_INPUTSINK = 0x00000100,
RIDEV_CAPTUREMOUSE = 0x00000200,
RIDEV_NOHOTKEYS = 0x00000200,
RIDEV_APPKEYS = 0x00000400,
RIDEV_EXMODEMASK = 0x00000F0
}
public enum RawInputDeviceCommand : int
{
RID_INPUT = 0x10000003,
RIDI_DEVICENAME = 0x20000007,
RIDI_DEVICEINFO = 0x2000000b
}
public enum HIDUsage : ushort
{
Pointer = 0x01,
Mouse = 0x02,
Joystick = 0x04,
Gamepad = 0x05,
Keyboard = 0x06,
Keypad = 0x07,
SystemControl = 0x80,
X = 0x30,
Y = 0x31,
Z = 0x32,
RelativeX = 0x33,
RelativeY = 0x34,
RelativeZ = 0x35,
Slider = 0x36,
Dial = 0x37,
Wheel = 0x38,
HatSwitch = 0x39,
CountedBuffer = 0x3A,
ByteCount = 0x3B,
MotionWakeup = 0x3C,
VX = 0x40,
VY = 0x41,
VZ = 0x42,
VBRX = 0x43,
VBRY = 0x44,
VBRZ = 0x45,
VNO = 0x46,
SystemControlPower = 0x81,
SystemControlSleep = 0x82,
SystemControlWake = 0x83,
SystemControlContextMenu = 0x84,
SystemControlMainMenu = 0x85,
SystemControlApplicationMenu = 0x86,
SystemControlHelpMenu = 0x87,
SystemControlMenuExit = 0x88,
SystemControlMenuSelect = 0x89,
SystemControlMenuRight = 0x8A,
SystemControlMenuLeft = 0x8B,
SystemControlMenuUp = 0x8C,
SystemControlMenuDown = 0x8D,
KeyboardNoEvent = 0x00,
KeyboardRollover = 0x01,
KeyboardPostFail = 0x02,
KeyboardUndefined = 0x03,
KeyboardaA = 0x04,
KeyboardzZ = 0x1D,
Keyboard1 = 0x1E,
Keyboard0 = 0x27,
KeyboardLeftControl = 0xE0,
KeyboardLeftShift = 0xE1,
KeyboardLeftALT = 0xE2,
KeyboardLeftGUI = 0xE3,
KeyboardRightControl = 0xE4,
KeyboardRightShift = 0xE5,
KeyboardRightALT = 0xE6,
KeyboardRightGUI = 0xE7,
KeyboardScrollLock = 0x47,
KeyboardNumLock = 0x53,
KeyboardCapsLock = 0x39,
KeyboardF1 = 0x3A,
KeyboardF12 = 0x45,
KeyboardReturn = 0x28,
KeyboardEscape = 0x29,
KeyboardDelete = 0x2A,
KeyboardPrintScreen = 0x46,
LEDNumLock = 0x01,
LEDCapsLock = 0x02,
LEDScrollLock = 0x03,
LEDCompose = 0x04,
LEDKana = 0x05,
LEDPower = 0x06,
LEDShift = 0x07,
LEDDoNotDisturb = 0x08,
LEDMute = 0x09,
LEDToneEnable = 0x0A,
LEDHighCutFilter = 0x0B,
LEDLowCutFilter = 0x0C,
LEDEqualizerEnable = 0x0D,
LEDSoundFieldOn = 0x0E,
LEDSurroundFieldOn = 0x0F,
LEDRepeat = 0x10,
LEDStereo = 0x11,
LEDSamplingRateDirect = 0x12,
LEDSpinning = 0x13,
LEDCAV = 0x14,
LEDCLV = 0x15,
LEDRecordingFormatDet = 0x16,
LEDOffHook = 0x17,
LEDRing = 0x18,
LEDMessageWaiting = 0x19,
LEDDataMode = 0x1A,
LEDBatteryOperation = 0x1B,
LEDBatteryOK = 0x1C,
LEDBatteryLow = 0x1D,
LEDSpeaker = 0x1E,
LEDHeadset = 0x1F,
LEDHold = 0x20,
LEDMicrophone = 0x21,
LEDCoverage = 0x22,
LEDNightMode = 0x23,
LEDSendCalls = 0x24,
LEDCallPickup = 0x25,
LEDConference = 0x26,
LEDStandBy = 0x27,
LEDCameraOn = 0x28,
LEDCameraOff = 0x29,
LEDOnLine = 0x2A,
LEDOffLine = 0x2B,
LEDBusy = 0x2C,
LEDReady = 0x2D,
LEDPaperOut = 0x2E,
LEDPaperJam = 0x2F,
LEDRemote = 0x30,
LEDForward = 0x31,
LEDReverse = 0x32,
LEDStop = 0x33,
LEDRewind = 0x34,
LEDFastForward = 0x35,
LEDPlay = 0x36,
LEDPause = 0x37,
LEDRecord = 0x38,
LEDError = 0x39,
LEDSelectedIndicator = 0x3A,
LEDInUseIndicator = 0x3B,
LEDMultiModeIndicator = 0x3C,
LEDIndicatorOn = 0x3D,
LEDIndicatorFlash = 0x3E,
LEDIndicatorSlowBlink = 0x3F,
LEDIndicatorFastBlink = 0x40,
LEDIndicatorOff = 0x41,
LEDFlashOnTime = 0x42,
LEDSlowBlinkOnTime = 0x43,
LEDSlowBlinkOffTime = 0x44,
LEDFastBlinkOnTime = 0x45,
LEDFastBlinkOffTime = 0x46,
LEDIndicatorColor = 0x47,
LEDRed = 0x48,
LEDGreen = 0x49,
LEDAmber = 0x4A,
LEDGenericIndicator = 0x3B,
TelephonyPhone = 0x01,
TelephonyAnsweringMachine = 0x02,
TelephonyMessageControls = 0x03,
TelephonyHandset = 0x04,
TelephonyHeadset = 0x05,
TelephonyKeypad = 0x06,
TelephonyProgrammableButton = 0x07,
SimulationRudder = 0xBA,
SimulationThrottle = 0xBB
}
public enum HIDUsagePage : ushort
{
Undefined = 0x00,
Generic = 0x01,
Simulation = 0x02,
VR = 0x03,
Sport = 0x04,
Game = 0x05,
Keyboard = 0x07,
LED = 0x08,
Button = 0x09,
Ordinal = 0x0A,
Telephony = 0x0B,
Consumer = 0x0C,
Digitizer = 0x0D,
PID = 0x0F,
Unicode = 0x10,
AlphaNumeric = 0x14,
Medical = 0x40,
MonitorPage0 = 0x80,
MonitorPage1 = 0x81,
MonitorPage2 = 0x82,
MonitorPage3 = 0x83,
PowerPage0 = 0x84,
PowerPage1 = 0x85,
PowerPage2 = 0x86,
PowerPage3 = 0x87,
BarCode = 0x8C,
Scale = 0x8D,
MSR = 0x8E
}
// SendInput section.
[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
public int dx;
public int dy;
public uint mouseData;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
}
[StructLayout(LayoutKind.Explicit)]
public struct MOUSEKEYBDHARDWAREINPUT
{
[FieldOffset(0)]
public MOUSEINPUT mi;
[FieldOffset(0)]
public KEYBDINPUT ki;
[FieldOffset(0)]
public HARDWAREINPUT hi;
}
[StructLayout(LayoutKind.Sequential)]
public struct INPUT
{
public int type;
public MOUSEKEYBDHARDWAREINPUT mkhi;
}
}
Program output after one WM_LBUTTONDOWN event:
In hook.
Extra info doesn't match. hookStruct.dwExtraInfo: 0
Received WM_INPUT.
rawInput.extraInfo: 0
Creating local mouse event.
Return value of SendInput: 1
Received WM_INPUT.
rawInput.extraInfo: 1000
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您尝试过 SendMessage(this.Handle, WM_... 吗?
Did you try SendMessage(this.Handle, WM_... ?