Мой код использует хук 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