| Index: content/browser/gamepad/gamepad_provider.cc
|
| diff --git a/content/browser/gamepad/gamepad_provider.cc b/content/browser/gamepad/gamepad_provider.cc
|
| index 1cc7aab73f5daba2e6984c3e626275c27fbf06b8..0d84452b1d1859a0385ac788653df09789265036 100644
|
| --- a/content/browser/gamepad/gamepad_provider.cc
|
| +++ b/content/browser/gamepad/gamepad_provider.cc
|
| @@ -15,9 +15,14 @@
|
| #include "content/browser/gamepad/gamepad_data_fetcher.h"
|
| #include "content/browser/gamepad/gamepad_platform_data_fetcher.h"
|
| #include "content/browser/gamepad/gamepad_provider.h"
|
| +#include "content/browser/gamepad/gamepad_service.h"
|
| #include "content/common/gamepad_hardware_buffer.h"
|
| #include "content/common/gamepad_messages.h"
|
| #include "content/common/gamepad_user_gesture.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +
|
| +using blink::WebGamepad;
|
| +using blink::WebGamepads;
|
|
|
| namespace content {
|
|
|
| @@ -34,14 +39,16 @@ GamepadProvider::ClosureAndThread::~ClosureAndThread() {
|
| GamepadProvider::GamepadProvider()
|
| : is_paused_(true),
|
| have_scheduled_do_poll_(false),
|
| - devices_changed_(true) {
|
| + devices_changed_(true),
|
| + ever_had_user_gesture_(false) {
|
| Initialize(scoped_ptr<GamepadDataFetcher>());
|
| }
|
|
|
| GamepadProvider::GamepadProvider(scoped_ptr<GamepadDataFetcher> fetcher)
|
| : is_paused_(true),
|
| have_scheduled_do_poll_(false),
|
| - devices_changed_(true) {
|
| + devices_changed_(true),
|
| + ever_had_user_gesture_(false) {
|
| Initialize(fetcher.Pass());
|
| }
|
|
|
| @@ -63,6 +70,12 @@ base::SharedMemoryHandle GamepadProvider::GetSharedMemoryHandleForProcess(
|
| return renderer_handle;
|
| }
|
|
|
| +void GamepadProvider::GetCurrentGamepadData(WebGamepads* data) {
|
| + const WebGamepads& pads = SharedMemoryAsHardwareBuffer()->buffer;
|
| + base::AutoLock lock(shared_memory_lock_);
|
| + *data = pads;
|
| +}
|
| +
|
| void GamepadProvider::Pause() {
|
| {
|
| base::AutoLock lock(is_paused_lock_);
|
| @@ -111,6 +124,7 @@ void GamepadProvider::Initialize(scoped_ptr<GamepadDataFetcher> fetcher) {
|
| CHECK(res);
|
| GamepadHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer();
|
| memset(hwbuf, 0, sizeof(GamepadHardwareBuffer));
|
| + pad_states_.reset(new PadState[WebGamepads::itemsLengthCap]);
|
|
|
| polling_thread_.reset(new base::Thread("Gamepad polling thread"));
|
| #if defined(OS_LINUX)
|
| @@ -148,6 +162,39 @@ void GamepadProvider::SendPauseHint(bool paused) {
|
| data_fetcher_->PauseHint(paused);
|
| }
|
|
|
| +bool GamepadProvider::PadState::Match(const WebGamepad& pad) const {
|
| + return connected == pad.connected &&
|
| + axes_length == pad.axesLength &&
|
| + buttons_length == pad.buttonsLength &&
|
| + memcmp(id, pad.id, arraysize(id)) == 0 &&
|
| + memcmp(mapping, pad.mapping, arraysize(mapping)) == 0;
|
| +}
|
| +
|
| +void GamepadProvider::PadState::SetPad(const WebGamepad& pad) {
|
| + DCHECK(pad.connected);
|
| + connected = true;
|
| + axes_length = pad.axesLength;
|
| + buttons_length = pad.buttonsLength;
|
| + memcpy(id, pad.id, arraysize(id));
|
| + memcpy(mapping, pad.mapping, arraysize(mapping));
|
| +}
|
| +
|
| +void GamepadProvider::PadState::SetDisconnected() {
|
| + connected = false;
|
| + axes_length = 0;
|
| + buttons_length = 0;
|
| + memset(id, 0, arraysize(id));
|
| + memset(mapping, 0, arraysize(mapping));
|
| +}
|
| +
|
| +void GamepadProvider::PadState::AsWebGamepad(WebGamepad* pad) {
|
| + pad->connected = connected;
|
| + pad->axesLength = axes_length;
|
| + pad->buttonsLength = buttons_length;
|
| + memcpy(pad->id, id, arraysize(id));
|
| + memcpy(pad->mapping, mapping, arraysize(mapping));
|
| +}
|
| +
|
| void GamepadProvider::DoPoll() {
|
| DCHECK(base::MessageLoop::current() == polling_thread_->message_loop());
|
| DCHECK(have_scheduled_do_poll_);
|
| @@ -158,7 +205,7 @@ void GamepadProvider::DoPoll() {
|
|
|
| ANNOTATE_BENIGN_RACE_SIZED(
|
| &hwbuf->buffer,
|
| - sizeof(blink::WebGamepads),
|
| + sizeof(WebGamepads),
|
| "Racey reads are discarded");
|
|
|
| {
|
| @@ -167,14 +214,35 @@ void GamepadProvider::DoPoll() {
|
| devices_changed_ = false;
|
| }
|
|
|
| - // Acquire the SeqLock. There is only ever one writer to this data.
|
| - // See gamepad_hardware_buffer.h.
|
| - hwbuf->sequence.WriteBegin();
|
| - data_fetcher_->GetGamepadData(&hwbuf->buffer, changed);
|
| - hwbuf->sequence.WriteEnd();
|
| + {
|
| + base::AutoLock lock(shared_memory_lock_);
|
| +
|
| + // Acquire the SeqLock. There is only ever one writer to this data.
|
| + // See gamepad_hardware_buffer.h.
|
| + hwbuf->sequence.WriteBegin();
|
| + data_fetcher_->GetGamepadData(&hwbuf->buffer, changed);
|
| + hwbuf->sequence.WriteEnd();
|
| + }
|
|
|
| CheckForUserGesture();
|
|
|
| + if (ever_had_user_gesture_) {
|
| + for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i) {
|
| + WebGamepad& pad = hwbuf->buffer.items[i];
|
| + PadState& state = pad_states_.get()[i];
|
| + if (pad.connected && !state.connected) {
|
| + OnGamepadConnectionChange(true, i, pad);
|
| + } else if (!pad.connected && state.connected) {
|
| + OnGamepadConnectionChange(false, i, pad);
|
| + } else if (pad.connected && state.connected && !state.Match(pad)) {
|
| + WebGamepad old_pad;
|
| + state.AsWebGamepad(&old_pad);
|
| + OnGamepadConnectionChange(false, i, old_pad);
|
| + OnGamepadConnectionChange(true, i, pad);
|
| + }
|
| + }
|
| + }
|
| +
|
| // Schedule our next interval of polling.
|
| ScheduleDoPoll();
|
| }
|
| @@ -197,6 +265,32 @@ void GamepadProvider::ScheduleDoPoll() {
|
| have_scheduled_do_poll_ = true;
|
| }
|
|
|
| +void GamepadProvider::OnGamepadConnectionChange(
|
| + bool connected, int index, const WebGamepad& pad) {
|
| + PadState& state = pad_states_.get()[index];
|
| + if (connected)
|
| + state.SetPad(pad);
|
| + else
|
| + state.SetDisconnected();
|
| +
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO,
|
| + FROM_HERE,
|
| + base::Bind(&GamepadProvider::DispatchGamepadConnectionChange,
|
| + base::Unretained(this),
|
| + connected,
|
| + index,
|
| + pad));
|
| +}
|
| +
|
| +void GamepadProvider::DispatchGamepadConnectionChange(
|
| + bool connected, int index, const WebGamepad& pad) {
|
| + if (connected)
|
| + GamepadService::GetInstance()->OnGamepadConnected(index, pad);
|
| + else
|
| + GamepadService::GetInstance()->OnGamepadDisconnected(index, pad);
|
| +}
|
| +
|
| GamepadHardwareBuffer* GamepadProvider::SharedMemoryAsHardwareBuffer() {
|
| void* mem = gamepad_shared_memory_.memory();
|
| CHECK(mem);
|
| @@ -205,10 +299,11 @@ GamepadHardwareBuffer* GamepadProvider::SharedMemoryAsHardwareBuffer() {
|
|
|
| void GamepadProvider::CheckForUserGesture() {
|
| base::AutoLock lock(user_gesture_lock_);
|
| - if (user_gesture_observers_.empty())
|
| - return; // Don't need to check if nobody is listening.
|
| + if (user_gesture_observers_.empty() && ever_had_user_gesture_)
|
| + return;
|
|
|
| if (GamepadsHaveUserGesture(SharedMemoryAsHardwareBuffer()->buffer)) {
|
| + ever_had_user_gesture_ = true;
|
| for (size_t i = 0; i < user_gesture_observers_.size(); i++) {
|
| user_gesture_observers_[i].message_loop->PostTask(FROM_HERE,
|
| user_gesture_observers_[i].closure);
|
|
|