What XInput internally does is open a device, then call DeviceIoControl
on it every time it reads the joypad. (control code 0x8000e00c)
You need to hook these functions imported by "XInput1_4.dll":
CreateFileW
from "api-ms-win-core-file-l1-1-0.dll"
DuplicateHandle
from "api-ms-win-core-handle-l1-1-0.dll"
CloseHandle
from "api-ms-win-core-handle-l1-1-0.dll"
DeviceIoControl
from "api-ms-win-core-io-l1-1-0.dll"
Using the hooks for CreateFileW
, DuplicateHandle
and CloseHandle
, you can keep track of what filename is associated with a handle.
Then when you see a call to DeviceIoControl
with control code 0x8000e00c, you will know what filename is being read.
The first time you call XInputGetState
, it will open multiple devices, and call DeviceIoControl
multiple times, regardless of what player number you have asked for. You are only interested in the last filename seen by DeviceIoControl
before XInputGetState
returns. And if XInputGetState
indicates the controller is not plugged in, disregard the filename you have collected for that controller number.
Examples of filenames I have seen on my own computer:
\\?\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}
edit:
One more hook is required as well.
CoCreateInstance
from "api-ms-win-core-com-l1-1-0.dll", to hook creating the undocumented IDeviceBroker
COM object. If it can successfully create an IDeviceBroker
COM object, it will use that instead of the call to CreateFileW
. Parameters will be: CLSID_DeviceBroker = {acc56a05-e277-4b1e-a43e-7a73e3cd6e6c}
, IID_IDeviceBroker = {8604b268-34a6-4b1a-a59f-cdbd8379fd98}
. The method OpenDeviceFromInterfacePath
will be called instead of CreateFileW
. Alternatively, you can make creating the IDeviceBroker
object simply fail, and it will proceed to use CreateFileW
as usual.