Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(98)

Side by Side Diff: content/browser/gamepad/gamepad_platform_data_fetcher_win.cc

Issue 12260011: Support DirectInput gamepads on Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Preserve controller index Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/gamepad/gamepad_platform_data_fetcher_win.h" 5 #include "content/browser/gamepad/gamepad_platform_data_fetcher_win.h"
6 6
7 #include <dinput.h>
8 #include <dinputd.h>
9
7 #include "base/debug/trace_event.h" 10 #include "base/debug/trace_event.h"
11 #include "base/stringprintf.h"
8 #include "content/common/gamepad_messages.h" 12 #include "content/common/gamepad_messages.h"
9 #include "content/common/gamepad_hardware_buffer.h" 13 #include "content/common/gamepad_hardware_buffer.h"
10 14
11 namespace content { 15 namespace content {
12 16
13 using namespace WebKit; 17 using namespace WebKit;
14 18
15 namespace { 19 namespace {
16 20
21 static const int kMaxXInputIndex = 3;
22
17 // See http://goo.gl/5VSJR. These are not available in all versions of the 23 // 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 24 // header, but they can be returned from the driver, so we define our own
19 // versions here. 25 // versions here.
20 static const BYTE kDeviceSubTypeGamepad = 1; 26 static const BYTE kDeviceSubTypeGamepad = 1;
21 static const BYTE kDeviceSubTypeWheel = 2; 27 static const BYTE kDeviceSubTypeWheel = 2;
22 static const BYTE kDeviceSubTypeArcadeStick = 3; 28 static const BYTE kDeviceSubTypeArcadeStick = 3;
23 static const BYTE kDeviceSubTypeFlightStick = 4; 29 static const BYTE kDeviceSubTypeFlightStick = 4;
24 static const BYTE kDeviceSubTypeDancePad = 5; 30 static const BYTE kDeviceSubTypeDancePad = 5;
25 static const BYTE kDeviceSubTypeGuitar = 6; 31 static const BYTE kDeviceSubTypeGuitar = 6;
26 static const BYTE kDeviceSubTypeGuitarAlternate = 7; 32 static const BYTE kDeviceSubTypeGuitarAlternate = 7;
27 static const BYTE kDeviceSubTypeDrumKit = 8; 33 static const BYTE kDeviceSubTypeDrumKit = 8;
28 static const BYTE kDeviceSubTypeGuitarBass = 11; 34 static const BYTE kDeviceSubTypeGuitarBass = 11;
29 static const BYTE kDeviceSubTypeArcadePad = 19; 35 static const BYTE kDeviceSubTypeArcadePad = 19;
30 36
31 float NormalizeAxis(SHORT value) { 37 float NormalizeXInputAxis(SHORT value) {
32 return ((value + 32768.f) / 32767.5f) - 1.f; 38 return ((value + 32768.f) / 32767.5f) - 1.f;
33 } 39 }
34 40
35 const WebUChar* const GamepadSubTypeName(BYTE sub_type) { 41 const WebUChar* const GamepadSubTypeName(BYTE sub_type) {
36 switch (sub_type) { 42 switch (sub_type) {
37 case kDeviceSubTypeGamepad: return L"GAMEPAD"; 43 case kDeviceSubTypeGamepad: return L"GAMEPAD";
38 case kDeviceSubTypeWheel: return L"WHEEL"; 44 case kDeviceSubTypeWheel: return L"WHEEL";
39 case kDeviceSubTypeArcadeStick: return L"ARCADE_STICK"; 45 case kDeviceSubTypeArcadeStick: return L"ARCADE_STICK";
40 case kDeviceSubTypeFlightStick: return L"FLIGHT_STICK"; 46 case kDeviceSubTypeFlightStick: return L"FLIGHT_STICK";
41 case kDeviceSubTypeDancePad: return L"DANCE_PAD"; 47 case kDeviceSubTypeDancePad: return L"DANCE_PAD";
42 case kDeviceSubTypeGuitar: return L"GUITAR"; 48 case kDeviceSubTypeGuitar: return L"GUITAR";
43 case kDeviceSubTypeGuitarAlternate: return L"GUITAR_ALTERNATE"; 49 case kDeviceSubTypeGuitarAlternate: return L"GUITAR_ALTERNATE";
44 case kDeviceSubTypeDrumKit: return L"DRUM_KIT"; 50 case kDeviceSubTypeDrumKit: return L"DRUM_KIT";
45 case kDeviceSubTypeGuitarBass: return L"GUITAR_BASS"; 51 case kDeviceSubTypeGuitarBass: return L"GUITAR_BASS";
46 case kDeviceSubTypeArcadePad: return L"ARCADE_PAD"; 52 case kDeviceSubTypeArcadePad: return L"ARCADE_PAD";
47 default: return L"<UNKNOWN>"; 53 default: return L"<UNKNOWN>";
48 } 54 }
49 } 55 }
50 56
57 bool GetDirectInputVendorProduct(IDirectInputDevice8* gamepad,
58 std::string* vendor,
59 std::string* product) {
60 DIPROPDWORD prop;
61 prop.diph.dwSize = sizeof(DIPROPDWORD);
62 prop.diph.dwHeaderSize = sizeof(DIPROPHEADER);
63 prop.diph.dwObj = 0;
64 prop.diph.dwHow = DIPH_DEVICE;
65
66 if (FAILED(gamepad->GetProperty(DIPROP_VIDPID, &prop.diph)))
67 return false;
68 *vendor = base::StringPrintf("%04x", LOWORD(prop.dwData));
69 *product = base::StringPrintf("%04x", HIWORD(prop.dwData));
70 return true;
71 }
72
73 // Sets the deadzone value for all axes of a gamepad.
74 // deadzone values range from 0 (no deadzone) to 10,000 (entire range
75 // is dead).
76 bool SetDirectInputDeadZone(IDirectInputDevice8* gamepad,
77 int deadzone) {
78 DIPROPDWORD prop;
79 prop.diph.dwSize = sizeof(DIPROPDWORD);
80 prop.diph.dwHeaderSize = sizeof(DIPROPHEADER);
81 prop.diph.dwObj = 0;
82 prop.diph.dwHow = DIPH_DEVICE;
83 prop.dwData = deadzone;
84 return SUCCEEDED(gamepad->SetProperty(DIPROP_DEADZONE, &prop.diph));
85 }
86
87 struct InternalDirectInputDevice {
88 IDirectInputDevice8* gamepad;
89 GamepadStandardMappingFunction mapper;
90 wchar_t id[WebGamepad::idLengthCap];
91 GUID guid;
92 };
93
94 struct EnumDevicesContext {
95 IDirectInput8* directinput_interface;
96 std::vector<InternalDirectInputDevice>* directinput_devices;
97 };
98
99 // We define our own data format structure to attempt to get as many
100 // axes as possible.
101 struct JoyData {
102 long axes[10];
103 char buttons[24];
104 DWORD pov; // Often used for D-pads.
105 };
106
107 BOOL CALLBACK DirectInputEnumDevicesCallback(const DIDEVICEINSTANCE* instance,
108 void* context) {
109 EnumDevicesContext* ctxt = (EnumDevicesContext*) context;
110 IDirectInputDevice8* gamepad;
111
112 if (FAILED(ctxt->directinput_interface->CreateDevice(instance->guidInstance,
113 &gamepad,
114 NULL)))
115 return DIENUM_CONTINUE;
116
117 gamepad->Acquire();
118
119 #define MAKE_AXIS(i) \
120 {0, FIELD_OFFSET(JoyData, axes) + 4 * i, \
121 DIDFT_AXIS | DIDFT_MAKEINSTANCE(i) | DIDFT_OPTIONAL, 0}
122 #define MAKE_BUTTON(i) \
123 {&GUID_Button, FIELD_OFFSET(JoyData, buttons) + i, \
124 DIDFT_BUTTON | DIDFT_MAKEINSTANCE(i) | DIDFT_OPTIONAL, 0}
125 #define MAKE_POV() \
126 {&GUID_POV, FIELD_OFFSET(JoyData, pov), DIDFT_POV | DIDFT_OPTIONAL, 0}
127 DIOBJECTDATAFORMAT rgodf[] = {
128 MAKE_AXIS(0),
129 MAKE_AXIS(1),
130 MAKE_AXIS(2),
131 MAKE_AXIS(3),
132 MAKE_AXIS(4),
133 MAKE_AXIS(5),
134 MAKE_AXIS(6),
135 MAKE_AXIS(7),
136 MAKE_AXIS(8),
137 MAKE_AXIS(9),
138 MAKE_BUTTON(0),
139 MAKE_BUTTON(1),
140 MAKE_BUTTON(2),
141 MAKE_BUTTON(3),
142 MAKE_BUTTON(4),
143 MAKE_BUTTON(5),
144 MAKE_BUTTON(6),
145 MAKE_BUTTON(7),
146 MAKE_BUTTON(8),
147 MAKE_BUTTON(9),
148 MAKE_BUTTON(10),
149 MAKE_BUTTON(11),
150 MAKE_BUTTON(12),
151 MAKE_BUTTON(13),
152 MAKE_BUTTON(14),
153 MAKE_BUTTON(15),
154 MAKE_BUTTON(16),
155 MAKE_POV(),
156 };
157 #undef MAKE_AXIS
158 #undef MAKE_BUTTON
159 #undef MAKE_POV
160
161 DIDATAFORMAT df = {
162 sizeof (DIDATAFORMAT),
163 sizeof (DIOBJECTDATAFORMAT),
164 DIDF_ABSAXIS,
165 sizeof (JoyData),
166 sizeof (rgodf) / sizeof (rgodf[0]),
167 rgodf
168 };
169
170 // If we can't set the data format on the device, don't add it to our
171 // list, since we won't know how to read data from it.
172 if (FAILED(gamepad->SetDataFormat(&df))) {
173 gamepad->Release();
174 return DIENUM_CONTINUE;
175 }
176
177 InternalDirectInputDevice device;
178 device.guid = instance->guidInstance;
179 device.gamepad = gamepad;
180 std::string vendor;
181 std::string product;
182 if (!GetDirectInputVendorProduct(gamepad, &vendor, &product)) {
183 gamepad->Release();
184 return DIENUM_CONTINUE;
185 }
186
187 // Set the dead zone to 10% of the axis length for all axes. This
188 // gives us a larger space for what's "neutral" so the controls don't
189 // slowly drift.
190 SetDirectInputDeadZone(gamepad, 1000);
191 device.mapper = GetGamepadStandardMappingFunction(vendor, product);
192 if (device.mapper) {
193 base::swprintf(device.id,
194 WebGamepad::idLengthCap,
195 L"STANDARD GAMEPAD (%ls)",
196 instance->tszProductName);
197 ctxt->directinput_devices->push_back(device);
198 } else {
199 gamepad->Release();
200 }
201 return DIENUM_CONTINUE;
202 }
203
51 } // namespace 204 } // namespace
52 205
53 GamepadPlatformDataFetcherWin::GamepadPlatformDataFetcherWin() 206 GamepadPlatformDataFetcherWin::GamepadPlatformDataFetcherWin()
54 : xinput_dll_(FilePath(FILE_PATH_LITERAL("xinput1_3.dll"))), 207 : xinput_dll_(FilePath(FILE_PATH_LITERAL("xinput1_3.dll"))),
55 xinput_available_(GetXinputDllFunctions()) { 208 xinput_available_(GetXInputDllFunctions()) {
209 directinput_available_ =
210 SUCCEEDED(DirectInput8Create(GetModuleHandle(NULL),
211 DIRECTINPUT_VERSION,
212 IID_IDirectInput8,
213 (void **)&directinput_interface_,
214 NULL));
215 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i)
216 pad_state_[i].status = DISCONNECTED;
56 } 217 }
57 218
58 GamepadPlatformDataFetcherWin::~GamepadPlatformDataFetcherWin() { 219 GamepadPlatformDataFetcherWin::~GamepadPlatformDataFetcherWin() {
59 } 220 }
60 221
222 int GamepadPlatformDataFetcherWin::FirstAvailableGamepadId() const {
223 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) {
224 if (pad_state_[i].status == DISCONNECTED)
225 return i;
226 }
227 return -1;
228 }
229
230 bool GamepadPlatformDataFetcherWin::HasXInputGamepad(int index) const {
231 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) {
232 if (pad_state_[i].status == XINPUT_CONNECTED &&
233 pad_state_[i].xinput_index == index)
234 return true;
235 }
236 return false;
237 }
238
239 bool GamepadPlatformDataFetcherWin::HasDirectInputGamepad(
240 const GUID &guid) const {
241 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) {
242 if (pad_state_[i].status == DIRECTINPUT_CONNECTED &&
243 pad_state_[i].guid == guid)
244 return true;
245 }
246 return false;
247 }
248
249 void GamepadPlatformDataFetcherWin::EnumerateDevices(
250 WebGamepads* pads) {
251 TRACE_EVENT0("GAMEPAD", "EnumerateDevices");
252
253 // Mark all disconnected pads DISCONNECTED.
254 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) {
255 if (!pads->items[i].connected)
256 pad_state_[i].status = DISCONNECTED;
257 }
258
259 for (size_t i = 0; i <= kMaxXInputIndex; ++i) {
scottmg 2013/02/14 23:31:59 < XUSER_MAX_COUNT (and remove constant)
teravest 2013/02/19 17:17:24 Done.
260 if (HasXInputGamepad(i))
261 continue;
262 int pad_index = FirstAvailableGamepadId();
263 if (pad_index == -1)
264 return; // We can't add any more gamepads.
265 WebGamepad &pad = pads->items[pad_index];
266 if (xinput_available_ && GetXInputPadConnectivity(i, &pad)) {
267 pad_state_[pad_index].status = XINPUT_CONNECTED;
268 pad_state_[pad_index].xinput_index = i;
269 }
270 }
271
272 if (directinput_available_) {
273 struct EnumDevicesContext context;
274 std::vector<InternalDirectInputDevice> directinput_gamepads;
275 context.directinput_interface = directinput_interface_;
276 context.directinput_devices = &directinput_gamepads;
277
278 directinput_interface_->EnumDevices(
279 DI8DEVCLASS_GAMECTRL,
280 &DirectInputEnumDevicesCallback,
281 &context,
282 DIEDFL_ATTACHEDONLY);
283 for (size_t i = 0; i < directinput_gamepads.size(); ++i) {
284 if (HasDirectInputGamepad(directinput_gamepads[i].guid))
285 continue;
286 int pad_index = FirstAvailableGamepadId();
287 if (pad_index == -1)
288 return;
289 WebGamepad &pad = pads->items[pad_index];
290 pad.connected = true;
291 wcscpy_s(pad.id, WebGamepad::idLengthCap, directinput_gamepads[i].id);
292 PadState &state = pad_state_[pad_index];
293 state.status = DIRECTINPUT_CONNECTED;
294 state.guid = directinput_gamepads[i].guid;
295 state.directinput_gamepad = directinput_gamepads[i].gamepad;
296 state.mapper = directinput_gamepads[i].mapper;
297 }
298 }
299 }
300
301
61 void GamepadPlatformDataFetcherWin::GetGamepadData(WebGamepads* pads, 302 void GamepadPlatformDataFetcherWin::GetGamepadData(WebGamepads* pads,
62 bool devices_changed_hint) { 303 bool devices_changed_hint) {
63 TRACE_EVENT0("GAMEPAD", "GetGamepadData"); 304 TRACE_EVENT0("GAMEPAD", "GetGamepadData");
64 305
65 // If there's no XInput DLL on the system, early out so that we don't 306 if (!xinput_available_ && !directinput_available_) {
66 // call any other XInput functions.
67 if (!xinput_available_) {
68 pads->length = 0; 307 pads->length = 0;
69 return; 308 return;
70 } 309 }
71 310
72 pads->length = WebGamepads::itemsLengthCap; 311 // A note on XInput devices:
73
74 // If we got notification that system devices have been updated, then 312 // If we got notification that system devices have been updated, then
75 // run GetCapabilities to update the connected status and the device 313 // run GetCapabilities to update the connected status and the device
76 // identifier. It can be slow to do to both GetCapabilities and 314 // 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 315 // 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 316 // here by only doing this when the devices are updated (despite
79 // documentation claiming it's OK to call it any time). 317 // documentation claiming it's OK to call it any time).
80 if (devices_changed_hint) { 318 if (devices_changed_hint)
81 for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i) { 319 EnumerateDevices(pads);
82 WebGamepad& pad = pads->items[i]; 320
83 TRACE_EVENT1("GAMEPAD", "GetCapabilities", "id", i); 321 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) {
84 XINPUT_CAPABILITIES caps; 322 WebGamepad& pad = pads->items[i];
85 DWORD res = xinput_get_capabilities_(i, XINPUT_FLAG_GAMEPAD, &caps); 323 if (pad_state_[i].status == XINPUT_CONNECTED)
86 if (res == ERROR_DEVICE_NOT_CONNECTED) { 324 GetXInputPadData(i, &pad);
87 pad.connected = false; 325 else if (pad_state_[i].status == DIRECTINPUT_CONNECTED)
88 } else { 326 GetDirectInputPadData(i, &pad);
89 pad.connected = true; 327 }
90 base::swprintf(pad.id, 328 pads->length = WebGamepads::itemsLengthCap;
91 WebGamepad::idLengthCap, 329 }
92 L"Xbox 360 Controller (XInput STANDARD %ls)", 330
93 GamepadSubTypeName(caps.SubType)); 331 bool GamepadPlatformDataFetcherWin::GetXInputPadConnectivity(
94 } 332 int i,
333 WebGamepad* pad) const {
334 DCHECK(pad);
335 TRACE_EVENT1("GAMEPAD", "GetXInputPadConnectivity", "id", i);
336 XINPUT_CAPABILITIES caps;
337 DWORD res = xinput_get_capabilities_(i, XINPUT_FLAG_GAMEPAD, &caps);
338 if (res == ERROR_DEVICE_NOT_CONNECTED) {
339 pad->connected = false;
340 return false;
341 } else {
342 pad->connected = true;
343 base::swprintf(pad->id,
344 WebGamepad::idLengthCap,
345 L"Xbox 360 Controller (XInput STANDARD %ls)",
346 GamepadSubTypeName(caps.SubType));
347 return true;
348 }
349 }
350
351 void GamepadPlatformDataFetcherWin::GetXInputPadData(
352 int i,
353 WebGamepad* pad) {
354 // We rely on device_changed and GetCapabilities to tell us that
355 // something's been connected, but we will mark as disconnected if
356 // GetState returns that we've lost the pad.
357 if (!pad->connected)
358 return;
359
360 XINPUT_STATE state;
361 memset(&state, 0, sizeof(XINPUT_STATE));
362 TRACE_EVENT_BEGIN1("GAMEPAD", "XInputGetState", "id", i);
363 DWORD dwResult = xinput_get_state_(pad_state_[i].xinput_index, &state);
364 TRACE_EVENT_END1("GAMEPAD", "XInputGetState", "id", i);
365
366 if (dwResult == ERROR_SUCCESS) {
367 pad->timestamp = state.dwPacketNumber;
368 pad->buttonsLength = 0;
369 #define ADD(b) pad->buttons[pad->buttonsLength++] = \
370 ((state.Gamepad.wButtons & (b)) ? 1.0 : 0.0);
371 ADD(XINPUT_GAMEPAD_A);
372 ADD(XINPUT_GAMEPAD_B);
373 ADD(XINPUT_GAMEPAD_X);
374 ADD(XINPUT_GAMEPAD_Y);
375 ADD(XINPUT_GAMEPAD_LEFT_SHOULDER);
376 ADD(XINPUT_GAMEPAD_RIGHT_SHOULDER);
377 pad->buttons[pad->buttonsLength++] = state.Gamepad.bLeftTrigger / 255.0;
378 pad->buttons[pad->buttonsLength++] = state.Gamepad.bRightTrigger / 255.0;
379 ADD(XINPUT_GAMEPAD_BACK);
380 ADD(XINPUT_GAMEPAD_START);
381 ADD(XINPUT_GAMEPAD_LEFT_THUMB);
382 ADD(XINPUT_GAMEPAD_RIGHT_THUMB);
383 ADD(XINPUT_GAMEPAD_DPAD_UP);
384 ADD(XINPUT_GAMEPAD_DPAD_DOWN);
385 ADD(XINPUT_GAMEPAD_DPAD_LEFT);
386 ADD(XINPUT_GAMEPAD_DPAD_RIGHT);
387 #undef ADD
388 pad->axesLength = 0;
389 // XInput are +up/+right, -down/-left, we want -up/-left.
390 pad->axes[pad->axesLength++] = NormalizeXInputAxis(state.Gamepad.sThumbLX);
391 pad->axes[pad->axesLength++] = -NormalizeXInputAxis(state.Gamepad.sThumbLY);
392 pad->axes[pad->axesLength++] = NormalizeXInputAxis(state.Gamepad.sThumbRX);
393 pad->axes[pad->axesLength++] = -NormalizeXInputAxis(state.Gamepad.sThumbRY);
394 } else {
395 pad->connected = false;
396 }
397 }
398
399 void GamepadPlatformDataFetcherWin::GetDirectInputPadData(
400 int index,
401 WebGamepad* pad) {
402 if (!pad->connected)
403 return;
404
405 IDirectInputDevice8* gamepad = pad_state_[index].directinput_gamepad;
406 if (FAILED(gamepad->Poll())) {
407 // Polling didn't work, try acquiring the gamepad.
408 if (FAILED(gamepad->Acquire())) {
409 pad->buttonsLength = 0;
410 pad->axesLength = 0;
411 return;
95 } 412 }
96 } 413 // Try polling again.
97 414 if (FAILED(gamepad->Poll())) {
98 // We've updated the connection state if necessary, now update the actual 415 pad->buttonsLength = 0;
99 // data for the devices that are connected. 416 pad->axesLength = 0;
100 for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i) { 417 return;
101 WebGamepad& pad = pads->items[i];
102
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;
108
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);
114
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;
145 } 418 }
146 } 419 }
147 } 420 JoyData state;
148 421 if (FAILED(gamepad->GetDeviceState(sizeof(JoyData), &state))) {
149 bool GamepadPlatformDataFetcherWin::GetXinputDllFunctions() { 422 pad->connected = false;
423 return;
424 }
425
426 WebGamepad raw;
427 raw.connected = true;
428 for (int i = 0; i < 16; i++)
429 raw.buttons[i] = (state.buttons[i] & 0x80) ? 1.0 : 0.0;
430
431 // We map the POV (often a D-pad) into the buttons 16-19.
432 // DirectInput gives pov measurements in hundredths of degrees,
433 // clockwise from "North".
434 // We use 22.5 degree slices so we can handle diagonal D-raw presses.
435 static const int arc_segment = 2250; // 22.5 degrees = 1/16 circle
436 if (state.pov > arc_segment && state.pov < 7 * arc_segment)
437 raw.buttons[19] = 1.0;
438 else
439 raw.buttons[19] = 0.0;
440
441 if (state.pov > 5 * arc_segment && state.pov < 11 * arc_segment)
442 raw.buttons[17] = 1.0;
443 else
444 raw.buttons[17] = 0.0;
445
446 if (state.pov > 9 * arc_segment && state.pov < 15 * arc_segment)
447 raw.buttons[18] = 1.0;
448 else
449 raw.buttons[18] = 0.0;
450
451 if (state.pov < 3 * arc_segment ||
452 (state.pov > 13 * arc_segment && state.pov < 36000))
453 raw.buttons[16] = 1.0;
454 else
455 raw.buttons[16] = 0.0;
456
457 for (int i = 0; i < 10; i++)
458 raw.axes[i] = state.axes[i];
459 pad_state_[index].mapper(raw, pad);
460 }
461
462 bool GamepadPlatformDataFetcherWin::GetXInputDllFunctions() {
150 xinput_get_capabilities_ = NULL; 463 xinput_get_capabilities_ = NULL;
151 xinput_get_state_ = NULL; 464 xinput_get_state_ = NULL;
152 xinput_enable_ = static_cast<XInputEnableFunc>( 465 xinput_enable_ = static_cast<XInputEnableFunc>(
153 xinput_dll_.GetFunctionPointer("XInputEnable")); 466 xinput_dll_.GetFunctionPointer("XInputEnable"));
154 if (!xinput_enable_) 467 if (!xinput_enable_)
155 return false; 468 return false;
156 xinput_get_capabilities_ = static_cast<XInputGetCapabilitiesFunc>( 469 xinput_get_capabilities_ = static_cast<XInputGetCapabilitiesFunc>(
157 xinput_dll_.GetFunctionPointer("XInputGetCapabilities")); 470 xinput_dll_.GetFunctionPointer("XInputGetCapabilities"));
158 if (!xinput_get_capabilities_) 471 if (!xinput_get_capabilities_)
159 return false; 472 return false;
160 xinput_get_state_ = static_cast<XInputGetStateFunc>( 473 xinput_get_state_ = static_cast<XInputGetStateFunc>(
161 xinput_dll_.GetFunctionPointer("XInputGetState")); 474 xinput_dll_.GetFunctionPointer("XInputGetState"));
162 if (!xinput_get_state_) 475 if (!xinput_get_state_)
163 return false; 476 return false;
164 xinput_enable_(true); 477 xinput_enable_(true);
165 return true; 478 return true;
166 } 479 }
167 480
168 } // namespace content 481 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/gamepad/gamepad_platform_data_fetcher_win.h ('k') | content/browser/gamepad/gamepad_standard_mappings_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698