1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "device/hid/hid_service_win.h"
9 #include "base/files/file.h"
10 #include "base/stl_util.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "device/hid/hid_connection_win.h"
13 #include "device/hid/hid_device_info.h"
14 #include "net/base/io_buffer.h"
22 #include "base/win/scoped_handle.h"
24 #endif // defined(OS_WIN)
26 // Setup API is required to enumerate HID devices.
27 #pragma comment(lib, "setupapi.lib")
28 #pragma comment(lib, "hid.lib")
33 const char kHIDClass
[] = "HIDClass";
37 HidServiceWin::HidServiceWin() {
41 HidServiceWin::~HidServiceWin() {}
43 void HidServiceWin::Enumerate() {
45 HDEVINFO device_info_set
;
46 SP_DEVINFO_DATA devinfo_data
;
47 SP_DEVICE_INTERFACE_DATA device_interface_data
;
49 memset(&devinfo_data
, 0, sizeof(SP_DEVINFO_DATA
));
50 devinfo_data
.cbSize
= sizeof(SP_DEVINFO_DATA
);
51 device_interface_data
.cbSize
= sizeof(SP_DEVICE_INTERFACE_DATA
);
53 device_info_set
= SetupDiGetClassDevs(
54 &GUID_DEVINTERFACE_HID
,
57 DIGCF_PRESENT
| DIGCF_DEVICEINTERFACE
);
59 std::set
<std::string
> connected_devices
;
61 if (device_info_set
!= INVALID_HANDLE_VALUE
) {
62 for (int device_index
= 0;
63 SetupDiEnumDeviceInterfaces(device_info_set
,
65 &GUID_DEVINTERFACE_HID
,
67 &device_interface_data
);
69 DWORD required_size
= 0;
71 // Determime the required size of detail struct.
72 SetupDiGetDeviceInterfaceDetailA(device_info_set
,
73 &device_interface_data
,
79 scoped_ptr
<SP_DEVICE_INTERFACE_DETAIL_DATA_A
, base::FreeDeleter
>
80 device_interface_detail_data(
81 static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_A
*>(
82 malloc(required_size
)));
83 device_interface_detail_data
->cbSize
=
84 sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A
);
86 // Get the detailed data for this device.
87 res
= SetupDiGetDeviceInterfaceDetailA(device_info_set
,
88 &device_interface_data
,
89 device_interface_detail_data
.get(),
96 // Enumerate device info. Looking for Setup Class "HIDClass".
98 SetupDiEnumDeviceInfo(device_info_set
, i
, &devinfo_data
);
100 char class_name
[256] = {0};
101 res
= SetupDiGetDeviceRegistryPropertyA(device_info_set
,
106 sizeof(class_name
) - 1,
110 if (memcmp(class_name
, kHIDClass
, sizeof(kHIDClass
)) == 0) {
111 char driver_name
[256] = {0};
112 // Get bounded driver.
113 res
= SetupDiGetDeviceRegistryPropertyA(device_info_set
,
118 sizeof(driver_name
) - 1,
130 PlatformAddDevice(device_interface_detail_data
->DevicePath
);
131 connected_devices
.insert(device_interface_detail_data
->DevicePath
);
135 // Find disconnected devices.
136 const DeviceMap
& devices
= GetDevicesNoEnumerate();
137 std::vector
<std::string
> disconnected_devices
;
138 for (DeviceMap::const_iterator it
= devices
.begin();
141 if (!ContainsKey(connected_devices
, it
->first
)) {
142 disconnected_devices
.push_back(it
->first
);
146 // Remove disconnected devices.
147 for (size_t i
= 0; i
< disconnected_devices
.size(); ++i
) {
148 PlatformRemoveDevice(disconnected_devices
[i
]);
152 void HidServiceWin::CollectInfoFromButtonCaps(
153 PHIDP_PREPARSED_DATA preparsed_data
,
154 HIDP_REPORT_TYPE report_type
,
155 USHORT button_caps_length
,
156 HidCollectionInfo
* collection_info
) {
157 if (button_caps_length
> 0) {
158 scoped_ptr
<HIDP_BUTTON_CAPS
[]> button_caps(
159 new HIDP_BUTTON_CAPS
[button_caps_length
]);
160 if (HidP_GetButtonCaps(report_type
,
163 preparsed_data
) == HIDP_STATUS_SUCCESS
) {
164 for (size_t i
= 0; i
< button_caps_length
; i
++) {
165 int report_id
= button_caps
[i
].ReportID
;
166 if (report_id
!= 0) {
167 collection_info
->report_ids
.insert(report_id
);
174 void HidServiceWin::CollectInfoFromValueCaps(
175 PHIDP_PREPARSED_DATA preparsed_data
,
176 HIDP_REPORT_TYPE report_type
,
177 USHORT value_caps_length
,
178 HidCollectionInfo
* collection_info
) {
179 if (value_caps_length
> 0) {
180 scoped_ptr
<HIDP_VALUE_CAPS
[]> value_caps(
181 new HIDP_VALUE_CAPS
[value_caps_length
]);
182 if (HidP_GetValueCaps(
183 report_type
, &value_caps
[0], &value_caps_length
, preparsed_data
) ==
184 HIDP_STATUS_SUCCESS
) {
185 for (size_t i
= 0; i
< value_caps_length
; i
++) {
186 int report_id
= value_caps
[i
].ReportID
;
187 if (report_id
!= 0) {
188 collection_info
->report_ids
.insert(report_id
);
195 void HidServiceWin::PlatformAddDevice(const std::string
& device_path
) {
196 HidDeviceInfo device_info
;
197 device_info
.device_id
= device_path
;
199 // Try to open the device.
200 base::win::ScopedHandle
device_handle(
201 CreateFileA(device_path
.c_str(),
202 GENERIC_WRITE
| GENERIC_READ
,
203 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
206 FILE_FLAG_OVERLAPPED
,
209 if (!device_handle
.IsValid() &&
210 GetLastError() == base::File::FILE_ERROR_ACCESS_DENIED
) {
211 base::win::ScopedHandle
device_handle(
212 CreateFileA(device_path
.c_str(),
217 FILE_FLAG_OVERLAPPED
,
220 if (!device_handle
.IsValid())
225 HIDD_ATTRIBUTES attrib
= {0};
226 attrib
.Size
= sizeof(HIDD_ATTRIBUTES
);
227 if (!HidD_GetAttributes(device_handle
.Get(), &attrib
))
230 device_info
.vendor_id
= attrib
.VendorID
;
231 device_info
.product_id
= attrib
.ProductID
;
234 HidD_SetNumInputBuffers(device_handle
.Get(), i
);
237 // Get usage and usage page (optional).
238 PHIDP_PREPARSED_DATA preparsed_data
;
239 if (HidD_GetPreparsedData(device_handle
.Get(), &preparsed_data
) &&
241 HIDP_CAPS capabilities
= {0};
242 if (HidP_GetCaps(preparsed_data
, &capabilities
) == HIDP_STATUS_SUCCESS
) {
243 device_info
.max_input_report_size
= capabilities
.InputReportByteLength
;
244 device_info
.max_output_report_size
= capabilities
.OutputReportByteLength
;
245 device_info
.max_feature_report_size
=
246 capabilities
.FeatureReportByteLength
;
247 HidCollectionInfo collection_info
;
248 collection_info
.usage
= HidUsageAndPage(
250 static_cast<HidUsageAndPage::Page
>(capabilities
.UsagePage
));
251 CollectInfoFromButtonCaps(preparsed_data
,
253 capabilities
.NumberInputButtonCaps
,
255 CollectInfoFromButtonCaps(preparsed_data
,
257 capabilities
.NumberOutputButtonCaps
,
259 CollectInfoFromButtonCaps(preparsed_data
,
261 capabilities
.NumberFeatureButtonCaps
,
263 CollectInfoFromValueCaps(preparsed_data
,
265 capabilities
.NumberInputValueCaps
,
267 CollectInfoFromValueCaps(preparsed_data
,
269 capabilities
.NumberOutputValueCaps
,
271 CollectInfoFromValueCaps(preparsed_data
,
273 capabilities
.NumberFeatureValueCaps
,
275 if (!collection_info
.report_ids
.empty()) {
276 device_info
.has_report_id
= true;
278 device_info
.collections
.push_back(collection_info
);
280 // Whether or not the device includes report IDs in its reports the size
281 // of the report ID is included in the value provided by Windows. This
282 // appears contrary to the MSDN documentation.
283 if (device_info
.max_input_report_size
> 0) {
284 device_info
.max_input_report_size
--;
286 if (device_info
.max_output_report_size
> 0) {
287 device_info
.max_output_report_size
--;
289 if (device_info
.max_feature_report_size
> 0) {
290 device_info
.max_feature_report_size
--;
292 HidD_FreePreparsedData(preparsed_data
);
295 AddDevice(device_info
);
298 void HidServiceWin::PlatformRemoveDevice(const std::string
& device_path
) {
299 RemoveDevice(device_path
);
302 void HidServiceWin::GetDevices(std::vector
<HidDeviceInfo
>* devices
) {
304 HidService::GetDevices(devices
);
307 scoped_refptr
<HidConnection
> HidServiceWin::Connect(
308 const HidDeviceId
& device_id
) {
309 HidDeviceInfo device_info
;
310 if (!GetDeviceInfo(device_id
, &device_info
))
312 scoped_refptr
<HidConnectionWin
> connection(new HidConnectionWin(device_info
));
313 if (!connection
->available()) {
314 PLOG(ERROR
) << "Failed to open device.";
320 } // namespace device