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