15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/gamepad/gamepad_platform_data_fetcher_win.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/trace_event.h" 8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 97dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/win/windows_version.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/common/gamepad_hardware_buffer.h" 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/common/gamepad_messages.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content { 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using namespace blink; 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// See http://goo.gl/5VSJR. These are not available in all versions of the 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// header, but they can be returned from the driver, so we define our own 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// versions here. 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const BYTE kDeviceSubTypeGamepad = 1; 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const BYTE kDeviceSubTypeWheel = 2; 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const BYTE kDeviceSubTypeArcadeStick = 3; 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const BYTE kDeviceSubTypeFlightStick = 4; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const BYTE kDeviceSubTypeDancePad = 5; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const BYTE kDeviceSubTypeGuitar = 6; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const BYTE kDeviceSubTypeGuitarAlternate = 7; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const BYTE kDeviceSubTypeDrumKit = 8; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const BYTE kDeviceSubTypeGuitarBass = 11; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const BYTE kDeviceSubTypeArcadePad = 19; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)float NormalizeXInputAxis(SHORT value) { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ((value + 32768.f) / 32767.5f) - 1.f; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const WebUChar* const GamepadSubTypeName(BYTE sub_type) { 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (sub_type) { 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case kDeviceSubTypeGamepad: return L"GAMEPAD"; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case kDeviceSubTypeWheel: return L"WHEEL"; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case kDeviceSubTypeArcadeStick: return L"ARCADE_STICK"; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case kDeviceSubTypeFlightStick: return L"FLIGHT_STICK"; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case kDeviceSubTypeDancePad: return L"DANCE_PAD"; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case kDeviceSubTypeGuitar: return L"GUITAR"; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case kDeviceSubTypeGuitarAlternate: return L"GUITAR_ALTERNATE"; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case kDeviceSubTypeDrumKit: return L"DRUM_KIT"; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case kDeviceSubTypeGuitarBass: return L"GUITAR_BASS"; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case kDeviceSubTypeArcadePad: return L"ARCADE_PAD"; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: return L"<UNKNOWN>"; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GamepadPlatformDataFetcherWin::GamepadPlatformDataFetcherWin() 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : xinput_dll_(base::FilePath(FILE_PATH_LITERAL("xinput1_3.dll"))), 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) xinput_available_(GetXInputDllFunctions()) { 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pad_state_[i].status = DISCONNECTED; 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raw_input_fetcher_.reset(new RawInputDataFetcher()); 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raw_input_fetcher_->StartMonitor(); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GamepadPlatformDataFetcherWin::~GamepadPlatformDataFetcherWin() { 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raw_input_fetcher_->StopMonitor(); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int GamepadPlatformDataFetcherWin::FirstAvailableGamepadId() const { 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (pad_state_[i].status == DISCONNECTED) 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return i; 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return -1; 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool GamepadPlatformDataFetcherWin::HasXInputGamepad(int index) const { 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (pad_state_[i].status == XINPUT_CONNECTED && 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pad_state_[i].xinput_index == index) 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GamepadPlatformDataFetcherWin::HasRawInputGamepad( 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const HANDLE handle) const { 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (pad_state_[i].status == RAWINPUT_CONNECTED && 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pad_state_[i].raw_input_handle == handle) 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void GamepadPlatformDataFetcherWin::EnumerateDevices( 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WebGamepads* pads) { 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TRACE_EVENT0("GAMEPAD", "EnumerateDevices"); 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Mark all disconnected pads DISCONNECTED. 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!pads->items[i].connected) 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pad_state_[i].status = DISCONNECTED; 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < XUSER_MAX_COUNT; ++i) { 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (HasXInputGamepad(i)) 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int pad_index = FirstAvailableGamepadId(); 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (pad_index == -1) 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; // We can't add any more gamepads. 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WebGamepad& pad = pads->items[pad_index]; 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (xinput_available_ && GetXInputPadConnectivity(i, &pad)) { 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pad_state_[pad_index].status = XINPUT_CONNECTED; 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pad_state_[pad_index].xinput_index = i; 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pad_state_[pad_index].mapper = NULL; 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pads->length++; 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (raw_input_fetcher_->Available()) { 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<RawGamepadInfo*> raw_inputs = 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raw_input_fetcher_->EnumerateDevices(); 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t i = 0; i < raw_inputs.size(); ++i) { 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RawGamepadInfo* gamepad = raw_inputs[i]; 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (HasRawInputGamepad(gamepad->handle)) 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int pad_index = FirstAvailableGamepadId(); 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (pad_index == -1) 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WebGamepad& pad = pads->items[pad_index]; 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pad.connected = true; 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PadState& state = pad_state_[pad_index]; 1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) state.status = RAWINPUT_CONNECTED; 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) state.raw_input_handle = gamepad->handle; 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string vendor = base::StringPrintf("%04x", gamepad->vendor_id); 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string product = base::StringPrintf("%04x", gamepad->product_id); 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) state.mapper = GetGamepadStandardMappingFunction(vendor, product); 1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) swprintf(pad.id, WebGamepad::idLengthCap, 1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) L"%ls (%lsVendor: %04x Product: %04x)", 1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) gamepad->id, state.mapper ? L"STANDARD GAMEPAD " : L"", 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) gamepad->vendor_id, gamepad->product_id); 145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (state.mapper) 147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) swprintf(pad.mapping, WebGamepad::mappingLengthCap, L"standard"); 148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) else 149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) pad.mapping[0] = 0; 150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pads->length++; 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadPlatformDataFetcherWin::GetGamepadData(WebGamepads* pads, 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool devices_changed_hint) { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TRACE_EVENT0("GAMEPAD", "GetGamepadData"); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!xinput_available_ && 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) !raw_input_fetcher_->Available()) { 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pads->length = 0; 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // A note on XInput devices: 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we got notification that system devices have been updated, then 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // run GetCapabilities to update the connected status and the device 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // identifier. It can be slow to do to both GetCapabilities and 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GetState on unconnected devices, so we want to avoid a 2-5ms pause 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // here by only doing this when the devices are updated (despite 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // documentation claiming it's OK to call it any time). 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (devices_changed_hint) 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EnumerateDevices(pads); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // We rely on device_changed and GetCapabilities to tell us that 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // something's been connected, but we will mark as disconnected if 1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Get___PadState returns that we've lost the pad. 1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!pads->items[i].connected) 1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (pad_state_[i].status == XINPUT_CONNECTED) 1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GetXInputPadData(i, &pads->items[i]); 1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) else if (pad_state_[i].status == RAWINPUT_CONNECTED) 1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GetRawInputPadData(i, &pads->items[i]); 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GamepadPlatformDataFetcherWin::PauseHint(bool pause) { 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (pause) 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raw_input_fetcher_->StopMonitor(); 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) else 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raw_input_fetcher_->StartMonitor(); 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool GamepadPlatformDataFetcherWin::GetXInputPadConnectivity( 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int i, 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WebGamepad* pad) const { 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(pad); 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TRACE_EVENT1("GAMEPAD", "GetXInputPadConnectivity", "id", i); 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) XINPUT_CAPABILITIES caps; 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DWORD res = xinput_get_capabilities_(i, XINPUT_FLAG_GAMEPAD, &caps); 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (res == ERROR_DEVICE_NOT_CONNECTED) { 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pad->connected = false; 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pad->connected = true; 210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) swprintf(pad->id, 211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) WebGamepad::idLengthCap, 212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) L"Xbox 360 Controller (XInput STANDARD %ls)", 213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) GamepadSubTypeName(caps.SubType)); 214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) swprintf(pad->mapping, WebGamepad::mappingLengthCap, L"standard"); 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void GamepadPlatformDataFetcherWin::GetXInputPadData( 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int i, 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WebGamepad* pad) { 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) XINPUT_STATE state; 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) memset(&state, 0, sizeof(XINPUT_STATE)); 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TRACE_EVENT_BEGIN1("GAMEPAD", "XInputGetState", "id", i); 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DWORD dwResult = xinput_get_state_(pad_state_[i].xinput_index, &state); 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TRACE_EVENT_END1("GAMEPAD", "XInputGetState", "id", i); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (dwResult == ERROR_SUCCESS) { 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pad->timestamp = state.dwPacketNumber; 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pad->buttonsLength = 0; 231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#define ADD(b) pad->buttons[pad->buttonsLength].pressed = \ 232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) (state.Gamepad.wButtons & (b)) != 0; \ 233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) pad->buttons[pad->buttonsLength++].value = \ 234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ((state.Gamepad.wButtons & (b)) ? 1.f : 0.f); 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ADD(XINPUT_GAMEPAD_A); 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ADD(XINPUT_GAMEPAD_B); 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ADD(XINPUT_GAMEPAD_X); 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ADD(XINPUT_GAMEPAD_Y); 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ADD(XINPUT_GAMEPAD_LEFT_SHOULDER); 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ADD(XINPUT_GAMEPAD_RIGHT_SHOULDER); 241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) pad->buttons[pad->buttonsLength].pressed = 242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state.Gamepad.bLeftTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD; 243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) pad->buttons[pad->buttonsLength++].value = 244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state.Gamepad.bLeftTrigger / 255.f; 245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) pad->buttons[pad->buttonsLength].pressed = 246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state.Gamepad.bRightTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD; 247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) pad->buttons[pad->buttonsLength++].value = 248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state.Gamepad.bRightTrigger / 255.f; 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ADD(XINPUT_GAMEPAD_BACK); 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ADD(XINPUT_GAMEPAD_START); 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ADD(XINPUT_GAMEPAD_LEFT_THUMB); 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ADD(XINPUT_GAMEPAD_RIGHT_THUMB); 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ADD(XINPUT_GAMEPAD_DPAD_UP); 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ADD(XINPUT_GAMEPAD_DPAD_DOWN); 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ADD(XINPUT_GAMEPAD_DPAD_LEFT); 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ADD(XINPUT_GAMEPAD_DPAD_RIGHT); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef ADD 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pad->axesLength = 0; 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // XInput are +up/+right, -down/-left, we want -up/-left. 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pad->axes[pad->axesLength++] = NormalizeXInputAxis(state.Gamepad.sThumbLX); 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pad->axes[pad->axesLength++] = -NormalizeXInputAxis(state.Gamepad.sThumbLY); 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pad->axes[pad->axesLength++] = NormalizeXInputAxis(state.Gamepad.sThumbRX); 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pad->axes[pad->axesLength++] = -NormalizeXInputAxis(state.Gamepad.sThumbRY); 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pad->connected = false; 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GamepadPlatformDataFetcherWin::GetRawInputPadData( 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int index, 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WebGamepad* pad) { 2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RawGamepadInfo* gamepad = raw_input_fetcher_->GetGamepadInfo( 2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pad_state_[index].raw_input_handle); 2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!gamepad) { 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pad->connected = false; 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) WebGamepad raw_pad = *pad; 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raw_pad.timestamp = gamepad->report_id; 2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raw_pad.buttonsLength = gamepad->buttons_length; 2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raw_pad.axesLength = gamepad->axes_length; 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (unsigned int i = 0; i < raw_pad.buttonsLength; i++) { 286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) raw_pad.buttons[i].pressed = gamepad->buttons[i]; 287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) raw_pad.buttons[i].value = gamepad->buttons[i] ? 1.0 : 0.0; 288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (unsigned int i = 0; i < raw_pad.axesLength; i++) 2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raw_pad.axes[i] = gamepad->axes[i].value; 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Copy to the current state to the output buffer, using the mapping 2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // function, if there is one available. 2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (pad_state_[index].mapper) 2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pad_state_[index].mapper(raw_pad, pad); 2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) else 2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *pad = raw_pad; 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool GamepadPlatformDataFetcherWin::GetXInputDllFunctions() { 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xinput_get_capabilities_ = NULL; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xinput_get_state_ = NULL; 30490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) xinput_enable_ = reinterpret_cast<XInputEnableFunc>( 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xinput_dll_.GetFunctionPointer("XInputEnable")); 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!xinput_enable_) 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 30890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) xinput_get_capabilities_ = reinterpret_cast<XInputGetCapabilitiesFunc>( 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xinput_dll_.GetFunctionPointer("XInputGetCapabilities")); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!xinput_get_capabilities_) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 31290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) xinput_get_state_ = reinterpret_cast<XInputGetStateFunc>( 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xinput_dll_.GetFunctionPointer("XInputGetState")); 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!xinput_get_state_) 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xinput_enable_(true); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace content 321