Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(148)

Unified Diff: device/hid/hid_service_win.cc

Issue 783773002: Register for HID device notifications on Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « device/hid/hid_service_win.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « device/hid/hid_service_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698