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