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. 4 5 #include "chrome/browser/extensions/api/hid/hid_device_manager.h" 6 7 #include <limits> 8 #include <vector> 9 10 #include "base/lazy_instance.h" 11 #include "device/hid/hid_service.h" 12 13 using device::HidService; 14 using device::HidUsageAndPage; 15 16 namespace extensions { 17 HidDeviceManager(content::BrowserContext * context)18HidDeviceManager::HidDeviceManager(content::BrowserContext* context) 19 : next_resource_id_(0) {} 20 ~HidDeviceManager()21HidDeviceManager::~HidDeviceManager() {} 22 23 // static 24 BrowserContextKeyedAPIFactory<HidDeviceManager>* GetFactoryInstance()25HidDeviceManager::GetFactoryInstance() { 26 static base::LazyInstance<BrowserContextKeyedAPIFactory<HidDeviceManager> > 27 factory = LAZY_INSTANCE_INITIALIZER; 28 return &factory.Get(); 29 } 30 GetApiDevices(uint16_t vendor_id,uint16_t product_id)31scoped_ptr<base::ListValue> HidDeviceManager::GetApiDevices( 32 uint16_t vendor_id, 33 uint16_t product_id) { 34 UpdateDevices(); 35 36 HidService* hid_service = HidService::GetInstance(); 37 DCHECK(hid_service); 38 base::ListValue* api_devices = new base::ListValue(); 39 for (ResourceIdToDeviceIdMap::const_iterator device_iter = 40 device_ids_.begin(); 41 device_iter != device_ids_.end(); 42 ++device_iter) { 43 int resource_id = device_iter->first; 44 device::HidDeviceId device_id = device_iter->second; 45 device::HidDeviceInfo device_info; 46 if (hid_service->GetDeviceInfo(device_id, &device_info)) { 47 if (device_info.vendor_id == vendor_id && 48 device_info.product_id == product_id && 49 IsDeviceAccessible(device_info)) { 50 api::hid::HidDeviceInfo api_device_info; 51 api_device_info.device_id = resource_id; 52 api_device_info.vendor_id = device_info.vendor_id; 53 api_device_info.product_id = device_info.product_id; 54 for (std::vector<device::HidUsageAndPage>::const_iterator usage_iter = 55 device_info.usages.begin(); 56 usage_iter != device_info.usages.end(); 57 ++usage_iter) { 58 api::hid::HidUsageAndPage* usage_and_page = 59 new api::hid::HidUsageAndPage(); 60 usage_and_page->usage_page = (*usage_iter).usage_page; 61 usage_and_page->usage = (*usage_iter).usage; 62 linked_ptr<api::hid::HidUsageAndPage> usage_and_page_ptr( 63 usage_and_page); 64 api_device_info.usages.push_back(usage_and_page_ptr); 65 } 66 api_devices->Append(api_device_info.ToValue().release()); 67 } 68 } 69 } 70 return scoped_ptr<base::ListValue>(api_devices); 71 } 72 GetDeviceInfo(int resource_id,device::HidDeviceInfo * device_info)73bool HidDeviceManager::GetDeviceInfo(int resource_id, 74 device::HidDeviceInfo* device_info) { 75 UpdateDevices(); 76 HidService* hid_service = HidService::GetInstance(); 77 DCHECK(hid_service); 78 79 ResourceIdToDeviceIdMap::const_iterator device_iter = 80 device_ids_.find(resource_id); 81 if (device_iter == device_ids_.end()) 82 return false; 83 84 return hid_service->GetDeviceInfo(device_iter->second, device_info); 85 } 86 UpdateDevices()87void HidDeviceManager::UpdateDevices() { 88 thread_checker_.CalledOnValidThread(); 89 HidService* hid_service = HidService::GetInstance(); 90 DCHECK(hid_service); 91 92 std::vector<device::HidDeviceInfo> devices; 93 hid_service->GetDevices(&devices); 94 95 // Build an updated bidi mapping between resource ID and underlying device ID. 96 DeviceIdToResourceIdMap new_resource_ids; 97 ResourceIdToDeviceIdMap new_device_ids; 98 for (std::vector<device::HidDeviceInfo>::const_iterator iter = 99 devices.begin(); 100 iter != devices.end(); 101 ++iter) { 102 const device::HidDeviceInfo& device_info = *iter; 103 DeviceIdToResourceIdMap::iterator resource_iter = 104 resource_ids_.find(device_info.device_id); 105 int new_id; 106 if (resource_iter != resource_ids_.end()) { 107 new_id = resource_iter->second; 108 } else { 109 DCHECK_LT(next_resource_id_, std::numeric_limits<int>::max()); 110 new_id = next_resource_id_++; 111 } 112 new_resource_ids[device_info.device_id] = new_id; 113 new_device_ids[new_id] = device_info.device_id; 114 } 115 device_ids_.swap(new_device_ids); 116 resource_ids_.swap(new_resource_ids); 117 } 118 119 // static 120 // TODO(rockot): Add some tests for this. IsDeviceAccessible(const device::HidDeviceInfo & device_info)121bool HidDeviceManager::IsDeviceAccessible( 122 const device::HidDeviceInfo& device_info) { 123 for (std::vector<device::HidUsageAndPage>::const_iterator iter = 124 device_info.usages.begin(); 125 iter != device_info.usages.end(); ++iter) { 126 if (!IsUsageAccessible(*iter)) { 127 return false; 128 } 129 } 130 return true; 131 } 132 133 // static IsUsageAccessible(const HidUsageAndPage & usage_and_page)134bool HidDeviceManager::IsUsageAccessible( 135 const HidUsageAndPage& usage_and_page) { 136 if (usage_and_page.usage_page == HidUsageAndPage::kPageKeyboard) 137 return false; 138 139 if (usage_and_page.usage_page != HidUsageAndPage::kPageGenericDesktop) 140 return true; 141 142 uint16_t usage = usage_and_page.usage; 143 if (usage == HidUsageAndPage::kGenericDesktopPointer || 144 usage == HidUsageAndPage::kGenericDesktopMouse || 145 usage == HidUsageAndPage::kGenericDesktopKeyboard || 146 usage == HidUsageAndPage::kGenericDesktopKeypad) { 147 return false; 148 } 149 150 if (usage >= HidUsageAndPage::kGenericDesktopSystemControl && 151 usage <= HidUsageAndPage::kGenericDesktopSystemWarmRestart) { 152 return false; 153 } 154 155 if (usage >= HidUsageAndPage::kGenericDesktopSystemDock && 156 usage <= HidUsageAndPage::kGenericDesktopSystemDisplaySwap) { 157 return false; 158 } 159 160 return true; 161 } 162 163 } // namespace extensions 164