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

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

Powered by Google App Engine
This is Rietveld 408576698