Get timestamps and ids working in WK2 gamepads (and test them!)
[WebKit-https.git] / Source / WebKit2 / UIProcess / Gamepad / UIGamepadProvider.cpp
1 /*
2  * Copyright (C) 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "UIGamepadProvider.h"
28
29 #if ENABLE(GAMEPAD)
30
31 #include "GamepadData.h"
32 #include "UIGamepad.h"
33 #include "WebProcessPool.h"
34 #include <WebCore/HIDGamepadProvider.h>
35 #include <WebCore/MockGamepadProvider.h>
36 #include <wtf/NeverDestroyed.h>
37
38 using namespace WebCore;
39
40 namespace WebKit {
41
42 static const double maximumGamepadUpdateInterval = 1 / 120.0;
43
44 UIGamepadProvider& UIGamepadProvider::singleton()
45 {
46     static NeverDestroyed<UIGamepadProvider> sharedProvider;
47     return sharedProvider;
48 }
49
50 UIGamepadProvider::UIGamepadProvider()
51     : m_gamepadSyncTimer(RunLoop::main(), this, &UIGamepadProvider::gamepadSyncTimerFired)
52 {
53     platformSetDefaultGamepadProvider();
54 }
55
56 UIGamepadProvider::~UIGamepadProvider()
57 {
58     if (!m_processPoolsUsingGamepads.isEmpty())
59         GamepadProvider::singleton().stopMonitoringGamepads(*this);
60 }
61
62 void UIGamepadProvider::gamepadSyncTimerFired()
63 {
64     auto webPageProxy = platformWebPageProxyForGamepadInput();
65     if (!webPageProxy || !m_processPoolsUsingGamepads.contains(&webPageProxy->process().processPool()))
66         return;
67
68     webPageProxy->gamepadActivity(snapshotGamepads());
69 }
70
71 void UIGamepadProvider::scheduleGamepadStateSync()
72 {
73     if (!m_isMonitoringGamepads || m_gamepadSyncTimer.isActive())
74         return;
75
76     if (m_gamepads.isEmpty() || m_processPoolsUsingGamepads.isEmpty()) {
77         m_gamepadSyncTimer.stop();
78         return;
79     }
80
81     m_gamepadSyncTimer.startOneShot(maximumGamepadUpdateInterval);
82 }
83
84 void UIGamepadProvider::setInitialConnectedGamepads(const Vector<PlatformGamepad*>& initialGamepads)
85 {
86     ASSERT(!m_hasInitialGamepads);
87
88     m_gamepads.resize(initialGamepads.size());
89
90     for (auto* gamepad : initialGamepads) {
91         if (!gamepad)
92             continue;
93         m_gamepads[gamepad->index()] = std::make_unique<UIGamepad>(*gamepad);
94     }
95
96     for (auto& pool : m_processPoolsUsingGamepads)
97         pool->setInitialConnectedGamepads(m_gamepads);
98
99     m_hasInitialGamepads = true;
100 }
101
102 void UIGamepadProvider::platformGamepadConnected(PlatformGamepad& gamepad)
103 {
104     if (m_gamepads.size() <= gamepad.index())
105         m_gamepads.resize(gamepad.index() + 1);
106
107     ASSERT(!m_gamepads[gamepad.index()]);
108     m_gamepads[gamepad.index()] = std::make_unique<UIGamepad>(gamepad);
109
110     scheduleGamepadStateSync();
111
112     for (auto& pool : m_processPoolsUsingGamepads)
113         pool->gamepadConnected(*m_gamepads[gamepad.index()]);
114 }
115
116 void UIGamepadProvider::platformGamepadDisconnected(PlatformGamepad& gamepad)
117 {
118     ASSERT(gamepad.index() < m_gamepads.size());
119     ASSERT(m_gamepads[gamepad.index()]);
120
121     std::unique_ptr<UIGamepad> disconnectedGamepad = WTFMove(m_gamepads[gamepad.index()]);
122
123     scheduleGamepadStateSync();
124
125     for (auto& pool : m_processPoolsUsingGamepads)
126         pool->gamepadDisconnected(*disconnectedGamepad);
127 }
128
129 void UIGamepadProvider::platformGamepadInputActivity()
130 {
131     auto platformGamepads = GamepadProvider::singleton().platformGamepads();
132     ASSERT(platformGamepads.size() == m_gamepads.size());
133
134     for (size_t i = 0; i < platformGamepads.size(); ++i) {
135         if (!platformGamepads[i]) {
136             ASSERT(!m_gamepads[i]);
137             continue;
138         }
139
140         ASSERT(m_gamepads[i]);
141         m_gamepads[i]->updateFromPlatformGamepad(*platformGamepads[i]);
142     }
143
144     scheduleGamepadStateSync();
145 }
146
147 void UIGamepadProvider::processPoolStartedUsingGamepads(WebProcessPool& pool)
148 {
149     ASSERT(!m_processPoolsUsingGamepads.contains(&pool));
150     m_processPoolsUsingGamepads.add(&pool);
151
152     if (!m_isMonitoringGamepads && platformWebPageProxyForGamepadInput())
153         startMonitoringGamepads();
154
155     scheduleGamepadStateSync();
156 }
157
158 void UIGamepadProvider::processPoolStoppedUsingGamepads(WebProcessPool& pool)
159 {
160     ASSERT(m_processPoolsUsingGamepads.contains(&pool));
161     m_processPoolsUsingGamepads.remove(&pool);
162
163     if (m_isMonitoringGamepads && !platformWebPageProxyForGamepadInput())
164         platformStopMonitoringInput();
165
166     scheduleGamepadStateSync();
167 }
168
169 void UIGamepadProvider::viewBecameActive(WebPageProxy& page)
170 {
171     if (!m_processPoolsUsingGamepads.contains(&page.process().processPool()))
172         return;
173
174     if (!m_isMonitoringGamepads)
175         startMonitoringGamepads();
176
177     if (platformWebPageProxyForGamepadInput())
178         platformStartMonitoringInput();
179 }
180
181 void UIGamepadProvider::viewBecameInactive(WebPageProxy& page)
182 {
183     auto pageForGamepadInput = platformWebPageProxyForGamepadInput();
184     if (pageForGamepadInput == &page)
185         platformStopMonitoringInput();
186 }
187
188 void UIGamepadProvider::startMonitoringGamepads()
189 {
190     if (m_isMonitoringGamepads)
191         return;
192
193     m_isMonitoringGamepads = true;
194     ASSERT(!m_processPoolsUsingGamepads.isEmpty());
195     GamepadProvider::singleton().startMonitoringGamepads(*this);
196 }
197
198 void UIGamepadProvider::stopMonitoringGamepads()
199 {
200     if (!m_isMonitoringGamepads)
201         return;
202
203     m_isMonitoringGamepads = false;
204
205     ASSERT(m_processPoolsUsingGamepads.isEmpty());
206     GamepadProvider::singleton().stopMonitoringGamepads(*this);
207
208     m_gamepads.clear();
209 }
210
211 Vector<GamepadData> UIGamepadProvider::snapshotGamepads()
212 {
213     Vector<GamepadData> gamepadDatas;
214     gamepadDatas.reserveInitialCapacity(m_gamepads.size());
215
216     for (auto& gamepad : m_gamepads) {
217         if (gamepad)
218             gamepadDatas.uncheckedAppend(gamepad->condensedGamepadData());
219         else
220             gamepadDatas.uncheckedAppend({ });
221     }
222
223     return gamepadDatas;
224 }
225
226 #if !PLATFORM(MAC)
227
228 void UIGamepadProvider::platformSetDefaultGamepadProvider()
229 {
230     // FIXME: Implement for other platforms
231 }
232
233 void UIGamepadProvider::platformStartMonitoringGamepads()
234 {
235     // FIXME: Implement for other platforms
236 }
237
238 void UIGamepadProvider::platformStopMonitoringGamepads()
239 {
240     // FIXME: Implement for other platforms
241 }
242
243 const Vector<PlatformGamepad*>& UIGamepadProvider::platformGamepads()
244 {
245     static NeverDestroyed<Vector<PlatformGamepad*>> emptyGamepads;
246     return emptyGamepads;
247
248     // FIXME: Implement for other platforms
249 }
250
251 WebProcessProxy* UIGamepadProvider::platformWebProcessProxyForGamepadInput()
252 {
253     // FIXME: Implement for other platforms
254 }
255
256 void UIGamepadProvider::platformStopMonitoringInput()
257 {
258 }
259
260 void UIGamepadProvider::platformStartMonitoringInput()
261 {
262 }
263
264 #endif // !PLATFORM(MAC)
265
266 }
267
268 #endif // ENABLE(GAMEPAD)