| Index: components/exo/gaming_seat.cc
|
| diff --git a/components/exo/gaming_seat.cc b/components/exo/gaming_seat.cc
|
| index 016be145bb90f467d7c47fe6376c15ef15f3cce4..64e3876cd39a4c25551447e3ef5286504c9ddf26 100644
|
| --- a/components/exo/gaming_seat.cc
|
| +++ b/components/exo/gaming_seat.cc
|
| @@ -1,308 +1,44 @@
|
| -// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include "components/exo/gaming_seat.h"
|
| -
|
| -#include <cmath>
|
| +#include <memory>
|
|
|
| -#include "base/bind.h"
|
| -#include "base/location.h"
|
| -#include "base/single_thread_task_runner.h"
|
| +#include "base/macros.h"
|
| +#include "base/sequenced_task_runner.h"
|
| #include "base/threading/thread.h"
|
| #include "base/threading/thread_task_runner_handle.h"
|
| -#include "components/exo/gamepad_delegate.h"
|
| -#include "components/exo/gaming_seat_delegate.h"
|
| -#include "components/exo/shell_surface.h"
|
| -#include "components/exo/surface.h"
|
| -#include "device/gamepad/gamepad_data_fetcher.h"
|
| -#include "device/gamepad/gamepad_pad_state_provider.h"
|
| -#include "device/gamepad/gamepad_platform_data_fetcher_linux.h"
|
| -#include "ui/aura/window.h"
|
| -
|
| -namespace exo {
|
| -namespace {
|
| -
|
| -constexpr double kGamepadButtonValueEpsilon = 0.001;
|
| -bool GamepadButtonValuesAreEqual(double a, double b) {
|
| - return fabs(a - b) < kGamepadButtonValueEpsilon;
|
| -}
|
| -
|
| -std::unique_ptr<device::GamepadDataFetcher> CreateGamepadPlatformDataFetcher() {
|
| - return std::unique_ptr<device::GamepadDataFetcher>(
|
| - new device::GamepadPlatformDataFetcherLinux());
|
| -}
|
| -
|
| -// Time between gamepad polls in milliseconds.
|
| -constexpr unsigned kPollingTimeIntervalMs = 16;
|
| -
|
| -} // namespace
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// GamingSeat::ThreadSafeGamepadChangeFetcher
|
| -
|
| -// Implements all methods and resources running on the polling thread.
|
| -// This class is reference counted to allow it to shut down safely on the
|
| -// polling thread even if the Gamepad has been destroyed on the origin thread.
|
| -class GamingSeat::ThreadSafeGamepadChangeFetcher
|
| - : public device::GamepadPadStateProvider,
|
| - public base::RefCountedThreadSafe<
|
| - GamingSeat::ThreadSafeGamepadChangeFetcher> {
|
| - public:
|
| - using ProcessGamepadChangesCallback =
|
| - base::Callback<void(int index, const device::Gamepad)>;
|
| -
|
| - ThreadSafeGamepadChangeFetcher(
|
| - const ProcessGamepadChangesCallback& post_gamepad_changes,
|
| - const CreateGamepadDataFetcherCallback& create_fetcher_callback,
|
| - base::SingleThreadTaskRunner* task_runner)
|
| - : process_gamepad_changes_(post_gamepad_changes),
|
| - create_fetcher_callback_(create_fetcher_callback),
|
| - polling_task_runner_(task_runner),
|
| - origin_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
|
| - thread_checker_.DetachFromThread();
|
| - }
|
| -
|
| - // Enable or disable gamepad polling. Can be called from any thread.
|
| - void EnablePolling(bool enabled) {
|
| - polling_task_runner_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(
|
| - &ThreadSafeGamepadChangeFetcher::EnablePollingOnPollingThread,
|
| - make_scoped_refptr(this), enabled));
|
| - }
|
| -
|
| - private:
|
| - friend class base::RefCountedThreadSafe<ThreadSafeGamepadChangeFetcher>;
|
| -
|
| - ~ThreadSafeGamepadChangeFetcher() override {}
|
| -
|
| - // Enables or disables polling.
|
| - void EnablePollingOnPollingThread(bool enabled) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - is_enabled_ = enabled;
|
| -
|
| - if (is_enabled_) {
|
| - if (!fetcher_) {
|
| - fetcher_ = create_fetcher_callback_.Run();
|
| - InitializeDataFetcher(fetcher_.get());
|
| - DCHECK(fetcher_);
|
| - }
|
| - SchedulePollOnPollingThread();
|
| - } else {
|
| - fetcher_.reset();
|
| - }
|
| - }
|
| -
|
| - // Schedules the next poll on the polling thread.
|
| - void SchedulePollOnPollingThread() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - DCHECK(fetcher_);
|
| -
|
| - if (!is_enabled_ || has_poll_scheduled_)
|
| - return;
|
| -
|
| - has_poll_scheduled_ = true;
|
| - polling_task_runner_->PostDelayedTask(
|
| - FROM_HERE,
|
| - base::Bind(&ThreadSafeGamepadChangeFetcher::PollOnPollingThread,
|
| - make_scoped_refptr(this)),
|
| - base::TimeDelta::FromMilliseconds(kPollingTimeIntervalMs));
|
| - }
|
| -
|
| - // Polls devices for new data and posts gamepad changes back to origin thread.
|
| - void PollOnPollingThread() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - has_poll_scheduled_ = false;
|
| - if (!is_enabled_)
|
| - return;
|
| -
|
| - DCHECK(fetcher_);
|
| -
|
| - device::Gamepads new_state = state_;
|
| - fetcher_->GetGamepadData(
|
| - false /* No hardware changed notification from the system */);
|
| -
|
| - for (size_t i = 0; i < device::Gamepads::kItemsLengthCap; ++i) {
|
| - device::PadState& pad_state = pad_states_.get()[i];
|
| -
|
| - // After querying the gamepad clear the state if it did not have it's
|
| - // active
|
| - // state updated but is still listed as being associated with a specific
|
| - // source. This indicates the gamepad is disconnected.
|
| - if (!pad_state.active_state &&
|
| - pad_state.source != device::GAMEPAD_SOURCE_NONE) {
|
| - ClearPadState(pad_state);
|
| - }
|
| -
|
| - MapAndSanitizeGamepadData(&pad_state, &new_state.items[i],
|
| - false /* Don't sanitize gamepad data */);
|
| -
|
| - // If the gamepad is still actively reporting the next call to
|
| - // GetGamepadData will set the active state to active again.
|
| - if (pad_state.active_state)
|
| - pad_state.active_state = device::GAMEPAD_INACTIVE;
|
| -
|
| - if (new_state.items[i].connected != state_.items[i].connected ||
|
| - new_state.items[i].timestamp > state_.items[i].timestamp) {
|
| - origin_task_runner_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(process_gamepad_changes_, i, new_state.items[i]));
|
| - }
|
| - }
|
| - state_ = new_state;
|
| - SchedulePollOnPollingThread();
|
| - }
|
| -
|
| - // Callback to ProcessGamepadChanges using weak reference to Gamepad.
|
| - ProcessGamepadChangesCallback process_gamepad_changes_;
|
| -
|
| - // Callback method to create a gamepad data fetcher.
|
| - CreateGamepadDataFetcherCallback create_fetcher_callback_;
|
| -
|
| - // Reference to task runner on polling thread.
|
| - scoped_refptr<base::SingleThreadTaskRunner> polling_task_runner_;
|
| -
|
| - // Reference to task runner on origin thread.
|
| - scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
|
| -
|
| - // Gamepad data fetcher used for querying gamepad devices.
|
| - std::unique_ptr<device::GamepadDataFetcher> fetcher_;
|
| -
|
| - // The current state of all gamepads.
|
| - device::Gamepads state_;
|
| -
|
| - // True if a poll has been scheduled.
|
| - bool has_poll_scheduled_ = false;
|
| -
|
| - // True if the polling thread is paused.
|
| - bool is_enabled_ = false;
|
| -
|
| - // ThreadChecker for the polling thread.
|
| - base::ThreadChecker thread_checker_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(ThreadSafeGamepadChangeFetcher);
|
| -};
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// GamingSeat, public:
|
| -
|
| -GamingSeat::GamingSeat(GamingSeatDelegate* gaming_seat_delegate,
|
| - base::SingleThreadTaskRunner* polling_task_runner)
|
| - : GamingSeat(gaming_seat_delegate,
|
| - polling_task_runner,
|
| - base::Bind(CreateGamepadPlatformDataFetcher)) {}
|
| -
|
| -GamingSeat::GamingSeat(GamingSeatDelegate* gaming_seat_delegate,
|
| - base::SingleThreadTaskRunner* polling_task_runner,
|
| - CreateGamepadDataFetcherCallback create_fetcher_callback)
|
| - : delegate_(gaming_seat_delegate),
|
| - gamepad_delegates_{nullptr},
|
| - weak_ptr_factory_(this) {
|
| - gamepad_change_fetcher_ = new ThreadSafeGamepadChangeFetcher(
|
| - base::Bind(&GamingSeat::ProcessGamepadChanges,
|
| - weak_ptr_factory_.GetWeakPtr()),
|
| - create_fetcher_callback, polling_task_runner);
|
| -
|
| - auto* helper = WMHelper::GetInstance();
|
| - helper->AddFocusObserver(this);
|
| - OnWindowFocused(helper->GetFocusedWindow(), nullptr);
|
| -}
|
| -
|
| -GamingSeat::~GamingSeat() {
|
| - // Disable polling. Since ThreadSafeGamepadChangeFetcher are reference
|
| - // counted, we can safely have it shut down after Gamepad has been destroyed.
|
| - gamepad_change_fetcher_->EnablePolling(false);
|
| -
|
| - delegate_->OnGamingSeatDestroying(this);
|
| - for (size_t i = 0; i < device::Gamepads::kItemsLengthCap; ++i) {
|
| - if (gamepad_delegates_[i]) {
|
| - gamepad_delegates_[i]->OnRemoved();
|
| - }
|
| - }
|
| - WMHelper::GetInstance()->RemoveFocusObserver(this);
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// aura::client::FocusChangeObserver overrides:
|
| +#include "components/exo/gaming_seat.h"
|
| +#include "components/exo/gaming_seat_joydev.h"
|
|
|
| -void GamingSeat::OnWindowFocused(aura::Window* gained_focus,
|
| - aura::Window* lost_focus) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - Surface* target = nullptr;
|
| - if (gained_focus) {
|
| - target = Surface::AsSurface(gained_focus);
|
| - if (!target) {
|
| - aura::Window* top_level_window = gained_focus->GetToplevelWindow();
|
| - if (top_level_window)
|
| - target = ShellSurface::GetMainSurface(top_level_window);
|
| - }
|
| - }
|
| +#if defined(USE_OZONE)
|
| +#include "components/exo/gaming_seat_ozone.h"
|
| +#endif
|
|
|
| - bool focused = target && delegate_->CanAcceptGamepadEventsForSurface(target);
|
| +namespace exo {
|
|
|
| - gamepad_change_fetcher_->EnablePolling(focused);
|
| +base::Thread* GamingSeat::CreatePollingThreadIfNeeded() {
|
| +#if defined(USE_OZONE) && defined(USE_OZONE_GAMEPAD)
|
| + return nullptr;
|
| +#else
|
| + base::Thread* polling_thread =
|
| + new base::Thread("Exo gaming input polling thread.");
|
| + polling_thread->StartWithOptions(
|
| + base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
|
| + return polling_thread;
|
| +#endif
|
| }
|
|
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// GamingSeat, private:
|
| -
|
| -void GamingSeat::ProcessGamepadChanges(int index,
|
| - const device::Gamepad new_pad) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - bool send_frame = false;
|
| -
|
| - device::Gamepad& pad_state = pad_state_.items[index];
|
| - // Update connection state.
|
| - GamepadDelegate* delegate = gamepad_delegates_[index];
|
| - if (new_pad.connected != pad_state.connected) {
|
| - // New pad is disconnected.
|
| - if (!new_pad.connected) {
|
| - // If gamepad is disconnected now, it should be connected before, then
|
| - // gamepad_delegate should not be null.
|
| - DCHECK(delegate);
|
| - delegate->OnRemoved();
|
| - gamepad_delegates_[index] = nullptr;
|
| - pad_state = new_pad;
|
| - return;
|
| - } else if (new_pad.connected) {
|
| - gamepad_delegates_[index] = delegate_->GamepadAdded();
|
| - }
|
| - }
|
| -
|
| - if (!delegate || !new_pad.connected ||
|
| - new_pad.timestamp <= pad_state.timestamp) {
|
| - pad_state = new_pad;
|
| - return;
|
| - }
|
| -
|
| - // Notify delegate of updated axes.
|
| - for (size_t axis = 0;
|
| - axis < std::max(pad_state.axes_length, new_pad.axes_length); ++axis) {
|
| - if (!GamepadButtonValuesAreEqual(new_pad.axes[axis],
|
| - pad_state.axes[axis])) {
|
| - send_frame = true;
|
| - delegate->OnAxis(axis, new_pad.axes[axis]);
|
| - }
|
| - }
|
| -
|
| - // Notify delegate of updated buttons.
|
| - for (size_t button_id = 0;
|
| - button_id < std::max(pad_state.buttons_length, new_pad.buttons_length);
|
| - ++button_id) {
|
| - auto button = pad_state.buttons[button_id];
|
| - auto new_button = new_pad.buttons[button_id];
|
| - if (button.pressed != new_button.pressed ||
|
| - !GamepadButtonValuesAreEqual(button.value, new_button.value)) {
|
| - send_frame = true;
|
| - delegate->OnButton(button_id, new_button.pressed, new_button.value);
|
| - }
|
| - }
|
| - if (send_frame)
|
| - delegate->OnFrame();
|
| -
|
| - pad_state = new_pad;
|
| +GamingSeat* GamingSeat::CreateGamingSeat(
|
| + GamingSeatDelegate* gaming_seat_delegate,
|
| + base::Thread* polling_thread) {
|
| +#if defined(USE_OZONE) && defined(USE_OZONE_GAMEPAD)
|
| + return new GamingSeatOzone(gaming_seat_delegate);
|
| +#else
|
| + DCHECK(polling_thread);
|
| + return new GamingSeatJoydev(gaming_seat_delegate,
|
| + polling_thread->task_runner().get());
|
| +#endif
|
| }
|
|
|
| } // namespace exo
|
|
|