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

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