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

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

Issue 1627643002: Revert of 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_provider.h" 5 #include "content/browser/gamepad/gamepad_provider.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <string.h> 8 #include <string.h>
9 #include <cmath> 9 #include <cmath>
10 #include <set>
10 #include <utility> 11 #include <utility>
11 #include <vector> 12 #include <vector>
12 13
13 #include "base/bind.h" 14 #include "base/bind.h"
14 #include "base/location.h" 15 #include "base/location.h"
15 #include "base/logging.h" 16 #include "base/logging.h"
16 #include "base/single_thread_task_runner.h" 17 #include "base/single_thread_task_runner.h"
17 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" 18 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
18 #include "base/thread_task_runner_handle.h" 19 #include "base/thread_task_runner_handle.h"
19 #include "base/threading/thread.h" 20 #include "base/threading/thread.h"
20 #include "base/threading/thread_restrictions.h" 21 #include "base/threading/thread_restrictions.h"
21 #include "build/build_config.h" 22 #include "build/build_config.h"
22 #include "content/browser/gamepad/gamepad_data_fetcher.h" 23 #include "content/browser/gamepad/gamepad_data_fetcher.h"
23 #include "content/browser/gamepad/gamepad_platform_data_fetcher.h" 24 #include "content/browser/gamepad/gamepad_platform_data_fetcher.h"
24 #include "content/browser/gamepad/gamepad_service.h" 25 #include "content/browser/gamepad/gamepad_service.h"
25 #include "content/common/gamepad_hardware_buffer.h" 26 #include "content/common/gamepad_hardware_buffer.h"
26 #include "content/common/gamepad_messages.h" 27 #include "content/common/gamepad_messages.h"
27 #include "content/common/gamepad_user_gesture.h" 28 #include "content/common/gamepad_user_gesture.h"
28 #include "content/public/browser/browser_thread.h" 29 #include "content/public/browser/browser_thread.h"
29 30
30 using blink::WebGamepad; 31 using blink::WebGamepad;
31 using blink::WebGamepads; 32 using blink::WebGamepads;
32 33
33 namespace {
34
35 const float kMinAxisResetValue = 0.1f;
36
37 } // namespace
38
39 namespace content { 34 namespace content {
40 35
41 GamepadProvider::ClosureAndThread::ClosureAndThread( 36 GamepadProvider::ClosureAndThread::ClosureAndThread(
42 const base::Closure& c, 37 const base::Closure& c,
43 const scoped_refptr<base::SingleThreadTaskRunner>& m) 38 const scoped_refptr<base::SingleThreadTaskRunner>& m)
44 : closure(c), task_runner(m) { 39 : closure(c), task_runner(m) {
45 } 40 }
46 41
47 GamepadProvider::ClosureAndThread::~ClosureAndThread() { 42 GamepadProvider::ClosureAndThread::~ClosureAndThread() {
48 } 43 }
49 44
50 GamepadProvider::GamepadProvider() 45 GamepadProvider::GamepadProvider()
51 : is_paused_(true), 46 : is_paused_(true),
52 have_scheduled_do_poll_(false), 47 have_scheduled_do_poll_(false),
53 devices_changed_(true), 48 devices_changed_(true),
54 ever_had_user_gesture_(false), 49 ever_had_user_gesture_(false) {
55 sanitize_(true) {
56 Initialize(scoped_ptr<GamepadDataFetcher>()); 50 Initialize(scoped_ptr<GamepadDataFetcher>());
57 } 51 }
58 52
59 GamepadProvider::GamepadProvider(scoped_ptr<GamepadDataFetcher> fetcher) 53 GamepadProvider::GamepadProvider(scoped_ptr<GamepadDataFetcher> fetcher)
60 : is_paused_(true), 54 : is_paused_(true),
61 have_scheduled_do_poll_(false), 55 have_scheduled_do_poll_(false),
62 devices_changed_(true), 56 devices_changed_(true),
63 ever_had_user_gesture_(false) { 57 ever_had_user_gesture_(false) {
64 Initialize(std::move(fetcher)); 58 Initialize(std::move(fetcher));
65 } 59 }
66 60
67 GamepadProvider::~GamepadProvider() { 61 GamepadProvider::~GamepadProvider() {
68 base::SystemMonitor* monitor = base::SystemMonitor::Get(); 62 base::SystemMonitor* monitor = base::SystemMonitor::Get();
69 if (monitor) 63 if (monitor)
70 monitor->RemoveDevicesChangedObserver(this); 64 monitor->RemoveDevicesChangedObserver(this);
71 65
72 // Use Stop() to join the polling thread, as there may be pending callbacks 66 // Use Stop() to join the polling thread, as there may be pending callbacks
73 // which dereference |polling_thread_|. 67 // which dereference |polling_thread_|.
74 polling_thread_->Stop(); 68 polling_thread_->Stop();
69 data_fetcher_.reset();
75 } 70 }
76 71
77 base::SharedMemoryHandle GamepadProvider::GetSharedMemoryHandleForProcess( 72 base::SharedMemoryHandle GamepadProvider::GetSharedMemoryHandleForProcess(
78 base::ProcessHandle process) { 73 base::ProcessHandle process) {
79 base::SharedMemoryHandle renderer_handle; 74 base::SharedMemoryHandle renderer_handle;
80 gamepad_shared_memory_.ShareToProcess(process, &renderer_handle); 75 gamepad_shared_memory_.ShareToProcess(process, &renderer_handle);
81 return renderer_handle; 76 return renderer_handle;
82 } 77 }
83 78
84 void GamepadProvider::GetCurrentGamepadData(WebGamepads* data) { 79 void GamepadProvider::GetCurrentGamepadData(WebGamepads* data) {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 size_t data_size = sizeof(GamepadHardwareBuffer); 125 size_t data_size = sizeof(GamepadHardwareBuffer);
131 base::SystemMonitor* monitor = base::SystemMonitor::Get(); 126 base::SystemMonitor* monitor = base::SystemMonitor::Get();
132 if (monitor) 127 if (monitor)
133 monitor->AddDevicesChangedObserver(this); 128 monitor->AddDevicesChangedObserver(this);
134 bool res = gamepad_shared_memory_.CreateAndMapAnonymous(data_size); 129 bool res = gamepad_shared_memory_.CreateAndMapAnonymous(data_size);
135 CHECK(res); 130 CHECK(res);
136 GamepadHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer(); 131 GamepadHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer();
137 memset(hwbuf, 0, sizeof(GamepadHardwareBuffer)); 132 memset(hwbuf, 0, sizeof(GamepadHardwareBuffer));
138 pad_states_.reset(new PadState[WebGamepads::itemsLengthCap]); 133 pad_states_.reset(new PadState[WebGamepads::itemsLengthCap]);
139 134
140 for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i)
141 ClearPadState(pad_states_.get()[i]);
142
143 polling_thread_.reset(new base::Thread("Gamepad polling thread")); 135 polling_thread_.reset(new base::Thread("Gamepad polling thread"));
144 #if defined(OS_LINUX) 136 #if defined(OS_LINUX)
145 // On Linux, the data fetcher needs to watch file descriptors, so the message 137 // On Linux, the data fetcher needs to watch file descriptors, so the message
146 // loop needs to be a libevent loop. 138 // loop needs to be a libevent loop.
147 const base::MessageLoop::Type kMessageLoopType = base::MessageLoop::TYPE_IO; 139 const base::MessageLoop::Type kMessageLoopType = base::MessageLoop::TYPE_IO;
148 #elif defined(OS_ANDROID) 140 #elif defined(OS_ANDROID)
149 // On Android, keeping a message loop of default type. 141 // On Android, keeping a message loop of default type.
150 const base::MessageLoop::Type kMessageLoopType = 142 const base::MessageLoop::Type kMessageLoopType =
151 base::MessageLoop::TYPE_DEFAULT; 143 base::MessageLoop::TYPE_DEFAULT;
152 #else 144 #else
153 // On Mac, the data fetcher uses IOKit which depends on CFRunLoop, so the 145 // On Mac, the data fetcher uses IOKit which depends on CFRunLoop, so the
154 // message loop needs to be a UI-type loop. On Windows it must be a UI loop 146 // message loop needs to be a UI-type loop. On Windows it must be a UI loop
155 // to properly pump the MessageWindow that captures device state. 147 // to properly pump the MessageWindow that captures device state.
156 const base::MessageLoop::Type kMessageLoopType = base::MessageLoop::TYPE_UI; 148 const base::MessageLoop::Type kMessageLoopType = base::MessageLoop::TYPE_UI;
157 #endif 149 #endif
158 polling_thread_->StartWithOptions(base::Thread::Options(kMessageLoopType, 0)); 150 polling_thread_->StartWithOptions(base::Thread::Options(kMessageLoopType, 0));
159 151
160 if (fetcher) {
161 AddGamepadDataFetcher(std::move(fetcher));
162 } else {
163 AddGamepadPlatformDataFetchers(this);
164 }
165 }
166
167 void GamepadProvider::AddGamepadDataFetcher(
168 scoped_ptr<GamepadDataFetcher> fetcher) {
169 polling_thread_->task_runner()->PostTask( 152 polling_thread_->task_runner()->PostTask(
170 FROM_HERE, base::Bind(&GamepadProvider::DoAddGamepadDataFetcher, 153 FROM_HERE, base::Bind(&GamepadProvider::DoInitializePollingThread,
171 base::Unretained(this), base::Passed(&fetcher))); 154 base::Unretained(this), base::Passed(&fetcher)));
172 } 155 }
173 156
174 void GamepadProvider::DoAddGamepadDataFetcher( 157 void GamepadProvider::DoInitializePollingThread(
175 scoped_ptr<GamepadDataFetcher> fetcher) { 158 scoped_ptr<GamepadDataFetcher> fetcher) {
176 DCHECK(base::MessageLoop::current() == polling_thread_->message_loop()); 159 DCHECK(base::MessageLoop::current() == polling_thread_->message_loop());
160 DCHECK(!data_fetcher_.get()); // Should only initialize once.
177 161
178 fetcher->InitializeProvider(this); 162 if (!fetcher)
179 163 fetcher.reset(new GamepadPlatformDataFetcher);
180 data_fetchers_.push_back(std::move(fetcher)); 164 data_fetcher_ = std::move(fetcher);
181 } 165 }
182 166
183 void GamepadProvider::SendPauseHint(bool paused) { 167 void GamepadProvider::SendPauseHint(bool paused) {
184 DCHECK(base::MessageLoop::current() == polling_thread_->message_loop()); 168 DCHECK(base::MessageLoop::current() == polling_thread_->message_loop());
185 for (const auto& it : data_fetchers_) { 169 if (data_fetcher_)
186 it->PauseHint(paused); 170 data_fetcher_->PauseHint(paused);
187 } 171 }
172
173 bool GamepadProvider::PadState::Match(const WebGamepad& pad) const {
174 return connected_ == pad.connected &&
175 axes_length_ == pad.axesLength &&
176 buttons_length_ == pad.buttonsLength &&
177 memcmp(id_, pad.id, sizeof(id_)) == 0 &&
178 memcmp(mapping_, pad.mapping, sizeof(mapping_)) == 0;
179 }
180
181 void GamepadProvider::PadState::SetPad(const WebGamepad& pad) {
182 connected_ = pad.connected;
183 axes_length_ = pad.axesLength;
184 buttons_length_ = pad.buttonsLength;
185 memcpy(id_, pad.id, sizeof(id_));
186 memcpy(mapping_, pad.mapping, sizeof(mapping_));
187 }
188
189 void GamepadProvider::PadState::SetDisconnected() {
190 connected_ = false;
191 axes_length_ = 0;
192 buttons_length_ = 0;
193 memset(id_, 0, sizeof(id_));
194 memset(mapping_, 0, sizeof(mapping_));
195 }
196
197 void GamepadProvider::PadState::AsWebGamepad(WebGamepad* pad) {
198 pad->connected = connected_;
199 pad->axesLength = axes_length_;
200 pad->buttonsLength = buttons_length_;
201 memcpy(pad->id, id_, sizeof(id_));
202 memcpy(pad->mapping, mapping_, sizeof(mapping_));
203 memset(pad->axes, 0, sizeof(pad->axes));
204 memset(pad->buttons, 0, sizeof(pad->buttons));
188 } 205 }
189 206
190 void GamepadProvider::DoPoll() { 207 void GamepadProvider::DoPoll() {
191 DCHECK(base::MessageLoop::current() == polling_thread_->message_loop()); 208 DCHECK(base::MessageLoop::current() == polling_thread_->message_loop());
192 DCHECK(have_scheduled_do_poll_); 209 DCHECK(have_scheduled_do_poll_);
193 have_scheduled_do_poll_ = false; 210 have_scheduled_do_poll_ = false;
194 211
195 bool changed; 212 bool changed;
196 GamepadHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer(); 213 GamepadHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer();
197 214
198 ANNOTATE_BENIGN_RACE_SIZED( 215 ANNOTATE_BENIGN_RACE_SIZED(
199 &hwbuf->buffer, 216 &hwbuf->buffer,
200 sizeof(WebGamepads), 217 sizeof(WebGamepads),
201 "Racey reads are discarded"); 218 "Racey reads are discarded");
202 219
203 { 220 {
204 base::AutoLock lock(devices_changed_lock_); 221 base::AutoLock lock(devices_changed_lock_);
205 changed = devices_changed_; 222 changed = devices_changed_;
206 devices_changed_ = false; 223 devices_changed_ = false;
207 } 224 }
208 225
209 // Loop through each registered data fetcher and poll its gamepad data.
210 // It's expected that GetGamepadData will mark each gamepad as active (via
211 // GetPadState). If a gamepad is not marked as active during the calls to
212 // GetGamepadData then it's assumed to be disconnected.
213 for (const auto& it : data_fetchers_) {
214 it->GetGamepadData(changed);
215 }
216
217 // Send out disconnect events using the last polled data before we wipe it out
218 // in the mapping step.
219 if (ever_had_user_gesture_) {
220 for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i) {
221 PadState& state = pad_states_.get()[i];
222
223 if (!state.active_state && state.source != GAMEPAD_SOURCE_NONE) {
224 OnGamepadConnectionChange(false, i, hwbuf->buffer.items[i]);
225 ClearPadState(state);
226 }
227 }
228 }
229
230 { 226 {
231 base::AutoLock lock(shared_memory_lock_); 227 base::AutoLock lock(shared_memory_lock_);
232 228
233 // Acquire the SeqLock. There is only ever one writer to this data. 229 // Acquire the SeqLock. There is only ever one writer to this data.
234 // See gamepad_hardware_buffer.h. 230 // See gamepad_hardware_buffer.h.
235 hwbuf->sequence.WriteBegin(); 231 hwbuf->sequence.WriteBegin();
236 hwbuf->buffer.length = 0; 232 data_fetcher_->GetGamepadData(&hwbuf->buffer, changed);
237 for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i) {
238 PadState& state = pad_states_.get()[i];
239 // Must run through the map+sanitize here or CheckForUserGesture may fail.
240 MapAndSanitizeGamepadData(&state, &hwbuf->buffer.items[i]);
241 if (state.active_state)
242 hwbuf->buffer.length++;
243 }
244 hwbuf->sequence.WriteEnd(); 233 hwbuf->sequence.WriteEnd();
245 } 234 }
246 235
247 if (ever_had_user_gesture_) { 236 if (ever_had_user_gesture_) {
248 for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i) { 237 for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i) {
238 WebGamepad& pad = hwbuf->buffer.items[i];
249 PadState& state = pad_states_.get()[i]; 239 PadState& state = pad_states_.get()[i];
250 240 if (pad.connected && !state.connected()) {
251 if (state.active_state) { 241 OnGamepadConnectionChange(true, i, pad);
252 if (state.active_state == GAMEPAD_NEWLY_ACTIVE) 242 } else if (!pad.connected && state.connected()) {
253 OnGamepadConnectionChange(true, i, hwbuf->buffer.items[i]); 243 OnGamepadConnectionChange(false, i, pad);
254 state.active_state = GAMEPAD_INACTIVE; 244 } else if (pad.connected && state.connected() && !state.Match(pad)) {
245 WebGamepad old_pad;
246 state.AsWebGamepad(&old_pad);
247 OnGamepadConnectionChange(false, i, old_pad);
248 OnGamepadConnectionChange(true, i, pad);
255 } 249 }
256 } 250 }
257 } 251 }
258 252
259 CheckForUserGesture(); 253 CheckForUserGesture();
260 254
261 // Schedule our next interval of polling. 255 // Schedule our next interval of polling.
262 ScheduleDoPoll(); 256 ScheduleDoPoll();
263 } 257 }
264 258
265 void GamepadProvider::ScheduleDoPoll() { 259 void GamepadProvider::ScheduleDoPoll() {
266 DCHECK(base::MessageLoop::current() == polling_thread_->message_loop()); 260 DCHECK(base::MessageLoop::current() == polling_thread_->message_loop());
267 if (have_scheduled_do_poll_) 261 if (have_scheduled_do_poll_)
268 return; 262 return;
269 263
270 { 264 {
271 base::AutoLock lock(is_paused_lock_); 265 base::AutoLock lock(is_paused_lock_);
272 if (is_paused_) 266 if (is_paused_)
273 return; 267 return;
274 } 268 }
275 269
276 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( 270 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
277 FROM_HERE, base::Bind(&GamepadProvider::DoPoll, Unretained(this)), 271 FROM_HERE, base::Bind(&GamepadProvider::DoPoll, Unretained(this)),
278 base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs)); 272 base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs));
279 have_scheduled_do_poll_ = true; 273 have_scheduled_do_poll_ = true;
280 } 274 }
281 275
282 void GamepadProvider::OnGamepadConnectionChange( 276 void GamepadProvider::OnGamepadConnectionChange(
283 bool connected, int index, const WebGamepad& pad) { 277 bool connected, int index, const WebGamepad& pad) {
278 PadState& state = pad_states_.get()[index];
279 if (connected)
280 state.SetPad(pad);
281 else
282 state.SetDisconnected();
283
284 BrowserThread::PostTask( 284 BrowserThread::PostTask(
285 BrowserThread::IO, 285 BrowserThread::IO,
286 FROM_HERE, 286 FROM_HERE,
287 base::Bind(&GamepadProvider::DispatchGamepadConnectionChange, 287 base::Bind(&GamepadProvider::DispatchGamepadConnectionChange,
288 base::Unretained(this), 288 base::Unretained(this),
289 connected, 289 connected,
290 index, 290 index,
291 pad)); 291 pad));
292 } 292 }
293 293
294 void GamepadProvider::DispatchGamepadConnectionChange( 294 void GamepadProvider::DispatchGamepadConnectionChange(
295 bool connected, int index, const WebGamepad& pad) { 295 bool connected, int index, const WebGamepad& pad) {
296 if (connected) 296 if (connected)
297 GamepadService::GetInstance()->OnGamepadConnected(index, pad); 297 GamepadService::GetInstance()->OnGamepadConnected(index, pad);
298 else 298 else
299 GamepadService::GetInstance()->OnGamepadDisconnected(index, pad); 299 GamepadService::GetInstance()->OnGamepadDisconnected(index, pad);
300 } 300 }
301 301
302 GamepadHardwareBuffer* GamepadProvider::SharedMemoryAsHardwareBuffer() { 302 GamepadHardwareBuffer* GamepadProvider::SharedMemoryAsHardwareBuffer() {
303 void* mem = gamepad_shared_memory_.memory(); 303 void* mem = gamepad_shared_memory_.memory();
304 CHECK(mem); 304 CHECK(mem);
305 return static_cast<GamepadHardwareBuffer*>(mem); 305 return static_cast<GamepadHardwareBuffer*>(mem);
306 } 306 }
307 307
308 void GamepadProvider::CheckForUserGesture() { 308 void GamepadProvider::CheckForUserGesture() {
309 base::AutoLock lock(user_gesture_lock_); 309 base::AutoLock lock(user_gesture_lock_);
310 if (user_gesture_observers_.empty() && ever_had_user_gesture_) 310 if (user_gesture_observers_.empty() && ever_had_user_gesture_)
311 return; 311 return;
312 312
313 bool had_gesture_before = ever_had_user_gesture_;
313 const WebGamepads& pads = SharedMemoryAsHardwareBuffer()->buffer; 314 const WebGamepads& pads = SharedMemoryAsHardwareBuffer()->buffer;
314 if (GamepadsHaveUserGesture(pads)) { 315 if (GamepadsHaveUserGesture(pads)) {
315 ever_had_user_gesture_ = true; 316 ever_had_user_gesture_ = true;
316 for (size_t i = 0; i < user_gesture_observers_.size(); i++) { 317 for (size_t i = 0; i < user_gesture_observers_.size(); i++) {
317 user_gesture_observers_[i].task_runner->PostTask( 318 user_gesture_observers_[i].task_runner->PostTask(
318 FROM_HERE, user_gesture_observers_[i].closure); 319 FROM_HERE, user_gesture_observers_[i].closure);
319 } 320 }
320 user_gesture_observers_.clear(); 321 user_gesture_observers_.clear();
321 } 322 }
322 } 323 if (!had_gesture_before && ever_had_user_gesture_) {
323 324 // Initialize pad_states_ for the first time.
324 void GamepadProvider::ClearPadState(PadState& state) { 325 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) {
325 memset(&state, 0, sizeof(PadState)); 326 pad_states_.get()[i].SetPad(pads.items[i]);
326 }
327
328 PadState* GamepadProvider::GetPadState(GamepadSource source, int source_id) {
329 // Check to see if the device already has a reserved slot
330 PadState* empty_slot = nullptr;
331 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) {
332 PadState& state = pad_states_.get()[i];
333 if (state.source == source &&
334 state.source_id == source_id) {
335 // Retrieving the pad state marks this gamepad as active.
336 state.active_state = GAMEPAD_ACTIVE;
337 return &state;
338 }
339 if (!empty_slot && state.source == GAMEPAD_SOURCE_NONE)
340 empty_slot = &state;
341 }
342 if (empty_slot) {
343 empty_slot->source = source;
344 empty_slot->source_id = source_id;
345 empty_slot->active_state = GAMEPAD_NEWLY_ACTIVE;
346 }
347 return empty_slot;
348 }
349
350 void GamepadProvider::MapAndSanitizeGamepadData(
351 PadState* pad_state, WebGamepad* pad) {
352 DCHECK(pad_state);
353 DCHECK(pad);
354
355 if (!pad_state->active_state) {
356 memset(pad, 0, sizeof(WebGamepad));
357 return;
358 }
359
360 // Copy the current state to the output buffer, using the mapping
361 // function, if there is one available.
362 if (pad_state->mapper)
363 pad_state->mapper(pad_state->data, pad);
364 else
365 *pad = pad_state->data;
366
367 pad->connected = true;
368
369 if (!sanitize_)
370 return;
371
372 // About sanitization: Gamepads may report input event if the user is not
373 // interacting with it, due to hardware problems or environmental ones (pad
374 // has something heavy leaning against an axis.) This may cause user gestures
375 // to be detected erroniously, exposing gamepad information when the user had
376 // no intention of doing so. To avoid this we require that each button or axis
377 // report being at rest (zero) at least once before exposing its value to the
378 // Gamepad API. This state is tracked by the axis_mask and button_mask
379 // bitfields. If the bit for an axis or button is 0 it means the axis has
380 // never reported being at rest, and the value will be forced to zero.
381
382 // We can skip axis sanitation if all available axes have been masked.
383 uint32_t full_axis_mask = (1 << pad->axesLength) - 1;
384 if (pad_state->axis_mask != full_axis_mask) {
385 for (size_t axis = 0; axis < pad->axesLength; ++axis) {
386 if (!(pad_state->axis_mask & 1 << axis)) {
387 if (fabs(pad->axes[axis]) < kMinAxisResetValue) {
388 pad_state->axis_mask |= 1 << axis;
389 } else {
390 pad->axes[axis] = 0.0f;
391 }
392 }
393 }
394 }
395
396 // We can skip button sanitation if all available buttons have been masked.
397 uint32_t full_button_mask = (1 << pad->buttonsLength) - 1;
398 if (pad_state->button_mask != full_button_mask) {
399 for (size_t button = 0; button < pad->buttonsLength; ++button) {
400 if (!(pad_state->button_mask & 1 << button)) {
401 if (!pad->buttons[button].pressed) {
402 pad_state->button_mask |= 1 << button;
403 } else {
404 pad->buttons[button].pressed = false;
405 pad->buttons[button].value = 0.0f;
406 }
407 }
408 } 327 }
409 } 328 }
410 } 329 }
411 330
412 } // namespace content 331 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/gamepad/gamepad_provider.h ('k') | content/browser/gamepad/gamepad_provider_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698