Index: device/hid/hid_service_win.cc |
diff --git a/device/hid/hid_service_win.cc b/device/hid/hid_service_win.cc |
index a0fce8f3c6af5b2ec848181ac2abf98fffb69532..ccc18a71f99e2ebad7e6c44dd20eb1c3b93e378d 100644 |
--- a/device/hid/hid_service_win.cc |
+++ b/device/hid/hid_service_win.cc |
@@ -4,30 +4,25 @@ |
#include "device/hid/hid_service_win.h" |
-#include <cstdlib> |
+#define INITGUID |
+ |
+#include <dbt.h> |
+#include <setupapi.h> |
+#include <winioctl.h> |
#include "base/bind.h" |
#include "base/files/file.h" |
#include "base/location.h" |
#include "base/single_thread_task_runner.h" |
-#include "base/stl_util.h" |
+#include "base/strings/string_util.h" |
#include "base/strings/sys_string_conversions.h" |
#include "base/thread_task_runner_handle.h" |
#include "base/threading/thread_restrictions.h" |
+#include "base/win/message_window.h" |
#include "device/hid/hid_connection_win.h" |
#include "device/hid/hid_device_info.h" |
#include "net/base/io_buffer.h" |
-#if defined(OS_WIN) |
- |
-#define INITGUID |
- |
-#include <setupapi.h> |
-#include <winioctl.h> |
-#include "base/win/scoped_handle.h" |
- |
-#endif // defined(OS_WIN) |
- |
// Setup API is required to enumerate HID devices. |
#pragma comment(lib, "setupapi.lib") |
#pragma comment(lib, "hid.lib") |
@@ -36,36 +31,94 @@ namespace device { |
namespace { |
const char kHIDClass[] = "HIDClass"; |
+const wchar_t kWindowClassName[] = L"HidServiceMessageWindow"; |
} // namespace |
HidServiceWin::HidServiceWin() { |
task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
DCHECK(task_runner_.get()); |
- Enumerate(); |
+ RegisterForDeviceNotifications(); |
+ DoInitialEnumeration(); |
} |
-HidServiceWin::~HidServiceWin() {} |
+void HidServiceWin::Connect(const HidDeviceId& device_id, |
+ const ConnectCallback& callback) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ const auto& map_entry = devices().find(device_id); |
+ if (map_entry == devices().end()) { |
+ task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); |
+ return; |
+ } |
+ const HidDeviceInfo& device_info = map_entry->second; |
-void HidServiceWin::Enumerate() { |
- BOOL res; |
- HDEVINFO device_info_set; |
- SP_DEVINFO_DATA devinfo_data; |
- SP_DEVICE_INTERFACE_DATA device_interface_data; |
+ base::win::ScopedHandle file(OpenDevice(device_info.device_id)); |
+ if (!file.IsValid()) { |
+ PLOG(ERROR) << "Failed to open device"; |
+ task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); |
+ return; |
+ } |
- memset(&devinfo_data, 0, sizeof(SP_DEVINFO_DATA)); |
- devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA); |
- device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); |
+ task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(callback, new HidConnectionWin(device_info, file.Pass()))); |
+} |
- device_info_set = SetupDiGetClassDevs( |
- &GUID_DEVINTERFACE_HID, |
- NULL, |
- NULL, |
- DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); |
+HidServiceWin::~HidServiceWin() { |
+ if (notify_handle_) { |
+ UnregisterDeviceNotification(notify_handle_); |
+ } |
+} |
- std::set<std::string> connected_devices; |
+void HidServiceWin::RegisterForDeviceNotifications() { |
+ window_.reset(new base::win::MessageWindow()); |
Ken Rockot(use gerrit already)
2014/12/05 23:27:53
nit: Maybe file a bug + add a TODO which expresses
|
+ if (!window_->CreateNamed( |
+ base::Bind(&HidServiceWin::HandleMessage, base::Unretained(this)), |
+ base::string16(kWindowClassName))) { |
+ LOG(ERROR) << "Failed to create message window: " << kWindowClassName; |
+ window_.reset(); |
+ } |
+ DEV_BROADCAST_DEVICEINTERFACE db = { sizeof(DEV_BROADCAST_DEVICEINTERFACE), |
+ DBT_DEVTYP_DEVICEINTERFACE, |
+ 0, |
+ GUID_DEVINTERFACE_HID }; |
+ notify_handle_ = RegisterDeviceNotification(window_->hwnd(), &db, |
+ DEVICE_NOTIFY_WINDOW_HANDLE); |
+ if (!notify_handle_) { |
+ LOG(ERROR) << "Failed to register for device notifications."; |
+ window_.reset(); |
+ } |
+} |
+ |
+bool HidServiceWin::HandleMessage(UINT message, |
+ WPARAM wparam, |
+ LPARAM lparam, |
+ LRESULT* result) { |
+ if (message == WM_DEVICECHANGE) { |
+ DEV_BROADCAST_DEVICEINTERFACE* db = |
+ reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(lparam); |
+ std::string device_path(base::SysWideToUTF8(db->dbcc_name)); |
+ DCHECK(base::IsStringASCII(device_path)); |
+ if (wparam == DBT_DEVICEARRIVAL) { |
+ PlatformAddDevice(base::StringToLowerASCII(device_path)); |
+ } else if (wparam == DBT_DEVICEREMOVECOMPLETE) { |
+ PlatformRemoveDevice(base::StringToLowerASCII(device_path)); |
+ } |
+ *result = NULL; |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+void HidServiceWin::DoInitialEnumeration() { |
+ HDEVINFO device_info_set = |
+ SetupDiGetClassDevs(&GUID_DEVINTERFACE_HID, NULL, NULL, |
+ DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); |
if (device_info_set != INVALID_HANDLE_VALUE) { |
+ SP_DEVICE_INTERFACE_DATA device_interface_data; |
+ device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); |
+ |
for (int device_index = 0; |
SetupDiEnumDeviceInterfaces(device_info_set, |
NULL, |
@@ -76,84 +129,32 @@ void HidServiceWin::Enumerate() { |
DWORD required_size = 0; |
// Determime the required size of detail struct. |
- SetupDiGetDeviceInterfaceDetailA(device_info_set, |
- &device_interface_data, |
- NULL, |
- 0, |
- &required_size, |
- NULL); |
+ SetupDiGetDeviceInterfaceDetail(device_info_set, &device_interface_data, |
+ NULL, 0, &required_size, NULL); |
- scoped_ptr<SP_DEVICE_INTERFACE_DETAIL_DATA_A, base::FreeDeleter> |
- device_interface_detail_data( |
- static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_A*>( |
- malloc(required_size))); |
+ scoped_ptr<SP_DEVICE_INTERFACE_DETAIL_DATA, base::FreeDeleter> |
+ device_interface_detail_data( |
+ static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>(malloc(required_size))); |
device_interface_detail_data->cbSize = |
- sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); |
+ sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); |
// Get the detailed data for this device. |
- res = SetupDiGetDeviceInterfaceDetailA(device_info_set, |
- &device_interface_data, |
- device_interface_detail_data.get(), |
- required_size, |
- NULL, |
- NULL); |
- if (!res) |
+ BOOL res = SetupDiGetDeviceInterfaceDetail( |
+ device_info_set, &device_interface_data, |
+ device_interface_detail_data.get(), required_size, NULL, NULL); |
+ if (!res) { |
continue; |
- |
- // Enumerate device info. Looking for Setup Class "HIDClass". |
- for (DWORD i = 0; |
- SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data); |
- i++) { |
- char class_name[256] = {0}; |
- res = SetupDiGetDeviceRegistryPropertyA(device_info_set, |
- &devinfo_data, |
- SPDRP_CLASS, |
- NULL, |
- (PBYTE) class_name, |
- sizeof(class_name) - 1, |
- NULL); |
- if (!res) |
- break; |
- if (memcmp(class_name, kHIDClass, sizeof(kHIDClass)) == 0) { |
- char driver_name[256] = {0}; |
- // Get bounded driver. |
- res = SetupDiGetDeviceRegistryPropertyA(device_info_set, |
- &devinfo_data, |
- SPDRP_DRIVER, |
- NULL, |
- (PBYTE) driver_name, |
- sizeof(driver_name) - 1, |
- NULL); |
- if (res) { |
- // Found the driver. |
- break; |
- } |
- } |
} |
- if (!res) |
- continue; |
- |
- PlatformAddDevice(device_interface_detail_data->DevicePath); |
- connected_devices.insert(device_interface_detail_data->DevicePath); |
- } |
- } |
- |
- // Find disconnected devices. |
- std::vector<std::string> disconnected_devices; |
- for (DeviceMap::const_iterator it = devices().begin(); it != devices().end(); |
- ++it) { |
- if (!ContainsKey(connected_devices, it->first)) { |
- disconnected_devices.push_back(it->first); |
+ std::string device_path( |
+ base::SysWideToUTF8(device_interface_detail_data->DevicePath)); |
+ DCHECK(base::IsStringASCII(device_path)); |
+ PlatformAddDevice(device_path); |
} |
} |
- |
- // Remove disconnected devices. |
- for (size_t i = 0; i < disconnected_devices.size(); ++i) { |
- PlatformRemoveDevice(disconnected_devices[i]); |
- } |
} |
+// static |
void HidServiceWin::CollectInfoFromButtonCaps( |
PHIDP_PREPARSED_DATA preparsed_data, |
HIDP_REPORT_TYPE report_type, |
@@ -176,6 +177,7 @@ void HidServiceWin::CollectInfoFromButtonCaps( |
} |
} |
+// static |
void HidServiceWin::CollectInfoFromValueCaps( |
PHIDP_PREPARSED_DATA preparsed_data, |
HIDP_REPORT_TYPE report_type, |
@@ -202,43 +204,21 @@ void HidServiceWin::PlatformAddDevice(const std::string& device_path) { |
device_info.device_id = device_path; |
// Try to open the device. |
- base::win::ScopedHandle device_handle( |
- CreateFileA(device_path.c_str(), |
- GENERIC_WRITE | GENERIC_READ, |
- FILE_SHARE_READ | FILE_SHARE_WRITE, |
- NULL, |
- OPEN_EXISTING, |
- FILE_FLAG_OVERLAPPED, |
- 0)); |
- |
- if (!device_handle.IsValid() && |
- GetLastError() == base::File::FILE_ERROR_ACCESS_DENIED) { |
- base::win::ScopedHandle device_handle( |
- CreateFileA(device_path.c_str(), |
- GENERIC_READ, |
- FILE_SHARE_READ, |
- NULL, |
- OPEN_EXISTING, |
- FILE_FLAG_OVERLAPPED, |
- 0)); |
- |
- if (!device_handle.IsValid()) |
- return; |
+ base::win::ScopedHandle device_handle(OpenDevice(device_path)); |
+ if (!device_handle.IsValid()) { |
+ return; |
} |
// Get VID/PID pair. |
HIDD_ATTRIBUTES attrib = {0}; |
attrib.Size = sizeof(HIDD_ATTRIBUTES); |
- if (!HidD_GetAttributes(device_handle.Get(), &attrib)) |
+ if (!HidD_GetAttributes(device_handle.Get(), &attrib)) { |
return; |
+ } |
device_info.vendor_id = attrib.VendorID; |
device_info.product_id = attrib.ProductID; |
- for (ULONG i = 32; |
- HidD_SetNumInputBuffers(device_handle.Get(), i); |
- i <<= 1); |
- |
// Get usage and usage page (optional). |
PHIDP_PREPARSED_DATA preparsed_data; |
if (HidD_GetPreparsedData(device_handle.Get(), &preparsed_data) && |
@@ -304,27 +284,18 @@ void HidServiceWin::PlatformRemoveDevice(const std::string& device_path) { |
RemoveDevice(device_path); |
} |
-void HidServiceWin::GetDevices(std::vector<HidDeviceInfo>* devices) { |
- Enumerate(); |
- HidService::GetDevices(devices); |
-} |
- |
-void HidServiceWin::Connect(const HidDeviceId& device_id, |
- const ConnectCallback& callback) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- const auto& map_entry = devices().find(device_id); |
- if (map_entry == devices().end()) { |
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); |
- return; |
- } |
- const HidDeviceInfo& device_info = map_entry->second; |
- |
- scoped_refptr<HidConnectionWin> connection(new HidConnectionWin(device_info)); |
- if (!connection->available()) { |
- PLOG(ERROR) << "Failed to open device"; |
- connection = nullptr; |
+base::win::ScopedHandle HidServiceWin::OpenDevice( |
+ const std::string& device_path) { |
+ base::win::ScopedHandle file( |
+ CreateFileA(device_path.c_str(), GENERIC_WRITE | GENERIC_READ, |
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, |
+ FILE_FLAG_OVERLAPPED, NULL)); |
+ if (!file.IsValid() && |
+ GetLastError() == base::File::FILE_ERROR_ACCESS_DENIED) { |
Nico
2015/12/09 17:05:45
Are you sure this is correct? The CreateFile() MSD
Reilly Grant (use Gerrit)
2015/12/09 18:49:29
Interesting. I wonder if this logic has ever been
Nico
2015/12/09 19:10:53
Deleting this block if it's broken and untested so
|
+ file.Set(CreateFileA(device_path.c_str(), GENERIC_READ, FILE_SHARE_READ, |
+ NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL)); |
} |
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, connection)); |
+ return file.Pass(); |
} |
} // namespace device |