diff options
author | reillyg <reillyg@chromium.org> | 2014-08-28 22:52:48 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-08-29 05:53:46 +0000 |
commit | f4dc9d143de2350fc4879c178059737997944016 (patch) | |
tree | de808301f613297af60b8ce5bdee43cc2b511264 | |
parent | 3a05d24b124114e117c2d81592edbd14bbcf1b1c (diff) | |
download | chromium_src-f4dc9d143de2350fc4879c178059737997944016.zip chromium_src-f4dc9d143de2350fc4879c178059737997944016.tar.gz chromium_src-f4dc9d143de2350fc4879c178059737997944016.tar.bz2 |
Add more generic filters to the chrome.hid.getDevices API.
Instead of specifying each of the USB vendor and product ID pairs an
app has permission to open this API extension allows filtering of
devices by vendor and product IDs as well as HID usage pages and
usages. The 'vendorId' and 'productId' properties of GetDevicesOptions
are still supported for backwards compatibility.
BUG=
Review URL: https://codereview.chromium.org/514923002
Cr-Commit-Position: refs/heads/master@{#292577}
-rw-r--r-- | device/device_tests.gyp | 1 | ||||
-rw-r--r-- | device/hid/BUILD.gn | 2 | ||||
-rw-r--r-- | device/hid/hid.gyp | 2 | ||||
-rw-r--r-- | device/hid/hid_device_filter.cc | 89 | ||||
-rw-r--r-- | device/hid/hid_device_filter.h | 43 | ||||
-rw-r--r-- | device/hid/hid_device_filter_unittest.cc | 116 | ||||
-rw-r--r-- | extensions/browser/api/hid/hid_api.cc | 52 | ||||
-rw-r--r-- | extensions/browser/api/hid/hid_device_manager.cc | 105 | ||||
-rw-r--r-- | extensions/browser/api/hid/hid_device_manager.h | 14 | ||||
-rw-r--r-- | extensions/common/api/hid.idl | 62 |
10 files changed, 393 insertions, 93 deletions
diff --git a/device/device_tests.gyp b/device/device_tests.gyp index 7e913e6..6b5a59b 100644 --- a/device/device_tests.gyp +++ b/device/device_tests.gyp @@ -44,6 +44,7 @@ 'usb/usb_ids_unittest.cc', 'usb/usb_service_unittest.cc', 'hid/hid_connection_unittest.cc', + 'hid/hid_device_filter_unittest.cc', 'hid/hid_report_descriptor_unittest.cc', 'hid/hid_service_unittest.cc', 'hid/input_service_linux_unittest.cc', diff --git a/device/hid/BUILD.gn b/device/hid/BUILD.gn index edd3ecb..bc450db 100644 --- a/device/hid/BUILD.gn +++ b/device/hid/BUILD.gn @@ -16,6 +16,8 @@ source_set("hid") { "hid_connection_mac.h", "hid_connection_win.cc", "hid_connection_win.h", + "hid_device_filter.cc", + "hid_device_filter.h", "hid_device_info.cc", "hid_device_info.h", "hid_report_descriptor.cc", diff --git a/device/hid/hid.gyp b/device/hid/hid.gyp index 2db80fd..1c01ca1 100644 --- a/device/hid/hid.gyp +++ b/device/hid/hid.gyp @@ -26,6 +26,8 @@ 'hid_connection_mac.h', 'hid_connection_win.cc', 'hid_connection_win.h', + 'hid_device_filter.cc', + 'hid_device_filter.h', 'hid_device_info.cc', 'hid_device_info.h', 'hid_report_descriptor.cc', diff --git a/device/hid/hid_device_filter.cc b/device/hid/hid_device_filter.cc new file mode 100644 index 0000000..70ebcf4 --- /dev/null +++ b/device/hid/hid_device_filter.cc @@ -0,0 +1,89 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device/hid/hid_device_filter.h" + +#include "device/hid/hid_device_info.h" + +namespace device { + +HidDeviceFilter::HidDeviceFilter() + : vendor_id_set_(false), + product_id_set_(false), + usage_page_set_(false), + usage_set_(false) { +} + +HidDeviceFilter::~HidDeviceFilter() { +} + +void HidDeviceFilter::SetVendorId(uint16_t vendor_id) { + vendor_id_set_ = true; + vendor_id_ = vendor_id; +} + +void HidDeviceFilter::SetProductId(uint16_t product_id) { + product_id_set_ = true; + product_id_ = product_id; +} + +void HidDeviceFilter::SetUsagePage(uint16_t usage_page) { + usage_page_set_ = true; + usage_page_ = usage_page; +} + +void HidDeviceFilter::SetUsage(uint16_t usage) { + usage_set_ = true; + usage_ = usage; +} + +bool HidDeviceFilter::Matches(const HidDeviceInfo& device_info) const { + if (vendor_id_set_) { + if (device_info.vendor_id != vendor_id_) { + return false; + } + + if (product_id_set_ && device_info.product_id != product_id_) { + return false; + } + } + + if (usage_page_set_) { + bool found_matching_collection = false; + for (std::vector<HidCollectionInfo>::const_iterator i = + device_info.collections.begin(); + i != device_info.collections.end() && !found_matching_collection; + ++i) { + const HidCollectionInfo& collection = *i; + if (collection.usage.usage_page != usage_page_) { + continue; + } + if (usage_set_ && collection.usage.usage != usage_) { + continue; + } + found_matching_collection = true; + } + if (!found_matching_collection) { + return false; + } + } + + return true; +} + +// static +bool HidDeviceFilter::MatchesAny( + const HidDeviceInfo& device_info, + const std::vector<HidDeviceFilter>& filters) { + for (std::vector<HidDeviceFilter>::const_iterator i = filters.begin(); + i != filters.end(); + ++i) { + if (i->Matches(device_info)) { + return true; + } + } + return false; +} + +} // namespace device diff --git a/device/hid/hid_device_filter.h b/device/hid/hid_device_filter.h new file mode 100644 index 0000000..a0abbb7 --- /dev/null +++ b/device/hid/hid_device_filter.h @@ -0,0 +1,43 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVICE_HID_HID_DEVICE_FILTER_H_ +#define DEVICE_HID_HID_DEVICE_FILTER_H_ + +#include <stdint.h> +#include <vector> + +namespace device { + +struct HidDeviceInfo; + +class HidDeviceFilter { + public: + HidDeviceFilter(); + ~HidDeviceFilter(); + + void SetVendorId(uint16_t vendor_id); + void SetProductId(uint16_t product_id); + void SetUsagePage(uint16_t usage_page); + void SetUsage(uint16_t usage); + + bool Matches(const HidDeviceInfo& device_info) const; + + static bool MatchesAny(const HidDeviceInfo& device_info, + const std::vector<HidDeviceFilter>& filters); + + private: + uint16_t vendor_id_; + uint16_t product_id_; + uint16_t usage_page_; + uint16_t usage_; + bool vendor_id_set_ : 1; + bool product_id_set_ : 1; + bool usage_page_set_ : 1; + bool usage_set_ : 1; +}; + +} // namespace device + +#endif // DEVICE_HID_HID_DEVICE_FILTER_H_ diff --git a/device/hid/hid_device_filter_unittest.cc b/device/hid/hid_device_filter_unittest.cc new file mode 100644 index 0000000..599dda4 --- /dev/null +++ b/device/hid/hid_device_filter_unittest.cc @@ -0,0 +1,116 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device/hid/hid_device_filter.h" +#include "device/hid/hid_device_info.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace device { + +namespace { + +class HidFilterTest : public testing::Test { + public: + virtual void SetUp() OVERRIDE { + device_info_.vendor_id = 0x046d; + device_info_.product_id = 0xc31c; + + HidCollectionInfo collection; + collection.usage.usage_page = HidUsageAndPage::kPageKeyboard; + collection.usage.usage = 0x01; + device_info_.collections.push_back(collection); + } + + protected: + HidDeviceInfo device_info_; +}; + +TEST_F(HidFilterTest, MatchAny) { + HidDeviceFilter filter; + ASSERT_TRUE(filter.Matches(device_info_)); +} + +TEST_F(HidFilterTest, MatchVendorId) { + HidDeviceFilter filter; + filter.SetVendorId(0x046d); + ASSERT_TRUE(filter.Matches(device_info_)); +} + +TEST_F(HidFilterTest, MatchVendorIdNegative) { + HidDeviceFilter filter; + filter.SetVendorId(0x18d1); + ASSERT_FALSE(filter.Matches(device_info_)); +} + +TEST_F(HidFilterTest, MatchProductId) { + HidDeviceFilter filter; + filter.SetVendorId(0x046d); + filter.SetProductId(0xc31c); + ASSERT_TRUE(filter.Matches(device_info_)); +} + +TEST_F(HidFilterTest, MatchProductIdNegative) { + HidDeviceFilter filter; + filter.SetVendorId(0x046d); + filter.SetProductId(0x0801); + ASSERT_FALSE(filter.Matches(device_info_)); +} + +TEST_F(HidFilterTest, MatchUsagePage) { + HidDeviceFilter filter; + filter.SetUsagePage(HidUsageAndPage::kPageKeyboard); + ASSERT_TRUE(filter.Matches(device_info_)); +} + +TEST_F(HidFilterTest, MatchUsagePageNegative) { + HidDeviceFilter filter; + filter.SetUsagePage(HidUsageAndPage::kPageLed); + ASSERT_FALSE(filter.Matches(device_info_)); +} + +TEST_F(HidFilterTest, MatchVendorAndUsagePage) { + HidDeviceFilter filter; + filter.SetVendorId(0x046d); + filter.SetUsagePage(HidUsageAndPage::kPageKeyboard); + ASSERT_TRUE(filter.Matches(device_info_)); +} + +TEST_F(HidFilterTest, MatchUsageAndPage) { + HidDeviceFilter filter; + filter.SetUsagePage(HidUsageAndPage::kPageKeyboard); + filter.SetUsage(0x01); + ASSERT_TRUE(filter.Matches(device_info_)); +} + +TEST_F(HidFilterTest, MatchUsageAndPageNegative) { + HidDeviceFilter filter; + filter.SetUsagePage(HidUsageAndPage::kPageKeyboard); + filter.SetUsage(0x02); + ASSERT_FALSE(filter.Matches(device_info_)); +} + +TEST_F(HidFilterTest, MatchEmptyFilterListNegative) { + std::vector<HidDeviceFilter> filters; + ASSERT_FALSE(HidDeviceFilter::MatchesAny(device_info_, filters)); +} + +TEST_F(HidFilterTest, MatchFilterList) { + std::vector<HidDeviceFilter> filters; + HidDeviceFilter filter; + filter.SetUsagePage(HidUsageAndPage::kPageKeyboard); + filters.push_back(filter); + ASSERT_TRUE(HidDeviceFilter::MatchesAny(device_info_, filters)); +} + +TEST_F(HidFilterTest, MatchFilterListNegative) { + std::vector<HidDeviceFilter> filters; + HidDeviceFilter filter; + filter.SetUsagePage(HidUsageAndPage::kPageLed); + filters.push_back(filter); + ASSERT_FALSE(HidDeviceFilter::MatchesAny(device_info_, filters)); +} + +} // namespace + +} // namespace device diff --git a/extensions/browser/api/hid/hid_api.cc b/extensions/browser/api/hid/hid_api.cc index e710af0..05f4720 100644 --- a/extensions/browser/api/hid/hid_api.cc +++ b/extensions/browser/api/hid/hid_api.cc @@ -8,18 +8,18 @@ #include <vector> #include "device/hid/hid_connection.h" +#include "device/hid/hid_device_filter.h" #include "device/hid/hid_device_info.h" #include "device/hid/hid_service.h" #include "extensions/browser/api/api_resource_manager.h" #include "extensions/browser/api/extensions_api_client.h" #include "extensions/common/api/hid.h" -#include "extensions/common/permissions/permissions_data.h" -#include "extensions/common/permissions/usb_device_permission.h" #include "net/base/io_buffer.h" namespace hid = extensions::core_api::hid; using device::HidConnection; +using device::HidDeviceFilter; using device::HidDeviceInfo; using device::HidService; @@ -38,6 +38,22 @@ base::Value* PopulateHidConnection(int connection_id, return connection_value.ToValue().release(); } +void ConvertHidDeviceFilter(linked_ptr<hid::DeviceFilter> input, + HidDeviceFilter* output) { + if (input->vendor_id) { + output->SetVendorId(*input->vendor_id); + } + if (input->product_id) { + output->SetProductId(*input->product_id); + } + if (input->usage_page) { + output->SetUsagePage(*input->usage_page); + } + if (input->usage) { + output->SetUsage(*input->usage); + } +} + } // namespace namespace extensions { @@ -84,18 +100,23 @@ bool HidGetDevicesFunction::Prepare() { } void HidGetDevicesFunction::AsyncWorkStart() { - const uint16_t vendor_id = parameters_->options.vendor_id; - const uint16_t product_id = parameters_->options.product_id; - UsbDevicePermission::CheckParam param( - vendor_id, product_id, UsbDevicePermissionData::UNSPECIFIED_INTERFACE); - if (!extension()->permissions_data()->CheckAPIPermissionWithParam( - APIPermission::kUsbDevice, ¶m)) { - LOG(WARNING) << "Insufficient permissions to access device."; - CompleteWithError(kErrorPermissionDenied); - return; + std::vector<HidDeviceFilter> filters; + if (parameters_->options.filters) { + filters.resize(parameters_->options.filters->size()); + for (size_t i = 0; i < parameters_->options.filters->size(); ++i) { + ConvertHidDeviceFilter(parameters_->options.filters->at(i), &filters[i]); + } + } + if (parameters_->options.vendor_id) { + HidDeviceFilter legacy_filter; + legacy_filter.SetVendorId(*parameters_->options.vendor_id); + if (parameters_->options.product_id) { + legacy_filter.SetProductId(*parameters_->options.product_id); + } + filters.push_back(legacy_filter); } - SetResult(device_manager_->GetApiDevices(vendor_id, product_id).release()); + SetResult(device_manager_->GetApiDevices(extension(), filters).release()); AsyncWorkCompleted(); } @@ -116,12 +137,7 @@ void HidConnectFunction::AsyncWorkStart() { return; } - UsbDevicePermission::CheckParam param( - device_info.vendor_id, - device_info.product_id, - UsbDevicePermissionData::UNSPECIFIED_INTERFACE); - if (!extension()->permissions_data()->CheckAPIPermissionWithParam( - APIPermission::kUsbDevice, ¶m)) { + if (!device_manager_->HasPermission(extension(), device_info)) { LOG(WARNING) << "Insufficient permissions to access device."; CompleteWithError(kErrorPermissionDenied); return; diff --git a/extensions/browser/api/hid/hid_device_manager.cc b/extensions/browser/api/hid/hid_device_manager.cc index 4992f05..16dd555 100644 --- a/extensions/browser/api/hid/hid_device_manager.cc +++ b/extensions/browser/api/hid/hid_device_manager.cc @@ -8,9 +8,13 @@ #include <vector> #include "base/lazy_instance.h" +#include "device/hid/hid_device_filter.h" #include "device/hid/hid_service.h" #include "extensions/browser/api/extensions_api_client.h" +#include "extensions/common/permissions/permissions_data.h" +#include "extensions/common/permissions/usb_device_permission.h" +using device::HidDeviceFilter; using device::HidService; using device::HidUsageAndPage; @@ -30,8 +34,8 @@ HidDeviceManager::GetFactoryInstance() { } scoped_ptr<base::ListValue> HidDeviceManager::GetApiDevices( - uint16_t vendor_id, - uint16_t product_id) { + const Extension* extension, + const std::vector<HidDeviceFilter>& filters) { UpdateDevices(); HidService* hid_service = ExtensionsAPIClient::Get()->GetHidService(); @@ -46,47 +50,52 @@ scoped_ptr<base::ListValue> HidDeviceManager::GetApiDevices( device::HidDeviceInfo device_info; if (hid_service->GetDeviceInfo(device_id, &device_info)) { - if (device_info.vendor_id == vendor_id && - device_info.product_id == product_id) { - core_api::hid::HidDeviceInfo api_device_info; - api_device_info.device_id = resource_id; - api_device_info.vendor_id = device_info.vendor_id; - api_device_info.product_id = device_info.product_id; - api_device_info.max_input_report_size = - device_info.max_input_report_size; - api_device_info.max_output_report_size = - device_info.max_output_report_size; - api_device_info.max_feature_report_size = - device_info.max_feature_report_size; - - for (std::vector<device::HidCollectionInfo>::const_iterator - collections_iter = device_info.collections.begin(); - collections_iter != device_info.collections.end(); - ++collections_iter) { - device::HidCollectionInfo collection = *collections_iter; - - // Don't expose sensitive data. - if (collection.usage.IsProtected()) { - continue; - } - - core_api::hid::HidCollectionInfo* api_collection = - new core_api::hid::HidCollectionInfo(); - api_collection->usage_page = collection.usage.usage_page; - api_collection->usage = collection.usage.usage; - - api_collection->report_ids.resize(collection.report_ids.size()); - std::copy(collection.report_ids.begin(), - collection.report_ids.end(), - api_collection->report_ids.begin()); - - api_device_info.collections.push_back( - make_linked_ptr(api_collection)); + if (!filters.empty() && + !HidDeviceFilter::MatchesAny(device_info, filters)) { + continue; + } + + if (!HasPermission(extension, device_info)) { + continue; + } + + core_api::hid::HidDeviceInfo api_device_info; + api_device_info.device_id = resource_id; + api_device_info.vendor_id = device_info.vendor_id; + api_device_info.product_id = device_info.product_id; + api_device_info.max_input_report_size = device_info.max_input_report_size; + api_device_info.max_output_report_size = + device_info.max_output_report_size; + api_device_info.max_feature_report_size = + device_info.max_feature_report_size; + + for (std::vector<device::HidCollectionInfo>::const_iterator + collections_iter = device_info.collections.begin(); + collections_iter != device_info.collections.end(); + ++collections_iter) { + const device::HidCollectionInfo& collection = *collections_iter; + + // Don't expose sensitive data. + if (collection.usage.IsProtected()) { + continue; } - // Expose devices with which user can communicate. - if (api_device_info.collections.size() > 0) - api_devices->Append(api_device_info.ToValue().release()); + core_api::hid::HidCollectionInfo* api_collection = + new core_api::hid::HidCollectionInfo(); + api_collection->usage_page = collection.usage.usage_page; + api_collection->usage = collection.usage.usage; + + api_collection->report_ids.resize(collection.report_ids.size()); + std::copy(collection.report_ids.begin(), + collection.report_ids.end(), + api_collection->report_ids.begin()); + + api_device_info.collections.push_back(make_linked_ptr(api_collection)); + } + + // Expose devices with which user can communicate. + if (api_device_info.collections.size() > 0) { + api_devices->Append(api_device_info.ToValue().release()); } } } @@ -108,6 +117,20 @@ bool HidDeviceManager::GetDeviceInfo(int resource_id, return hid_service->GetDeviceInfo(device_iter->second, device_info); } +bool HidDeviceManager::HasPermission(const Extension* extension, + const device::HidDeviceInfo& device_info) { + UsbDevicePermission::CheckParam usbParam( + device_info.vendor_id, + device_info.product_id, + UsbDevicePermissionData::UNSPECIFIED_INTERFACE); + if (extension->permissions_data()->CheckAPIPermissionWithParam( + APIPermission::kUsbDevice, &usbParam)) { + return true; + } + + return false; +} + void HidDeviceManager::UpdateDevices() { thread_checker_.CalledOnValidThread(); HidService* hid_service = ExtensionsAPIClient::Get()->GetHidService(); diff --git a/extensions/browser/api/hid/hid_device_manager.h b/extensions/browser/api/hid/hid_device_manager.h index de94960..a258be4 100644 --- a/extensions/browser/api/hid/hid_device_manager.h +++ b/extensions/browser/api/hid/hid_device_manager.h @@ -16,8 +16,14 @@ #include "extensions/browser/browser_context_keyed_api_factory.h" #include "extensions/common/api/hid.h" +namespace device { +class HidDeviceFilter; +} + namespace extensions { +class Extension; + class HidDeviceManager : public BrowserContextKeyedAPI { public: explicit HidDeviceManager(content::BrowserContext* context); @@ -31,11 +37,15 @@ class HidDeviceManager : public BrowserContextKeyedAPI { return BrowserContextKeyedAPIFactory<HidDeviceManager>::Get(context); } - scoped_ptr<base::ListValue> GetApiDevices(uint16_t vendor_id, - uint16_t product_id); + scoped_ptr<base::ListValue> GetApiDevices( + const Extension* extension, + const std::vector<device::HidDeviceFilter>& filters); bool GetDeviceInfo(int resource_id, device::HidDeviceInfo* device_info); + bool HasPermission(const Extension* extension, + const device::HidDeviceInfo& device_info); + private: friend class BrowserContextKeyedAPIFactory<HidDeviceManager>; diff --git a/extensions/common/api/hid.idl b/extensions/common/api/hid.idl index c6bb316..efdace1 100644 --- a/extensions/common/api/hid.idl +++ b/extensions/common/api/hid.idl @@ -6,33 +6,29 @@ // This API provides access to HID operations from within the context of an app. // Using this API, apps can function as drivers for hardware devices. namespace hid { - // HID top-level collection attributes. - // Each enumerated device interface exposes an array of these objects. - // |usagePage|: HID usage page identifier. - // |usage|: Page-defined usage identifier. - // |reportIds|: Report IDs which belong to the collection and to its children. dictionary HidCollectionInfo { + // HID usage page identifier. long usagePage; + // Page-defined usage identifier. long usage; + // Report IDs which belong to the collection and to its children. long[] reportIds; }; - // Returned by <code>getDevices</code> functions to describes a connected HID - // device. Use <code>connect</code> to connect to any of the returned devices. - // |deviceId|: Device opaque ID. - // |vendorId|: Vendor ID. - // |productId|: Product ID. - // |collections|: Top-level collections from this device's report descriptor. - // |maxInputReportSize|: Top-level collection's max input report size. - // |maxOutputReportSize|: Top-level collection's max output report size. - // |maxFeatureReportSize|: Top-level collection's max feature report size. - dictionary HidDeviceInfo { + [noinline_doc] dictionary HidDeviceInfo { + // Device opaque ID. long deviceId; + // Vendor ID. long vendorId; + // Product ID. long productId; + // Top-level collections from this device's report descriptors. HidCollectionInfo[] collections; + // Top-level collection's maximum input report size. long maxInputReportSize; + // Top-level collection's maximum output report size. long maxOutputReportSize; + // Top-level collection's maximum feature report size. long maxFeatureReportSize; }; @@ -42,48 +38,54 @@ namespace hid { long connectionId; }; - // Searching criteria to enumerate devices with. + [noinline_doc] dictionary DeviceFilter { + // Device vendor ID. + long? vendorId; + // Device product ID, only checked only if the vendor ID matches. + long? productId; + // HID usage page identifier. + long? usagePage; + // HID usage identifier, checked only if the HID usage page matches. + long? usage; + }; + dictionary GetDevicesOptions { - long vendorId; - long productId; + [deprecated="Equivalent to setting $(ref:DeviceFilter.vendorId)."] + long? vendorId; + [deprecated="Equivalent to setting $(ref:DeviceFilter.productId)."] + long? productId; + // A device matching any given filter will be returned. An empty filter list + // will return all devices the app has permission for. + DeviceFilter[]? filters; }; callback GetDevicesCallback = void (HidDeviceInfo[] devices); callback ConnectCallback = void (HidConnectInfo connection); callback DisconnectCallback = void (); - // The callback to be invoked when a <code>receive</code> call is finished. // |reportId|: The ID of the report. // |data|: The content of the report. callback ReceiveCallback = void (long reportId, ArrayBuffer data); - // The callback to be invoked when a <code>receiveFeatureReport</code> call - // is finished. // |data|: The content of the report. callback ReceiveFeatureReportCallback = void (ArrayBuffer data); - // The callback to be invoked when a <code>send</code> or - // <code>sendFeatureReport</code> call is finished. callback SendCallback = void(); interface Functions { - // Enumerate all the connected HID devices specified by the vendorId/ - // productId/interfaceId tuple. + // Enumerate connected HID devices. // |options|: The properties to search for on target devices. - // |callback|: Invoked with the <code>HidDeviceInfo</code> array on success. static void getDevices(GetDevicesOptions options, GetDevicesCallback callback); // Open a connection to an HID device for communication. // |deviceId|: The ID of the device to open. - // |callback|: Invoked with an <code>HidConnectInfo</code>. static void connect(long deviceId, ConnectCallback callback); // Disconnect from a device. Invoking operations on a device after calling // this is safe but has no effect. // |connectionId|: The connection to close. - // |callback|: The callback to invoke once the device is closed. static void disconnect(long connectionId, optional DisconnectCallback callback); @@ -91,7 +93,6 @@ namespace hid { // // Input reports are returned to the host through the INTERRUPT IN endpoint. // |connectionId|: The connection from which to receive a report. - // |callback|: The callback to invoke with received report. static void receive(long connectionId, ReceiveCallback callback); @@ -103,7 +104,6 @@ namespace hid { // |connectionId|: The connection to which to send a report. // |reportId|: The report ID to use, or <code>0</code> if none. // |data|: The report data. - // |callback|: The callback to invoke once the write is finished. static void send(long connectionId, long reportId, ArrayBuffer data, @@ -113,7 +113,6 @@ namespace hid { // // |connectionId|: The connection to read Input report from. // |reportId|: The report ID, or zero if none. - // |callback|: The callback to invoke once the write is finished. static void receiveFeatureReport(long connectionId, long reportId, ReceiveFeatureReportCallback callback); @@ -125,7 +124,6 @@ namespace hid { // |connectionId|: The connection to read Input report from. // |reportId|: The report ID to use, or <code>0</code> if none. // |data|: The report data. - // |callback|: The callback to invoke once the write is finished. static void sendFeatureReport(long connectionId, long reportId, ArrayBuffer data, |