c#低电平输入解码消息参数

时间:2018-11-21 03:32:10

标签: c# raw-input low-level

我正在制作一个用于处理全局按键的低级键盘挂钩,并将其转发到Raw Input API,以检查其来自哪个键盘设备。

我通过在钩子中使用SendMessage函数来实现此目的,该函数可以被API接收。

我的问题是API无法读取lParam的缓冲区,返回false

>> Error getting the rawinput buffer

如何调整该钩子,以使该消息的lParam被API成功解码?

(我正在使用Rawkeyboard结构,但我觉得这可能不是正确的方法,我也尝试过使用其他一些运气不好的方法)

挂钩

//^ DLL Imports, SetWindowsHookEx, etc^

public int HookProc(int Code, int wParam, ref CWPRETSTRUCT lParam) {
    if (Code >= 0) {
        // Block
        Rawkeyboard lParamKeyboard = new Rawkeyboard();
        int result = SendMessage(Handle, 0x00FF, wParam, ref lParamKeyboard ); // Send to API
        if (result == 1) {
            return 1;
        }
    }
    // Allow
    return CallNextHookEx(Handle, Code, wParam, ref lParam);
}

[StructLayout(LayoutKind.Sequential)]
public struct Rawkeyboard {
    public ushort Makecode;                 // Scan code from the key depression
    public ushort Flags;                    // One or more of RI_KEY_MAKE, RI_KEY_BREAK, RI_KEY_E0, RI_KEY_E1
    private readonly ushort Reserved;       // Always 0    
    public ushort VKey;                     // Virtual Key Code
    public uint Message;                    // Corresponding Windows message for exmaple (WM_KEYDOWN, WM_SYASKEYDOWN etc)
    public uint ExtraInformation;           // The device-specific addition information for the event (seems to always be zero for keyboards)

    public override string ToString() {
        return string.Format("Rawkeyboard\n Makecode: {0}\n Makecode(hex) : {0:X}\n Flags: {1}\n Reserved: {2}\n VKeyName: {3}\n Message: {4}\n ExtraInformation {5}\n",
                                            Makecode, Flags, Reserved, VKey, Message, ExtraInformation);
    }
}

[StructLayout(LayoutKind.Sequential)]
public struct CWPRETSTRUCT {
    IntPtr lResult;
    IntPtr lParam;
    IntPtr wParam;
    uint message;
    IntPtr hWnd;
}

API

protected override void WndProc(ref Message message){
        switch (message.Msg){
            // Message Received!
            case 0x00FF:{
                bool result = false;
                hdevice = message.LParam;
                if (_deviceList.Count == 0) return false;
                var dwSize = 0;

                Win32.GetRawInputData(hdevice, DataCommand.RID_INPUT, IntPtr.Zero, ref dwSize, Marshal.SizeOf(typeof(Rawinputheader)));
                if (dwSize != Win32.GetRawInputData(hdevice, DataCommand.RID_INPUT, out _rawBuffer, ref dwSize, Marshal.SizeOf(typeof (Rawinputheader)))){
                    Debug.WriteLine("Error getting the rawinput buffer");
                    result = false;
                }
                else{
                    // Do checks here
                    result = true;
                }
                message.Result = (IntPtr)Convert.ToInt32(result);
            }
            break;
        }
        base.WndProc(ref message);
    }


[StructLayout(LayoutKind.Sequential)]
public struct Rawinputheader
{
    public uint dwType;                     // Type of raw input (RIM_TYPEHID 2, RIM_TYPEKEYBOARD 1, RIM_TYPEMOUSE 0)
    public uint dwSize;                     // Size in bytes of the entire input packet of data. This includes RAWINPUT plus possible extra input reports in the RAWHID variable length array. 
    public IntPtr hDevice;                  // A handle to the device generating the raw input data. 
    public IntPtr wParam;                   // RIM_INPUT 0 if input occurred while application was in the foreground else RIM_INPUTSINK 1 if it was not.

    public override string ToString()
    {
        return string.Format("RawInputHeader\n dwType : {0}\n dwSize : {1}\n hDevice : {2}\n wParam : {3}", dwType, dwSize, hDevice, wParam);
    }
}

1 个答案:

答案 0 :(得分:2)

lParamHookProc的{​​{1}}的类型不同。

对于SendMessage(WM_INPUT),它是CWPRETSTRUCT结构。

对于HookProc,它是RAWINPUT结构。

因此,您需要创建一个新的SendMessage(WM_INPUT)对象,然后传递给RAWINPUT方法。