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..8e7644ef46ec4c40fa1729c59a631a79bfb7f1c1 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,41 @@ 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_)); |
+ memset(pad->axes, 0, arraysize(pad->axes)); |
+ memset(pad->buttons, 0, arraysize(pad->buttons)); |
+} |
+ |
void GamepadProvider::DoPoll() { |
DCHECK(base::MessageLoop::current() == polling_thread_->message_loop()); |
DCHECK(have_scheduled_do_poll_); |
@@ -158,7 +207,7 @@ void GamepadProvider::DoPoll() { |
ANNOTATE_BENIGN_RACE_SIZED( |
&hwbuf->buffer, |
- sizeof(blink::WebGamepads), |
+ sizeof(WebGamepads), |
"Racey reads are discarded"); |
{ |
@@ -167,14 +216,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 +267,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 +301,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); |