WH_MOUSE_LL Hook не вызывается для внедренных событий (mouse_event, SendInput) - PullRequest
4 голосов
/ 01 февраля 2010

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

1 Ответ

0 голосов
/ 03 декабря 2011

Вы пробовали SendMessage (this.Handle, WM _...?

...