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

Side by Side 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, 5 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/exo/gamepad.h"
6
7 #include <cmath>
8
9 #include "ash/shell.h"
10 #include "base/bind.h"
11 #include "base/location.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/threading/thread.h"
14 #include "base/threading/thread_task_runner_handle.h"
15 #include "components/exo/gamepad_delegate.h"
16 #include "components/exo/shell_surface.h"
17 #include "components/exo/surface.h"
18 #include "device/gamepad/gamepad_data_fetcher.h"
19 #include "device/gamepad/gamepad_platform_data_fetcher.h"
20 #include "ui/aura/client/focus_client.h"
21 #include "ui/aura/window.h"
22
23 namespace exo {
24 namespace {
25
26 constexpr double kGamepadButtonValueEpsilon = 0.001;
27 bool GamepadButtonValuesAreEqual(double a, double b) {
28 return fabs(a - b) < kGamepadButtonValueEpsilon;
29 }
30
31 // Time between gamepad polls in milliseconds.
32 constexpr unsigned kPollingTimeIntervalMs = 16;
33
34 } // namespace
35
36 ////////////////////////////////////////////////////////////////////////////////
37 // Gamepad, public:
38
39 Gamepad::Gamepad(GamepadDelegate* delegate) : Gamepad(delegate, nullptr) {}
40
41 Gamepad::Gamepad(GamepadDelegate* delegate, device::GamepadDataFetcher* fetcher)
42 : delegate_(delegate),
43 origin_task_runner_(base::ThreadTaskRunnerHandle::Get()),
44 polling_thread_(new base::Thread("Exo gamepad polling thread")),
45 external_fetcher_(fetcher),
46 weak_factory_(this) {
47 polling_thread_checker_.DetachFromThread();
48 post_gamepad_changes_callback_ =
49 base::Bind(&Gamepad::PostGamepadChanges, weak_factory_.GetWeakPtr());
50
51 polling_thread_->StartWithOptions(
52 base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
53
54 aura::client::FocusClient* focus_client =
55 aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
56 focus_client->AddObserver(this);
57 OnWindowFocused(focus_client->GetFocusedWindow(), nullptr);
58 }
59
60 Gamepad::~Gamepad() {
61 polling_thread_->Stop();
62 delegate_->OnGamepadDestroying(this);
63 aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow())
64 ->RemoveObserver(this);
65 }
66
67 ////////////////////////////////////////////////////////////////////////////////
68 // aura::client::FocusChangeObserver overrides:
69
70 void Gamepad::OnWindowFocused(aura::Window* gained_focus,
71 aura::Window* lost_focus) {
72 DCHECK(origin_thread_checker_.CalledOnValidThread());
73 Surface* target = nullptr;
74 if (gained_focus) {
75 target = Surface::AsSurface(gained_focus);
76 if (!target) {
77 aura::Window* top_level_window = gained_focus->GetToplevelWindow();
78 if (top_level_window)
79 target = ShellSurface::GetMainSurface(top_level_window);
80 }
81 }
82
83 bool focused = target && delegate_->CanAcceptGamepadEventsForSurface(target);
84 if (focused) {
85 polling_thread_->task_runner()->PostTask(
86 FROM_HERE, base::Bind(&Gamepad::ResumePolling, base::Unretained(this)));
87 } else {
88 polling_thread_->task_runner()->PostTask(
89 FROM_HERE, base::Bind(&Gamepad::PausePolling, base::Unretained(this)));
90 }
91 }
92
93 ////////////////////////////////////////////////////////////////////////////////
94 // Gamepad, private:
95
96 void Gamepad::PausePolling() {
97 DCHECK(polling_thread_checker_.CalledOnValidThread());
98 is_paused_ = true;
99 }
100
101 void Gamepad::ResumePolling() {
102 DCHECK(polling_thread_checker_.CalledOnValidThread());
103 if (!is_paused_)
104 return;
105
106 is_paused_ = false;
107 ScheduleOnPoll();
108 }
109
110 void Gamepad::ScheduleOnPoll() {
111 DCHECK(polling_thread_checker_.CalledOnValidThread());
112 if (is_paused_) {
113 internal_fetcher_.reset();
114 return;
115 }
116
117 if (has_poll_scheduled_)
118 return;
119
120 has_poll_scheduled_ = true;
121 polling_thread_->task_runner()->PostDelayedTask(
122 FROM_HERE, base::Bind(&Gamepad::OnPoll, base::Unretained(this)),
123 base::TimeDelta::FromMilliseconds(kPollingTimeIntervalMs));
124 }
125
126 void Gamepad::OnPoll() {
127 DCHECK(polling_thread_checker_.CalledOnValidThread());
128 blink::WebGamepads new_state = state_;
129
130 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.
131 external_fetcher_->GetGamepadData(&new_state, false);
132 } else {
133 if (!internal_fetcher_)
134 internal_fetcher_.reset(new device::GamepadPlatformDataFetcher());
135 internal_fetcher_->GetGamepadData(&new_state, false);
136 }
137
138 if (std::max(new_state.length, state_.length) > 0) {
139 if (new_state.items[0].connected != state_.items[0].connected ||
140 new_state.items[0].timestamp > state_.items[0].timestamp) {
141 origin_task_runner_->PostTask(
142 FROM_HERE,
143 base::Bind(post_gamepad_changes_callback_, new_state.items[0]));
144 }
145 }
146
147 state_ = new_state;
148 has_poll_scheduled_ = false;
149 ScheduleOnPoll();
150 }
151
152 void Gamepad::PostGamepadChanges(const blink::WebGamepad new_pad) {
153 DCHECK(origin_thread_checker_.CalledOnValidThread());
154 bool send_frame = false;
155
156 // Update connection state.
157 if (new_pad.connected != pad_state_.connected) {
158 delegate_->OnStateChange(new_pad.connected);
159 }
160
161 if (!new_pad.connected || new_pad.timestamp <= pad_state_.timestamp) {
162 pad_state_ = new_pad;
163 return;
164 }
165
166 // Notify delegate of updated axes.
167 for (size_t axis = 0;
168 axis < std::max(pad_state_.axesLength, new_pad.axesLength); ++axis) {
169 if (!GamepadButtonValuesAreEqual(new_pad.axes[axis],
170 pad_state_.axes[axis])) {
171 send_frame = true;
172 delegate_->OnAxis(axis, new_pad.axes[axis]);
173 }
174 }
175
176 // Notify delegate of updated buttons.
177 for (size_t button_id = 0;
178 button_id < std::max(pad_state_.buttonsLength, new_pad.buttonsLength);
179 ++button_id) {
180 auto button = pad_state_.buttons[button_id];
181 auto new_button = new_pad.buttons[button_id];
182 if (button.pressed != new_button.pressed ||
183 !GamepadButtonValuesAreEqual(button.value, new_button.value)) {
184 send_frame = true;
185 delegate_->OnButton(button_id, new_button.pressed, new_button.value);
186 }
187 }
188 if (send_frame)
189 delegate_->OnFrame();
190
191 pad_state_ = new_pad;
192 }
193
194 } // namespace exo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698