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"
32 #include "base/win/scoped_handle.h"
34 #endif // defined(OS_WIN)
36 // Setup API is required to enumerate HID devices.
37 #pragma comment(lib, "setupapi.lib")
38 #pragma comment(lib, "hid.lib")
43 const char kHIDClass[] = "HIDClass";
47 HidServiceWin::HidServiceWin() {
51 HidServiceWin::~HidServiceWin() {}
53 void HidServiceWin::Enumerate() {
55 HDEVINFO device_info_set;
56 SP_DEVINFO_DATA devinfo_data;
57 SP_DEVICE_INTERFACE_DATA device_interface_data;
59 memset(&devinfo_data, 0, sizeof(SP_DEVINFO_DATA));
60 devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
61 device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
63 device_info_set = SetupDiGetClassDevs(
64 &GUID_DEVINTERFACE_HID,
67 DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
69 std::set<std::string> connected_devices;
71 if (device_info_set != INVALID_HANDLE_VALUE) {
72 for (int device_index = 0;
73 SetupDiEnumDeviceInterfaces(device_info_set,
75 &GUID_DEVINTERFACE_HID,
77 &device_interface_data);
79 DWORD required_size = 0;
81 // Determime the required size of detail struct.
82 SetupDiGetDeviceInterfaceDetailA(device_info_set,
83 &device_interface_data,
89 scoped_ptr<SP_DEVICE_INTERFACE_DETAIL_DATA_A, base::FreeDeleter>
90 device_interface_detail_data(
91 static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_A*>(
92 malloc(required_size)));
93 device_interface_detail_data->cbSize =
94 sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
96 // Get the detailed data for this device.
97 res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
98 &device_interface_data,
99 device_interface_detail_data.get(),
106 // Enumerate device info. Looking for Setup Class "HIDClass".
108 SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);
110 char class_name[256] = {0};
111 res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
116 sizeof(class_name) - 1,
120 if (memcmp(class_name, kHIDClass, sizeof(kHIDClass)) == 0) {
121 char driver_name[256] = {0};
122 // Get bounded driver.
123 res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
128 sizeof(driver_name) - 1,
140 PlatformAddDevice(device_interface_detail_data->DevicePath);
141 connected_devices.insert(device_interface_detail_data->DevicePath);
145 // Find disconnected devices.
146 const DeviceMap& devices = GetDevicesNoEnumerate();
147 std::vector<std::string> disconnected_devices;
148 for (DeviceMap::const_iterator it = devices.begin();
151 if (!ContainsKey(connected_devices, it->first)) {
152 disconnected_devices.push_back(it->first);
156 // Remove disconnected devices.
157 for (size_t i = 0; i < disconnected_devices.size(); ++i) {
158 PlatformRemoveDevice(disconnected_devices[i]);
162 void HidServiceWin::PlatformAddDevice(const std::string& device_path) {
163 HidDeviceInfo device_info;
164 device_info.device_id = device_path;
166 // Try to open the device.
167 base::win::ScopedHandle device_handle(
168 CreateFileA(device_path.c_str(),
169 GENERIC_WRITE | GENERIC_READ,
170 FILE_SHARE_READ | FILE_SHARE_WRITE,
173 FILE_FLAG_OVERLAPPED,
176 if (!device_handle.IsValid() &&
177 GetLastError() == base::File::FILE_ERROR_ACCESS_DENIED) {
178 base::win::ScopedHandle device_handle(
179 CreateFileA(device_path.c_str(),
184 FILE_FLAG_OVERLAPPED,
187 if (!device_handle.IsValid())
192 HIDD_ATTRIBUTES attrib = {0};
193 attrib.Size = sizeof(HIDD_ATTRIBUTES);
194 if (!HidD_GetAttributes(device_handle.Get(), &attrib))
197 device_info.vendor_id = attrib.VendorID;
198 device_info.product_id = attrib.ProductID;
201 HidD_SetNumInputBuffers(device_handle.Get(), i);
204 // Get usage and usage page (optional).
205 PHIDP_PREPARSED_DATA preparsed_data;
206 if (HidD_GetPreparsedData(device_handle.Get(), &preparsed_data) &&
208 HIDP_CAPS capabilities = {0};
209 if (HidP_GetCaps(preparsed_data, &capabilities) == HIDP_STATUS_SUCCESS) {
210 device_info.max_input_report_size = capabilities.InputReportByteLength;
211 device_info.max_output_report_size = capabilities.OutputReportByteLength;
212 device_info.max_feature_report_size =
213 capabilities.FeatureReportByteLength;
214 HidCollectionInfo collection_info;
215 collection_info.usage = HidUsageAndPage(
217 static_cast<HidUsageAndPage::Page>(capabilities.UsagePage));
218 USHORT button_caps_length = capabilities.NumberInputButtonCaps;
219 if (button_caps_length > 0) {
220 scoped_ptr<HIDP_BUTTON_CAPS[]> button_caps(
221 new HIDP_BUTTON_CAPS[button_caps_length]);
222 if (HidP_GetButtonCaps(HidP_Input,
225 preparsed_data) == HIDP_STATUS_SUCCESS) {
226 for (int i = 0; i < button_caps_length; i++) {
227 int report_id = button_caps[i].ReportID;
228 if (report_id != 0) {
229 collection_info.report_ids.insert(report_id);
230 device_info.has_report_id = true;
235 USHORT value_caps_length = capabilities.NumberInputValueCaps;
236 if (value_caps_length > 0) {
237 scoped_ptr<HIDP_VALUE_CAPS[]> value_caps(
238 new HIDP_VALUE_CAPS[value_caps_length]);
239 if (HidP_GetValueCaps(HidP_Input,
242 preparsed_data) == HIDP_STATUS_SUCCESS) {
243 for (int i = 0; i < value_caps_length; i++) {
244 int report_id = value_caps[i].ReportID;
245 if (report_id != 0) {
246 collection_info.report_ids.insert(report_id);
247 device_info.has_report_id = true;
252 device_info.collections.push_back(collection_info);
254 // Whether or not the device includes report IDs in its reports the size
255 // of the report ID is included in the value provided by Windows. This
256 // appears contrary to the MSDN documentation.
257 if (device_info.max_input_report_size > 0) {
258 device_info.max_input_report_size--;
260 if (device_info.max_output_report_size > 0) {
261 device_info.max_output_report_size--;
263 if (device_info.max_feature_report_size > 0) {
264 device_info.max_feature_report_size--;
266 HidD_FreePreparsedData(preparsed_data);
269 AddDevice(device_info);
272 void HidServiceWin::PlatformRemoveDevice(const std::string& device_path) {
273 RemoveDevice(device_path);
276 void HidServiceWin::GetDevices(std::vector<HidDeviceInfo>* devices) {
278 HidService::GetDevices(devices);
281 scoped_refptr<HidConnection> HidServiceWin::Connect(
282 const HidDeviceId& device_id) {
283 HidDeviceInfo device_info;
284 if (!GetDeviceInfo(device_id, &device_info))
286 scoped_refptr<HidConnectionWin> connection(new HidConnectionWin(device_info));
287 if (!connection->available()) {
288 PLOG(ERROR) << "Failed to open device.";
294 } // namespace device