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