从 C# 中的 RawInput 注册设备接收输入

Receiving Input From RawInput Registered Devices In c#

所以我有一个控制台应用程序,我从 user32.dll

导入了 RegisterRawInputDevices

您无法将设备注册到控制台 window 处理程序,因此我创建了一个继承自 Form 的 class。这也是覆盖 WndProc 的 class。现在我要做的就是将 message.Msg 写入控制台。

所以我实例化表单并将 window 处理程序传递给 RegisterRawInputDevices,它在其中注册鼠标和键盘。但此后 window 不再收到任何消息。
编辑:添加了一些代码来显示我当前正在尝试的内容。
这是我的主要方法(尽管我还有一些其他代码可以使 window 保持活动状态):

Input window = new Input();
PS4Input.RegisterControllers(window.Handle);

这是我用来创建 window 的 class。相当基本:

public class Input : Form
{
    protected override void WndProc(ref Message message)
    {
        Console.WriteLine(message.Msg);
        base.WndProc(ref message);
    }
}

这是我注册设备的方法。它目前说它有效。

[DllImport("User32.dll", SetLastError = true)]
extern static uint GetRawInputDeviceList(IntPtr pRawInputDeviceList, ref uint uiNumDevices, uint cbSize);

[DllImport("User32.dll", SetLastError = true)]
extern static uint GetRawInputDeviceInfo(IntPtr hDevice, uint uiCommand, IntPtr pData, ref uint pcbSize);

[DllImport("user32.dll", SetLastError = true)]
static extern uint GetRawInputDeviceInfo(IntPtr hDevice, uint uiCommand, ref DeviceInfo pData, ref uint pcbSize);

[DllImport("user32.dll", SetLastError = true)]
static extern bool RegisterRawInputDevices(RawInputDevice[] pRawInputDevice, uint numberDevices, uint size);

[DllImport("user32.dll", SetLastError = true)]
internal extern static uint GetRegisteredRawInputDevices(RawInputDevice[] pRawInputDevice, ref uint puiNumDevices, uint cbSize);

public static void RegisterControllers(IntPtr hwnd)
{
    uint deviceCount = 0;
    int dwSize = Marshal.SizeOf(typeof(RawInputDeviceList));

    if (GetRawInputDeviceList(IntPtr.Zero, ref deviceCount, (uint)dwSize) == 0)
    {
        IntPtr pRawInputDeviceList = Marshal.AllocHGlobal((int)(dwSize * deviceCount));
        GetRawInputDeviceList(pRawInputDeviceList, ref deviceCount, (uint)dwSize);

        for (int i = 0; i < deviceCount; i++)
        {
            RawInputDeviceList rid = (RawInputDeviceList)Marshal.PtrToStructure(new IntPtr(pRawInputDeviceList.ToInt32() + (dwSize * i)), typeof(RawInputDeviceList));

            uint size = (uint)Marshal.SizeOf(typeof(DeviceInfo));
            var di = new DeviceInfo { Size = Marshal.SizeOf(typeof(DeviceInfo)) };

            GetRawInputDeviceInfo(rid.hDevice, (uint)RawInputDeviceInfo.RIDI_DEVICEINFO, ref di, ref size);

            if (di.Type == DeviceType.RimTypeHid && di.HIDInfo.Usage == (ushort)HidUsage.Gamepad && di.HIDInfo.UsagePage == (ushort)HidUsagePage.GENERIC)
            {
                var device = new RawInputDevice();
                Console.WriteLine("Registering Device");

                device.UsagePage = di.HIDInfo.UsagePage;
                device.Usage = (ushort)HidUsage.Keyboard;
                device.Flags = RawInputDeviceFlags.INPUTSINK;
                device.Target = hwnd;

                RawInputDevice[] devices = new RawInputDevice[1];
                devices[0] = device;

                if (RegisterRawInputDevices(devices, (uint)devices.Length, (uint)Marshal.SizeOf(typeof(RawInputDevice))) == false)
                {
                    Console.WriteLine("Failure");
                    return;
                }
                else
                {
                    Console.WriteLine("Success!");
                }
                break;
            }
        }

        Marshal.FreeHGlobal(pRawInputDeviceList);
    }
    else
    {
        Console.WriteLine(Marshal.GetLastWin32Error());
    }
}

[StructLayout(LayoutKind.Sequential)]
internal struct RawInputDevice
{
    internal ushort UsagePage;
    internal ushort Usage;
    internal RawInputDeviceFlags Flags;
    internal IntPtr Target;

    public override string ToString()
    {
        return string.Format("{0}/{1}, flags: {2}, target: {3}", UsagePage, Usage, Flags, Target);
    }
}

[StructLayout(LayoutKind.Sequential)]
internal struct RawInputDeviceList
{
    public IntPtr hDevice;
    public uint dwType;
}

[StructLayout(LayoutKind.Explicit)]
public struct DeviceInfo
{
    [FieldOffset(0)]
    public int Size;
    [FieldOffset(4)]
    public int Type;

    [FieldOffset(8)]
    public DeviceInfoMouse MouseInfo;
    [FieldOffset(8)]
    public DeviceInfoKeyboard KeyboardInfo;
    [FieldOffset(8)]
    public DeviceInfoHid HIDInfo;

    public override string ToString()
    {
        return string.Format("DeviceInfo\n Size: {0}\n Type: {1}\n", Size, Type);
    }
}

不够详细,但我认为您的代码如下所示:

public static void Main(string[] args)
{
    MyClass messageReciever = new MyClass();
    messageReciever.StartRecievingMessages();
    Console.WriteLine("Press Q to exit...");
    while (Console.ReadKey(true).Key != ConsoleKey.Q) { }
}

将 [STAThread] 添加到您的入口点以保持 window 活动:

[STAThread]
public static void Main(string[] args)

更新: 我有一个解决方案给你我的朋友!在程序入口你需要添加这个:

Application.Run(window);

并且还在输入 class 中覆盖 OnShow(以在出现时隐藏 window):

protected override void OnShown(EventArgs e)
{
    base.OnShown(e);
    Hide();
}

原因是Form必须先获得焦点,Flag-"keep capturing in background"才起作用