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

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: Focus handling. Process gamepad delta on origin thread. Add focus unittest. 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;
reveman 2016/06/30 18:06:11 I'm still not sure we can land this unless we can
denniskempin 2016/07/01 02:34:35 I've done some experimenting. What we can do is
reveman 2016/07/07 22:14:02 Thanks for looking into this. This sgtm.
33
34 } // namespace
35
36 ////////////////////////////////////////////////////////////////////////////////
37 // Gamepad, public:
38
39 Gamepad::Gamepad(GamepadDelegate* delegate) : Gamepad(delegate, nullptr) {}
40
41 Gamepad::Gamepad(GamepadDelegate* delegate,
42 std::unique_ptr<device::GamepadDataFetcher> fetcher)
43 : delegate_(delegate),
44 origin_task_runner_(base::ThreadTaskRunnerHandle::Get()),
45 polling_thread_(new base::Thread("Exo gamepad polling thread")),
46 fetcher_(std::move(fetcher)),
47 weak_factory_(this) {
48 polling_thread_checker_.DetachFromThread();
49 weak_this_ = weak_factory_.GetWeakPtr();
50
51 aura::client::FocusClient* focus_client =
52 aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
53 focus_client->AddObserver(this);
54 OnWindowFocused(focus_client->GetFocusedWindow(), nullptr);
55
56 polling_thread_->StartWithOptions(
57 base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
58 polling_thread_->task_runner()->PostTask(
59 FROM_HERE,
60 base::Bind(&Gamepad::InitializePollingThread, base::Unretained(this)));
61 }
62
63 Gamepad::~Gamepad() {
64 polling_thread_->Stop();
65 delegate_->OnGamepadDestroying(this);
66 aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow())
67 ->RemoveObserver(this);
68 }
69
70 ////////////////////////////////////////////////////////////////////////////////
71 // aura::client::FocusChangeObserver overrides:
72
73 void Gamepad::OnWindowFocused(aura::Window* gained_focus,
74 aura::Window* lost_focus) {
75 DCHECK(origin_thread_checker_.CalledOnValidThread());
76 Surface* target = nullptr;
77 if (gained_focus) {
78 target = Surface::AsSurface(gained_focus);
79 if (!target) {
80 aura::Window* top_level_window = gained_focus->GetToplevelWindow();
81 if (top_level_window)
82 target = ShellSurface::GetMainSurface(top_level_window);
83 }
84 }
85 exo_focused_ = target && delegate_->CanAcceptGamepadEventsForSurface(target);
reveman 2016/06/30 18:06:11 What if the target is destroyed? Don't we need to
denniskempin 2016/07/01 02:34:35 Shouldn't we get an OnWindowFocused event in that
reveman 2016/07/07 22:14:02 Probably fine for now but it would be good in the
86 }
87
88 ////////////////////////////////////////////////////////////////////////////////
89 // Gamepad, private:
90
91 void Gamepad::ScheduleOnPoll() {
92 polling_thread_->task_runner()->PostDelayedTask(
93 FROM_HERE, base::Bind(&Gamepad::OnPoll, base::Unretained(this)),
94 base::TimeDelta::FromMilliseconds(kPollingTimeIntervalMs));
95 }
96
97 void Gamepad::InitializePollingThread() {
98 DCHECK(polling_thread_checker_.CalledOnValidThread());
99 // The platform data fetcher has to be initialized on the polling thread.
100 if (!fetcher_)
101 fetcher_.reset(new device::GamepadPlatformDataFetcher());
102 ScheduleOnPoll();
103 }
104
105 void Gamepad::OnPoll() {
106 DCHECK(polling_thread_checker_.CalledOnValidThread());
107 DCHECK(fetcher_);
108
109 blink::WebGamepads new_state = state_;
110 fetcher_->GetGamepadData(&new_state, false);
111
112 if (std::max(new_state.length, state_.length) > 0) {
113 if (new_state.items[0].connected != state_.items[0].connected ||
114 new_state.items[0].timestamp > state_.items[0].timestamp) {
115 origin_task_runner_->PostTask(
116 FROM_HERE, base::Bind(&Gamepad::PostGamepadChanges, weak_this_,
117 new_state.items[0]));
118 }
119 }
120
121 state_ = new_state;
122 ScheduleOnPoll();
123 }
124
125 void Gamepad::PostGamepadChanges(const blink::WebGamepad new_pad) {
126 DCHECK(origin_thread_checker_.CalledOnValidThread());
127 bool send_frame = false;
128
129 // Do not update internal state, nor send updates until we are focused again.
130 if (!exo_focused_)
131 return;
132
133 // Update connection state.
134 if (new_pad.connected != pad_state_.connected) {
135 delegate_->OnStateChange(new_pad.connected);
136 }
137
138 if (!new_pad.connected || new_pad.timestamp <= pad_state_.timestamp) {
139 pad_state_ = new_pad;
140 return;
141 }
142
143 // Notify delegate of updated axes.
144 for (size_t axis = 0;
145 axis < std::max(pad_state_.axesLength, new_pad.axesLength); ++axis) {
146 if (!GamepadButtonValuesAreEqual(new_pad.axes[axis],
147 pad_state_.axes[axis])) {
148 send_frame = true;
149 delegate_->OnAxis(axis, new_pad.axes[axis]);
150 }
151 }
152
153 // Notify delegate of updated buttons.
154 for (size_t button_id = 0;
155 button_id < std::max(pad_state_.buttonsLength, new_pad.buttonsLength);
156 ++button_id) {
157 auto button = pad_state_.buttons[button_id];
158 auto new_button = new_pad.buttons[button_id];
159 if (button.pressed != new_button.pressed ||
160 !GamepadButtonValuesAreEqual(button.value, new_button.value)) {
161 send_frame = true;
162 delegate_->OnButton(button_id, new_button.pressed, new_button.value);
163 }
164 }
165 if (send_frame)
166 delegate_->OnFrame();
167
168 pad_state_ = new_pad;
169 }
170
171 } // namespace exo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698