从 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"才起作用
所以我有一个控制台应用程序,我从 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"才起作用