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/stl_util.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "device/hid/hid_connection_win.h"
12 #include "device/hid/hid_device_info.h"
13 #include "net/base/io_buffer.h"
31 #include "base/win/scoped_handle.h"
33 #endif // defined(OS_WIN)
35 // Setup API is required to enumerate HID devices.
36 #pragma comment(lib, "setupapi.lib")
37 #pragma comment(lib, "hid.lib")
42 const char kHIDClass
[] = "HIDClass";
46 HidServiceWin::HidServiceWin() {
50 HidServiceWin::~HidServiceWin() {}
52 void HidServiceWin::Enumerate() {
54 HDEVINFO device_info_set
;
55 SP_DEVINFO_DATA devinfo_data
;
56 SP_DEVICE_INTERFACE_DATA device_interface_data
;
58 memset(&devinfo_data
, 0, sizeof(SP_DEVINFO_DATA
));
59 devinfo_data
.cbSize
= sizeof(SP_DEVINFO_DATA
);
60 device_interface_data
.cbSize
= sizeof(SP_DEVICE_INTERFACE_DATA
);
62 device_info_set
= SetupDiGetClassDevs(
63 &GUID_DEVINTERFACE_HID
,
66 DIGCF_PRESENT
| DIGCF_DEVICEINTERFACE
);
68 if (device_info_set
== INVALID_HANDLE_VALUE
)
71 for (int device_index
= 0;
72 SetupDiEnumDeviceInterfaces(device_info_set
,
74 &GUID_DEVINTERFACE_HID
,
76 &device_interface_data
);
78 DWORD required_size
= 0;
80 // Determime the required size of detail struct.
81 SetupDiGetDeviceInterfaceDetailA(device_info_set
,
82 &device_interface_data
,
88 scoped_ptr
<SP_DEVICE_INTERFACE_DETAIL_DATA_A
, base::FreeDeleter
>
89 device_interface_detail_data(
90 static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_A
*>(
91 malloc(required_size
)));
92 device_interface_detail_data
->cbSize
=
93 sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A
);
95 // Get the detailed data for this device.
96 res
= SetupDiGetDeviceInterfaceDetailA(device_info_set
,
97 &device_interface_data
,
98 device_interface_detail_data
.get(),
105 // Enumerate device info. Looking for Setup Class "HIDClass".
107 SetupDiEnumDeviceInfo(device_info_set
, i
, &devinfo_data
);
109 char class_name
[256] = {0};
110 res
= SetupDiGetDeviceRegistryPropertyA(device_info_set
,
115 sizeof(class_name
) - 1,
119 if (memcmp(class_name
, kHIDClass
, sizeof(kHIDClass
)) == 0) {
120 char driver_name
[256] = {0};
121 // Get bounded driver.
122 res
= SetupDiGetDeviceRegistryPropertyA(device_info_set
,
127 sizeof(driver_name
) - 1,
139 PlatformAddDevice(device_interface_detail_data
->DevicePath
);
143 void HidServiceWin::PlatformAddDevice(const std::string
& device_path
) {
144 HidDeviceInfo device_info
;
145 device_info
.device_id
= device_path
;
147 // Try to open the device.
148 base::win::ScopedHandle
device_handle(
149 CreateFileA(device_path
.c_str(),
154 FILE_FLAG_OVERLAPPED
,
156 if (!device_handle
.IsValid())
160 HIDD_ATTRIBUTES attrib
= {0};
161 attrib
.Size
= sizeof(HIDD_ATTRIBUTES
);
162 if (!HidD_GetAttributes(device_handle
.Get(), &attrib
))
165 device_info
.vendor_id
= attrib
.VendorID
;
166 device_info
.product_id
= attrib
.ProductID
;
169 HidD_SetNumInputBuffers(device_handle
.Get(), i
);
172 // Get usage and usage page (optional).
173 PHIDP_PREPARSED_DATA preparsed_data
;
174 if (HidD_GetPreparsedData(device_handle
.Get(), &preparsed_data
) &&
176 HIDP_CAPS capabilities
;
177 if (HidP_GetCaps(preparsed_data
, &capabilities
) == HIDP_STATUS_SUCCESS
) {
178 device_info
.input_report_size
= capabilities
.InputReportByteLength
;
179 device_info
.output_report_size
= capabilities
.OutputReportByteLength
;
180 device_info
.feature_report_size
= capabilities
.FeatureReportByteLength
;
181 device_info
.usages
.push_back(HidUsageAndPage(
183 static_cast<HidUsageAndPage::Page
>(capabilities
.UsagePage
)));
185 // Detect if the device supports report ids.
186 if (capabilities
.NumberInputValueCaps
> 0) {
187 scoped_ptr
<HIDP_VALUE_CAPS
[]> value_caps(
188 new HIDP_VALUE_CAPS
[capabilities
.NumberInputValueCaps
]);
189 USHORT value_caps_length
= capabilities
.NumberInputValueCaps
;
190 if (HidP_GetValueCaps(HidP_Input
, &value_caps
[0], &value_caps_length
,
191 preparsed_data
) == HIDP_STATUS_SUCCESS
) {
192 device_info
.has_report_id
= (value_caps
[0].ReportID
!= 0);
195 if (!device_info
.has_report_id
&& capabilities
.NumberInputButtonCaps
> 0)
197 scoped_ptr
<HIDP_BUTTON_CAPS
[]> button_caps(
198 new HIDP_BUTTON_CAPS
[capabilities
.NumberInputButtonCaps
]);
199 USHORT button_caps_length
= capabilities
.NumberInputButtonCaps
;
200 if (HidP_GetButtonCaps(HidP_Input
,
203 preparsed_data
) == HIDP_STATUS_SUCCESS
) {
204 device_info
.has_report_id
= (button_caps
[0].ReportID
!= 0);
208 HidD_FreePreparsedData(preparsed_data
);
211 AddDevice(device_info
);
214 void HidServiceWin::PlatformRemoveDevice(const std::string
& device_path
) {
215 RemoveDevice(device_path
);
218 void HidServiceWin::GetDevices(std::vector
<HidDeviceInfo
>* devices
) {
220 HidService::GetDevices(devices
);
223 scoped_refptr
<HidConnection
> HidServiceWin::Connect(
224 const HidDeviceId
& device_id
) {
225 HidDeviceInfo device_info
;
226 if (!GetDeviceInfo(device_id
, &device_info
))
228 scoped_refptr
<HidConnectionWin
> connection(new HidConnectionWin(device_info
));
229 if (!connection
->available()) {
230 LOG_GETLASTERROR(ERROR
) << "Failed to open device.";
236 } // namespace device