问题描述
通常,仅使用与控制器的播放器编号相对应的索引来标识XInput控制器。有没有办法获取有关具有特定索引的控制器的更多信息,例如其供应商ID,产品ID或设备名称?
更好的是,标识符唯一且一致地仅与该控制器相对应,以便可以将其与所有其他XInput设备区分开来,而不管其索引如何,包括具有相同型号(即相同产品和供应商ID)的另一个控制器,类似于可使用DirectInput的实例GUID。
这可以使用XInput或其他Microsoft API完成吗?如果需要,我也愿意使用未记录的功能。
解决方法
XInput 内部所做的是打开一个设备,然后在每次读取游戏手柄时调用它的 DeviceIoControl
。 (控制码0x8000e00c)
需要hook这些由“XInput1_4.dll”导入的函数:
-
CreateFileW
来自“api-ms-win-core-file-l1-1-0.dll” -
DuplicateHandle
来自“api-ms-win-core-handle-l1-1-0.dll” -
CloseHandle
来自“api-ms-win-core-handle-l1-1-0.dll” -
DeviceIoControl
来自“api-ms-win-core-io-l1-1-0.dll”
使用 CreateFileW
、DuplicateHandle
和 CloseHandle
的挂钩,您可以跟踪与句柄关联的文件名。
然后,当您看到控制代码为 0x8000e00c 的对 DeviceIoControl
的调用时,您就会知道正在读取的文件名。
第一次调用 XInputGetState
时,它会打开多个设备,并多次调用 DeviceIoControl
,无论您请求的是哪个玩家号码。您只对 DeviceIoControl
在 XInputGetState
返回之前看到的最后一个文件名感兴趣。如果 XInputGetState
表示控制器未插入,请忽略您为该控制器编号收集的文件名。
我在自己的计算机上看到的文件名示例:
\\?\hid#{00001124-0000-1000-8000-00805f9b34fb}&vid_045e&pid_02e0&ig_00#8&7074921&2&0000#{ec87f1e3-c13b-4100-b5f7-8b84d54260cb}
\\?\usb#vid_045e&pid_028e#1&1a590e2c&1&01#{ec87f1e3-c13b-4100-b5f7-8b84d54260cb}
编辑:
还需要一个钩子。
-
CoCreateInstance
来自“api-ms-win-core-com-l1-1-0.dll”,用于挂钩创建未记录的IDeviceBroker
COM 对象。如果它可以成功创建一个IDeviceBroker
COM 对象,它将使用该对象而不是对CreateFileW
的调用。参数将为:CLSID_DeviceBroker = {acc56a05-e277-4b1e-a43e-7a73e3cd6e6c}
、IID_IDeviceBroker = {8604b268-34a6-4b1a-a59f-cdbd8379fd98}
。将调用方法OpenDeviceFromInterfacePath
而不是CreateFileW
。或者,您可以简单地创建IDeviceBroker
对象失败,它会继续像往常一样使用CreateFileW
。