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

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

Issue 1586663006: Refactoring gamepad polling to support dynamically added sources (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Avoid crash on Android content_unittests Created 4 years, 11 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 <stddef.h> 7 #include <stddef.h>
8 #include <string.h> 8 #include <string.h>
9 9
10 #include "base/strings/stringprintf.h" 10 #include "base/strings/stringprintf.h"
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 case kDeviceSubTypeDrumKit: return L"DRUM_KIT"; 49 case kDeviceSubTypeDrumKit: return L"DRUM_KIT";
50 case kDeviceSubTypeGuitarBass: return L"GUITAR_BASS"; 50 case kDeviceSubTypeGuitarBass: return L"GUITAR_BASS";
51 case kDeviceSubTypeArcadePad: return L"ARCADE_PAD"; 51 case kDeviceSubTypeArcadePad: return L"ARCADE_PAD";
52 default: return L"<UNKNOWN>"; 52 default: return L"<UNKNOWN>";
53 } 53 }
54 } 54 }
55 55
56 } // namespace 56 } // namespace
57 57
58 GamepadPlatformDataFetcherWin::GamepadPlatformDataFetcherWin() 58 GamepadPlatformDataFetcherWin::GamepadPlatformDataFetcherWin()
59 : xinput_dll_(base::FilePath(FILE_PATH_LITERAL("xinput1_3.dll"))), 59 : xinput_available_(false) {
60 xinput_available_(GetXInputDllFunctions()) { 60 for (size_t i = 0; i < XUSER_MAX_COUNT; ++i)
61 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { 61 xinput_connected_[i] = false;
62 platform_pad_state_[i].status = DISCONNECTED;
63 pad_state_[i].mapper = NULL;
64 pad_state_[i].axis_mask = 0;
65 pad_state_[i].button_mask = 0;
66 }
67
68 raw_input_fetcher_.reset(new RawInputDataFetcher());
69 raw_input_fetcher_->StartMonitor();
70 } 62 }
71 63
72 GamepadPlatformDataFetcherWin::~GamepadPlatformDataFetcherWin() { 64 GamepadPlatformDataFetcherWin::~GamepadPlatformDataFetcherWin() {
73 raw_input_fetcher_->StopMonitor();
74 } 65 }
75 66
76 int GamepadPlatformDataFetcherWin::FirstAvailableGamepadId() const { 67 void GamepadPlatformDataFetcherWin::OnAddedToProvider() {
77 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { 68 xinput_dll_.Reset(base::LoadNativeLibrary(
78 if (platform_pad_state_[i].status == DISCONNECTED) 69 base::FilePath(FILE_PATH_LITERAL("xinput1_3.dll")), nullptr));
79 return i; 70 xinput_available_ = GetXInputDllFunctions();
80 }
81 return -1;
82 }
83
84 bool GamepadPlatformDataFetcherWin::HasXInputGamepad(int index) const {
85 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) {
86 if (platform_pad_state_[i].status == XINPUT_CONNECTED &&
87 platform_pad_state_[i].xinput_index == index)
88 return true;
89 }
90 return false;
91 }
92
93 bool GamepadPlatformDataFetcherWin::HasRawInputGamepad(
94 const HANDLE handle) const {
95 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) {
96 if (platform_pad_state_[i].status == RAWINPUT_CONNECTED &&
97 platform_pad_state_[i].raw_input_handle == handle)
98 return true;
99 }
100 return false;
101 } 71 }
102 72
103 void GamepadPlatformDataFetcherWin::EnumerateDevices() { 73 void GamepadPlatformDataFetcherWin::EnumerateDevices() {
104 TRACE_EVENT0("GAMEPAD", "EnumerateDevices"); 74 TRACE_EVENT0("GAMEPAD", "EnumerateDevices");
105 75
106 // Mark all disconnected pads DISCONNECTED. 76 if (xinput_available_) {
107 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { 77 for (size_t i = 0; i < XUSER_MAX_COUNT; ++i) {
108 if (!pad_state_[i].data.connected) 78 // Check to see if the xinput device is connected
109 platform_pad_state_[i].status = DISCONNECTED; 79 XINPUT_CAPABILITIES caps;
110 } 80 DWORD res = xinput_get_capabilities_(i, XINPUT_FLAG_GAMEPAD, &caps);
81 xinput_connected_[i] = (res == ERROR_SUCCESS);
82 if (!xinput_connected_[i])
83 continue;
111 84
112 for (size_t i = 0; i < XUSER_MAX_COUNT; ++i) { 85 PadState* state = provider()->GetPadState(GAMEPAD_SOURCE_WIN_XINPUT, i);
113 if (HasXInputGamepad(i)) 86 if (!state)
114 continue; 87 continue; // No slot available for this gamepad.
115 int pad_index = FirstAvailableGamepadId();
116 if (pad_index == -1)
117 return; // We can't add any more gamepads.
118 WebGamepad& pad = pad_state_[pad_index].data;
119 if (xinput_available_ && GetXInputPadConnectivity(i, &pad)) {
120 platform_pad_state_[pad_index].status = XINPUT_CONNECTED;
121 platform_pad_state_[pad_index].xinput_index = i;
122 pad_state_[pad_index].mapper = NULL;
123 pad_state_[pad_index].axis_mask = 0;
124 pad_state_[pad_index].button_mask = 0;
125 }
126 }
127 88
128 if (raw_input_fetcher_->Available()) { 89 WebGamepad& pad = state->data;
129 std::vector<RawGamepadInfo*> raw_inputs =
130 raw_input_fetcher_->EnumerateDevices();
131 for (size_t i = 0; i < raw_inputs.size(); ++i) {
132 RawGamepadInfo* gamepad = raw_inputs[i];
133 if (gamepad->buttons_length == 0 && gamepad->axes_length == 0)
134 continue;
135 if (HasRawInputGamepad(gamepad->handle))
136 continue;
137 int pad_index = FirstAvailableGamepadId();
138 if (pad_index == -1)
139 return;
140 WebGamepad& pad = pad_state_[pad_index].data;
141 pad.connected = true;
142 PadState& state = pad_state_[pad_index];
143 PlatformPadState& platform_state = platform_pad_state_[pad_index];
144 platform_state.status = RAWINPUT_CONNECTED;
145 platform_state.raw_input_handle = gamepad->handle;
146 90
147 std::string vendor = base::StringPrintf("%04x", gamepad->vendor_id); 91 if (state->active_state == GAMEPAD_NEWLY_ACTIVE) {
148 std::string product = base::StringPrintf("%04x", gamepad->product_id); 92 // This is the first time we've seen this device, so do some one-time
149 state.mapper = GetGamepadStandardMappingFunction(vendor, product); 93 // initialization
150 state.axis_mask = 0; 94 pad.connected = true;
151 state.button_mask = 0; 95 swprintf(pad.id,
152 96 WebGamepad::idLengthCap,
153 swprintf(pad.id, WebGamepad::idLengthCap, 97 L"Xbox 360 Controller (XInput STANDARD %ls)",
154 L"%ls (%lsVendor: %04x Product: %04x)", 98 GamepadSubTypeName(caps.SubType));
155 gamepad->id, state.mapper ? L"STANDARD GAMEPAD " : L"",
156 gamepad->vendor_id, gamepad->product_id);
157
158 if (state.mapper)
159 swprintf(pad.mapping, WebGamepad::mappingLengthCap, L"standard"); 99 swprintf(pad.mapping, WebGamepad::mappingLengthCap, L"standard");
160 else 100 }
161 pad.mapping[0] = 0;
162 } 101 }
163 } 102 }
164 } 103 }
165 104
166 void GamepadPlatformDataFetcherWin::GetGamepadData(WebGamepads* pads, 105 void GamepadPlatformDataFetcherWin::GetGamepadData(bool devices_changed_hint) {
167 bool devices_changed_hint) {
168 TRACE_EVENT0("GAMEPAD", "GetGamepadData"); 106 TRACE_EVENT0("GAMEPAD", "GetGamepadData");
169 107
170 if (!xinput_available_ && 108 if (!xinput_available_)
171 !raw_input_fetcher_->Available()) {
172 pads->length = 0;
173 return; 109 return;
174 }
175 110
176 // A note on XInput devices: 111 // A note on XInput devices:
177 // If we got notification that system devices have been updated, then 112 // If we got notification that system devices have been updated, then
178 // run GetCapabilities to update the connected status and the device 113 // run GetCapabilities to update the connected status and the device
179 // identifier. It can be slow to do to both GetCapabilities and 114 // identifier. It can be slow to do to both GetCapabilities and
180 // GetState on unconnected devices, so we want to avoid a 2-5ms pause 115 // GetState on unconnected devices, so we want to avoid a 2-5ms pause
181 // here by only doing this when the devices are updated (despite 116 // here by only doing this when the devices are updated (despite
182 // documentation claiming it's OK to call it any time). 117 // documentation claiming it's OK to call it any time).
183 if (devices_changed_hint) 118 if (devices_changed_hint)
184 EnumerateDevices(); 119 EnumerateDevices();
185 120
186 pads->length = 0; 121 for (size_t i = 0; i < XUSER_MAX_COUNT; ++i) {
187 122 if (xinput_connected_[i])
188 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { 123 GetXInputPadData(i);
189 // We rely on device_changed and GetCapabilities to tell us that
190 // something's been connected, but we will mark as disconnected if
191 // Get___PadState returns that we've lost the pad.
192 if (!pad_state_[i].data.connected)
193 continue;
194
195 if (platform_pad_state_[i].status == XINPUT_CONNECTED)
196 GetXInputPadData(i, &pad_state_[i].data);
197 else if (platform_pad_state_[i].status == RAWINPUT_CONNECTED)
198 GetRawInputPadData(i, &pad_state_[i].data);
199
200 MapAndSanitizeGamepadData(&pad_state_[i], &pads->items[i]);
201
202 if (pads->items[i].connected)
203 pads->length++;
204 } 124 }
205 } 125 }
206 126
207 void GamepadPlatformDataFetcherWin::PauseHint(bool pause) { 127 void GamepadPlatformDataFetcherWin::GetXInputPadData(int i) {
208 if (pause) 128 PadState* pad_state = provider()->GetPadState(GAMEPAD_SOURCE_WIN_XINPUT, i);
209 raw_input_fetcher_->StopMonitor(); 129 if (!pad_state)
210 else 130 return;
211 raw_input_fetcher_->StartMonitor();
212 }
213 131
214 bool GamepadPlatformDataFetcherWin::GetXInputPadConnectivity( 132 WebGamepad& pad = pad_state->data;
215 int i,
216 WebGamepad* pad) const {
217 DCHECK(pad);
218 TRACE_EVENT1("GAMEPAD", "GetXInputPadConnectivity", "id", i);
219 XINPUT_CAPABILITIES caps;
220 DWORD res = xinput_get_capabilities_(i, XINPUT_FLAG_GAMEPAD, &caps);
221 if (res == ERROR_DEVICE_NOT_CONNECTED) {
222 pad->connected = false;
223 return false;
224 } else {
225 pad->connected = true;
226 swprintf(pad->id,
227 WebGamepad::idLengthCap,
228 L"Xbox 360 Controller (XInput STANDARD %ls)",
229 GamepadSubTypeName(caps.SubType));
230 swprintf(pad->mapping, WebGamepad::mappingLengthCap, L"standard");
231 return true;
232 }
233 }
234 133
235 void GamepadPlatformDataFetcherWin::GetXInputPadData(
236 int i,
237 WebGamepad* pad) {
238 XINPUT_STATE state; 134 XINPUT_STATE state;
239 memset(&state, 0, sizeof(XINPUT_STATE)); 135 memset(&state, 0, sizeof(XINPUT_STATE));
240 TRACE_EVENT_BEGIN1("GAMEPAD", "XInputGetState", "id", i); 136 TRACE_EVENT_BEGIN1("GAMEPAD", "XInputGetState", "id", i);
241 DWORD dwResult = xinput_get_state_(platform_pad_state_[i].xinput_index, 137 DWORD dwResult = xinput_get_state_(i, &state);
242 &state);
243 TRACE_EVENT_END1("GAMEPAD", "XInputGetState", "id", i); 138 TRACE_EVENT_END1("GAMEPAD", "XInputGetState", "id", i);
244 139
245 if (dwResult == ERROR_SUCCESS) { 140 if (dwResult == ERROR_SUCCESS) {
246 pad->timestamp = state.dwPacketNumber; 141 pad.timestamp = state.dwPacketNumber;
247 pad->buttonsLength = 0; 142 pad.buttonsLength = 0;
248 WORD val = state.Gamepad.wButtons; 143 WORD val = state.Gamepad.wButtons;
249 #define ADD(b) pad->buttons[pad->buttonsLength].pressed = (val & (b)) != 0; \ 144 #define ADD(b) pad.buttons[pad.buttonsLength].pressed = (val & (b)) != 0; \
250 pad->buttons[pad->buttonsLength++].value = ((val & (b)) ? 1.f : 0.f); 145 pad.buttons[pad.buttonsLength++].value = ((val & (b)) ? 1.f : 0.f);
251 ADD(XINPUT_GAMEPAD_A); 146 ADD(XINPUT_GAMEPAD_A);
252 ADD(XINPUT_GAMEPAD_B); 147 ADD(XINPUT_GAMEPAD_B);
253 ADD(XINPUT_GAMEPAD_X); 148 ADD(XINPUT_GAMEPAD_X);
254 ADD(XINPUT_GAMEPAD_Y); 149 ADD(XINPUT_GAMEPAD_Y);
255 ADD(XINPUT_GAMEPAD_LEFT_SHOULDER); 150 ADD(XINPUT_GAMEPAD_LEFT_SHOULDER);
256 ADD(XINPUT_GAMEPAD_RIGHT_SHOULDER); 151 ADD(XINPUT_GAMEPAD_RIGHT_SHOULDER);
257 152
258 pad->buttons[pad->buttonsLength].pressed = 153 pad.buttons[pad.buttonsLength].pressed =
259 state.Gamepad.bLeftTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD; 154 state.Gamepad.bLeftTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD;
260 pad->buttons[pad->buttonsLength++].value = 155 pad.buttons[pad.buttonsLength++].value =
261 state.Gamepad.bLeftTrigger / 255.f; 156 state.Gamepad.bLeftTrigger / 255.f;
262 157
263 pad->buttons[pad->buttonsLength].pressed = 158 pad.buttons[pad.buttonsLength].pressed =
264 state.Gamepad.bRightTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD; 159 state.Gamepad.bRightTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD;
265 pad->buttons[pad->buttonsLength++].value = 160 pad.buttons[pad.buttonsLength++].value =
266 state.Gamepad.bRightTrigger / 255.f; 161 state.Gamepad.bRightTrigger / 255.f;
267 162
268 ADD(XINPUT_GAMEPAD_BACK); 163 ADD(XINPUT_GAMEPAD_BACK);
269 ADD(XINPUT_GAMEPAD_START); 164 ADD(XINPUT_GAMEPAD_START);
270 ADD(XINPUT_GAMEPAD_LEFT_THUMB); 165 ADD(XINPUT_GAMEPAD_LEFT_THUMB);
271 ADD(XINPUT_GAMEPAD_RIGHT_THUMB); 166 ADD(XINPUT_GAMEPAD_RIGHT_THUMB);
272 ADD(XINPUT_GAMEPAD_DPAD_UP); 167 ADD(XINPUT_GAMEPAD_DPAD_UP);
273 ADD(XINPUT_GAMEPAD_DPAD_DOWN); 168 ADD(XINPUT_GAMEPAD_DPAD_DOWN);
274 ADD(XINPUT_GAMEPAD_DPAD_LEFT); 169 ADD(XINPUT_GAMEPAD_DPAD_LEFT);
275 ADD(XINPUT_GAMEPAD_DPAD_RIGHT); 170 ADD(XINPUT_GAMEPAD_DPAD_RIGHT);
276 #undef ADD 171 #undef ADD
277 pad->axesLength = 0; 172 pad.axesLength = 0;
278 173
279 float value = 0.0; 174 float value = 0.0;
280 #define ADD(a, factor) value = factor * NormalizeXInputAxis(a); \ 175 #define ADD(a, factor) value = factor * NormalizeXInputAxis(a); \
281 pad->axes[pad->axesLength++] = value; 176 pad.axes[pad.axesLength++] = value;
282 177
283 // XInput are +up/+right, -down/-left, we want -up/-left. 178 // XInput are +up/+right, -down/-left, we want -up/-left.
284 ADD(state.Gamepad.sThumbLX, 1); 179 ADD(state.Gamepad.sThumbLX, 1);
285 ADD(state.Gamepad.sThumbLY, -1); 180 ADD(state.Gamepad.sThumbLY, -1);
286 ADD(state.Gamepad.sThumbRX, 1); 181 ADD(state.Gamepad.sThumbRX, 1);
287 ADD(state.Gamepad.sThumbRY, -1); 182 ADD(state.Gamepad.sThumbRY, -1);
288 #undef ADD 183 #undef ADD
289 } else {
290 pad->connected = false;
291 } 184 }
292 } 185 }
293 186
294 void GamepadPlatformDataFetcherWin::GetRawInputPadData(
295 int index,
296 WebGamepad* pad) {
297 RawGamepadInfo* gamepad = raw_input_fetcher_->GetGamepadInfo(
298 platform_pad_state_[index].raw_input_handle);
299 if (!gamepad) {
300 pad->connected = false;
301 return;
302 }
303
304 pad->timestamp = gamepad->report_id;
305 pad->buttonsLength = gamepad->buttons_length;
306 pad->axesLength = gamepad->axes_length;
307
308 for (unsigned int i = 0; i < pad->buttonsLength; i++) {
309 pad->buttons[i].pressed = gamepad->buttons[i];
310 pad->buttons[i].value = gamepad->buttons[i] ? 1.0 : 0.0;
311 }
312
313 for (unsigned int i = 0; i < pad->axesLength; i++)
314 pad->axes[i] = gamepad->axes[i].value;
315 }
316
317 bool GamepadPlatformDataFetcherWin::GetXInputDllFunctions() { 187 bool GamepadPlatformDataFetcherWin::GetXInputDllFunctions() {
318 xinput_get_capabilities_ = NULL; 188 xinput_get_capabilities_ = NULL;
319 xinput_get_state_ = NULL; 189 xinput_get_state_ = NULL;
320 xinput_enable_ = reinterpret_cast<XInputEnableFunc>( 190 xinput_enable_ = reinterpret_cast<XInputEnableFunc>(
321 xinput_dll_.GetFunctionPointer("XInputEnable")); 191 xinput_dll_.GetFunctionPointer("XInputEnable"));
322 if (!xinput_enable_) 192 if (!xinput_enable_)
323 return false; 193 return false;
324 xinput_get_capabilities_ = reinterpret_cast<XInputGetCapabilitiesFunc>( 194 xinput_get_capabilities_ = reinterpret_cast<XInputGetCapabilitiesFunc>(
325 xinput_dll_.GetFunctionPointer("XInputGetCapabilities")); 195 xinput_dll_.GetFunctionPointer("XInputGetCapabilities"));
326 if (!xinput_get_capabilities_) 196 if (!xinput_get_capabilities_)
327 return false; 197 return false;
328 xinput_get_state_ = reinterpret_cast<XInputGetStateFunc>( 198 xinput_get_state_ = reinterpret_cast<XInputGetStateFunc>(
329 xinput_dll_.GetFunctionPointer("XInputGetState")); 199 xinput_dll_.GetFunctionPointer("XInputGetState"));
330 if (!xinput_get_state_) 200 if (!xinput_get_state_)
331 return false; 201 return false;
332 xinput_enable_(true); 202 xinput_enable_(true);
333 return true; 203 return true;
334 } 204 }
335 205
336 } // namespace content 206 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/gamepad/gamepad_platform_data_fetcher_win.h ('k') | content/browser/gamepad/gamepad_provider.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698