Associate HID Touch Device with Pnp Monitor

2020-03-26 11:55发布

I am developing a tool that displays a status about various hardware components on a system we use at work. Currently, we have 16 touch screen monitors (all by 3M) plugged in to a Windows 10 box. I need to verify that any given monitor has an associated touch screen recognized by windows. This is to assess the system for any hardware malfunctions i.e. bad cable, bad USB port, bad Monitor, etc. We see this more than we would like to admit, usually where a monitor's display will be working fine but the USB controller on either end drops out and needs to be reset by unplugging/plugging back in

Unfortunately my code posting will be limited due to work constraints.

I can enumerate all of the monitors plugged in to the system via winapi's EnumDisplayDevices and EnumerateDisplayMonitors. I am able to build a list of all the HID touch screen devices using HIDApi.

From here I have no direction on where to go to link these two things together, if it is even possible. My first thought was the HID device information should have some sort of identifier shared by the results of calling the EnumDisplayDevices and EnumerateDisplayMonitors, but I have not found this to be the case. Another possibility would be to compare the coordinates/size of a monitor to a region that one of the touch controllers is responsible for. Again, not sure if that is possible.

In short, is there a way to associate a Touch device with it's corresponding monitor via c++?

2条回答
混吃等死
2楼-- · 2020-03-26 12:37

After the suggestions in the comments and looking deeper into the registry, I've found a way to link Touch controllers to a monitor.

Using HIDApi, you can poll the system and find a list of all the Touch Controllers you need to monitor. I filtered by the VID of the monitors we are using. A sample return value for the path looks something like this:

"\\?\hid#vid_0596&pid_0520&col02#8&33d9e616&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}"

The bold part can be used to link to the entries in HKLM/Software/Microsoft/Wisp/Pen/Digimon. An example entry is this:

"\\?\HID#VID_0596&PID_0520&Col03#8&33d9e616&0&0002#{4d1e55b2-f16f-11cf-88cb-001111000030}" "\\?\DISPLAY#MSY1C2B#7&1083071f&0&UID524#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}"

The first bold matches the data found through HIDApi and the second set of bolding, the monitor name and a UID, is listed in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\DISPLAY. Under here you can use the combination of monitor name and UID to find the Driver entry. Below is a sample driver entry:

{4d36e96e-e325-11ce-bfc1-08002be10318}\0010

The last bold number can then be used to match up with a DeviceID returned from EnumDisplayDevices(). Below is a sample DeviceID:

"MONITOR\MSY1C2B\{4d36e96e-e325-11ce-bfc1-08002be10318}\0010".

Then you can use this bolded section to match up to names of monitors returned from EnumDisplayMonitors().

查看更多
迷人小祖宗
3楼-- · 2020-03-26 12:38

I think you were just lucky that this driver suffix matched your monitor configuration. In my Windows 10 multi-monitor setup I get wrong displays when I look them up with this number in the driver entry as you described.

A reliable way for associating a HID device with a display seems to be:

  1. Call GetRawInputDeviceList() to obtain the HID devices
  2. Call GetRawInputDeviceInfo() with RIDI_DEVICEINFO to determine Usage and UsagePage
  3. Call GetRawInputDeviceInfo() with RIDI_DEVICENAME to get a device string in the form \\\\?\\HID#VID_0EEF&PID_7200&Col01#6&152cc7f9&1&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
  4. Query the registry for the mapping table at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wisp\Pen\Digimon and look up the display device name. In my case the HID names are all prefixed with 20- there but the remaining part seems to match the name queried by GetRawInputDeviceInfo() exactly. As a fallback method in case there is no match, I also parse the middle part as Clay Brooks described in his answer.
  5. Call EnumDisplayDevices() with a null pointer for lpDevice and 0 for dwFlags in a loop until the function returns zero.
  6. Within each loop iteration, call EnumDisplayDevices() again with the current device as lpDevice and EDD_GET_DEVICE_INTERFACE_NAME for dwFlags and observe that it returns a DeviceID in the form \\\\?\\DISPLAY#ELO2243#5&607b301&0&UID24833#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
  7. Loop until a HID <-> display match is found and take the DeviceName returned by the "outer" EnumDisplayDevices() call which should be something like \\.\DISPLAY3
查看更多
登录 后发表回答