Merge lp:~robertcarr/mir/input-injecter-api into lp:mir
- input-injecter-api
- Merge into development-branch
Status: | Superseded | ||||
---|---|---|---|---|---|
Proposed branch: | lp:~robertcarr/mir/input-injecter-api | ||||
Merge into: | lp:mir | ||||
Diff against target: |
1070 lines (+735/-3) 22 files modified
3rd_party/android-input/android/frameworks/base/services/input/InputDispatcher.cpp (+55/-0) 3rd_party/android-input/android/frameworks/base/services/input/InputDispatcher.h (+13/-2) include/server/mir/default_server_configuration.h (+3/-0) include/server/mir/input/android/dispatcher_input_configuration.h (+2/-0) include/server/mir/input/input_configuration.h (+2/-0) include/server/mir/input/null_input_configuration.h (+1/-0) include/server/mir/shell/input_injecter.h (+55/-0) include/server/mir/shell/surface.h (+4/-0) include/shared/mir/input/android/android_input_lexicon.h (+1/-0) include/test/mir_test_doubles/mock_input_dispatcher.h (+2/-0) src/server/default_server_configuration.cpp (+10/-0) src/server/input/android/CMakeLists.txt (+1/-0) src/server/input/android/android_input_injecter.cpp (+58/-0) src/server/input/android/android_input_injecter.h (+69/-0) src/server/input/android/dispatcher_input_configuration.cpp (+10/-0) src/server/input/null_input_configuration.cpp (+13/-0) src/server/shell/surface.cpp (+13/-0) src/shared/input/android/android_input_lexicon.cpp (+58/-0) tests/acceptance-tests/test_client_input.cpp (+121/-0) tests/unit-tests/input/android/CMakeLists.txt (+1/-0) tests/unit-tests/input/android/test_android_input_injecter.cpp (+93/-0) tests/unit-tests/input/android/test_android_input_lexicon.cpp (+150/-1) |
||||
To merge this branch: | bzr merge lp:~robertcarr/mir/input-injecter-api | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mir development team | Pending | ||
Review via email: mp+188743@code.launchpad.net |
This proposal has been superseded by a proposal from 2013-10-02.
Commit message
Implement input injection API to satisfy the shell hud use case.
Description of the change
Implement input injection API to satisfy the shell hud use case.
-- Still work in progress -- needs a little cleanup and an additional unit test for android input lexicon. Just getting some early air. --
- 1104. By Robert Carr
-
Complete android input lexicon reversal tests
- 1105. By Robert Carr
-
Merge development branch
- 1106. By Robert Carr
-
Clarify exception case
- 1107. By Robert Carr
-
Cleanup
- 1108. By Robert Carr
-
Cleanup
- 1109. By Robert Carr
-
Fix unitialized event structures in test
- 1110. By Robert Carr
-
Correct uninitialized portion of android event to silence valgrind errors
- 1111. By Robert Carr
-
Correct ordering
Unmerged revisions
- 1111. By Robert Carr
-
Correct ordering
- 1110. By Robert Carr
-
Correct uninitialized portion of android event to silence valgrind errors
- 1109. By Robert Carr
-
Fix unitialized event structures in test
- 1108. By Robert Carr
-
Cleanup
- 1107. By Robert Carr
-
Cleanup
- 1106. By Robert Carr
-
Clarify exception case
- 1105. By Robert Carr
-
Merge development branch
- 1104. By Robert Carr
-
Complete android input lexicon reversal tests
- 1103. By Robert Carr
-
Implement injected dispatch of motion events. ACceptance test passes
- 1102. By Robert Carr
-
Support reverse motion event mapping
Preview Diff
1 | === modified file '3rd_party/android-input/android/frameworks/base/services/input/InputDispatcher.cpp' |
2 | --- 3rd_party/android-input/android/frameworks/base/services/input/InputDispatcher.cpp 2013-08-28 03:41:48 +0000 |
3 | +++ 3rd_party/android-input/android/frameworks/base/services/input/InputDispatcher.cpp 2013-10-01 22:23:19 +0000 |
4 | @@ -4266,6 +4266,61 @@ |
5 | return haveSlipperyForegroundWindow; |
6 | } |
7 | |
8 | +void InputDispatcher::publishEventToConnectionLocked(sp<Connection> const& connection, InputEvent const* event) |
9 | +{ |
10 | + switch (event->getType()) |
11 | + { |
12 | + case AINPUT_EVENT_TYPE_KEY: |
13 | + { |
14 | + auto seq = DispatchEntry::nextSeq(); |
15 | + auto kev = static_cast<KeyEvent const*>(event); |
16 | + auto status = connection->inputPublisher.publishKeyEvent(seq, |
17 | + kev->getDeviceId(), kev->getSource(), |
18 | + kev->getAction(), kev->getFlags(), |
19 | + kev->getKeyCode(), kev->getScanCode(), |
20 | + kev->getMetaState(), kev->getRepeatCount(), kev->getDownTime(), |
21 | + kev->getEventTime()); |
22 | + |
23 | + input_report->published_key_event(connection->inputChannel->getFd(), |
24 | + seq, |
25 | + kev->getEventTime()); |
26 | + break; |
27 | + } |
28 | + case AINPUT_EVENT_TYPE_MOTION: |
29 | + { |
30 | + auto seq = DispatchEntry::nextSeq(); |
31 | + auto mev = static_cast<MotionEvent const*>(event); |
32 | + auto status = connection->inputPublisher.publishMotionEvent(seq, |
33 | + mev->getDeviceId(), mev->getSource(), |
34 | + mev->getAction(), mev->getFlags(), |
35 | + mev->getEdgeFlags(), mev->getMetaState(), mev->getButtonState(), |
36 | + mev->getXOffset(), mev->getYOffset(), |
37 | + mev->getXPrecision(), mev->getYPrecision(), |
38 | + mev->getDownTime(), mev->getEventTime(), |
39 | + mev->getPointerCount(), mev->getPointerProperties(), mev->getSamplePointerCoords()); |
40 | + input_report->published_motion_event(connection->inputChannel->getFd(), |
41 | + seq, |
42 | + mev->getEventTime()); |
43 | + } |
44 | + default: |
45 | + break; |
46 | + } |
47 | +} |
48 | + |
49 | + |
50 | +void InputDispatcher::injectEventToWindow(sp<InputWindowHandle> const& windowHandle, InputEvent const* event) |
51 | +{ |
52 | + AutoMutex _l(mLock); |
53 | + |
54 | + auto index = getConnectionIndexLocked(windowHandle->getInfo()->inputChannel); |
55 | + |
56 | + if (index >= 0) |
57 | + { |
58 | + auto connection = mConnectionsByFd.valueAt(index); |
59 | + publishEventToConnectionLocked(connection, event); |
60 | + } |
61 | +} |
62 | + |
63 | |
64 | // --- InputDispatcherThread --- |
65 | |
66 | |
67 | === modified file '3rd_party/android-input/android/frameworks/base/services/input/InputDispatcher.h' |
68 | --- 3rd_party/android-input/android/frameworks/base/services/input/InputDispatcher.h 2013-05-30 19:24:29 +0000 |
69 | +++ 3rd_party/android-input/android/frameworks/base/services/input/InputDispatcher.h 2013-10-01 22:23:19 +0000 |
70 | @@ -323,6 +323,13 @@ |
71 | * This method may be called on any thread. |
72 | */ |
73 | virtual void setKeyboardFocus(const sp<InputWindowHandle>& windowHandle) = 0; |
74 | + |
75 | + /* |
76 | + * Asynchronously publish an event directly to a given input channel. |
77 | + * |
78 | + * This method may be called on any thread. |
79 | + */ |
80 | + virtual void injectEventToWindow(sp<InputWindowHandle> const& windowHandle, InputEvent const* event) = 0; |
81 | /* |
82 | * Notify that a window handle is about to vanish |
83 | |
84 | @@ -423,6 +430,8 @@ |
85 | virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, |
86 | const sp<InputWindowHandle>& inputWindowHandle, bool monitor); |
87 | virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel); |
88 | + |
89 | + void injectEventToWindow(sp<InputWindowHandle> const& windowHandle, InputEvent const* event); |
90 | |
91 | private: |
92 | std::shared_ptr<mir::input::InputReport> const input_report; |
93 | @@ -586,10 +595,10 @@ |
94 | return targetFlags & InputTarget::FLAG_SPLIT; |
95 | } |
96 | |
97 | + static uint32_t nextSeq(); |
98 | + |
99 | private: |
100 | static android_atomic_int32_t sNextSeqAtomic; |
101 | - |
102 | - static uint32_t nextSeq(); |
103 | }; |
104 | |
105 | // A command entry captures state and behavior for an action to be performed in the |
106 | @@ -1117,6 +1126,8 @@ |
107 | int32_t injectionResult, nsecs_t timeSpentWaitingForApplication); |
108 | |
109 | void setKeyboardFocusLocked(const sp<InputWindowHandle>& windowHandle); |
110 | + |
111 | + void publishEventToConnectionLocked(sp<Connection> const& connection, InputEvent const* event); |
112 | }; |
113 | |
114 | /* Enqueues and dispatches input events, endlessly. */ |
115 | |
116 | === modified file 'include/server/mir/default_server_configuration.h' |
117 | --- include/server/mir/default_server_configuration.h 2013-09-27 16:53:41 +0000 |
118 | +++ include/server/mir/default_server_configuration.h 2013-10-01 22:23:19 +0000 |
119 | @@ -58,6 +58,7 @@ |
120 | class SurfaceBuilder; |
121 | class SurfaceController; |
122 | class InputTargeter; |
123 | +class InputInjecter; |
124 | class SessionContainer; |
125 | class FocusSetter; |
126 | class FocusSequence; |
127 | @@ -225,6 +226,7 @@ |
128 | virtual std::shared_ptr<input::CompositeEventFilter> the_composite_event_filter(); |
129 | virtual std::shared_ptr<surfaces::InputRegistrar> the_input_registrar(); |
130 | virtual std::shared_ptr<shell::InputTargeter> the_input_targeter(); |
131 | + virtual std::shared_ptr<shell::InputInjecter> the_input_injecter(); |
132 | virtual std::shared_ptr<input::CursorListener> the_cursor_listener(); |
133 | virtual std::shared_ptr<input::InputRegion> the_input_region(); |
134 | /** @} */ |
135 | @@ -263,6 +265,7 @@ |
136 | CachedPtr<input::InputRegion> input_region; |
137 | CachedPtr<surfaces::InputRegistrar> input_registrar; |
138 | CachedPtr<shell::InputTargeter> input_targeter; |
139 | + CachedPtr<shell::InputInjecter> input_injecter; |
140 | CachedPtr<input::CursorListener> cursor_listener; |
141 | CachedPtr<graphics::Platform> graphics_platform; |
142 | CachedPtr<graphics::BufferInitializer> buffer_initializer; |
143 | |
144 | === modified file 'include/server/mir/input/android/dispatcher_input_configuration.h' |
145 | --- include/server/mir/input/android/dispatcher_input_configuration.h 2013-09-10 16:42:04 +0000 |
146 | +++ include/server/mir/input/android/dispatcher_input_configuration.h 2013-10-01 22:23:19 +0000 |
147 | @@ -93,6 +93,7 @@ |
148 | std::shared_ptr<surfaces::InputRegistrar> the_input_registrar(); |
149 | std::shared_ptr<shell::InputTargeter> the_input_targeter(); |
150 | std::shared_ptr<input::InputManager> the_input_manager(); |
151 | + std::shared_ptr<shell::InputInjecter> the_input_injecter(); |
152 | |
153 | void set_input_targets(std::shared_ptr<input::InputTargets> const& targets); |
154 | |
155 | @@ -119,6 +120,7 @@ |
156 | CachedPtr<InputRegistrar> input_registrar; |
157 | |
158 | CachedPtr<shell::InputTargeter> input_targeter; |
159 | + CachedPtr<shell::InputInjecter> input_injecter; |
160 | |
161 | CachedAndroidPtr<droidinput::InputDispatcherPolicyInterface> dispatcher_policy; |
162 | }; |
163 | |
164 | === modified file 'include/server/mir/input/input_configuration.h' |
165 | --- include/server/mir/input/input_configuration.h 2013-05-24 19:27:37 +0000 |
166 | +++ include/server/mir/input/input_configuration.h 2013-10-01 22:23:19 +0000 |
167 | @@ -30,6 +30,7 @@ |
168 | namespace shell |
169 | { |
170 | class InputTargeter; |
171 | +class InputInjecter; |
172 | } |
173 | namespace input |
174 | { |
175 | @@ -44,6 +45,7 @@ |
176 | virtual std::shared_ptr<surfaces::InputRegistrar> the_input_registrar() = 0; |
177 | virtual std::shared_ptr<shell::InputTargeter> the_input_targeter() = 0; |
178 | virtual std::shared_ptr<input::InputManager> the_input_manager() = 0; |
179 | + virtual std::shared_ptr<shell::InputInjecter> the_input_injecter() = 0; |
180 | |
181 | virtual void set_input_targets(std::shared_ptr<input::InputTargets> const& targets) = 0; |
182 | |
183 | |
184 | === modified file 'include/server/mir/input/null_input_configuration.h' |
185 | --- include/server/mir/input/null_input_configuration.h 2013-05-28 13:31:27 +0000 |
186 | +++ include/server/mir/input/null_input_configuration.h 2013-10-01 22:23:19 +0000 |
187 | @@ -34,6 +34,7 @@ |
188 | |
189 | std::shared_ptr<surfaces::InputRegistrar> the_input_registrar(); |
190 | std::shared_ptr<shell::InputTargeter> the_input_targeter(); |
191 | + std::shared_ptr<shell::InputInjecter> the_input_injecter(); |
192 | std::shared_ptr<InputManager> the_input_manager(); |
193 | |
194 | void set_input_targets(std::shared_ptr<InputTargets> const& /* targets */); |
195 | |
196 | === added file 'include/server/mir/shell/input_injecter.h' |
197 | --- include/server/mir/shell/input_injecter.h 1970-01-01 00:00:00 +0000 |
198 | +++ include/server/mir/shell/input_injecter.h 2013-10-01 22:23:19 +0000 |
199 | @@ -0,0 +1,55 @@ |
200 | +/* |
201 | + * Copyright © 2013 Canonical Ltd. |
202 | + * |
203 | + * This program is free software: you can redistribute it and/or modify it |
204 | + * under the terms of the GNU General Public License version 3, |
205 | + * as published by the Free Software Foundation. |
206 | + * |
207 | + * This program is distributed in the hope that it will be useful, |
208 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
209 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
210 | + * GNU General Public License for more details. |
211 | + * |
212 | + * You should have received a copy of the GNU General Public License |
213 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
214 | + * |
215 | + * Authored by: Robert Carr <robert.carr@canonical.com> |
216 | + */ |
217 | + |
218 | +#ifndef MIR_SHELL_INPUT_INJECTER_H_ |
219 | +#define MIR_SHELL_INPUT_INJECTER_H_ |
220 | + |
221 | +#include "mir_toolkit/event.h" |
222 | + |
223 | +#include <memory> |
224 | + |
225 | +namespace mir |
226 | +{ |
227 | + |
228 | +namespace input |
229 | +{ |
230 | +class InputChannel; |
231 | +} |
232 | + |
233 | +namespace shell |
234 | +{ |
235 | + |
236 | +/// An interface used to control the selection of keyboard input focus. |
237 | +class InputInjecter |
238 | +{ |
239 | +public: |
240 | + virtual ~InputInjecter() = default; |
241 | + |
242 | + virtual void inject_input(std::shared_ptr<input::InputChannel const> const& target, |
243 | + MirEvent const& ev) = 0; |
244 | + |
245 | +protected: |
246 | + InputInjecter() = default; |
247 | + InputInjecter(InputInjecter const&) = delete; |
248 | + InputInjecter& operator=(InputInjecter const&) = delete; |
249 | +}; |
250 | + |
251 | +} |
252 | +} // namespace mir |
253 | + |
254 | +#endif // MIR_SHELL_INPUT_INJECTER_H_ |
255 | |
256 | === modified file 'include/server/mir/shell/surface.h' |
257 | --- include/server/mir/shell/surface.h 2013-08-28 03:41:48 +0000 |
258 | +++ include/server/mir/shell/surface.h 2013-10-01 22:23:19 +0000 |
259 | @@ -26,6 +26,7 @@ |
260 | #include "mir/surfaces/surface.h" |
261 | |
262 | #include "mir_toolkit/common.h" |
263 | +#include "mir_toolkit/event.h" |
264 | |
265 | #include <string> |
266 | |
267 | @@ -42,6 +43,7 @@ |
268 | class SurfaceBuilder; |
269 | class SurfaceConfigurator; |
270 | class SurfaceController; |
271 | +class InputInjecter; |
272 | struct SurfaceCreationParameters; |
273 | |
274 | class Surface : public frontend::ClientTrackingSurface, public shell::SurfaceBufferAccess |
275 | @@ -90,6 +92,8 @@ |
276 | virtual void allow_framedropping(bool); |
277 | |
278 | virtual void raise(std::shared_ptr<SurfaceController> const& controller); |
279 | + |
280 | + virtual void inject_input(std::shared_ptr<InputInjecter> const& injecter, MirEvent const& ev); |
281 | private: |
282 | bool set_type(MirSurfaceType t); // Use configure() to make public changes |
283 | bool set_state(MirSurfaceState s); |
284 | |
285 | === modified file 'include/shared/mir/input/android/android_input_lexicon.h' |
286 | --- include/shared/mir/input/android/android_input_lexicon.h 2013-04-24 05:22:20 +0000 |
287 | +++ include/shared/mir/input/android/android_input_lexicon.h 2013-10-01 22:23:19 +0000 |
288 | @@ -42,6 +42,7 @@ |
289 | { |
290 | public: |
291 | static void translate(const droidinput::InputEvent *android_event, MirEvent &mir_event); |
292 | + static void translate(MirEvent const& mir_event, droidinput::InputEvent **android_event); |
293 | }; |
294 | |
295 | } |
296 | |
297 | === modified file 'include/test/mir_test_doubles/mock_input_dispatcher.h' |
298 | --- include/test/mir_test_doubles/mock_input_dispatcher.h 2013-05-24 18:23:48 +0000 |
299 | +++ include/test/mir_test_doubles/mock_input_dispatcher.h 2013-10-01 22:23:19 +0000 |
300 | @@ -48,6 +48,8 @@ |
301 | |
302 | MOCK_METHOD1(setKeyboardFocus, void(droidinput::sp<droidinput::InputWindowHandle> const&)); |
303 | MOCK_METHOD1(notifyWindowRemoved, void(droidinput::sp<droidinput::InputWindowHandle> const&)); |
304 | + |
305 | + MOCK_METHOD2(injectEventToWindow, void(droidinput::sp<droidinput::InputWindowHandle> const&, droidinput::InputEvent const*)); |
306 | |
307 | // droidinput::InputListener interface |
308 | MOCK_METHOD1(notifyConfigurationChanged, void(droidinput::NotifyConfigurationChangedArgs const*)); |
309 | |
310 | === modified file 'src/server/default_server_configuration.cpp' |
311 | --- src/server/default_server_configuration.cpp 2013-09-30 08:41:27 +0000 |
312 | +++ src/server/default_server_configuration.cpp 2013-10-01 22:23:19 +0000 |
313 | @@ -45,6 +45,7 @@ |
314 | #include "mir/shell/graphics_display_layout.h" |
315 | #include "mir/shell/surface_configurator.h" |
316 | #include "mir/shell/broadcasting_session_event_sink.h" |
317 | +#include "mir/shell/input_injecter.h" |
318 | #include "mir/graphics/cursor.h" |
319 | #include "mir/graphics/nested/host_connection.h" |
320 | #include "mir/shell/null_session_listener.h" |
321 | @@ -929,6 +930,15 @@ |
322 | }); |
323 | } |
324 | |
325 | +std::shared_ptr<msh::InputInjecter> mir::DefaultServerConfiguration::the_input_injecter() |
326 | +{ |
327 | + return input_injecter( |
328 | + [&]() -> std::shared_ptr<msh::InputInjecter> |
329 | + { |
330 | + return the_input_configuration()->the_input_injecter(); |
331 | + }); |
332 | +} |
333 | + |
334 | std::shared_ptr<ms::InputRegistrar> mir::DefaultServerConfiguration::the_input_registrar() |
335 | { |
336 | return input_registrar( |
337 | |
338 | === modified file 'src/server/input/android/CMakeLists.txt' |
339 | --- src/server/input/android/CMakeLists.txt 2013-09-06 10:06:15 +0000 |
340 | +++ src/server/input/android/CMakeLists.txt 2013-10-01 22:23:19 +0000 |
341 | @@ -11,6 +11,7 @@ |
342 | ${CMAKE_CURRENT_SOURCE_DIR}/android_input_window_handle.cpp |
343 | ${CMAKE_CURRENT_SOURCE_DIR}/android_input_registrar.cpp |
344 | ${CMAKE_CURRENT_SOURCE_DIR}/android_input_targeter.cpp |
345 | + ${CMAKE_CURRENT_SOURCE_DIR}/android_input_injecter.cpp |
346 | ${CMAKE_CURRENT_SOURCE_DIR}/android_input_target_enumerator.cpp |
347 | ${CMAKE_CURRENT_SOURCE_DIR}/dispatcher_input_configuration.cpp |
348 | ${CMAKE_CURRENT_SOURCE_DIR}/input_dispatcher_manager.cpp |
349 | |
350 | === added file 'src/server/input/android/android_input_injecter.cpp' |
351 | --- src/server/input/android/android_input_injecter.cpp 1970-01-01 00:00:00 +0000 |
352 | +++ src/server/input/android/android_input_injecter.cpp 2013-10-01 22:23:19 +0000 |
353 | @@ -0,0 +1,58 @@ |
354 | +/* |
355 | + * Copyright © 2013 Canonical Ltd. |
356 | + * |
357 | + * This program is free software: you can redistribute it and/or modify it |
358 | + * under the terms of the GNU General Public License version 3, |
359 | + * as published by the Free Software Foundation. |
360 | + * |
361 | + * This program is distributed in the hope that it will be useful, |
362 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
363 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
364 | + * GNU General Public License for more details. |
365 | + * |
366 | + * You should have received a copy of the GNU General Public License |
367 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
368 | + * |
369 | + * Authored by: Robert Carr <robert.carr@canonical.com> |
370 | + */ |
371 | + |
372 | +#include "android_input_injecter.h" |
373 | +#include "android_input_registrar.h" |
374 | + |
375 | +#include "android_input_window_handle.h" |
376 | +#include "android_input_application_handle.h" |
377 | + |
378 | +#include "mir/input/android/android_input_lexicon.h" |
379 | + |
380 | +#include <InputDispatcher.h> |
381 | + |
382 | +#include <boost/throw_exception.hpp> |
383 | + |
384 | +#include <stdexcept> |
385 | +#include <mutex> |
386 | + |
387 | +namespace mi = mir::input; |
388 | +namespace mia = mi::android; |
389 | +namespace ms = mir::surfaces; |
390 | + |
391 | +mia::InputInjecter::InputInjecter(droidinput::sp<droidinput::InputDispatcherInterface> const& input_dispatcher, |
392 | + std::shared_ptr<mia::WindowHandleRepository> const& repository) : |
393 | + input_dispatcher(input_dispatcher), |
394 | + repository(repository) |
395 | +{ |
396 | +} |
397 | + |
398 | +mia::InputInjecter::~InputInjecter() noexcept(true) {} |
399 | + |
400 | +void mia::InputInjecter::inject_input(std::shared_ptr<mi::InputChannel const> const& focus_channel, |
401 | + MirEvent const& ev) |
402 | +{ |
403 | + auto window_handle = repository->handle_for_channel(focus_channel); |
404 | + |
405 | + if (window_handle == NULL) |
406 | + BOOST_THROW_EXCEPTION(std::logic_error("Attempt to inject input to an unregistered input channel")); |
407 | + |
408 | + droidinput::InputEvent *android_event; |
409 | + mia::Lexicon::translate(ev, &android_event); |
410 | + input_dispatcher->injectEventToWindow(window_handle, android_event); |
411 | +} |
412 | |
413 | === added file 'src/server/input/android/android_input_injecter.h' |
414 | --- src/server/input/android/android_input_injecter.h 1970-01-01 00:00:00 +0000 |
415 | +++ src/server/input/android/android_input_injecter.h 2013-10-01 22:23:19 +0000 |
416 | @@ -0,0 +1,69 @@ |
417 | +/* |
418 | + * Copyright © 2013 Canonical Ltd. |
419 | + * |
420 | + * This program is free software: you can redistribute it and/or modify it |
421 | + * under the terms of the GNU General Public License version 3, |
422 | + * as published by the Free Software Foundation. |
423 | + * |
424 | + * This program is distributed in the hope that it will be useful, |
425 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
426 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
427 | + * GNU General Public License for more details. |
428 | + * |
429 | + * You should have received a copy of the GNU General Public License |
430 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
431 | + * |
432 | + * Authored by: Robert Carr <robert.carr@canonical.com> |
433 | + */ |
434 | + |
435 | +#ifndef MIR_INPUT_ANDROID_INJECTER_H_ |
436 | +#define MIR_INPUT_ANDROID_INJECTER_H_ |
437 | + |
438 | +#include "mir/shell/input_injecter.h" |
439 | + |
440 | +#include <utils/StrongPointer.h> |
441 | + |
442 | +#include <mutex> |
443 | + |
444 | +namespace android |
445 | +{ |
446 | +class InputDispatcherInterface; |
447 | +class InputWindowHandle; |
448 | +} |
449 | + |
450 | +namespace droidinput = android; |
451 | + |
452 | +namespace mir |
453 | +{ |
454 | +namespace input |
455 | +{ |
456 | +namespace android |
457 | +{ |
458 | +class InputConfiguration; |
459 | +class WindowHandleRepository; |
460 | + |
461 | +class InputInjecter : public shell::InputInjecter |
462 | +{ |
463 | +public: |
464 | + explicit InputInjecter(droidinput::sp<droidinput::InputDispatcherInterface> const& input_dispatcher, |
465 | + std::shared_ptr<WindowHandleRepository> const& repository); |
466 | + virtual ~InputInjecter() noexcept(true); |
467 | + |
468 | + void inject_input(std::shared_ptr<input::InputChannel const> const& target, |
469 | + MirEvent const& ev); |
470 | + |
471 | +protected: |
472 | + InputInjecter(const InputInjecter&) = delete; |
473 | + InputInjecter& operator=(const InputInjecter&) = delete; |
474 | + |
475 | +private: |
476 | + droidinput::sp<droidinput::InputDispatcherInterface> input_dispatcher; |
477 | + |
478 | + std::shared_ptr<WindowHandleRepository> const repository; |
479 | +}; |
480 | + |
481 | +} |
482 | +} |
483 | +} // namespace mir |
484 | + |
485 | +#endif // MIR_INPUT_ANDROID_INJECTER_H_ |
486 | |
487 | === modified file 'src/server/input/android/dispatcher_input_configuration.cpp' |
488 | --- src/server/input/android/dispatcher_input_configuration.cpp 2013-09-10 16:42:04 +0000 |
489 | +++ src/server/input/android/dispatcher_input_configuration.cpp 2013-10-01 22:23:19 +0000 |
490 | @@ -22,6 +22,7 @@ |
491 | #include "android_input_thread.h" |
492 | #include "android_input_registrar.h" |
493 | #include "android_input_targeter.h" |
494 | +#include "android_input_injecter.h" |
495 | #include "android_input_target_enumerator.h" |
496 | #include "android_input_manager.h" |
497 | #include "mir/input/event_filter.h" |
498 | @@ -135,6 +136,15 @@ |
499 | }); |
500 | } |
501 | |
502 | +std::shared_ptr<msh::InputInjecter> mia::DispatcherInputConfiguration::the_input_injecter() |
503 | +{ |
504 | + return input_injecter( |
505 | + [this]() |
506 | + { |
507 | + return std::make_shared<mia::InputInjecter>(the_dispatcher(), the_window_handle_repository()); |
508 | + }); |
509 | +} |
510 | + |
511 | bool mia::DispatcherInputConfiguration::is_key_repeat_enabled() |
512 | { |
513 | return true; |
514 | |
515 | === modified file 'src/server/input/null_input_configuration.cpp' |
516 | --- src/server/input/null_input_configuration.cpp 2013-08-28 03:41:48 +0000 |
517 | +++ src/server/input/null_input_configuration.cpp 2013-10-01 22:23:19 +0000 |
518 | @@ -20,6 +20,7 @@ |
519 | |
520 | #include "mir/surfaces/input_registrar.h" |
521 | #include "mir/shell/input_targeter.h" |
522 | +#include "mir/shell/input_injecter.h" |
523 | #include "mir/input/input_manager.h" |
524 | |
525 | namespace mi = mir::input; |
526 | @@ -73,6 +74,13 @@ |
527 | } |
528 | }; |
529 | |
530 | +struct NullInputInjecter : public msh::InputInjecter |
531 | +{ |
532 | + void inject_input(std::shared_ptr<mi::InputChannel const> const&, MirEvent const&) |
533 | + { |
534 | + } |
535 | +}; |
536 | + |
537 | } |
538 | |
539 | std::shared_ptr<ms::InputRegistrar> mi::NullInputConfiguration::the_input_registrar() |
540 | @@ -85,6 +93,11 @@ |
541 | return std::make_shared<NullInputTargeter>(); |
542 | } |
543 | |
544 | +std::shared_ptr<msh::InputInjecter> mi::NullInputConfiguration::the_input_injecter() |
545 | +{ |
546 | + return std::make_shared<NullInputInjecter>(); |
547 | +} |
548 | + |
549 | std::shared_ptr<mi::InputManager> mi::NullInputConfiguration::the_input_manager() |
550 | { |
551 | return std::make_shared<NullInputManager>(); |
552 | |
553 | === modified file 'src/server/shell/surface.cpp' |
554 | --- src/server/shell/surface.cpp 2013-08-28 03:41:48 +0000 |
555 | +++ src/server/shell/surface.cpp 2013-10-01 22:23:19 +0000 |
556 | @@ -21,6 +21,7 @@ |
557 | #include "mir/shell/surface_configurator.h" |
558 | #include "mir/shell/surface_controller.h" |
559 | #include "mir/shell/input_targeter.h" |
560 | +#include "mir/shell/input_injecter.h" |
561 | #include "mir/input/input_channel.h" |
562 | #include "mir/frontend/event_sink.h" |
563 | |
564 | @@ -349,3 +350,15 @@ |
565 | BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface")); |
566 | } |
567 | } |
568 | + |
569 | +void msh::Surface::inject_input(std::shared_ptr<msh::InputInjecter> const& injecter, MirEvent const& ev) |
570 | +{ |
571 | + if (auto const& s = surface.lock()) |
572 | + { |
573 | + injecter->inject_input(s->input_channel(), ev); |
574 | + } |
575 | + else |
576 | + { |
577 | + BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface")); |
578 | + } |
579 | +} |
580 | |
581 | === modified file 'src/shared/input/android/android_input_lexicon.cpp' |
582 | --- src/shared/input/android/android_input_lexicon.cpp 2013-08-28 03:41:48 +0000 |
583 | +++ src/shared/input/android/android_input_lexicon.cpp 2013-10-01 22:23:19 +0000 |
584 | @@ -81,3 +81,61 @@ |
585 | |
586 | } |
587 | |
588 | +void mia::Lexicon::translate(MirEvent const& mir_event, droidinput::InputEvent **android_event) |
589 | +{ |
590 | + switch (mir_event.type) |
591 | + { |
592 | + case mir_event_type_key: |
593 | + { |
594 | + auto key_event = new droidinput::KeyEvent(); |
595 | + key_event->initialize(mir_event.key.device_id, mir_event.key.source_id, |
596 | + mir_event.key.action, mir_event.key.flags, mir_event.key.key_code, |
597 | + mir_event.key.scan_code, mir_event.key.modifiers, |
598 | + mir_event.key.repeat_count, mir_event.key.down_time, mir_event.key.event_time); |
599 | + *android_event = key_event; |
600 | + break; |
601 | + } |
602 | + case mir_event_type_motion: |
603 | + { |
604 | + auto motion_event = new droidinput::MotionEvent(); |
605 | + auto const& mmev = mir_event.motion; |
606 | + auto pc = mmev.pointer_count; |
607 | + |
608 | + droidinput::PointerProperties *pointer_properties = new droidinput::PointerProperties[pc]; |
609 | + droidinput::PointerCoords *pointer_coords = new droidinput::PointerCoords[pc]; |
610 | + |
611 | + for (unsigned int i = 0; i < pc; i++) |
612 | + { |
613 | + auto const& mir_coords = mmev.pointer_coordinates[i]; |
614 | + pointer_properties[i].id = mir_coords.id; |
615 | + |
616 | + auto &coords = pointer_coords[i]; |
617 | + coords.setAxisValue(AMOTION_EVENT_AXIS_X, mir_coords.x); |
618 | + coords.setAxisValue(AMOTION_EVENT_AXIS_Y, mir_coords.y); |
619 | + coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, |
620 | + mir_coords.touch_major); |
621 | + coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, |
622 | + mir_coords.touch_minor); |
623 | + coords.setAxisValue(AMOTION_EVENT_AXIS_SIZE, mir_coords.size); |
624 | + coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, |
625 | + mir_coords.pressure); |
626 | + coords.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, |
627 | + mir_coords.orientation); |
628 | + } |
629 | + |
630 | + motion_event->initialize(mmev.device_id, mmev.source_id, mmev.action, mmev.flags, |
631 | + mmev.edge_flags, mmev.modifiers, mmev.button_state, |
632 | + mmev.x_offset, mmev.y_offset, mmev.x_precision, mmev.y_precision, |
633 | + mmev.down_time, mmev.event_time, mmev.pointer_count, |
634 | + pointer_properties, pointer_coords); |
635 | + *android_event = motion_event; |
636 | + |
637 | + delete pointer_properties; |
638 | + delete pointer_coords; |
639 | + } |
640 | + case mir_event_type_surface: |
641 | + default: |
642 | + // TODO: LOL |
643 | + break; |
644 | + } |
645 | +} |
646 | |
647 | === modified file 'tests/acceptance-tests/test_client_input.cpp' |
648 | --- tests/acceptance-tests/test_client_input.cpp 2013-09-25 18:39:57 +0000 |
649 | +++ tests/acceptance-tests/test_client_input.cpp 2013-10-01 22:23:19 +0000 |
650 | @@ -23,6 +23,8 @@ |
651 | #include "mir/shell/surface.h" |
652 | #include "mir/shell/session_container.h" |
653 | #include "mir/shell/session.h" |
654 | +#include "mir/shell/focus_sequence.h" |
655 | +#include "mir/shell/input_injecter.h" |
656 | #include "mir/surfaces/surface_controller.h" |
657 | #include "mir/surfaces/surface_stack_model.h" |
658 | |
659 | @@ -943,3 +945,122 @@ |
660 | launch_client_process(client_1); |
661 | launch_client_process(client_2); |
662 | } |
663 | + |
664 | + |
665 | +TEST_F(TestClientInput, clients_receive_shell_injected_key_input_per_norm) |
666 | +{ |
667 | + using namespace ::testing; |
668 | + |
669 | + static std::string const test_client_name = "1"; |
670 | + |
671 | + mtf::CrossProcessSync fence; |
672 | + |
673 | + struct ServerConfiguration : mtf::InputTestingServerConfiguration |
674 | + { |
675 | + mtf::CrossProcessSync input_cb_setup_fence; |
676 | + |
677 | + ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence) |
678 | + : input_cb_setup_fence(input_cb_setup_fence) |
679 | + { |
680 | + } |
681 | + |
682 | + std::shared_ptr<msh::Surface> the_most_default_surface() |
683 | + { |
684 | + return the_shell_focus_sequence()->default_focus()->default_surface(); |
685 | + } |
686 | + |
687 | + void inject_event_to_default_surface(MirEvent &ev) |
688 | + { |
689 | + the_most_default_surface()->inject_input(the_input_injecter(), ev); |
690 | + } |
691 | + |
692 | + void inject_input() |
693 | + { |
694 | + wait_until_client_appears(test_client_name); |
695 | + input_cb_setup_fence.wait_for_signal_ready_for(); |
696 | + |
697 | + MirEvent ev; |
698 | + ev.type = mir_event_type_key; |
699 | + ev.key.action = mir_key_action_down; |
700 | + |
701 | + inject_event_to_default_surface(ev); |
702 | + } |
703 | + } server_config(fence); |
704 | + launch_server_process(server_config); |
705 | + |
706 | + struct KeyReceivingClient : InputClient |
707 | + { |
708 | + KeyReceivingClient(const mtf::CrossProcessSync& fence) : InputClient(fence, test_client_name) {} |
709 | + void expect_input(mt::WaitCondition& events_received) override |
710 | + { |
711 | + using namespace ::testing; |
712 | + InSequence seq; |
713 | + |
714 | + EXPECT_CALL(*handler, handle_input(KeyDownEvent())).Times(1) |
715 | + .WillOnce(mt::WakeUp(&events_received)); |
716 | + } |
717 | + } client_config(fence); |
718 | + launch_client_process(client_config); |
719 | +} |
720 | + |
721 | +TEST_F(TestClientInput, clients_receive_shell_injected_pointer_input_per_norm) |
722 | +{ |
723 | + using namespace ::testing; |
724 | + |
725 | + static std::string const test_client_name = "1"; |
726 | + |
727 | + mtf::CrossProcessSync fence; |
728 | + |
729 | + struct ServerConfiguration : mtf::InputTestingServerConfiguration |
730 | + { |
731 | + mtf::CrossProcessSync input_cb_setup_fence; |
732 | + |
733 | + ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence) |
734 | + : input_cb_setup_fence(input_cb_setup_fence) |
735 | + { |
736 | + } |
737 | + |
738 | + std::shared_ptr<msh::Surface> the_most_default_surface() |
739 | + { |
740 | + return the_shell_focus_sequence()->default_focus()->default_surface(); |
741 | + } |
742 | + |
743 | + void inject_event_to_default_surface(MirEvent &ev) |
744 | + { |
745 | + the_most_default_surface()->inject_input(the_input_injecter(), ev); |
746 | + } |
747 | + |
748 | + void inject_input() |
749 | + { |
750 | + wait_until_client_appears(test_client_name); |
751 | + input_cb_setup_fence.wait_for_signal_ready_for(); |
752 | + |
753 | + MirEvent ev; |
754 | + ev.type = mir_event_type_motion; |
755 | + auto &mev = ev.motion; |
756 | + mev.action = mir_motion_action_down; |
757 | + mev.button_state = mir_motion_button_primary; |
758 | + |
759 | + mev.pointer_count = 1; |
760 | + mev.pointer_coordinates[0].x = 1; |
761 | + mev.pointer_coordinates[0].y = 1; |
762 | + |
763 | + inject_event_to_default_surface(ev); |
764 | + } |
765 | + } server_config(fence); |
766 | + launch_server_process(server_config); |
767 | + |
768 | + struct MotionReceivingClient : InputClient |
769 | + { |
770 | + MotionReceivingClient(const mtf::CrossProcessSync& fence) : InputClient(fence, test_client_name) {} |
771 | + void expect_input(mt::WaitCondition& events_received) override |
772 | + { |
773 | + using namespace ::testing; |
774 | + InSequence seq; |
775 | + |
776 | + EXPECT_CALL(*handler, handle_input(ButtonDownEvent(1, 1))).Times(1) |
777 | + .WillOnce(mt::WakeUp(&events_received)); |
778 | + } |
779 | + } client_config(fence); |
780 | + launch_client_process(client_config); |
781 | +} |
782 | |
783 | === modified file 'tests/unit-tests/input/android/CMakeLists.txt' |
784 | --- tests/unit-tests/input/android/CMakeLists.txt 2013-08-28 03:41:48 +0000 |
785 | +++ tests/unit-tests/input/android/CMakeLists.txt 2013-10-01 22:23:19 +0000 |
786 | @@ -8,6 +8,7 @@ |
787 | ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_application_handle.cpp |
788 | ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_window_handle.cpp |
789 | ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_targeter.cpp |
790 | + ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_injecter.cpp |
791 | ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_target_enumerator.cpp |
792 | ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_registrar.cpp |
793 | ) |
794 | |
795 | === added file 'tests/unit-tests/input/android/test_android_input_injecter.cpp' |
796 | --- tests/unit-tests/input/android/test_android_input_injecter.cpp 1970-01-01 00:00:00 +0000 |
797 | +++ tests/unit-tests/input/android/test_android_input_injecter.cpp 2013-10-01 22:23:19 +0000 |
798 | @@ -0,0 +1,93 @@ |
799 | +/* |
800 | + * Copyright © 2013 Canonical Ltd. |
801 | + * |
802 | + * This program is free software: you can redistribute it and/or modify it |
803 | + * under the terms of the GNU General Public License version 3, |
804 | + * as published by the Free Software Foundation. |
805 | + * |
806 | + * This program is distributed in the hope that it will be useful, |
807 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
808 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
809 | + * GNU General Public License for more details. |
810 | + * |
811 | + * You should have received a copy of the GNU General Public License |
812 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
813 | + * |
814 | + * Authored by: Robert Carr <robert.carr@canonical.com> |
815 | + */ |
816 | + |
817 | +#include "src/server/input/android/android_input_injecter.h" |
818 | +#include "src/server/input/android/android_input_registrar.h" |
819 | +#include "src/server/input/android/android_window_handle_repository.h" |
820 | + |
821 | +#include "mir/input/input_channel.h" |
822 | + |
823 | +#include "mir_test_doubles/mock_input_dispatcher.h" |
824 | +#include "mir_test_doubles/stub_input_channel.h" |
825 | + |
826 | +#include "mir_test/fake_shared.h" |
827 | +#include "mir_test_doubles/stub_input_channel.h" |
828 | +#include "mir_test_doubles/stub_input_handles.h" |
829 | +#include "mir_test_doubles/mock_window_handle_repository.h" |
830 | + |
831 | +#include <InputWindow.h> |
832 | +#include <InputApplication.h> |
833 | + |
834 | +#include <gtest/gtest.h> |
835 | +#include <gmock/gmock.h> |
836 | + |
837 | +#include <sys/types.h> |
838 | +#include <sys/socket.h> |
839 | + |
840 | +#include <stdexcept> |
841 | + |
842 | +namespace mi = mir::input; |
843 | +namespace mia = mi::android; |
844 | +namespace mt = mir::test; |
845 | +namespace mtd = mt::doubles; |
846 | + |
847 | +TEST(AndroidInputInjecterSetup, inject_input_throw_behavior) |
848 | +{ |
849 | + using namespace ::testing; |
850 | + |
851 | + droidinput::sp<mtd::MockInputDispatcher> dispatcher = new mtd::MockInputDispatcher; |
852 | + mtd::MockWindowHandleRepository repository; |
853 | + mia::InputInjecter injecter(dispatcher, mt::fake_shared(repository)); |
854 | + |
855 | + std::shared_ptr<mi::InputChannel const> stub_channel = std::make_shared<mtd::StubInputChannel>(); |
856 | + |
857 | + EXPECT_CALL(repository, handle_for_channel(stub_channel)) |
858 | + .Times(1) |
859 | + .WillOnce(Return(droidinput::sp<droidinput::InputWindowHandle>())); |
860 | + |
861 | + EXPECT_THROW({ |
862 | + // We can't inject input to unregistered channels |
863 | + MirEvent ev; |
864 | + memset(&ev, 0, sizeof(MirEvent)); |
865 | + |
866 | + injecter.inject_input(stub_channel, ev); |
867 | + }, std::logic_error); |
868 | +} |
869 | + |
870 | +TEST(AndroidInputInjecterSetup, inject_input_behavior) |
871 | +{ |
872 | + using namespace ::testing; |
873 | + |
874 | + std::shared_ptr<mi::InputChannel const> stub_channel = std::make_shared<mtd::StubInputChannel>(); |
875 | + mtd::MockWindowHandleRepository repository; |
876 | + |
877 | + droidinput::sp<mtd::MockInputDispatcher> dispatcher = new mtd::MockInputDispatcher; |
878 | + droidinput::sp<droidinput::InputWindowHandle> stub_window_handle = new mtd::StubWindowHandle; |
879 | + |
880 | + EXPECT_CALL(*dispatcher, injectEventToWindow(stub_window_handle, _)) |
881 | + .Times(1); |
882 | + EXPECT_CALL(repository, handle_for_channel(stub_channel)) |
883 | + .Times(1) |
884 | + .WillOnce(Return(stub_window_handle)); |
885 | + mia::InputInjecter injecter(dispatcher, mt::fake_shared(repository)); |
886 | + |
887 | + MirEvent ev; |
888 | + |
889 | + memset(&ev, 0, sizeof(MirEvent)); |
890 | + injecter.inject_input(stub_channel, ev); |
891 | +} |
892 | |
893 | === modified file 'tests/unit-tests/input/android/test_android_input_lexicon.cpp' |
894 | --- tests/unit-tests/input/android/test_android_input_lexicon.cpp 2013-08-28 03:41:48 +0000 |
895 | +++ tests/unit-tests/input/android/test_android_input_lexicon.cpp 2013-10-01 22:23:19 +0000 |
896 | @@ -27,6 +27,7 @@ |
897 | namespace mi = mir::input; |
898 | namespace mia = mir::input::android; |
899 | |
900 | +// Translate key events from android::KeyEvent to MirEvent |
901 | TEST(AndroidInputLexicon, translates_key_events) |
902 | { |
903 | using namespace ::testing; |
904 | @@ -71,6 +72,54 @@ |
905 | delete android_key_ev; |
906 | } |
907 | |
908 | +// Translate MirEvent to android::KeyEvent |
909 | +TEST(AndroidInputLexicon, translates_key_events_in_reverse) |
910 | +{ |
911 | + using namespace ::testing; |
912 | + |
913 | + const int32_t device_id = 1; |
914 | + const int32_t source_id = 2; |
915 | + const int32_t action = 3; |
916 | + const int32_t flags = 4; |
917 | + const int32_t key_code = 5; |
918 | + const int32_t scan_code = 6; |
919 | + const int32_t meta_state = 7; |
920 | + const int32_t repeat_count = 8; |
921 | + const nsecs_t down_time = 9; |
922 | + const nsecs_t event_time = 10; |
923 | + |
924 | + MirEvent mir_ev; |
925 | + mir_ev.type = mir_event_type_key; |
926 | + mir_ev.key.device_id = device_id; |
927 | + mir_ev.key.source_id = source_id; |
928 | + mir_ev.key.action = static_cast<MirKeyAction>(action); |
929 | + mir_ev.key.flags = static_cast<MirKeyFlag>(flags); |
930 | + mir_ev.key.key_code = key_code; |
931 | + mir_ev.key.scan_code = scan_code; |
932 | + mir_ev.key.modifiers = meta_state; |
933 | + mir_ev.key.repeat_count = repeat_count; |
934 | + mir_ev.key.down_time = down_time; |
935 | + mir_ev.key.event_time = event_time; |
936 | + |
937 | + droidinput::InputEvent *aev; |
938 | + mia::Lexicon::translate(mir_ev, &aev); |
939 | + auto android_key_ev = dynamic_cast<droidinput::KeyEvent*>(aev); |
940 | + |
941 | + EXPECT_EQ(device_id, android_key_ev->getDeviceId()); |
942 | + EXPECT_EQ(source_id, android_key_ev->getSource()); |
943 | + EXPECT_EQ(action, android_key_ev->getAction()); |
944 | + EXPECT_EQ(flags, android_key_ev->getFlags()); |
945 | + EXPECT_EQ(meta_state, android_key_ev->getMetaState()); |
946 | + EXPECT_EQ(AINPUT_EVENT_TYPE_KEY, android_key_ev->getType()); |
947 | + EXPECT_EQ(key_code, android_key_ev->getKeyCode()); |
948 | + EXPECT_EQ(scan_code, android_key_ev->getScanCode()); |
949 | + EXPECT_EQ(repeat_count, android_key_ev->getRepeatCount()); |
950 | + EXPECT_EQ(down_time, android_key_ev->getDownTime()); |
951 | + EXPECT_EQ(event_time, android_key_ev->getEventTime()); |
952 | + |
953 | + delete android_key_ev; |
954 | +} |
955 | + |
956 | TEST(AndroidInputLexicon, translates_single_pointer_motion_events) |
957 | { |
958 | using namespace ::testing; |
959 | @@ -160,10 +209,110 @@ |
960 | EXPECT_EQ(mir_pointer_coords->pressure, pressure); |
961 | EXPECT_EQ(mir_pointer_coords->orientation, orientation); |
962 | |
963 | - |
964 | delete android_motion_ev; |
965 | } |
966 | |
967 | +TEST(AndroidInputLexicon, translates_single_pointer_motion_events_in_reverse) |
968 | +{ |
969 | + using namespace ::testing; |
970 | + |
971 | + // Common event properties |
972 | + const int32_t device_id = 1; |
973 | + const int32_t source_id = 2; |
974 | + const int32_t action = 3; |
975 | + const int32_t flags = 4; |
976 | + const int32_t edge_flags = 5; |
977 | + const int32_t meta_state = 6; |
978 | + const int32_t button_state = 7; |
979 | + const float x_offset = 8; |
980 | + const float y_offset = 9; |
981 | + const float x_precision = 10; |
982 | + const float y_precision = 11; |
983 | + const nsecs_t down_time = 12; |
984 | + const nsecs_t event_time = 13; |
985 | + const size_t pointer_count = 1; |
986 | + |
987 | + // Set up the MirEvent for translation |
988 | + // General event properties |
989 | + MirEvent mir_ev; |
990 | + auto mmev = &mir_ev.motion; |
991 | + mir_ev.type = mir_event_type_motion; |
992 | + // General motion event properties |
993 | + mmev->device_id = device_id; |
994 | + mmev->source_id = source_id; |
995 | + mmev->action = action; |
996 | + mmev->flags = static_cast<MirMotionFlag>(flags); |
997 | + mmev->edge_flags = edge_flags; |
998 | + mmev->modifiers = meta_state; |
999 | + mmev->button_state = static_cast<MirMotionButton>(button_state); |
1000 | + mmev->down_time = down_time; |
1001 | + mmev->event_time = event_time; |
1002 | + mmev->x_offset = x_offset; |
1003 | + mmev->y_offset = y_offset; |
1004 | + mmev->x_precision = x_precision; |
1005 | + mmev->y_precision = y_precision; |
1006 | + mmev->pointer_count = pointer_count; |
1007 | + |
1008 | + // Pointer specific properties |
1009 | + const int pointer_id = 1; |
1010 | + const float x_axis = 100.0; |
1011 | + const float y_axis = 200.0; |
1012 | + const float touch_minor = 300.0; |
1013 | + const float touch_major = 400.0; |
1014 | + const float size = 500.0; |
1015 | + const float pressure = 600.0; |
1016 | + const float orientation = 700.0; |
1017 | + |
1018 | + auto coords = &mmev->pointer_coordinates[0]; |
1019 | + coords->id = pointer_id; |
1020 | + coords->x = x_axis; |
1021 | + coords->y = y_axis; |
1022 | + coords->raw_x = x_axis; |
1023 | + coords->raw_y = y_axis; |
1024 | + coords->touch_minor = touch_minor; |
1025 | + coords->touch_major = touch_major; |
1026 | + coords->size = size; |
1027 | + coords->pressure = pressure; |
1028 | + coords->orientation = orientation; |
1029 | + |
1030 | + droidinput::InputEvent *android_ev; |
1031 | + mia::Lexicon::translate(mir_ev, &android_ev); |
1032 | + |
1033 | + // Verify the produced android event |
1034 | + // General event properties |
1035 | + EXPECT_EQ(AINPUT_EVENT_TYPE_MOTION, android_ev->getType()); |
1036 | + // Motion event properties |
1037 | + auto android_mev = static_cast<droidinput::MotionEvent*>(android_ev); |
1038 | + EXPECT_EQ(device_id, android_mev->getDeviceId()); |
1039 | + EXPECT_EQ(source_id, android_mev->getSource()); |
1040 | + EXPECT_EQ(action, android_mev->getAction()); |
1041 | + EXPECT_EQ(flags, android_mev->getFlags()); |
1042 | + EXPECT_EQ(edge_flags, android_mev->getEdgeFlags()); |
1043 | + EXPECT_EQ(meta_state, android_mev->getMetaState()); |
1044 | + EXPECT_EQ(button_state, android_mev->getButtonState()); |
1045 | + EXPECT_EQ(down_time, android_mev->getDownTime()); |
1046 | + EXPECT_EQ(event_time, android_mev->getEventTime()); |
1047 | + EXPECT_EQ(x_offset, android_mev->getXOffset()); |
1048 | + EXPECT_EQ(y_offset, android_mev->getYOffset()); |
1049 | + EXPECT_EQ(x_precision, android_mev->getXPrecision()); |
1050 | + EXPECT_EQ(y_precision, android_mev->getYPrecision()); |
1051 | + EXPECT_EQ(pointer_count, android_mev->getPointerCount()); |
1052 | + |
1053 | + // Pointer properties and coordinates |
1054 | + auto a_pp = android_mev->getPointerProperties(0); |
1055 | + auto a_pc = android_mev->getRawPointerCoords(0); |
1056 | + EXPECT_EQ(pointer_id, a_pp->id); |
1057 | + EXPECT_EQ(x_axis, a_pc->getAxisValue(AMOTION_EVENT_AXIS_X)); |
1058 | + EXPECT_EQ(y_axis, a_pc->getAxisValue(AMOTION_EVENT_AXIS_Y)); |
1059 | + EXPECT_EQ(touch_major, a_pc->getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR)); |
1060 | + EXPECT_EQ(touch_minor, a_pc->getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR)); |
1061 | + EXPECT_EQ(size, a_pc->getAxisValue(AMOTION_EVENT_AXIS_SIZE)); |
1062 | + EXPECT_EQ(pressure, a_pc->getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); |
1063 | + EXPECT_EQ(orientation, a_pc->getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); |
1064 | + |
1065 | + delete android_ev; |
1066 | +} |
1067 | + |
1068 | TEST(AndroidInputLexicon, translates_multi_pointer_motion_events) |
1069 | { |
1070 | using namespace ::testing; |