15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cmath>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
119ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_restrictions.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/gamepad/gamepad_data_fetcher.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/gamepad/gamepad_platform_data_fetcher.h"
179ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "content/browser/gamepad/gamepad_provider.h"
18010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "content/browser/gamepad/gamepad_service.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/common/gamepad_hardware_buffer.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/common/gamepad_messages.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/common/gamepad_user_gesture.h"
22010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
23010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
24010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)using blink::WebGamepad;
25010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)using blink::WebGamepads;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GamepadProvider::ClosureAndThread::ClosureAndThread(
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Closure& c,
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const scoped_refptr<base::MessageLoopProxy>& m)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : closure(c),
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      message_loop(m) {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GamepadProvider::ClosureAndThread::~ClosureAndThread() {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GamepadProvider::GamepadProvider()
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : is_paused_(true),
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      have_scheduled_do_poll_(false),
42010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      devices_changed_(true),
43010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      ever_had_user_gesture_(false) {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Initialize(scoped_ptr<GamepadDataFetcher>());
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GamepadProvider::GamepadProvider(scoped_ptr<GamepadDataFetcher> fetcher)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : is_paused_(true),
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      have_scheduled_do_poll_(false),
50010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      devices_changed_(true),
51010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      ever_had_user_gesture_(false) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Initialize(fetcher.Pass());
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GamepadProvider::~GamepadProvider() {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::SystemMonitor* monitor = base::SystemMonitor::Get();
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (monitor)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    monitor->RemoveDevicesChangedObserver(this);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Use Stop() to join the polling thread, as there may be pending callbacks
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // which dereference |polling_thread_|.
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  polling_thread_->Stop();
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data_fetcher_.reset();
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::SharedMemoryHandle GamepadProvider::GetSharedMemoryHandleForProcess(
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ProcessHandle process) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::SharedMemoryHandle renderer_handle;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gamepad_shared_memory_.ShareToProcess(process, &renderer_handle);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return renderer_handle;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
73010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void GamepadProvider::GetCurrentGamepadData(WebGamepads* data) {
74010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const WebGamepads& pads = SharedMemoryAsHardwareBuffer()->buffer;
75010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  base::AutoLock lock(shared_memory_lock_);
76010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  *data = pads;
77010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
78010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadProvider::Pause() {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock lock(is_paused_lock_);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_paused_ = true;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::MessageLoop* polling_loop = polling_thread_->message_loop();
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  polling_loop->PostTask(
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&GamepadProvider::SendPauseHint, Unretained(this), true));
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadProvider::Resume() {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock lock(is_paused_lock_);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!is_paused_)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_paused_ = false;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::MessageLoop* polling_loop = polling_thread_->message_loop();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  polling_loop->PostTask(
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&GamepadProvider::SendPauseHint, Unretained(this), false));
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  polling_loop->PostTask(
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&GamepadProvider::ScheduleDoPoll, Unretained(this)));
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadProvider::RegisterForUserGesture(const base::Closure& closure) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock lock(user_gesture_lock_);
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  user_gesture_observers_.push_back(ClosureAndThread(
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      closure, base::MessageLoop::current()->message_loop_proxy()));
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadProvider::OnDevicesChanged(base::SystemMonitor::DeviceType type) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock lock(devices_changed_lock_);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  devices_changed_ = true;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadProvider::Initialize(scoped_ptr<GamepadDataFetcher> fetcher) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t data_size = sizeof(GamepadHardwareBuffer);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::SystemMonitor* monitor = base::SystemMonitor::Get();
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (monitor)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    monitor->AddDevicesChangedObserver(this);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool res = gamepad_shared_memory_.CreateAndMapAnonymous(data_size);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(res);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GamepadHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(hwbuf, 0, sizeof(GamepadHardwareBuffer));
127010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  pad_states_.reset(new PadState[WebGamepads::itemsLengthCap]);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  polling_thread_.reset(new base::Thread("Gamepad polling thread"));
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_LINUX)
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // On Linux, the data fetcher needs to watch file descriptors, so the message
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // loop needs to be a libevent loop.
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const base::MessageLoop::Type kMessageLoopType = base::MessageLoop::TYPE_IO;
13446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#elif defined(OS_ANDROID)
13546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // On Android, keeping a message loop of default type.
13646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const base::MessageLoop::Type kMessageLoopType =
13746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::MessageLoop::TYPE_DEFAULT;
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#else
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // On Mac, the data fetcher uses IOKit which depends on CFRunLoop, so the
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // message loop needs to be a UI-type loop. On Windows it must be a UI loop
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // to properly pump the MessageWindow that captures device state.
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::MessageLoop::Type kMessageLoopType = base::MessageLoop::TYPE_UI;
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  polling_thread_->StartWithOptions(base::Thread::Options(kMessageLoopType, 0));
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  polling_thread_->message_loop()->PostTask(
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&GamepadProvider::DoInitializePollingThread,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Unretained(this),
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Passed(&fetcher)));
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadProvider::DoInitializePollingThread(
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<GamepadDataFetcher> fetcher) {
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == polling_thread_->message_loop());
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!data_fetcher_.get());  // Should only initialize once.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!fetcher)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fetcher.reset(new GamepadPlatformDataFetcher);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data_fetcher_ = fetcher.Pass();
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadProvider::SendPauseHint(bool paused) {
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == polling_thread_->message_loop());
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (data_fetcher_)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data_fetcher_->PauseHint(paused);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
169010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool GamepadProvider::PadState::Match(const WebGamepad& pad) const {
170010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return connected_ == pad.connected &&
171010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)         axes_length_ == pad.axesLength &&
172010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)         buttons_length_ == pad.buttonsLength &&
173010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)         memcmp(id_, pad.id, arraysize(id_)) == 0 &&
174010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)         memcmp(mapping_, pad.mapping, arraysize(mapping_)) == 0;
175010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
176010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
177010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void GamepadProvider::PadState::SetPad(const WebGamepad& pad) {
178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  connected_ = pad.connected;
179010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  axes_length_ = pad.axesLength;
180010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  buttons_length_ = pad.buttonsLength;
181010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  memcpy(id_, pad.id, arraysize(id_));
182010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  memcpy(mapping_, pad.mapping, arraysize(mapping_));
183010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
184010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
185010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void GamepadProvider::PadState::SetDisconnected() {
186010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  connected_ = false;
187010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  axes_length_ = 0;
188010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  buttons_length_ = 0;
189010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  memset(id_, 0, arraysize(id_));
190010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  memset(mapping_, 0, arraysize(mapping_));
191010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
192010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
193010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void GamepadProvider::PadState::AsWebGamepad(WebGamepad* pad) {
194010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  pad->connected = connected_;
195010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  pad->axesLength = axes_length_;
196010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  pad->buttonsLength = buttons_length_;
197010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  memcpy(pad->id, id_, arraysize(id_));
198010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  memcpy(pad->mapping, mapping_, arraysize(mapping_));
199010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  memset(pad->axes, 0, arraysize(pad->axes));
200010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  memset(pad->buttons, 0, arraysize(pad->buttons));
201010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
202010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadProvider::DoPoll() {
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == polling_thread_->message_loop());
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(have_scheduled_do_poll_);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  have_scheduled_do_poll_ = false;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool changed;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GamepadHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer();
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ANNOTATE_BENIGN_RACE_SIZED(
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &hwbuf->buffer,
213010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      sizeof(WebGamepads),
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Racey reads are discarded");
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock lock(devices_changed_lock_);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changed = devices_changed_;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    devices_changed_ = false;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
222010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  {
223010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    base::AutoLock lock(shared_memory_lock_);
224010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
225010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // Acquire the SeqLock. There is only ever one writer to this data.
226010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // See gamepad_hardware_buffer.h.
227010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    hwbuf->sequence.WriteBegin();
228010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    data_fetcher_->GetGamepadData(&hwbuf->buffer, changed);
229010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    hwbuf->sequence.WriteEnd();
230010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
232010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (ever_had_user_gesture_) {
233010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i) {
234010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      WebGamepad& pad = hwbuf->buffer.items[i];
235010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      PadState& state = pad_states_.get()[i];
236010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      if (pad.connected && !state.connected()) {
237010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        OnGamepadConnectionChange(true, i, pad);
238010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      } else if (!pad.connected && state.connected()) {
239010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        OnGamepadConnectionChange(false, i, pad);
240010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      } else if (pad.connected && state.connected() && !state.Match(pad)) {
241010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        WebGamepad old_pad;
242010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        state.AsWebGamepad(&old_pad);
243010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        OnGamepadConnectionChange(false, i, old_pad);
244010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        OnGamepadConnectionChange(true, i, pad);
245010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      }
246010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
247010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
248010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
249116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CheckForUserGesture();
250116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Schedule our next interval of polling.
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleDoPoll();
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadProvider::ScheduleDoPoll() {
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == polling_thread_->message_loop());
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (have_scheduled_do_poll_)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock lock(is_paused_lock_);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (is_paused_)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&GamepadProvider::DoPoll, Unretained(this)),
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs));
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  have_scheduled_do_poll_ = true;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
273010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void GamepadProvider::OnGamepadConnectionChange(
274010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    bool connected, int index, const WebGamepad& pad) {
275010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  PadState& state = pad_states_.get()[index];
276010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (connected)
277010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    state.SetPad(pad);
278010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  else
279010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    state.SetDisconnected();
280010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
281010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  BrowserThread::PostTask(
282010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      BrowserThread::IO,
283010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      FROM_HERE,
284010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      base::Bind(&GamepadProvider::DispatchGamepadConnectionChange,
285010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                 base::Unretained(this),
286010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                 connected,
287010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                 index,
288010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                 pad));
289010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
290010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
291010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void GamepadProvider::DispatchGamepadConnectionChange(
292010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    bool connected, int index, const WebGamepad& pad) {
293010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (connected)
294010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    GamepadService::GetInstance()->OnGamepadConnected(index, pad);
295010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  else
296010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    GamepadService::GetInstance()->OnGamepadDisconnected(index, pad);
297010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
298010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GamepadHardwareBuffer* GamepadProvider::SharedMemoryAsHardwareBuffer() {
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* mem = gamepad_shared_memory_.memory();
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(mem);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<GamepadHardwareBuffer*>(mem);
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadProvider::CheckForUserGesture() {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock lock(user_gesture_lock_);
307010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (user_gesture_observers_.empty() && ever_had_user_gesture_)
308010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
310116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool had_gesture_before = ever_had_user_gesture_;
311116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const WebGamepads& pads = SharedMemoryAsHardwareBuffer()->buffer;
312116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (GamepadsHaveUserGesture(pads)) {
313010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    ever_had_user_gesture_ = true;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < user_gesture_observers_.size(); i++) {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      user_gesture_observers_[i].message_loop->PostTask(FROM_HERE,
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          user_gesture_observers_[i].closure);
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    user_gesture_observers_.clear();
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
320116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!had_gesture_before && ever_had_user_gesture_) {
321116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Initialize pad_states_ for the first time.
322116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) {
323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      pad_states_.get()[i].SetPad(pads.items[i]);
324116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
325116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
329