Home | History | Annotate | Download | only in hid
      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 
     18 HidDeviceManager::HidDeviceManager(content::BrowserContext* context)
     19   : next_resource_id_(0) {}
     20 
     21 HidDeviceManager::~HidDeviceManager() {}
     22 
     23 // static
     24 BrowserContextKeyedAPIFactory<HidDeviceManager>*
     25 HidDeviceManager::GetFactoryInstance() {
     26   static base::LazyInstance<BrowserContextKeyedAPIFactory<HidDeviceManager> >
     27       factory = LAZY_INSTANCE_INITIALIZER;
     28   return &factory.Get();
     29 }
     30 
     31 scoped_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 
     73 bool 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 
     87 void 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.
    121 bool 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
    134 bool 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