By moving the call to Load() up in SearchProvider::Start(), we are giving a chance...
[chromium-blink-merge.git] / content / browser / gamepad / gamepad_platform_data_fetcher_win.cc
blob838a626d0184b093df64cb1ba6a2269dd9060022
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/gamepad/gamepad_platform_data_fetcher_win.h"
7 #include "base/debug/trace_event.h"
8 #include "content/common/gamepad_messages.h"
9 #include "content/common/gamepad_hardware_buffer.h"
11 namespace content {
13 using namespace WebKit;
15 namespace {
17 // See http://goo.gl/5VSJR. These are not available in all versions of the
18 // header, but they can be returned from the driver, so we define our own
19 // versions here.
20 static const BYTE kDeviceSubTypeGamepad = 1;
21 static const BYTE kDeviceSubTypeWheel = 2;
22 static const BYTE kDeviceSubTypeArcadeStick = 3;
23 static const BYTE kDeviceSubTypeFlightStick = 4;
24 static const BYTE kDeviceSubTypeDancePad = 5;
25 static const BYTE kDeviceSubTypeGuitar = 6;
26 static const BYTE kDeviceSubTypeGuitarAlternate = 7;
27 static const BYTE kDeviceSubTypeDrumKit = 8;
28 static const BYTE kDeviceSubTypeGuitarBass = 11;
29 static const BYTE kDeviceSubTypeArcadePad = 19;
31 float NormalizeAxis(SHORT value) {
32 return ((value + 32768.f) / 32767.5f) - 1.f;
35 const WebUChar* const GamepadSubTypeName(BYTE sub_type) {
36 switch (sub_type) {
37 case kDeviceSubTypeGamepad: return L"GAMEPAD";
38 case kDeviceSubTypeWheel: return L"WHEEL";
39 case kDeviceSubTypeArcadeStick: return L"ARCADE_STICK";
40 case kDeviceSubTypeFlightStick: return L"FLIGHT_STICK";
41 case kDeviceSubTypeDancePad: return L"DANCE_PAD";
42 case kDeviceSubTypeGuitar: return L"GUITAR";
43 case kDeviceSubTypeGuitarAlternate: return L"GUITAR_ALTERNATE";
44 case kDeviceSubTypeDrumKit: return L"DRUM_KIT";
45 case kDeviceSubTypeGuitarBass: return L"GUITAR_BASS";
46 case kDeviceSubTypeArcadePad: return L"ARCADE_PAD";
47 default: return L"<UNKNOWN>";
51 } // namespace
53 GamepadPlatformDataFetcherWin::GamepadPlatformDataFetcherWin()
54 : xinput_dll_(FilePath(FILE_PATH_LITERAL("xinput1_3.dll"))),
55 xinput_available_(GetXinputDllFunctions()) {
58 GamepadPlatformDataFetcherWin::~GamepadPlatformDataFetcherWin() {
61 void GamepadPlatformDataFetcherWin::GetGamepadData(WebGamepads* pads,
62 bool devices_changed_hint) {
63 TRACE_EVENT0("GAMEPAD", "GetGamepadData");
65 // If there's no XInput DLL on the system, early out so that we don't
66 // call any other XInput functions.
67 if (!xinput_available_) {
68 pads->length = 0;
69 return;
72 pads->length = WebGamepads::itemsLengthCap;
74 // If we got notification that system devices have been updated, then
75 // run GetCapabilities to update the connected status and the device
76 // identifier. It can be slow to do to both GetCapabilities and
77 // GetState on unconnected devices, so we want to avoid a 2-5ms pause
78 // here by only doing this when the devices are updated (despite
79 // documentation claiming it's OK to call it any time).
80 if (devices_changed_hint) {
81 for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i) {
82 WebGamepad& pad = pads->items[i];
83 TRACE_EVENT1("GAMEPAD", "GetCapabilities", "id", i);
84 XINPUT_CAPABILITIES caps;
85 DWORD res = xinput_get_capabilities_(i, XINPUT_FLAG_GAMEPAD, &caps);
86 if (res == ERROR_DEVICE_NOT_CONNECTED) {
87 pad.connected = false;
88 } else {
89 pad.connected = true;
90 base::swprintf(pad.id,
91 WebGamepad::idLengthCap,
92 L"Xbox 360 Controller (XInput STANDARD %ls)",
93 GamepadSubTypeName(caps.SubType));
98 // We've updated the connection state if necessary, now update the actual
99 // data for the devices that are connected.
100 for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i) {
101 WebGamepad& pad = pads->items[i];
103 // We rely on device_changed and GetCapabilities to tell us that
104 // something's been connected, but we will mark as disconnected if
105 // GetState returns that we've lost the pad.
106 if (!pad.connected)
107 continue;
109 XINPUT_STATE state;
110 memset(&state, 0, sizeof(XINPUT_STATE));
111 TRACE_EVENT_BEGIN1("GAMEPAD", "XInputGetState", "id", i);
112 DWORD dwResult = xinput_get_state_(i, &state);
113 TRACE_EVENT_END1("GAMEPAD", "XInputGetState", "id", i);
115 if (dwResult == ERROR_SUCCESS) {
116 pad.timestamp = state.dwPacketNumber;
117 pad.buttonsLength = 0;
118 #define ADD(b) pad.buttons[pad.buttonsLength++] = \
119 ((state.Gamepad.wButtons & (b)) ? 1.0 : 0.0);
120 ADD(XINPUT_GAMEPAD_A);
121 ADD(XINPUT_GAMEPAD_B);
122 ADD(XINPUT_GAMEPAD_X);
123 ADD(XINPUT_GAMEPAD_Y);
124 ADD(XINPUT_GAMEPAD_LEFT_SHOULDER);
125 ADD(XINPUT_GAMEPAD_RIGHT_SHOULDER);
126 pad.buttons[pad.buttonsLength++] = state.Gamepad.bLeftTrigger / 255.0;
127 pad.buttons[pad.buttonsLength++] = state.Gamepad.bRightTrigger / 255.0;
128 ADD(XINPUT_GAMEPAD_BACK);
129 ADD(XINPUT_GAMEPAD_START);
130 ADD(XINPUT_GAMEPAD_LEFT_THUMB);
131 ADD(XINPUT_GAMEPAD_RIGHT_THUMB);
132 ADD(XINPUT_GAMEPAD_DPAD_UP);
133 ADD(XINPUT_GAMEPAD_DPAD_DOWN);
134 ADD(XINPUT_GAMEPAD_DPAD_LEFT);
135 ADD(XINPUT_GAMEPAD_DPAD_RIGHT);
136 #undef ADD
137 pad.axesLength = 0;
138 // XInput are +up/+right, -down/-left, we want -up/-left.
139 pad.axes[pad.axesLength++] = NormalizeAxis(state.Gamepad.sThumbLX);
140 pad.axes[pad.axesLength++] = -NormalizeAxis(state.Gamepad.sThumbLY);
141 pad.axes[pad.axesLength++] = NormalizeAxis(state.Gamepad.sThumbRX);
142 pad.axes[pad.axesLength++] = -NormalizeAxis(state.Gamepad.sThumbRY);
143 } else {
144 pad.connected = false;
149 bool GamepadPlatformDataFetcherWin::GetXinputDllFunctions() {
150 xinput_get_capabilities_ = NULL;
151 xinput_get_state_ = NULL;
152 xinput_enable_ = static_cast<XInputEnableFunc>(
153 xinput_dll_.GetFunctionPointer("XInputEnable"));
154 if (!xinput_enable_)
155 return false;
156 xinput_get_capabilities_ = static_cast<XInputGetCapabilitiesFunc>(
157 xinput_dll_.GetFunctionPointer("XInputGetCapabilities"));
158 if (!xinput_get_capabilities_)
159 return false;
160 xinput_get_state_ = static_cast<XInputGetStateFunc>(
161 xinput_dll_.GetFunctionPointer("XInputGetState"));
162 if (!xinput_get_state_)
163 return false;
164 xinput_enable_(true);
165 return true;
168 } // namespace content