Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(697)

Unified Diff: components/exo/gamepad.cc

Issue 2076013002: exo: Implement wayland gamepad support (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@serv
Patch Set: limit polling to when exo windows are focused Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/exo/gamepad.cc
diff --git a/components/exo/gamepad.cc b/components/exo/gamepad.cc
new file mode 100644
index 0000000000000000000000000000000000000000..83b4beea52d43553399ad0f5f1f4ea39e0e1b237
--- /dev/null
+++ b/components/exo/gamepad.cc
@@ -0,0 +1,194 @@
+// Copyright 2016 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/gamepad.h"
+
+#include <cmath>
+
+#include "ash/shell.h"
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_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/shell_surface.h"
+#include "components/exo/surface.h"
+#include "device/gamepad/gamepad_data_fetcher.h"
+#include "device/gamepad/gamepad_platform_data_fetcher.h"
+#include "ui/aura/client/focus_client.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;
+}
+
+// Time between gamepad polls in milliseconds.
+constexpr unsigned kPollingTimeIntervalMs = 16;
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// Gamepad, public:
+
+Gamepad::Gamepad(GamepadDelegate* delegate) : Gamepad(delegate, nullptr) {}
+
+Gamepad::Gamepad(GamepadDelegate* delegate, device::GamepadDataFetcher* fetcher)
+ : delegate_(delegate),
+ origin_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ polling_thread_(new base::Thread("Exo gamepad polling thread")),
+ external_fetcher_(fetcher),
+ weak_factory_(this) {
+ polling_thread_checker_.DetachFromThread();
+ post_gamepad_changes_callback_ =
+ base::Bind(&Gamepad::PostGamepadChanges, weak_factory_.GetWeakPtr());
+
+ polling_thread_->StartWithOptions(
+ base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
+
+ aura::client::FocusClient* focus_client =
+ aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
+ focus_client->AddObserver(this);
+ OnWindowFocused(focus_client->GetFocusedWindow(), nullptr);
+}
+
+Gamepad::~Gamepad() {
+ polling_thread_->Stop();
+ delegate_->OnGamepadDestroying(this);
+ aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow())
+ ->RemoveObserver(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// aura::client::FocusChangeObserver overrides:
+
+void Gamepad::OnWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus) {
+ DCHECK(origin_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);
+ }
+ }
+
+ bool focused = target && delegate_->CanAcceptGamepadEventsForSurface(target);
+ if (focused) {
+ polling_thread_->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&Gamepad::ResumePolling, base::Unretained(this)));
+ } else {
+ polling_thread_->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&Gamepad::PausePolling, base::Unretained(this)));
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Gamepad, private:
+
+void Gamepad::PausePolling() {
+ DCHECK(polling_thread_checker_.CalledOnValidThread());
+ is_paused_ = true;
+}
+
+void Gamepad::ResumePolling() {
+ DCHECK(polling_thread_checker_.CalledOnValidThread());
+ if (!is_paused_)
+ return;
+
+ is_paused_ = false;
+ ScheduleOnPoll();
+}
+
+void Gamepad::ScheduleOnPoll() {
+ DCHECK(polling_thread_checker_.CalledOnValidThread());
+ if (is_paused_) {
+ internal_fetcher_.reset();
+ return;
+ }
+
+ if (has_poll_scheduled_)
+ return;
+
+ has_poll_scheduled_ = true;
+ polling_thread_->task_runner()->PostDelayedTask(
+ FROM_HERE, base::Bind(&Gamepad::OnPoll, base::Unretained(this)),
+ base::TimeDelta::FromMilliseconds(kPollingTimeIntervalMs));
+}
+
+void Gamepad::OnPoll() {
+ DCHECK(polling_thread_checker_.CalledOnValidThread());
+ blink::WebGamepads new_state = state_;
+
+ if (external_fetcher_) {
reveman 2016/07/07 22:14:02 hm, when I suggested a refactor to avoid confusing
denniskempin 2016/07/08 23:49:40 Done.
+ external_fetcher_->GetGamepadData(&new_state, false);
+ } else {
+ if (!internal_fetcher_)
+ internal_fetcher_.reset(new device::GamepadPlatformDataFetcher());
+ internal_fetcher_->GetGamepadData(&new_state, false);
+ }
+
+ if (std::max(new_state.length, state_.length) > 0) {
+ if (new_state.items[0].connected != state_.items[0].connected ||
+ new_state.items[0].timestamp > state_.items[0].timestamp) {
+ origin_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(post_gamepad_changes_callback_, new_state.items[0]));
+ }
+ }
+
+ state_ = new_state;
+ has_poll_scheduled_ = false;
+ ScheduleOnPoll();
+}
+
+void Gamepad::PostGamepadChanges(const blink::WebGamepad new_pad) {
+ DCHECK(origin_thread_checker_.CalledOnValidThread());
+ bool send_frame = false;
+
+ // Update connection state.
+ if (new_pad.connected != pad_state_.connected) {
+ delegate_->OnStateChange(new_pad.connected);
+ }
+
+ if (!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_.axesLength, new_pad.axesLength); ++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_.buttonsLength, new_pad.buttonsLength);
+ ++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;
+}
+
+} // namespace exo

Powered by Google App Engine
This is Rietveld 408576698