123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// found in the LICENSE file.
423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "content/browser/gamepad/raw_input_data_fetcher_win.h"
623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "base/debug/trace_event.h"
823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "content/common/gamepad_hardware_buffer.h"
923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "content/common/gamepad_messages.h"
1023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
1123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)namespace content {
1223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
1323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)using namespace blink;
1423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
1523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)namespace {
1623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
1723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)float NormalizeAxis(long value, long min, long max) {
1823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return (2.f * (value - min) / static_cast<float>(max - min)) - 1.f;
1923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
2023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
2123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// From the HID Usage Tables specification.
2223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)USHORT DeviceUsages[] = {
2323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  0x04,  // Joysticks
2423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  0x05,  // Gamepads
2523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  0x08,  // Multi Axis
2623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)};
2723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
2823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)const uint32_t kAxisMinimumUsageNumber = 0x30;
2923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)const uint32_t kGameControlsUsagePage = 0x05;
3023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
3123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}   // namespace
3223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
3323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)RawInputDataFetcher::RawInputDataFetcher()
3423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    : hid_dll_(base::FilePath(FILE_PATH_LITERAL("hid.dll")))
3523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    , rawinput_available_(GetHidDllFunctions())
3623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    , filter_xinput_(true)
3723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    , events_monitored_(false) {}
3823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
3923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)RawInputDataFetcher::~RawInputDataFetcher() {
4023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DCHECK(!window_);
4123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DCHECK(!events_monitored_);
4223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
4323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
4423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void RawInputDataFetcher::WillDestroyCurrentMessageLoop() {
4523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  StopMonitor();
4623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
4723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
4823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)RAWINPUTDEVICE* RawInputDataFetcher::GetRawInputDevices(DWORD flags) {
4923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  int usage_count = arraysize(DeviceUsages);
5023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  scoped_ptr<RAWINPUTDEVICE[]> devices(new RAWINPUTDEVICE[usage_count]);
5123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  for (int i = 0; i < usage_count; ++i) {
5223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    devices[i].dwFlags = flags;
5323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    devices[i].usUsagePage = 1;
5423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    devices[i].usUsage = DeviceUsages[i];
5523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    devices[i].hwndTarget = window_->hwnd();
5623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
5723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return devices.release();
5823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
5923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
6023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void RawInputDataFetcher::StartMonitor() {
6123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!rawinput_available_ || events_monitored_)
6223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return;
6323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
6423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!window_) {
6523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    window_.reset(new base::win::MessageWindow());
6623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (!window_->Create(base::Bind(&RawInputDataFetcher::HandleMessage,
6723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                    base::Unretained(this)))) {
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      PLOG(ERROR) << "Failed to create the raw input window";
6923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      window_.reset();
7023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      return;
7123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
7223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
7323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
7423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Register to receive raw HID input.
7523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  scoped_ptr<RAWINPUTDEVICE[]> devices(GetRawInputDevices(RIDEV_INPUTSINK));
7623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!RegisterRawInputDevices(devices.get(), arraysize(DeviceUsages),
7723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      sizeof(RAWINPUTDEVICE))) {
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "RegisterRawInputDevices() failed for RIDEV_INPUTSINK";
7923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    window_.reset();
8023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return;
8123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
8223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
8323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Start observing message loop destruction if we start monitoring the first
8423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // event.
8523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!events_monitored_)
8623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    base::MessageLoop::current()->AddDestructionObserver(this);
8723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
8823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  events_monitored_ = true;
8923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
9023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
9123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void RawInputDataFetcher::StopMonitor() {
9223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!rawinput_available_ || !events_monitored_)
9323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return;
9423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
9523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Stop receiving raw input.
9623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DCHECK(window_);
9723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  scoped_ptr<RAWINPUTDEVICE[]> devices(GetRawInputDevices(RIDEV_REMOVE));
9823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
9923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!RegisterRawInputDevices(devices.get(), arraysize(DeviceUsages),
10023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      sizeof(RAWINPUTDEVICE))) {
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(INFO) << "RegisterRawInputDevices() failed for RIDEV_REMOVE";
10223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
10323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
10423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  events_monitored_ = false;
10523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  window_.reset();
10623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  ClearControllers();
10723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
10823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Stop observing message loop destruction if no event is being monitored.
10923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  base::MessageLoop::current()->RemoveDestructionObserver(this);
11023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
11123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
11223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void RawInputDataFetcher::ClearControllers() {
11323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  while (!controllers_.empty()) {
11423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    RawGamepadInfo* gamepad_info = controllers_.begin()->second;
11523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    controllers_.erase(gamepad_info->handle);
11623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    delete gamepad_info;
11723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
11823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
11923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
12023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)std::vector<RawGamepadInfo*> RawInputDataFetcher::EnumerateDevices() {
12123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  std::vector<RawGamepadInfo*> valid_controllers;
12223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
12323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  ClearControllers();
12423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
12523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  UINT count = 0;
12623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  UINT result = GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST));
12723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (result == static_cast<UINT>(-1)) {
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "GetRawInputDeviceList() failed";
12923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return valid_controllers;
13023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
13123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DCHECK_EQ(0u, result);
13223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
13323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  scoped_ptr<RAWINPUTDEVICELIST[]> device_list(new RAWINPUTDEVICELIST[count]);
13423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  result = GetRawInputDeviceList(device_list.get(), &count,
13523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      sizeof(RAWINPUTDEVICELIST));
13623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (result == static_cast<UINT>(-1)) {
137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "GetRawInputDeviceList() failed";
13823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return valid_controllers;
13923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
14023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DCHECK_EQ(count, result);
14123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
14223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  for (UINT i = 0; i < count; ++i) {
14323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (device_list[i].dwType == RIM_TYPEHID) {
14423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      HANDLE device_handle = device_list[i].hDevice;
14523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      RawGamepadInfo* gamepad_info = ParseGamepadInfo(device_handle);
14623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      if (gamepad_info) {
14723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        controllers_[device_handle] = gamepad_info;
14823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        valid_controllers.push_back(gamepad_info);
14923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      }
15023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
15123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
15223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return valid_controllers;
15323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
15423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
15523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)RawGamepadInfo* RawInputDataFetcher::GetGamepadInfo(HANDLE handle) {
15623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  std::map<HANDLE, RawGamepadInfo*>::iterator it = controllers_.find(handle);
15723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (it != controllers_.end())
15823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return it->second;
15923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
16023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return NULL;
16123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
16223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
16323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)RawGamepadInfo* RawInputDataFetcher::ParseGamepadInfo(HANDLE hDevice) {
16423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  UINT size = 0;
16523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
16623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Do we already have this device in the map?
16723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (GetGamepadInfo(hDevice))
16823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return NULL;
16923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
17023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Query basic device info.
17123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  UINT result = GetRawInputDeviceInfo(hDevice, RIDI_DEVICEINFO,
17223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      NULL, &size);
17323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (result == static_cast<UINT>(-1)) {
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "GetRawInputDeviceInfo() failed";
17523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return NULL;
17623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
17723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DCHECK_EQ(0u, result);
17823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
17923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  scoped_ptr<uint8[]> di_buffer(new uint8[size]);
18023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  RID_DEVICE_INFO* device_info =
18123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      reinterpret_cast<RID_DEVICE_INFO*>(di_buffer.get());
18223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  result = GetRawInputDeviceInfo(hDevice, RIDI_DEVICEINFO,
18323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      di_buffer.get(), &size);
18423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (result == static_cast<UINT>(-1)) {
185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "GetRawInputDeviceInfo() failed";
18623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return NULL;
18723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
18823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DCHECK_EQ(size, result);
18923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
19023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Make sure this device is of a type that we want to observe.
19123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  bool valid_type = false;
19223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  for (int i = 0; i < arraysize(DeviceUsages); ++i) {
19323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (device_info->hid.usUsage == DeviceUsages[i]) {
19423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      valid_type = true;
19523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      break;
19623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
19723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
19823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
19923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!valid_type)
20023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return NULL;
20123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
20223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  scoped_ptr<RawGamepadInfo> gamepad_info(new RawGamepadInfo);
20323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  gamepad_info->handle = hDevice;
20423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  gamepad_info->report_id = 0;
20523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  gamepad_info->vendor_id = device_info->hid.dwVendorId;
20623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  gamepad_info->product_id = device_info->hid.dwProductId;
20723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  gamepad_info->buttons_length = 0;
20823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  ZeroMemory(gamepad_info->buttons, sizeof(gamepad_info->buttons));
20923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  gamepad_info->axes_length = 0;
21023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  ZeroMemory(gamepad_info->axes, sizeof(gamepad_info->axes));
21123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
21223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Query device identifier
21323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  result = GetRawInputDeviceInfo(hDevice, RIDI_DEVICENAME,
21423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      NULL, &size);
21523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (result == static_cast<UINT>(-1)) {
216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "GetRawInputDeviceInfo() failed";
21723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return NULL;
21823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
21923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DCHECK_EQ(0u, result);
22023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
22123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  scoped_ptr<wchar_t[]> name_buffer(new wchar_t[size]);
22223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  result = GetRawInputDeviceInfo(hDevice, RIDI_DEVICENAME,
22323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      name_buffer.get(), &size);
22423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (result == static_cast<UINT>(-1)) {
225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "GetRawInputDeviceInfo() failed";
22623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return NULL;
22723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
22823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DCHECK_EQ(size, result);
22923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
23023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // The presence of "IG_" in the device name indicates that this is an XInput
23123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Gamepad. Skip enumerating these devices and let the XInput path handle it.
23223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // http://msdn.microsoft.com/en-us/library/windows/desktop/ee417014.aspx
23323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (filter_xinput_ && wcsstr( name_buffer.get(), L"IG_" ) )
23423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return NULL;
23523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
23623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Get a friendly device name
23723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  BOOLEAN got_product_string = FALSE;
23823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  HANDLE hid_handle = CreateFile(name_buffer.get(), GENERIC_READ|GENERIC_WRITE,
23923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
24023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (hid_handle) {
24123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    got_product_string = hidd_get_product_string_(hid_handle, gamepad_info->id,
24223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        sizeof(gamepad_info->id));
24323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    CloseHandle(hid_handle);
24423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
24523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
24623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!got_product_string)
24723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    swprintf(gamepad_info->id, WebGamepad::idLengthCap, L"Unknown Gamepad");
24823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
24923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Query device capabilities.
25023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  result = GetRawInputDeviceInfo(hDevice, RIDI_PREPARSEDDATA,
25123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      NULL, &size);
25223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (result == static_cast<UINT>(-1)) {
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "GetRawInputDeviceInfo() failed";
25423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return NULL;
25523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
25623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DCHECK_EQ(0u, result);
25723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
25823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  gamepad_info->ppd_buffer.reset(new uint8[size]);
25923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  gamepad_info->preparsed_data =
26023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      reinterpret_cast<PHIDP_PREPARSED_DATA>(gamepad_info->ppd_buffer.get());
26123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  result = GetRawInputDeviceInfo(hDevice, RIDI_PREPARSEDDATA,
26223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)       gamepad_info->ppd_buffer.get(), &size);
26323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (result == static_cast<UINT>(-1)) {
264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "GetRawInputDeviceInfo() failed";
26523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return NULL;
26623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
26723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DCHECK_EQ(size, result);
26823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
26923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  HIDP_CAPS caps;
27023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  NTSTATUS status = hidp_get_caps_(gamepad_info->preparsed_data, &caps);
27123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DCHECK_EQ(HIDP_STATUS_SUCCESS, status);
27223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
27323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Query button information.
27423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  USHORT count = caps.NumberInputButtonCaps;
27523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (count > 0) {
27623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    scoped_ptr<HIDP_BUTTON_CAPS[]> button_caps(new HIDP_BUTTON_CAPS[count]);
27723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    status = hidp_get_button_caps_(
27823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        HidP_Input, button_caps.get(), &count, gamepad_info->preparsed_data);
27923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    DCHECK_EQ(HIDP_STATUS_SUCCESS, status);
28023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
28123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    for (uint32_t i = 0; i < count; ++i) {
28223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      if (button_caps[i].Range.UsageMin <= WebGamepad::buttonsLengthCap) {
28323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        uint32_t max_index =
28423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            std::min(WebGamepad::buttonsLengthCap,
28523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                     static_cast<size_t>(button_caps[i].Range.UsageMax));
28623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        gamepad_info->buttons_length = std::max(
28723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            gamepad_info->buttons_length, max_index);
28823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      }
28923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
29023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
29123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
29223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Query axis information.
29323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  count = caps.NumberInputValueCaps;
29423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  scoped_ptr<HIDP_VALUE_CAPS[]> axes_caps(new HIDP_VALUE_CAPS[count]);
29523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  status = hidp_get_value_caps_(HidP_Input, axes_caps.get(), &count,
29623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      gamepad_info->preparsed_data);
29723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
29823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  bool mapped_all_axes = true;
29923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
30023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  for (UINT i = 0; i < count; i++) {
30123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    uint32_t axis_index = axes_caps[i].Range.UsageMin - kAxisMinimumUsageNumber;
30223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (axis_index < WebGamepad::axesLengthCap) {
30323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      gamepad_info->axes[axis_index].caps = axes_caps[i];
30423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      gamepad_info->axes[axis_index].value = 0;
30523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      gamepad_info->axes[axis_index].active = true;
30623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      gamepad_info->axes_length =
30723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          std::max(gamepad_info->axes_length, axis_index + 1);
30823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    } else {
30923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      mapped_all_axes = false;
31023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
31123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
31223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
31323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!mapped_all_axes) {
31423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    // For axes who's usage puts them outside the standard axesLengthCap range.
31523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    uint32_t next_index = 0;
31623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    for (UINT i = 0; i < count; i++) {
31723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      uint32_t usage = axes_caps[i].Range.UsageMin - kAxisMinimumUsageNumber;
31823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      if (usage >= WebGamepad::axesLengthCap &&
31923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          axes_caps[i].UsagePage <= kGameControlsUsagePage) {
32023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
32123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        for (; next_index < WebGamepad::axesLengthCap; ++next_index) {
32223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          if (!gamepad_info->axes[next_index].active)
32323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            break;
32423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        }
32523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        if (next_index < WebGamepad::axesLengthCap) {
32623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          gamepad_info->axes[next_index].caps = axes_caps[i];
32723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          gamepad_info->axes[next_index].value = 0;
32823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          gamepad_info->axes[next_index].active = true;
32923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          gamepad_info->axes_length =
33023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)              std::max(gamepad_info->axes_length, next_index + 1);
33123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        }
33223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      }
33323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
33423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      if (next_index >= WebGamepad::axesLengthCap)
33523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        break;
33623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
33723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
33823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
33923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return gamepad_info.release();
34023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
34123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
34223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void RawInputDataFetcher::UpdateGamepad(
34323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    RAWINPUT* input,
34423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    RawGamepadInfo* gamepad_info) {
34523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  NTSTATUS status;
34623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
34723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  gamepad_info->report_id++;
34823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
34923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Query button state.
35023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (gamepad_info->buttons_length) {
35123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    // Clear the button state
35223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    ZeroMemory(gamepad_info->buttons, sizeof(gamepad_info->buttons));
35323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    ULONG buttons_length = 0;
35423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
35523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    hidp_get_usages_ex_(HidP_Input,
35623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        0,
35723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        NULL,
35823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        &buttons_length,
35923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        gamepad_info->preparsed_data,
36023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        reinterpret_cast<PCHAR>(input->data.hid.bRawData),
36123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        input->data.hid.dwSizeHid);
36223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
36323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    scoped_ptr<USAGE_AND_PAGE[]> usages(new USAGE_AND_PAGE[buttons_length]);
36423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    status =
36523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        hidp_get_usages_ex_(HidP_Input,
36623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                            0,
36723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                            usages.get(),
36823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                            &buttons_length,
36923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                            gamepad_info->preparsed_data,
37023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                            reinterpret_cast<PCHAR>(input->data.hid.bRawData),
37123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                            input->data.hid.dwSizeHid);
37223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
37323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (status == HIDP_STATUS_SUCCESS) {
37423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      // Set each reported button to true.
37523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      for (uint32_t j = 0; j < buttons_length; j++) {
37623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        int32_t button_index = usages[j].Usage - 1;
37723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        if (button_index >= 0 &&
37823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            button_index < blink::WebGamepad::buttonsLengthCap)
37923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          gamepad_info->buttons[button_index] = true;
38023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      }
38123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
38223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
38323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
38423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Query axis state.
38523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  ULONG axis_value = 0;
38623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  LONG scaled_axis_value = 0;
38723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  for (uint32_t i = 0; i < gamepad_info->axes_length; i++) {
38823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    RawGamepadAxis* axis = &gamepad_info->axes[i];
38923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
39023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    // If the min is < 0 we have to query the scaled value, otherwise we need
39123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    // the normal unscaled value.
39223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (axis->caps.LogicalMin < 0) {
39323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      status = hidp_get_scaled_usage_value_(HidP_Input, axis->caps.UsagePage, 0,
39423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          axis->caps.Range.UsageMin, &scaled_axis_value,
39523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          gamepad_info->preparsed_data,
39623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          reinterpret_cast<PCHAR>(input->data.hid.bRawData),
39723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          input->data.hid.dwSizeHid);
39823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      if (status == HIDP_STATUS_SUCCESS) {
39923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        axis->value = NormalizeAxis(scaled_axis_value,
40023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            axis->caps.LogicalMin, axis->caps.LogicalMax);
40123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      }
40223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    } else {
40323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      status = hidp_get_usage_value_(HidP_Input, axis->caps.UsagePage, 0,
40423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          axis->caps.Range.UsageMin, &axis_value,
40523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          gamepad_info->preparsed_data,
40623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          reinterpret_cast<PCHAR>(input->data.hid.bRawData),
40723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          input->data.hid.dwSizeHid);
40823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      if (status == HIDP_STATUS_SUCCESS) {
40923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        axis->value = NormalizeAxis(axis_value,
41023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            axis->caps.LogicalMin, axis->caps.LogicalMax);
41123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      }
41223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
41323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
41423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
41523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
41623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)LRESULT RawInputDataFetcher::OnInput(HRAWINPUT input_handle) {
41723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Get the size of the input record.
41823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  UINT size = 0;
41923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  UINT result = GetRawInputData(
42023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      input_handle, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
42123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (result == static_cast<UINT>(-1)) {
422cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "GetRawInputData() failed";
42323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return 0;
42423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
42523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DCHECK_EQ(0u, result);
42623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
42723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Retrieve the input record.
42823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  scoped_ptr<uint8[]> buffer(new uint8[size]);
42923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  RAWINPUT* input = reinterpret_cast<RAWINPUT*>(buffer.get());
43023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  result = GetRawInputData(
43123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      input_handle, RID_INPUT, buffer.get(), &size, sizeof(RAWINPUTHEADER));
43223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (result == static_cast<UINT>(-1)) {
433cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "GetRawInputData() failed";
43423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return 0;
43523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
43623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DCHECK_EQ(size, result);
43723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
43823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Notify the observer about events generated locally.
43923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (input->header.dwType == RIM_TYPEHID && input->header.hDevice != NULL) {
44023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    RawGamepadInfo* gamepad = GetGamepadInfo(input->header.hDevice);
44123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (gamepad)
44223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      UpdateGamepad(input, gamepad);
44323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
44423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
44523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return DefRawInputProc(&input, 1, sizeof(RAWINPUTHEADER));
44623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
44723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
44823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)bool RawInputDataFetcher::HandleMessage(UINT message,
44923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                            WPARAM wparam,
45023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                            LPARAM lparam,
45123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                            LRESULT* result) {
45223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  switch (message) {
45323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    case WM_INPUT:
45423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      *result = OnInput(reinterpret_cast<HRAWINPUT>(lparam));
45523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      return true;
45623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
45723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    default:
45823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      return false;
45923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
46023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
46123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
46223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)bool RawInputDataFetcher::GetHidDllFunctions() {
46323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  hidp_get_caps_ = NULL;
46423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  hidp_get_button_caps_ = NULL;
46523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  hidp_get_value_caps_ = NULL;
46623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  hidp_get_usages_ex_ = NULL;
46723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  hidp_get_usage_value_ = NULL;
46823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  hidp_get_scaled_usage_value_ = NULL;
46923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  hidd_get_product_string_ = NULL;
47023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
47123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!hid_dll_.is_valid()) return false;
47223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
47323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  hidp_get_caps_ = reinterpret_cast<HidPGetCapsFunc>(
47423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      hid_dll_.GetFunctionPointer("HidP_GetCaps"));
47523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!hidp_get_caps_)
47623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return false;
47723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  hidp_get_button_caps_ = reinterpret_cast<HidPGetButtonCapsFunc>(
47823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      hid_dll_.GetFunctionPointer("HidP_GetButtonCaps"));
47923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!hidp_get_button_caps_)
48023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return false;
48123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  hidp_get_value_caps_ = reinterpret_cast<HidPGetValueCapsFunc>(
48223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      hid_dll_.GetFunctionPointer("HidP_GetValueCaps"));
48323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!hidp_get_value_caps_)
48423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return false;
48523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  hidp_get_usages_ex_ = reinterpret_cast<HidPGetUsagesExFunc>(
48623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      hid_dll_.GetFunctionPointer("HidP_GetUsagesEx"));
48723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!hidp_get_usages_ex_)
48823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return false;
48923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  hidp_get_usage_value_ = reinterpret_cast<HidPGetUsageValueFunc>(
49023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      hid_dll_.GetFunctionPointer("HidP_GetUsageValue"));
49123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!hidp_get_usage_value_)
49223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return false;
49323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  hidp_get_scaled_usage_value_ = reinterpret_cast<HidPGetScaledUsageValueFunc>(
49423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      hid_dll_.GetFunctionPointer("HidP_GetScaledUsageValue"));
49523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!hidp_get_scaled_usage_value_)
49623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return false;
49723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  hidd_get_product_string_ = reinterpret_cast<HidDGetStringFunc>(
49823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      hid_dll_.GetFunctionPointer("HidD_GetProductString"));
49923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!hidd_get_product_string_)
50023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return false;
50123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
50223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return true;
50323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
50423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
50523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}  // namespace content
506