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

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: 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) {
scottmg 2016/01/18 22:54:51 Initialize xinput_connected_ array here.
60 xinput_available_(GetXInputDllFunctions()) {
61 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) {
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 } 60 }
71 61
72 GamepadPlatformDataFetcherWin::~GamepadPlatformDataFetcherWin() { 62 GamepadPlatformDataFetcherWin::~GamepadPlatformDataFetcherWin() {
73 raw_input_fetcher_->StopMonitor();
74 } 63 }
75 64
76 int GamepadPlatformDataFetcherWin::FirstAvailableGamepadId() const { 65 void GamepadPlatformDataFetcherWin::OnAddedToProvider() {
77 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { 66 xinput_dll_.Reset(base::LoadNativeLibrary(
78 if (platform_pad_state_[i].status == DISCONNECTED) 67 base::FilePath(FILE_PATH_LITERAL("xinput1_3.dll")), nullptr));
79 return i; 68 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 } 69 }
102 70
103 void GamepadPlatformDataFetcherWin::EnumerateDevices() { 71 void GamepadPlatformDataFetcherWin::EnumerateDevices() {
104 TRACE_EVENT0("GAMEPAD", "EnumerateDevices"); 72 TRACE_EVENT0("GAMEPAD", "EnumerateDevices");
105 73
106 // Mark all disconnected pads DISCONNECTED. 74 if (xinput_available_) {
107 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { 75 for (size_t i = 0; i < XUSER_MAX_COUNT; ++i) {
108 if (!pad_state_[i].data.connected) 76 // Check to see if the xinput device is connected
109 platform_pad_state_[i].status = DISCONNECTED; 77 XINPUT_CAPABILITIES caps;
110 } 78 DWORD res = xinput_get_capabilities_(i, XINPUT_FLAG_GAMEPAD, &caps);
79 xinuput_connected_[i] = (res == ERROR_SUCCESS);
80 if (!xinuput_connected_[i])
81 continue;
111 82
112 for (size_t i = 0; i < XUSER_MAX_COUNT; ++i) { 83 PadState* state = provider()->GetPadState(GAMEPAD_SOURCE_WIN_XINPUT, i);
113 if (HasXInputGamepad(i)) 84 if (!state)
114 continue; 85 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 86
128 if (raw_input_fetcher_->Available()) { 87 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 88
147 std::string vendor = base::StringPrintf("%04x", gamepad->vendor_id); 89 if (state->active_state == GAMEPAD_NEWLY_ACTIVE) {
148 std::string product = base::StringPrintf("%04x", gamepad->product_id); 90 // This is the first time we've seen this device, so do some one-time
149 state.mapper = GetGamepadStandardMappingFunction(vendor, product); 91 // initialization
150 state.axis_mask = 0; 92 pad.connected = true;
151 state.button_mask = 0; 93 swprintf(pad.id,
152 94 WebGamepad::idLengthCap,
153 swprintf(pad.id, WebGamepad::idLengthCap, 95 L"Xbox 360 Controller (XInput STANDARD %ls)",
154 L"%ls (%lsVendor: %04x Product: %04x)", 96 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"); 97 swprintf(pad.mapping, WebGamepad::mappingLengthCap, L"standard");
160 else 98 }
161 pad.mapping[0] = 0;
162 } 99 }
163 } 100 }
164 } 101 }
165 102
166 void GamepadPlatformDataFetcherWin::GetGamepadData(WebGamepads* pads, 103 void GamepadPlatformDataFetcherWin::GetGamepadData(bool devices_changed_hint) {
167 bool devices_changed_hint) {
168 TRACE_EVENT0("GAMEPAD", "GetGamepadData"); 104 TRACE_EVENT0("GAMEPAD", "GetGamepadData");
169 105
170 if (!xinput_available_ && 106 if (!xinput_available_)
171 !raw_input_fetcher_->Available()) {
172 pads->length = 0;
173 return; 107 return;
174 }
175 108
176 // A note on XInput devices: 109 // A note on XInput devices:
177 // If we got notification that system devices have been updated, then 110 // If we got notification that system devices have been updated, then
178 // run GetCapabilities to update the connected status and the device 111 // run GetCapabilities to update the connected status and the device
179 // identifier. It can be slow to do to both GetCapabilities and 112 // 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 113 // 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 114 // here by only doing this when the devices are updated (despite
182 // documentation claiming it's OK to call it any time). 115 // documentation claiming it's OK to call it any time).
183 if (devices_changed_hint) 116 if (devices_changed_hint)
184 EnumerateDevices(); 117 EnumerateDevices();
185 118
186 pads->length = 0; 119 for (size_t i = 0; i < XUSER_MAX_COUNT; ++i) {
187 120 if (xinuput_connected_[i])
188 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { 121 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 } 122 }
205 } 123 }
206 124
207 void GamepadPlatformDataFetcherWin::PauseHint(bool pause) { 125 void GamepadPlatformDataFetcherWin::GetXInputPadData(int i) {
208 if (pause)
209 raw_input_fetcher_->StopMonitor();
210 else
211 raw_input_fetcher_->StartMonitor();
212 }
213 126
scottmg 2016/01/18 22:54:51 Extra blank line.
214 bool GamepadPlatformDataFetcherWin::GetXInputPadConnectivity( 127 PadState* pad_state = provider()->GetPadState(GAMEPAD_SOURCE_WIN_XINPUT, i);
215 int i, 128 if (!pad_state)
216 WebGamepad* pad) const { 129 return;
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 130
235 void GamepadPlatformDataFetcherWin::GetXInputPadData( 131 WebGamepad& pad = pad_state->data;
236 int i, 132
237 WebGamepad* pad) {
238 XINPUT_STATE state; 133 XINPUT_STATE state;
239 memset(&state, 0, sizeof(XINPUT_STATE)); 134 memset(&state, 0, sizeof(XINPUT_STATE));
240 TRACE_EVENT_BEGIN1("GAMEPAD", "XInputGetState", "id", i); 135 TRACE_EVENT_BEGIN1("GAMEPAD", "XInputGetState", "id", i);
241 DWORD dwResult = xinput_get_state_(platform_pad_state_[i].xinput_index, 136 DWORD dwResult = xinput_get_state_(i, &state);
242 &state);
243 TRACE_EVENT_END1("GAMEPAD", "XInputGetState", "id", i); 137 TRACE_EVENT_END1("GAMEPAD", "XInputGetState", "id", i);
244 138
245 if (dwResult == ERROR_SUCCESS) { 139 if (dwResult == ERROR_SUCCESS) {
246 pad->timestamp = state.dwPacketNumber; 140 pad.timestamp = state.dwPacketNumber;
247 pad->buttonsLength = 0; 141 pad.buttonsLength = 0;
248 WORD val = state.Gamepad.wButtons; 142 WORD val = state.Gamepad.wButtons;
249 #define ADD(b) pad->buttons[pad->buttonsLength].pressed = (val & (b)) != 0; \ 143 #define ADD(b) pad.buttons[pad.buttonsLength].pressed = (val & (b)) != 0; \
250 pad->buttons[pad->buttonsLength++].value = ((val & (b)) ? 1.f : 0.f); 144 pad.buttons[pad.buttonsLength++].value = ((val & (b)) ? 1.f : 0.f);
251 ADD(XINPUT_GAMEPAD_A); 145 ADD(XINPUT_GAMEPAD_A);
252 ADD(XINPUT_GAMEPAD_B); 146 ADD(XINPUT_GAMEPAD_B);
253 ADD(XINPUT_GAMEPAD_X); 147 ADD(XINPUT_GAMEPAD_X);
254 ADD(XINPUT_GAMEPAD_Y); 148 ADD(XINPUT_GAMEPAD_Y);
255 ADD(XINPUT_GAMEPAD_LEFT_SHOULDER); 149 ADD(XINPUT_GAMEPAD_LEFT_SHOULDER);
256 ADD(XINPUT_GAMEPAD_RIGHT_SHOULDER); 150 ADD(XINPUT_GAMEPAD_RIGHT_SHOULDER);
257 151
258 pad->buttons[pad->buttonsLength].pressed = 152 pad.buttons[pad.buttonsLength].pressed =
259 state.Gamepad.bLeftTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD; 153 state.Gamepad.bLeftTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD;
260 pad->buttons[pad->buttonsLength++].value = 154 pad.buttons[pad.buttonsLength++].value =
261 state.Gamepad.bLeftTrigger / 255.f; 155 state.Gamepad.bLeftTrigger / 255.f;
262 156
263 pad->buttons[pad->buttonsLength].pressed = 157 pad.buttons[pad.buttonsLength].pressed =
264 state.Gamepad.bRightTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD; 158 state.Gamepad.bRightTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD;
265 pad->buttons[pad->buttonsLength++].value = 159 pad.buttons[pad.buttonsLength++].value =
266 state.Gamepad.bRightTrigger / 255.f; 160 state.Gamepad.bRightTrigger / 255.f;
267 161
268 ADD(XINPUT_GAMEPAD_BACK); 162 ADD(XINPUT_GAMEPAD_BACK);
269 ADD(XINPUT_GAMEPAD_START); 163 ADD(XINPUT_GAMEPAD_START);
270 ADD(XINPUT_GAMEPAD_LEFT_THUMB); 164 ADD(XINPUT_GAMEPAD_LEFT_THUMB);
271 ADD(XINPUT_GAMEPAD_RIGHT_THUMB); 165 ADD(XINPUT_GAMEPAD_RIGHT_THUMB);
272 ADD(XINPUT_GAMEPAD_DPAD_UP); 166 ADD(XINPUT_GAMEPAD_DPAD_UP);
273 ADD(XINPUT_GAMEPAD_DPAD_DOWN); 167 ADD(XINPUT_GAMEPAD_DPAD_DOWN);
274 ADD(XINPUT_GAMEPAD_DPAD_LEFT); 168 ADD(XINPUT_GAMEPAD_DPAD_LEFT);
275 ADD(XINPUT_GAMEPAD_DPAD_RIGHT); 169 ADD(XINPUT_GAMEPAD_DPAD_RIGHT);
276 #undef ADD 170 #undef ADD
277 pad->axesLength = 0; 171 pad.axesLength = 0;
278 172
279 float value = 0.0; 173 float value = 0.0;
280 #define ADD(a, factor) value = factor * NormalizeXInputAxis(a); \ 174 #define ADD(a, factor) value = factor * NormalizeXInputAxis(a); \
281 pad->axes[pad->axesLength++] = value; 175 pad.axes[pad.axesLength++] = value;
282 176
283 // XInput are +up/+right, -down/-left, we want -up/-left. 177 // XInput are +up/+right, -down/-left, we want -up/-left.
284 ADD(state.Gamepad.sThumbLX, 1); 178 ADD(state.Gamepad.sThumbLX, 1);
285 ADD(state.Gamepad.sThumbLY, -1); 179 ADD(state.Gamepad.sThumbLY, -1);
286 ADD(state.Gamepad.sThumbRX, 1); 180 ADD(state.Gamepad.sThumbRX, 1);
287 ADD(state.Gamepad.sThumbRY, -1); 181 ADD(state.Gamepad.sThumbRY, -1);
288 #undef ADD 182 #undef ADD
289 } else {
290 pad->connected = false;
291 } 183 }
292 } 184 }
293 185
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() { 186 bool GamepadPlatformDataFetcherWin::GetXInputDllFunctions() {
318 xinput_get_capabilities_ = NULL; 187 xinput_get_capabilities_ = NULL;
319 xinput_get_state_ = NULL; 188 xinput_get_state_ = NULL;
320 xinput_enable_ = reinterpret_cast<XInputEnableFunc>( 189 xinput_enable_ = reinterpret_cast<XInputEnableFunc>(
321 xinput_dll_.GetFunctionPointer("XInputEnable")); 190 xinput_dll_.GetFunctionPointer("XInputEnable"));
322 if (!xinput_enable_) 191 if (!xinput_enable_)
323 return false; 192 return false;
324 xinput_get_capabilities_ = reinterpret_cast<XInputGetCapabilitiesFunc>( 193 xinput_get_capabilities_ = reinterpret_cast<XInputGetCapabilitiesFunc>(
325 xinput_dll_.GetFunctionPointer("XInputGetCapabilities")); 194 xinput_dll_.GetFunctionPointer("XInputGetCapabilities"));
326 if (!xinput_get_capabilities_) 195 if (!xinput_get_capabilities_)
327 return false; 196 return false;
328 xinput_get_state_ = reinterpret_cast<XInputGetStateFunc>( 197 xinput_get_state_ = reinterpret_cast<XInputGetStateFunc>(
329 xinput_dll_.GetFunctionPointer("XInputGetState")); 198 xinput_dll_.GetFunctionPointer("XInputGetState"));
330 if (!xinput_get_state_) 199 if (!xinput_get_state_)
331 return false; 200 return false;
332 xinput_enable_(true); 201 xinput_enable_(true);
333 return true; 202 return true;
334 } 203 }
335 204
336 } // namespace content 205 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698