Mir

Merge lp:~mir-team/mir/unify-pointer-button into lp:mir

Proposed by Robert Carr
Status: Superseded
Proposed branch: lp:~mir-team/mir/unify-pointer-button
Merge into: lp:mir
Prerequisite: lp:~mir-team/mir/remaining-nsec-removal
Diff against target: 2677 lines (+854/-963)
40 files modified
3rd_party/android-input/android/frameworks/base/services/input/InputDispatcher.cpp (+11/-11)
include/client/mir/events/event_builders.h (+1/-2)
include/client/mir_toolkit/events/input/pointer_event.h (+15/-5)
src/client/events/event_builders.cpp (+19/-30)
src/client/input/android/android_input_lexicon.cpp (+1/-1)
src/client/input/android/event_conversion_helpers.cpp (+34/-0)
src/client/input/input_event.cpp (+11/-5)
src/client/symbols.map (+3/-0)
src/include/common/mir/events/event_private.h (+1/-9)
src/include/common/mir/input/android/event_conversion_helpers.h (+3/-1)
src/server/input/android/android_input_dispatcher.cpp (+1/-1)
src/server/input/android/input_sender.cpp (+1/-1)
src/server/input/android/input_translator.cpp (+1/-1)
src/server/input/default_configuration.cpp (+2/-0)
src/server/input/default_input_device_hub.cpp (+16/-1)
src/server/input/default_input_device_hub.h (+4/-0)
tests/acceptance-tests/test_client_input.cpp (+510/-69)
tests/acceptance-tests/test_surface_modifications.cpp (+2/-4)
tests/acceptance-tests/test_surface_placement.cpp (+1/-1)
tests/acceptance-tests/throwback/CMakeLists.txt (+0/-1)
tests/acceptance-tests/throwback/test_client_input.cpp (+0/-704)
tests/acceptance-tests/throwback/test_custom_input_targeter.cpp (+0/-1)
tests/include/mir_test/event_matchers.h (+28/-27)
tests/include/mir_test_framework/input_testing_server_configuration.h (+0/-22)
tests/include/mir_test_framework/placement_applying_shell.h (+59/-0)
tests/integration-tests/input/CMakeLists.txt (+1/-4)
tests/integration-tests/input/android/CMakeLists.txt (+0/-9)
tests/integration-tests/input/test_cursor_listener.cpp (+17/-10)
tests/mir_test_framework/CMakeLists.txt (+1/-0)
tests/mir_test_framework/fake_input_device_impl.cpp (+3/-3)
tests/mir_test_framework/fake_input_device_impl.h (+1/-3)
tests/mir_test_framework/input_testing_server_options.cpp (+0/-17)
tests/mir_test_framework/placement_applying_shell.cpp (+59/-0)
tests/unit-tests/input/android/test_android_input_dispatcher.cpp (+5/-4)
tests/unit-tests/input/android/test_android_input_lexicon.cpp (+2/-5)
tests/unit-tests/input/android/test_input_translator.cpp (+2/-3)
tests/unit-tests/input/test_default_input_device_hub.cpp (+28/-1)
tests/unit-tests/input/test_event_builders.cpp (+2/-4)
tests/unit-tests/input/test_input_event.cpp (+8/-2)
tests/unit-tests/scene/test_abstract_shell.cpp (+1/-1)
To merge this branch: bzr merge lp:~mir-team/mir/unify-pointer-button
Reviewer Review Type Date Requested Status
Alan Griffiths Needs Fixing
Alexandros Frantzis (community) Approve
Daniel van Vugt Needs Fixing
PS Jenkins bot (community) continuous-integration Approve
Andreas Pokorny (community) Approve
Kevin DuBois (community) Needs Information
Review via email: mp+258322@code.launchpad.net

This proposal has been superseded by a proposal from 2015-05-14.

Commit message

Unify the pointer button enums. The new style event buttons are not using a mask so as to allow for extensibility so there is some churn in the change of the internal representation.

Description of the change

Unify the pointer button enums. The new style event buttons are not using a mask so as to allow for extensibility so there is some churn in the change of the internal representation.

This branch is part of the event cleaning pipeline:

Pluck-low-hanging-event-fruit: Remove unused event members.
Unify-event-modifiers: Consolidate modifier enums (https://code.launchpad.net/~mir-team/mir/unify-event-modifiers/+merge/258218)
Unify-keyboard-actions: Consolidate keyboard action enums and key repeat representation (https://code.launchpad.net/~mir-team/mir/unify-keyboard-actions/+merge/258288)
Remaining-nsec-removal: Remove usage of nsecs_t in event_private.h https://code.launchpad.net/~mir-team/mir/remaining-nsec-removal/+merge/258292
unify-pointer-button: Consolidate pointer button enums
https://code.launchpad.net/~mir-team/mir/unify-pointer-button

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

> The new style event buttons are not using a mask so as to allow for extensibility so there
> is some churn in the change of the internal representation.

How is having a mask reduce extensibility? Do you mean running out of bits?

190+ bool button_state[mir_pointer_button_forward + 1];

This will break if we add a new member to the enum (although we will probably catch the issue at compile time). In any case, it's best to introduce a mir_pointer_button_count (or similar) value, and actually make it a policy to have such a member in all suitable enums.

Needs info/fixing

review: Needs Fixing
Revision history for this message
Robert Carr (robertcarr) wrote :

Added mir_pointer_button_Count...good call...tbh I dont like this solution that much but I'm concerned about the extensibility with flags (e.g. running out of bits). In particular what if devices have buttons only available through some sort of mir_input_device_list_buttons_ API (e.g. they don't correspond to forward/back...)? ON the other hand I guess this device wouldn't be a pointer...maybe flags are fine...I'd like to get another opinion! RAOF?

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Seems self-consistent.

But I'm a little concerned that other APIs treat buttons as bitmasks (e.g. "143+ android_state |= AMOTION_EVENT_BUTTON_PRIMARY;"). Apart from not matching expectations are we really sure we know better?

review: Needs Information
Revision history for this message
Robert Carr (robertcarr) wrote :

I've thought through my concerns that related to nto storing buttons as a flag. Primarly I was worried about exotic devices and allocating button indices for them and potentially running out of flag values. I suppose if anything though such devices would not be pointers and only available throuhg the raw input API so I'm not concerned. Updated branch to use flag...required more client ABI break :)

Revision history for this message
Kevin DuBois (kdub) wrote :

nonblocking comment:
The bitmask seems okay for now, plenty of unused bits left.

needs-info
77+ mev.button_state[mir_pointer_button_tertiary] = true;

Since this appears private now, could we have something more like:
mev.button_state[mir_pointer_button_tertiary] = pressed;
It took a bit of reading of the struct to figure out what was going on in the present form.

review: Needs Information
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

ok looks good apart from the merge conflict

Revision history for this message
Andreas Pokorny (andreas-pokorny) :
review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

(0) MirPointerButton: Definitely a client ABI break now, so we must remember to bump to libmirclient9 ASAP (Alan is working on it but blocked by CI annoyances).

(1) I guess this isn't well tested yet because there's a logic error (should be "&="):
365 - buttons.erase(remove(begin(buttons), end(buttons), button));
366 + buttons |= ~button;

review: Needs Fixing
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Besides Daniel's "Needs Fixing", looks good.

Nit:

239-

Why remove the line?

review: Approve
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Agree with Daniel about test coverage and Alexandros about whitespace.

review: Needs Fixing

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '3rd_party/android-input/android/frameworks/base/services/input/InputDispatcher.cpp'
--- 3rd_party/android-input/android/frameworks/base/services/input/InputDispatcher.cpp 2015-05-01 08:54:27 +0000
+++ 3rd_party/android-input/android/frameworks/base/services/input/InputDispatcher.cpp 2015-05-14 18:12:40 +0000
@@ -20,30 +20,30 @@
20//#define LOG_NDEBUG 020//#define LOG_NDEBUG 0
2121
22// Log detailed debug messages about each inbound event notification to the dispatcher.22// Log detailed debug messages about each inbound event notification to the dispatcher.
23#define DEBUG_INBOUND_EVENT_DETAILS 023#define DEBUG_INBOUND_EVENT_DETAILS 1
2424
25// Log detailed debug messages about each outbound event processed by the dispatcher.25// Log detailed debug messages about each outbound event processed by the dispatcher.
26#define DEBUG_OUTBOUND_EVENT_DETAILS 026#define DEBUG_OUTBOUND_EVENT_DETAILS 1
2727
28// Log debug messages about the dispatch cycle.28// Log debug messages about the dispatch cycle.
29#define DEBUG_DISPATCH_CYCLE 029#define DEBUG_DISPATCH_CYCLE 1
3030
31// Log debug messages about registrations.31// Log debug messages about registrations.
32#define DEBUG_REGISTRATION 032#define DEBUG_REGISTRATION 1
3333
34// Log debug messages about input event injection.34 // Log debug messages about input event injection.
35#define DEBUG_INJECTION 035#define DEBUG_INJECTION 1
3636
37// Log debug messages about input focus tracking.37// Log debug messages about input focus tracking.
38#define DEBUG_FOCUS 038#define DEBUG_FOCUS 1
3939
40// Log debug messages about the app switch latency optimization.40// Log debug messages about the app switch latency optimization.
41#define DEBUG_APP_SWITCH 041#define DEBUG_APP_SWITCH 1
4242
43// Log debug messages about hover events.43// Log debug messages about hover events.
44#define DEBUG_HOVER 044#define DEBUG_HOVER 1
4545
46#define ENABLE_APP_SWITCH_OPTIMIZATION 046#define ENABLE_APP_SWITCH_OPTIMIZATION 1
4747
48#include "InputDispatcher.h"48#include "InputDispatcher.h"
4949
@@ -3464,7 +3464,7 @@
3464 originalKeyCode, keyEntry->action, keyEntry->repeatCount,3464 originalKeyCode, keyEntry->action, keyEntry->repeatCount,
3465 keyEntry->policyFlags);3465 keyEntry->policyFlags);
3466#endif3466#endif
3467 return false;3467 return false;
3468 }3468 }
34693469
3470 // Dispatch the unhandled key to the policy.3470 // Dispatch the unhandled key to the policy.
34713471
=== modified file 'include/client/mir/events/event_builders.h'
--- include/client/mir/events/event_builders.h 2015-05-05 18:01:08 +0000
+++ include/client/mir/events/event_builders.h 2015-05-14 18:12:40 +0000
@@ -25,7 +25,6 @@
25#include "mir/frontend/surface_id.h"25#include "mir/frontend/surface_id.h"
2626
27#include <memory>27#include <memory>
28#include <vector>
29#include <functional>28#include <functional>
30#include <chrono>29#include <chrono>
3130
@@ -63,7 +62,7 @@
63// Pointer event62// Pointer event
64EventUPtr make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp,63EventUPtr make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp,
65 MirInputEventModifiers modifiers, MirPointerAction action,64 MirInputEventModifiers modifiers, MirPointerAction action,
66 std::vector<MirPointerButton> const& buttons_pressed,65 MirPointerButtons buttons_pressed,
67 float x_axis_value, float y_axis_value,66 float x_axis_value, float y_axis_value,
68 float hscroll_value, float vscroll_value);67 float hscroll_value, float vscroll_value);
69}68}
7069
=== modified file 'include/client/mir_toolkit/events/input/pointer_event.h'
--- include/client/mir_toolkit/events/input/pointer_event.h 2015-03-31 02:35:42 +0000
+++ include/client/mir_toolkit/events/input/pointer_event.h 2015-05-14 18:12:40 +0000
@@ -68,12 +68,13 @@
68 * Identifiers for pointer buttons68 * Identifiers for pointer buttons
69 */69 */
70typedef enum {70typedef enum {
71 mir_pointer_button_primary = 1,71 mir_pointer_button_primary = 1 << 0,
72 mir_pointer_button_secondary = 2,72 mir_pointer_button_secondary = 1 << 1,
73 mir_pointer_button_tertiary = 3,73 mir_pointer_button_tertiary = 1 << 2,
74 mir_pointer_button_back = 4,74 mir_pointer_button_back = 1 << 3,
75 mir_pointer_button_forward = 575 mir_pointer_button_forward = 1 << 4
76} MirPointerButton;76} MirPointerButton;
77typedef unsigned int MirPointerButtons;
7778
78/**79/**
79 * Retrieve the modifier keys pressed when the pointer action occured.80 * Retrieve the modifier keys pressed when the pointer action occured.
@@ -103,6 +104,15 @@
103 MirPointerButton button);104 MirPointerButton button);
104105
105/**106/**
107 * Retreive the pointer button state as a masked set of values.
108 *
109 * \param [in] event The pointer event
110 *
111 * \return The button state
112 */
113MirPointerButtons mir_pointer_event_buttons(MirPointerEvent const* event);
114
115/**
106 * Retrieve the axis value reported by a given pointer event.116 * Retrieve the axis value reported by a given pointer event.
107 *117 *
108 * \param [in] event The pointer event118 * \param [in] event The pointer event
109119
=== modified file 'src/client/events/event_builders.cpp'
--- src/client/events/event_builders.cpp 2015-05-08 20:54:52 +0000
+++ src/client/events/event_builders.cpp 2015-05-14 18:12:40 +0000
@@ -231,29 +231,40 @@
231231
232namespace232namespace
233{233{
234MirMotionAction old_action_from_pointer_action(MirPointerAction action, MirMotionButton button_state)234MirMotionAction old_action_from_pointer_action(MirPointerAction action, int buttons_pressed)
235{235{
236 switch (action)236 switch (action)
237 {237 {
238 case mir_pointer_action_button_up:238 case mir_pointer_action_button_up:
239 return mir_motion_action_up;239 return buttons_pressed == 0 ? mir_motion_action_up : mir_motion_action_pointer_up;
240 case mir_pointer_action_button_down:240 case mir_pointer_action_button_down:
241 return mir_motion_action_down;241 return buttons_pressed == 1 ? mir_motion_action_down : mir_motion_action_pointer_down;
242 case mir_pointer_action_enter:242 case mir_pointer_action_enter:
243 return mir_motion_action_hover_enter;243 return mir_motion_action_hover_enter;
244 case mir_pointer_action_leave:244 case mir_pointer_action_leave:
245 return mir_motion_action_hover_exit;245 return mir_motion_action_hover_exit;
246 case mir_pointer_action_motion:246 case mir_pointer_action_motion:
247 return button_state ? mir_motion_action_move : mir_motion_action_hover_move;247 return buttons_pressed ? mir_motion_action_move : mir_motion_action_hover_move;
248 default:248 default:
249 BOOST_THROW_EXCEPTION(std::logic_error("Invalid pointer action"));249 BOOST_THROW_EXCEPTION(std::logic_error("Invalid pointer action"));
250 }250 }
251}251}
252int count_buttons(MirPointerButtons buttons)
253{
254 int ret = 0;
255 if (buttons & mir_pointer_button_primary) ret++;
256 if (buttons & mir_pointer_button_secondary) ret++;
257 if (buttons & mir_pointer_button_tertiary) ret++;
258 if (buttons & mir_pointer_button_forward) ret++;
259 if (buttons & mir_pointer_button_back) ret++;
260
261 return ret;
262}
252}263}
253264
254mir::EventUPtr mev::make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp,265mir::EventUPtr mev::make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp,
255 MirInputEventModifiers modifiers, MirPointerAction action,266 MirInputEventModifiers modifiers, MirPointerAction action,
256 std::vector<MirPointerButton> const& buttons_pressed,267 MirPointerButtons buttons_pressed,
257 float x_axis_value, float y_axis_value,268 float x_axis_value, float y_axis_value,
258 float hscroll_value, float vscroll_value)269 float hscroll_value, float vscroll_value)
259{270{
@@ -266,31 +277,9 @@
266 mev.event_time = timestamp;277 mev.event_time = timestamp;
267 mev.modifiers = modifiers;278 mev.modifiers = modifiers;
268 mev.source_id = AINPUT_SOURCE_MOUSE;279 mev.source_id = AINPUT_SOURCE_MOUSE;
269280 mev.buttons = buttons_pressed;
270 int button_state = 0;281
271 for (auto button : buttons_pressed)282 mev.action = old_action_from_pointer_action(action, count_buttons(buttons_pressed));
272 {
273 switch (button)
274 {
275 case mir_pointer_button_primary:
276 button_state |= mir_motion_button_primary;
277 break;
278 case mir_pointer_button_secondary:
279 button_state |= mir_motion_button_secondary;
280 break;
281 case mir_pointer_button_tertiary:
282 button_state |= mir_motion_button_tertiary;
283 break;
284 case mir_pointer_button_back:
285 button_state |= mir_motion_button_back;
286 break;
287 case mir_pointer_button_forward:
288 button_state |= mir_motion_button_forward;
289 break;
290 }
291 }
292 mev.button_state = static_cast<MirMotionButton>(button_state);
293 mev.action = old_action_from_pointer_action(action, mev.button_state);
294283
295 mev.pointer_count = 1;284 mev.pointer_count = 1;
296 auto& pc = mev.pointer_coordinates[0];285 auto& pc = mev.pointer_coordinates[0];
297286
=== modified file 'src/client/input/android/android_input_lexicon.cpp'
--- src/client/input/android/android_input_lexicon.cpp 2015-05-05 18:01:08 +0000
+++ src/client/input/android/android_input_lexicon.cpp 2015-05-14 18:12:40 +0000
@@ -50,7 +50,7 @@
50 mir_event.motion.source_id = android_event->getSource();50 mir_event.motion.source_id = android_event->getSource();
51 mir_event.motion.action = mev->getAction();51 mir_event.motion.action = mev->getAction();
52 mir_event.motion.modifiers = mia::mir_modifiers_from_android(mev->getMetaState());52 mir_event.motion.modifiers = mia::mir_modifiers_from_android(mev->getMetaState());
53 mir_event.motion.button_state = static_cast<MirMotionButton>(mev->getButtonState());53 mir_event.motion.buttons = mia::mir_pointer_buttons_from_android(mev->getButtonState());
54 mir_event.motion.event_time = mev->getEventTime();54 mir_event.motion.event_time = mev->getEventTime();
55 mir_event.motion.pointer_count = mev->getPointerCount();55 mir_event.motion.pointer_count = mev->getPointerCount();
56 for(unsigned int i = 0; i < mev->getPointerCount(); i++)56 for(unsigned int i = 0; i < mev->getPointerCount(); i++)
5757
=== modified file 'src/client/input/android/event_conversion_helpers.cpp'
--- src/client/input/android/event_conversion_helpers.cpp 2015-05-08 20:44:56 +0000
+++ src/client/input/android/event_conversion_helpers.cpp 2015-05-14 18:12:40 +0000
@@ -100,3 +100,37 @@
100 return AKEY_EVENT_ACTION_UP;100 return AKEY_EVENT_ACTION_UP;
101 }101 }
102}102}
103
104MirPointerButtons mia::mir_pointer_buttons_from_android(int32_t android_state)
105{
106 MirPointerButtons buttons = 0;
107
108 if (android_state & AMOTION_EVENT_BUTTON_PRIMARY)
109 buttons |= mir_pointer_button_primary;
110 if (android_state & AMOTION_EVENT_BUTTON_SECONDARY)
111 buttons |= mir_pointer_button_secondary;
112 if (android_state & AMOTION_EVENT_BUTTON_TERTIARY)
113 buttons |= mir_pointer_button_tertiary;
114 if (android_state & AMOTION_EVENT_BUTTON_BACK)
115 buttons |= mir_pointer_button_back;
116 if (android_state & AMOTION_EVENT_BUTTON_FORWARD)
117 buttons |= mir_pointer_button_forward;
118
119 return buttons;
120}
121
122int32_t mia::android_pointer_buttons_from_mir(MirPointerButtons buttons)
123{
124 int32_t android_state = 0;
125 if (buttons & mir_pointer_button_primary)
126 android_state |= AMOTION_EVENT_BUTTON_PRIMARY;
127 if (buttons & mir_pointer_button_secondary)
128 android_state |= AMOTION_EVENT_BUTTON_SECONDARY;
129 if (buttons & mir_pointer_button_tertiary)
130 android_state |= AMOTION_EVENT_BUTTON_TERTIARY;
131 if (buttons & mir_pointer_button_back)
132 android_state |= AMOTION_EVENT_BUTTON_BACK;
133 if (buttons & mir_pointer_button_forward)
134 android_state |= AMOTION_EVENT_BUTTON_FORWARD;
135 return android_state;
136}
103137
=== modified file 'src/client/input/input_event.cpp'
--- src/client/input/input_event.cpp 2015-05-05 18:01:08 +0000
+++ src/client/input/input_event.cpp 2015-05-14 18:12:40 +0000
@@ -424,20 +424,26 @@
424 switch (button)424 switch (button)
425 {425 {
426 case mir_pointer_button_primary:426 case mir_pointer_button_primary:
427 return old_mev.button_state & mir_motion_button_primary;427 return old_mev.buttons & mir_pointer_button_primary;
428 case mir_pointer_button_secondary:428 case mir_pointer_button_secondary:
429 return old_mev.button_state & mir_motion_button_secondary;429 return old_mev.buttons & mir_pointer_button_secondary;
430 case mir_pointer_button_tertiary:430 case mir_pointer_button_tertiary:
431 return old_mev.button_state & mir_motion_button_tertiary;431 return old_mev.buttons & mir_pointer_button_tertiary;
432 case mir_pointer_button_back:432 case mir_pointer_button_back:
433 return old_mev.button_state & mir_motion_button_back;433 return old_mev.buttons & mir_pointer_button_back;
434 case mir_pointer_button_forward:434 case mir_pointer_button_forward:
435 return old_mev.button_state & mir_motion_button_forward;435 return old_mev.buttons & mir_pointer_button_forward;
436 default:436 default:
437 return false;437 return false;
438 }438 }
439}439}
440440
441MirPointerButtons mir_pointer_event_buttons(MirPointerEvent const* pev)
442{
443 auto const& old_mev = old_mev_from_new(pev);
444 return old_mev.buttons;
445}
446
441float mir_pointer_event_axis_value(MirPointerEvent const* pev, MirPointerAxis axis)447float mir_pointer_event_axis_value(MirPointerEvent const* pev, MirPointerAxis axis)
442{448{
443 auto const& old_mev = old_mev_from_new(pev);449 auto const& old_mev = old_mev_from_new(pev);
444450
=== modified file 'src/client/symbols.map'
--- src/client/symbols.map 2015-05-07 19:41:08 +0000
+++ src/client/symbols.map 2015-05-14 18:12:40 +0000
@@ -196,6 +196,7 @@
196 mir_buffer_stream_release;196 mir_buffer_stream_release;
197 mir_buffer_stream_release_sync;197 mir_buffer_stream_release_sync;
198 mir_buffer_stream_is_valid;198 mir_buffer_stream_is_valid;
199 mir_pointer_event_buttons; # Move to 8.5
199} MIR_CLIENT_8.3;200} MIR_CLIENT_8.3;
200201
201MIR_CLIENT_DETAIL_8 {202MIR_CLIENT_DETAIL_8 {
@@ -208,6 +209,8 @@
208 mir::input::android::mir_modifiers_from_android*;209 mir::input::android::mir_modifiers_from_android*;
209 mir::input::android::mir_keyboard_action_from_android*;210 mir::input::android::mir_keyboard_action_from_android*;
210 mir::input::android::android_keyboard_action_from_mir*;211 mir::input::android::android_keyboard_action_from_mir*;
212 mir::input::android::mir_pointer_buttons_from_android*;
213 mir::input::android::android_pointer_buttons_from_mir*;
211 mir::client::DefaultConnectionConfiguration::DefaultConnectionConfiguration*;214 mir::client::DefaultConnectionConfiguration::DefaultConnectionConfiguration*;
212 mir::client::DefaultConnectionConfiguration::the_surface_map*;215 mir::client::DefaultConnectionConfiguration::the_surface_map*;
213 mir::client::DefaultConnectionConfiguration::the_rpc_channel*;216 mir::client::DefaultConnectionConfiguration::the_rpc_channel*;
214217
=== modified file 'src/include/common/mir/events/event_private.h'
--- src/include/common/mir/events/event_private.h 2015-05-07 19:43:49 +0000
+++ src/include/common/mir/events/event_private.h 2015-05-14 18:12:40 +0000
@@ -60,14 +60,6 @@
60} MirMotionAction;60} MirMotionAction;
6161
62typedef enum {62typedef enum {
63 mir_motion_button_primary = 1 << 0,
64 mir_motion_button_secondary = 1 << 1,
65 mir_motion_button_tertiary = 1 << 2,
66 mir_motion_button_back = 1 << 3,
67 mir_motion_button_forward = 1 << 4
68} MirMotionButton;
69
70typedef enum {
71 mir_motion_tool_type_unknown = 0,63 mir_motion_tool_type_unknown = 0,
72 mir_motion_tool_type_finger = 1,64 mir_motion_tool_type_finger = 1,
73 mir_motion_tool_type_stylus = 2,65 mir_motion_tool_type_stylus = 2,
@@ -125,7 +117,7 @@
125 int action;117 int action;
126 MirInputEventModifiers modifiers;118 MirInputEventModifiers modifiers;
127119
128 MirMotionButton button_state;120 MirPointerButtons buttons;
129 std::chrono::nanoseconds event_time;121 std::chrono::nanoseconds event_time;
130122
131 size_t pointer_count;123 size_t pointer_count;
132124
=== modified file 'src/include/common/mir/input/android/event_conversion_helpers.h'
--- src/include/common/mir/input/android/event_conversion_helpers.h 2015-05-08 20:44:56 +0000
+++ src/include/common/mir/input/android/event_conversion_helpers.h 2015-05-14 18:12:40 +0000
@@ -31,13 +31,15 @@
31int32_t android_modifiers_from_mir(MirInputEventModifiers modifiers);31int32_t android_modifiers_from_mir(MirInputEventModifiers modifiers);
3232
33MirKeyboardAction mir_keyboard_action_from_android(int32_t android_action, int32_t repeat_count);33MirKeyboardAction mir_keyboard_action_from_android(int32_t android_action, int32_t repeat_count);
34
35// Mir differentiates between mir_keyboard_action_down34// Mir differentiates between mir_keyboard_action_down
36// and mir_keyboard_action_repeat whereas android encodes35// and mir_keyboard_action_repeat whereas android encodes
37// keyrepeats as AKEY_EVENT_ACTION_DOWN and a repeatCount of > 036// keyrepeats as AKEY_EVENT_ACTION_DOWN and a repeatCount of > 0
38// Thus when converting from MirKeyboardAction to an android37// Thus when converting from MirKeyboardAction to an android
39// action we must also fetch a repeat count for the android event.38// action we must also fetch a repeat count for the android event.
40int32_t android_keyboard_action_from_mir(int32_t& repeat_count_out, MirKeyboardAction action);39int32_t android_keyboard_action_from_mir(int32_t& repeat_count_out, MirKeyboardAction action);
40
41MirPointerButtons mir_pointer_buttons_from_android(int32_t android_state);
42int32_t android_pointer_buttons_from_mir(MirPointerButtons buttons);
41}43}
42}44}
43}45}
4446
=== modified file 'src/server/input/android/android_input_dispatcher.cpp'
--- src/server/input/android/android_input_dispatcher.cpp 2015-05-08 20:54:52 +0000
+++ src/server/input/android/android_input_dispatcher.cpp 2015-05-14 18:12:40 +0000
@@ -102,7 +102,7 @@
102 event.motion.action,102 event.motion.action,
103 0, /* flags */103 0, /* flags */
104 mia::android_modifiers_from_mir(event.motion.modifiers),104 mia::android_modifiers_from_mir(event.motion.modifiers),
105 event.motion.button_state,105 mia::android_pointer_buttons_from_mir(event.motion.buttons),
106 0, /* edge_flags */106 0, /* edge_flags */
107 event.motion.pointer_count,107 event.motion.pointer_count,
108 pointer_properties.data(),108 pointer_properties.data(),
109109
=== modified file 'src/server/input/android/input_sender.cpp'
--- src/server/input/android/input_sender.cpp 2015-05-08 20:54:52 +0000
+++ src/server/input/android/input_sender.cpp 2015-05-14 18:12:40 +0000
@@ -288,7 +288,7 @@
288 0, /* flags */288 0, /* flags */
289 0, /* edge flags */289 0, /* edge flags */
290 mia::android_modifiers_from_mir(event.modifiers),290 mia::android_modifiers_from_mir(event.modifiers),
291 static_cast<int32_t>(event.button_state),291 mia::android_pointer_buttons_from_mir(event.buttons),
292 0.0f, // event.x_offset,292 0.0f, // event.x_offset,
293 0.0f, // event.y_offset,293 0.0f, // event.y_offset,
294 0, 0, /* unused x/y precision */294 0, 0, /* unused x/y precision */
295295
=== modified file 'src/server/input/android/input_translator.cpp'
--- src/server/input/android/input_translator.cpp 2015-05-07 19:43:49 +0000
+++ src/server/input/android/input_translator.cpp 2015-05-14 18:12:40 +0000
@@ -147,7 +147,7 @@
147 mir_event.motion.source_id = args->source;147 mir_event.motion.source_id = args->source;
148 mir_event.motion.action = args->action;148 mir_event.motion.action = args->action;
149 mir_event.motion.modifiers = mia::mir_modifiers_from_android(args->metaState);149 mir_event.motion.modifiers = mia::mir_modifiers_from_android(args->metaState);
150 mir_event.motion.button_state = static_cast<MirMotionButton>(args->buttonState);150 mir_event.motion.buttons = mia::mir_pointer_buttons_from_android(args->buttonState);
151 mir_event.motion.event_time = args->eventTime;151 mir_event.motion.event_time = args->eventTime;
152 mir_event.motion.pointer_count = args->pointerCount;152 mir_event.motion.pointer_count = args->pointerCount;
153 for(unsigned int i = 0; i < args->pointerCount; i++)153 for(unsigned int i = 0; i < args->pointerCount; i++)
154154
=== modified file 'src/server/input/default_configuration.cpp'
--- src/server/input/default_configuration.cpp 2015-05-04 10:45:05 +0000
+++ src/server/input/default_configuration.cpp 2015-05-14 18:12:40 +0000
@@ -426,6 +426,7 @@
426 the_input_reading_multiplexer(),426 the_input_reading_multiplexer(),
427 the_main_loop(),427 the_main_loop(),
428 the_touch_visualizer(),428 the_touch_visualizer(),
429 the_cursor_listener(),
429 the_input_region());430 the_input_region());
430 });431 });
431}432}
@@ -439,6 +440,7 @@
439 the_input_reading_multiplexer(),440 the_input_reading_multiplexer(),
440 the_main_loop(),441 the_main_loop(),
441 the_touch_visualizer(),442 the_touch_visualizer(),
443 the_cursor_listener(),
442 the_input_region());444 the_input_region());
443 });445 });
444}446}
445447
=== modified file 'src/server/input/default_input_device_hub.cpp'
--- src/server/input/default_input_device_hub.cpp 2015-04-14 11:08:21 +0000
+++ src/server/input/default_input_device_hub.cpp 2015-05-14 18:12:40 +0000
@@ -23,6 +23,7 @@
23#include "mir/input/input_dispatcher.h"23#include "mir/input/input_dispatcher.h"
24#include "mir/input/input_device.h"24#include "mir/input/input_device.h"
25#include "mir/input/input_device_observer.h"25#include "mir/input/input_device_observer.h"
26#include "mir/input/cursor_listener.h"
26#include "mir/input/input_region.h"27#include "mir/input/input_region.h"
27#include "mir/events/event_private.h"28#include "mir/events/event_private.h"
28#include "mir/dispatch/multiplexing_dispatchable.h"29#include "mir/dispatch/multiplexing_dispatchable.h"
@@ -42,9 +43,10 @@
42 std::shared_ptr<dispatch::MultiplexingDispatchable> const& input_multiplexer,43 std::shared_ptr<dispatch::MultiplexingDispatchable> const& input_multiplexer,
43 std::shared_ptr<mir::ServerActionQueue> const& observer_queue,44 std::shared_ptr<mir::ServerActionQueue> const& observer_queue,
44 std::shared_ptr<TouchVisualizer> const& touch_visualizer,45 std::shared_ptr<TouchVisualizer> const& touch_visualizer,
46 std::shared_ptr<CursorListener> const& cursor_listener,
45 std::shared_ptr<InputRegion> const& input_region)47 std::shared_ptr<InputRegion> const& input_region)
46 : input_dispatcher(input_dispatcher), input_dispatchable{input_multiplexer}, observer_queue(observer_queue),48 : input_dispatcher(input_dispatcher), input_dispatchable{input_multiplexer}, observer_queue(observer_queue),
47 touch_visualizer(touch_visualizer), input_region(input_region)49 touch_visualizer(touch_visualizer), cursor_listener(cursor_listener), input_region(input_region)
48{50{
49}51}
5052
@@ -163,9 +165,22 @@
163 BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid input event receivd from device"));165 BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid input event receivd from device"));
164166
165 update_spots(mir_event_get_input_event(&event));167 update_spots(mir_event_get_input_event(&event));
168 notify_cursor_listener(mir_event_get_input_event(&event));
166 dispatcher->dispatch(event);169 dispatcher->dispatch(event);
167}170}
168171
172void mi::DefaultInputDeviceHub::RegisteredDevice::notify_cursor_listener(MirInputEvent const* event)
173{
174 if (mir_input_event_get_type(event) != mir_input_event_type_pointer)
175 return;
176
177 auto pointer_ev = mir_input_event_get_pointer_event(event);
178 hub->cursor_listener->cursor_moved_to(
179 mir_pointer_event_axis_value(pointer_ev, mir_pointer_axis_x),
180 mir_pointer_event_axis_value(pointer_ev, mir_pointer_axis_y)
181 );
182}
183
169void mi::DefaultInputDeviceHub::RegisteredDevice::update_spots(MirInputEvent const* event)184void mi::DefaultInputDeviceHub::RegisteredDevice::update_spots(MirInputEvent const* event)
170{185{
171 if (mir_input_event_get_type(event) != mir_input_event_type_touch)186 if (mir_input_event_get_type(event) != mir_input_event_type_touch)
172187
=== modified file 'src/server/input/default_input_device_hub.h'
--- src/server/input/default_input_device_hub.h 2015-04-14 11:08:21 +0000
+++ src/server/input/default_input_device_hub.h 2015-05-14 18:12:40 +0000
@@ -46,6 +46,7 @@
46class InputDeviceObserver;46class InputDeviceObserver;
47class TouchVisualizer;47class TouchVisualizer;
48class InputRegion;48class InputRegion;
49class CursorListener;
4950
50class DefaultInputDeviceHub : public InputDeviceRegistry, public InputDeviceHub51class DefaultInputDeviceHub : public InputDeviceRegistry, public InputDeviceHub
51{52{
@@ -54,6 +55,7 @@
54 std::shared_ptr<dispatch::MultiplexingDispatchable> const& input_multiplexer,55 std::shared_ptr<dispatch::MultiplexingDispatchable> const& input_multiplexer,
55 std::shared_ptr<ServerActionQueue> const& observer_queue,56 std::shared_ptr<ServerActionQueue> const& observer_queue,
56 std::shared_ptr<TouchVisualizer> const& touch_visualizer,57 std::shared_ptr<TouchVisualizer> const& touch_visualizer,
58 std::shared_ptr<CursorListener> const& cursor_listener,
57 std::shared_ptr<InputRegion> const& input_region);59 std::shared_ptr<InputRegion> const& input_region);
5860
59 // InputDeviceRegistry - calls from mi::Platform61 // InputDeviceRegistry - calls from mi::Platform
@@ -72,6 +74,7 @@
72 std::shared_ptr<dispatch::MultiplexingDispatchable> const input_dispatchable;74 std::shared_ptr<dispatch::MultiplexingDispatchable> const input_dispatchable;
73 std::shared_ptr<ServerActionQueue> const observer_queue;75 std::shared_ptr<ServerActionQueue> const observer_queue;
74 std::shared_ptr<TouchVisualizer> const touch_visualizer;76 std::shared_ptr<TouchVisualizer> const touch_visualizer;
77 std::shared_ptr<CursorListener> const cursor_listener;
75 std::shared_ptr<InputRegion> const input_region;78 std::shared_ptr<InputRegion> const input_region;
7679
77 struct RegisteredDevice : public InputSink80 struct RegisteredDevice : public InputSink
@@ -89,6 +92,7 @@
89 std::vector<TouchVisualizer::Spot> const& spots() const;92 std::vector<TouchVisualizer::Spot> const& spots() const;
90 private:93 private:
91 void update_spots(MirInputEvent const* event);94 void update_spots(MirInputEvent const* event);
95 void notify_cursor_listener(MirInputEvent const* event);
92 static int32_t create_new_device_id();96 static int32_t create_new_device_id();
93 int32_t device_id;97 int32_t device_id;
94 std::shared_ptr<InputDevice> const device;98 std::shared_ptr<InputDevice> const device;
9599
=== modified file 'tests/acceptance-tests/test_client_input.cpp'
--- tests/acceptance-tests/test_client_input.cpp 2015-05-04 17:33:07 +0000
+++ tests/acceptance-tests/test_client_input.cpp 2015-05-14 18:12:40 +0000
@@ -16,20 +16,22 @@
16 * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>16 * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
17 */17 */
1818
19#define MIR_INCLUDE_DEPRECATED_EVENT_HEADER
20
21#include "mir/input/input_device_info.h"19#include "mir/input/input_device_info.h"
22#include "mir/input/event_filter.h"20#include "mir/input/event_filter.h"
23#include "mir/input/composite_event_filter.h"21#include "mir/input/composite_event_filter.h"
2422
25#include "mir_test_framework/connected_client_with_a_surface.h"23#include "mir_test_framework/headless_in_process_server.h"
26#include "mir_test_framework/fake_input_device.h"24#include "mir_test_framework/fake_input_device.h"
25#include "mir_test_framework/placement_applying_shell.h"
27#include "mir_test_framework/stub_server_platform_factory.h"26#include "mir_test_framework/stub_server_platform_factory.h"
28#include "mir_test/wait_condition.h"27#include "mir_test/wait_condition.h"
29#include "mir_test/spin_wait.h"28#include "mir_test/spin_wait.h"
30#include "mir_test/event_matchers.h"29#include "mir_test/event_matchers.h"
31#include "mir_test/event_factory.h"30#include "mir_test/event_factory.h"
3231
32#include "mir_toolkit/mir_client_library.h"
33#include "mir/events/event_builders.h"
34
33#include <gtest/gtest.h>35#include <gtest/gtest.h>
34#include <gmock/gmock.h>36#include <gmock/gmock.h>
3537
@@ -41,17 +43,14 @@
4143
42namespace mi = mir::input;44namespace mi = mir::input;
43namespace mt = mir::test;45namespace mt = mir::test;
46namespace ms = mir::scene;
44namespace mis = mir::input::synthesis;47namespace mis = mir::input::synthesis;
45namespace mtf = mir_test_framework;48namespace mtf = mir_test_framework;
49namespace geom = mir::geometry;
4650
47namespace51namespace
48{52{
4953
50struct MockInputHandler
51{
52 MOCK_METHOD1(handle_input, void(MirEvent const*));
53};
54
55struct MockEventFilter : public mi::EventFilter54struct MockEventFilter : public mi::EventFilter
56{55{
57 // Work around GMock wanting to know how to construct MirEvent56 // Work around GMock wanting to know how to construct MirEvent
@@ -63,71 +62,127 @@
63 }62 }
64};63};
6564
66struct TestClientInputNew : mtf::ConnectedClientWithASurface65const int surface_width = 100;
66const int surface_height = 100;
67
68struct Client
67{69{
68 void SetUp() override70 MirSurface* surface{nullptr};
71
72 MOCK_METHOD1(handle_input, void(MirEvent const*));
73 MOCK_METHOD1(handle_keymap, void(MirEvent const*));
74
75 Client(std::string const& con, std::string const& name)
69 {76 {
70 ConnectedClientWithASurface::SetUp();77 connection = mir_connect_sync(con.c_str(), name.c_str());
7178
72 mir_surface_set_event_handler(surface, handle_input, this);79 if (!mir_connection_is_valid(connection))
80 {
81 BOOST_THROW_EXCEPTION(
82 std::runtime_error{std::string{"Failed to connect to test server: "} +
83 mir_connection_get_error_message(connection)});
84 }
85 auto spec = mir_connection_create_spec_for_normal_surface(connection, surface_width,
86 surface_height, mir_pixel_format_abgr_8888);
87 mir_surface_spec_set_name(spec, name.c_str());
88 surface = mir_surface_create_sync(spec);
89 mir_surface_spec_release(spec);
90 if (!mir_surface_is_valid(surface))
91 BOOST_THROW_EXCEPTION(std::runtime_error{std::string{"Failed creating a surface: "}+
92 mir_surface_get_error_message(surface)});
93
94 mir_surface_set_event_handler(surface, handle_event, this);
73 mir_buffer_stream_swap_buffers_sync(95 mir_buffer_stream_swap_buffers_sync(
74 mir_surface_get_buffer_stream(surface));96 mir_surface_get_buffer_stream(surface));
7597
76 wait_for_surface_to_become_focused_and_exposed();98 ready_to_accept_events.wait_for_at_most_seconds(4);
77 ready_to_accept_events.wake_up_everyone();99 if (!ready_to_accept_events.woken())
100 BOOST_THROW_EXCEPTION(std::runtime_error("Timeout waiting for surface to become focused and exposed"));
78 }101 }
79102
80 static void handle_input(MirSurface*, MirEvent const* ev, void* context)103 static void handle_event(MirSurface*, MirEvent const* ev, void* context)
81 {104 {
82 auto const client = static_cast<TestClientInputNew*>(context);105 auto const client = static_cast<Client*>(context);
83 auto type = mir_event_get_type(ev);106 auto type = mir_event_get_type(ev);
107 if (type == mir_event_type_surface)
108 {
109 auto surface_event = mir_event_get_surface_event(ev);
110
111 if (mir_surface_attrib_focus == mir_surface_event_get_attribute(surface_event) &&
112 1 == mir_surface_event_get_attribute_value(surface_event))
113 client->ready_to_accept_events.wake_up_everyone();
114 }
84 if (type == mir_event_type_input)115 if (type == mir_event_type_input)
85 client->handler.handle_input(ev);116 client->handle_input(ev);
86 }117 if (type == mir_event_type_keymap)
87118 client->handle_keymap(ev);
88 void wait_for_surface_to_become_focused_and_exposed()119 }
89 {120 ~Client()
90 bool success = mt::spin_wait_for_condition_or_timeout(121 {
91 [&]122 mir_surface_release_sync(surface);
123 mir_connection_release(connection);
124 }
125 MirConnection * connection;
126 mir::test::WaitCondition ready_to_accept_events;
127 mir::test::WaitCondition all_events_received;
128};
129
130struct TestClientInput : mtf::HeadlessInProcessServer
131{
132 void SetUp() override
133 {
134 initial_display_layout({screen_geometry});
135
136 server.wrap_shell(
137 [this](std::shared_ptr<mir::shell::Shell> const& wrapped)
92 {138 {
93 return mir_surface_get_visibility(surface) == mir_surface_visibility_exposed &&139 return std::make_shared<mtf::PlacementApplyingShell>(
94 mir_surface_get_focus(surface) == mir_surface_focused;140 wrapped,
95 },141 input_regions, positions, depths);
96 std::chrono::seconds{5});142 });
97143
98 if (!success)144 HeadlessInProcessServer::SetUp();
99 throw std::runtime_error("Timeout waiting for surface to become focused and exposed");145
146 depths[first] = ms::DepthId{0};
147 positions[first] = geom::Rectangle{{0,0}, {surface_width, surface_height}};
100 }148 }
101149
102 std::unique_ptr<mtf::FakeInputDevice> fake_keyboard{150 std::unique_ptr<mtf::FakeInputDevice> fake_keyboard{
103 mtf::add_fake_input_device(mi::InputDeviceInfo{ 0, "keyboard", "keyboard-uid" , mi::DeviceCapability::keyboard})151 mtf::add_fake_input_device(mi::InputDeviceInfo{ 0, "keyboard", "keyboard-uid" , mi::DeviceCapability::keyboard})
104 };152 };
105 ::testing::NiceMock<MockInputHandler> handler;153 std::unique_ptr<mtf::FakeInputDevice> fake_mouse{
106 mir::test::WaitCondition all_events_received;154 mtf::add_fake_input_device(mi::InputDeviceInfo{ 0, "mouse", "mouse-uid" , mi::DeviceCapability::pointer})
107 mir::test::WaitCondition ready_to_accept_events;155 };
156 std::unique_ptr<mtf::FakeInputDevice> fake_touch_screen{mtf::add_fake_input_device(mi::InputDeviceInfo{
157 0, "touch screen", "touch-screen-uid", mi::DeviceCapability::touchscreen | mi::DeviceCapability::multitouch})};
108158
159 std::string first{"first"};
160 std::string second{"second"};
161 mtf::ClientInputRegions input_regions;
162 mtf::ClientPositions positions;
163 mtf::ClientDepths depths;
164 geom::Rectangle screen_geometry{{0,0}, {1000,800}};
109 std::shared_ptr<MockEventFilter> mock_event_filter = std::make_shared<MockEventFilter>();165 std::shared_ptr<MockEventFilter> mock_event_filter = std::make_shared<MockEventFilter>();
110};166};
111167
112}168}
113169
170using namespace ::testing;
114171
115TEST_F(TestClientInputNew, clients_receive_keys)172TEST_F(TestClientInput, clients_receive_keys)
116{173{
117 using namespace testing;174 Client first_client(new_connection(), first);
118175
119 InSequence seq;176 InSequence seq;
120 EXPECT_CALL(handler, handle_input(AllOf(mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_Shift_R))));177 EXPECT_CALL(first_client, handle_input(AllOf(mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_Shift_R))));
121 EXPECT_CALL(handler, handle_input(AllOf(mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_M))));178 EXPECT_CALL(first_client, handle_input(AllOf(mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_M))));
122 EXPECT_CALL(handler, handle_input(AllOf(mt::KeyUpEvent(), mt::KeyOfSymbol(XKB_KEY_M))));179 EXPECT_CALL(first_client, handle_input(AllOf(mt::KeyUpEvent(), mt::KeyOfSymbol(XKB_KEY_M))));
123 EXPECT_CALL(handler, handle_input(AllOf(mt::KeyUpEvent(), mt::KeyOfSymbol(XKB_KEY_Shift_R))));180 EXPECT_CALL(first_client, handle_input(AllOf(mt::KeyUpEvent(), mt::KeyOfSymbol(XKB_KEY_Shift_R))));
124 EXPECT_CALL(handler, handle_input(AllOf(mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_i))));181 EXPECT_CALL(first_client, handle_input(AllOf(mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_i))));
125 EXPECT_CALL(handler, handle_input(AllOf(mt::KeyUpEvent(), mt::KeyOfSymbol(XKB_KEY_i))));182 EXPECT_CALL(first_client, handle_input(AllOf(mt::KeyUpEvent(), mt::KeyOfSymbol(XKB_KEY_i))));
126 EXPECT_CALL(handler, handle_input(AllOf(mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_r))));183 EXPECT_CALL(first_client, handle_input(AllOf(mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_r))));
127 EXPECT_CALL(handler, handle_input(AllOf(mt::KeyUpEvent(), mt::KeyOfSymbol(XKB_KEY_r)))).WillOnce(184 EXPECT_CALL(first_client, handle_input(AllOf(mt::KeyUpEvent(), mt::KeyOfSymbol(XKB_KEY_r)))).WillOnce(
128 mt::WakeUp(&all_events_received));185 mt::WakeUp(&first_client.all_events_received));
129
130 ready_to_accept_events.wait_for_at_most_seconds(5);
131186
132 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_RIGHTSHIFT));187 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_RIGHTSHIFT));
133 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_M));188 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_M));
@@ -138,38 +193,424 @@
138 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_R));193 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_R));
139 fake_keyboard->emit_event(mis::a_key_up_event().of_scancode(KEY_R));194 fake_keyboard->emit_event(mis::a_key_up_event().of_scancode(KEY_R));
140195
141 all_events_received.wait_for_at_most_seconds(10);196 first_client.all_events_received.wait_for_at_most_seconds(10);
142}197}
143198
144namespace199TEST_F(TestClientInput, clients_receive_us_english_mapped_keys)
145{200{
146struct TestClientInputNewEventFilter : public TestClientInputNew201 Client first_client(new_connection(), first);
147{202
148 void SetUp() override203 InSequence seq;
149 {204 EXPECT_CALL(first_client, handle_input(AllOf(mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_Shift_L))));
150 TestClientInputNew::SetUp();205 EXPECT_CALL(first_client, handle_input(AllOf(mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_dollar))))
151 server.the_composite_event_filter()->append(mock_event_filter);206 .WillOnce(mt::WakeUp(&first_client.all_events_received));
152 }207
208 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_LEFTSHIFT));
209 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_4));
210 first_client.all_events_received.wait_for_at_most_seconds(10);
211}
212
213TEST_F(TestClientInput, clients_receive_pointer_inside_window_and_crossing_events)
214{
215 positions[first] = geom::Rectangle{{0,0}, {surface_width, surface_height}};
216 Client first_client(new_connection(), first);
217
218 // We should see the cursor enter
219 InSequence seq;
220 EXPECT_CALL(first_client, handle_input(mt::PointerEnterEvent()));
221 EXPECT_CALL(first_client, handle_input(mt::PointerEventWithPosition(surface_width - 1, surface_height - 1)));
222 EXPECT_CALL(first_client, handle_input(mt::PointerLeaveEvent()))
223 .WillOnce(mt::WakeUp(&first_client.all_events_received));
224 // But we should not receive an event for the second movement outside of our surface!
225
226 fake_mouse->emit_event(mis::a_pointer_event().with_movement(surface_width - 1, surface_height - 1));
227 fake_mouse->emit_event(mis::a_pointer_event().with_movement(2, 2));
228
229 first_client.all_events_received.wait_for_at_most_seconds(120);
230}
231
232TEST_F(TestClientInput, clients_receive_button_events_inside_window)
233{
234 Client first_client(new_connection(), first);
235 // The cursor starts at (0, 0).
236 EXPECT_CALL(first_client, handle_input(mt::ButtonDownEvent(0, 0)))
237 .WillOnce(mt::WakeUp(&first_client.all_events_received));
238
239 fake_mouse->emit_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
240
241 first_client.all_events_received.wait_for_at_most_seconds(10);
242}
243
244TEST_F(TestClientInput, clients_receive_many_button_events_inside_window)
245{
246 Client first_client(new_connection(), first);
247 // The cursor starts at (0, 0).
248
249 InSequence seq;
250 auto expect_buttons = [&](MirPointerButtons b) {
251 EXPECT_CALL(first_client, handle_input(mt::ButtonsDown(0, 0, b)));
252 };
253
254 MirPointerButtons buttons = mir_pointer_button_primary;
255 expect_buttons(buttons);
256 expect_buttons(buttons |= mir_pointer_button_secondary);
257 expect_buttons(buttons |= mir_pointer_button_tertiary);
258 expect_buttons(buttons |= mir_pointer_button_forward);
259 expect_buttons(buttons |= mir_pointer_button_back);
260 expect_buttons(buttons &= ~mir_pointer_button_back);
261 expect_buttons(buttons &= ~mir_pointer_button_forward);
262 expect_buttons(buttons &= ~mir_pointer_button_tertiary);
263 expect_buttons(buttons &= ~mir_pointer_button_secondary);
264 EXPECT_CALL(first_client, handle_input(mt::ButtonsDown(0, 0, 0))).WillOnce(
265 mt::WakeUp(&first_client.all_events_received));
266
267 auto press_button = [&](int button) {
268 fake_mouse->emit_event(mis::a_button_down_event().of_button(button).with_action(mis::EventAction::Down));
269 };
270 auto release_button = [&](int button) {
271 fake_mouse->emit_event(mis::a_button_up_event().of_button(button).with_action(mis::EventAction::Up));
272 };
273 press_button(BTN_LEFT);
274 press_button(BTN_RIGHT);
275 press_button(BTN_MIDDLE);
276 press_button(BTN_FORWARD);
277 press_button(BTN_BACK);
278 release_button(BTN_BACK);
279 release_button(BTN_FORWARD);
280 release_button(BTN_MIDDLE);
281 release_button(BTN_RIGHT);
282 release_button(BTN_LEFT);
283
284 first_client.all_events_received.wait_for_at_most_seconds(10);
285}
286
287TEST_F(TestClientInput, multiple_clients_receive_pointer_inside_windows)
288{
289 int const screen_width = screen_geometry.size.width.as_int();
290 int const screen_height = screen_geometry.size.height.as_int();
291 int const client_height = screen_height / 2;
292 int const client_width = screen_width / 2;
293
294 positions[first] = {{0, 0}, {client_width, client_height}};
295 positions[second] = {{client_width, client_height}, {client_width, client_height}};
296
297 Client first_client(new_connection(), first);
298 Client second_client(new_connection(), second);
299
300 {
301 InSequence seq;
302 EXPECT_CALL(first_client, handle_input(mt::PointerEnterEvent()));
303 EXPECT_CALL(first_client, handle_input(mt::PointerEventWithPosition(client_width - 1, client_height - 1)));
304 EXPECT_CALL(first_client, handle_input(mt::PointerLeaveEvent()))
305 .WillOnce(mt::WakeUp(&first_client.all_events_received));
306 }
307
308 {
309 InSequence seq;
310 EXPECT_CALL(second_client, handle_input(mt::PointerEnterEvent()));
311 EXPECT_CALL(second_client, handle_input(mt::PointerEventWithPosition(client_width - 1, client_height - 1)))
312 .WillOnce(mt::WakeUp(&second_client.all_events_received));
313 }
314
315 // In the bounds of the first surface
316 fake_mouse->emit_event(mis::a_pointer_event().with_movement(client_width - 1, client_height - 1));
317 // In the bounds of the second surface
318 fake_mouse->emit_event(mis::a_pointer_event().with_movement(client_width, client_height));
319
320 first_client.all_events_received.wait_for_at_most_seconds(2);
321 second_client.all_events_received.wait_for_at_most_seconds(2);
322}
323
324TEST_F(TestClientInput, clients_do_not_receive_pointer_outside_input_region)
325{
326 int const client_height = surface_height;
327 int const client_width = surface_width;
328
329 input_regions[first] = {{{0, 0}, {client_width - 80, client_height}},
330 {{client_width - 20, 0}, {client_width - 80, client_height}}};
331
332 Client first_client(new_connection(), first);
333
334 EXPECT_CALL(first_client, handle_input(mt::PointerEnterEvent())).Times(AnyNumber());
335 EXPECT_CALL(first_client, handle_input(mt::PointerLeaveEvent())).Times(AnyNumber());
336 EXPECT_CALL(first_client, handle_input(mt::PointerMovementEvent())).Times(AnyNumber());
337
338 {
339 // We should see two of the three button pairs.
340 InSequence seq;
341 EXPECT_CALL(first_client, handle_input(mt::ButtonDownEvent(1, 1)));
342 EXPECT_CALL(first_client, handle_input(mt::ButtonUpEvent(1, 1)));
343 EXPECT_CALL(first_client, handle_input(mt::ButtonDownEvent(99, 99)));
344 EXPECT_CALL(first_client, handle_input(mt::ButtonUpEvent(99, 99)))
345 .WillOnce(mt::WakeUp(&first_client.all_events_received));
346 }
347
348 // First we will move the cursor in to the input region on the left side of
349 // the window. We should see a click here.
350 fake_mouse->emit_event(mis::a_pointer_event().with_movement(1, 1));
351 fake_mouse->emit_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
352 fake_mouse->emit_event(mis::a_button_up_event().of_button(BTN_LEFT));
353
354 // Now in to the dead zone in the center of the window. We should not see
355 // a click here.
356 fake_mouse->emit_event(mis::a_pointer_event().with_movement(49, 49));
357 fake_mouse->emit_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
358 fake_mouse->emit_event(mis::a_button_up_event().of_button(BTN_LEFT));
359
360 // Now in to the right edge of the window, in the right input region.
361 // Again we should see a click.
362 fake_mouse->emit_event(mis::a_pointer_event().with_movement(49, 49));
363 fake_mouse->emit_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
364 fake_mouse->emit_event(mis::a_button_up_event().of_button(BTN_LEFT));
365
366 first_client.all_events_received.wait_for_at_most_seconds(5);
367}
368
369TEST_F(TestClientInput, scene_obscure_motion_events_by_stacking)
370{
371 auto smaller_geometry = screen_geometry;
372 smaller_geometry.size.width =
373 geom::Width{screen_geometry.size.width.as_uint32_t() / 2};
374
375 positions[first] = screen_geometry;
376 positions[second] = smaller_geometry;
377 depths[second] = ms::DepthId{1};
378
379 Client first_client(new_connection(), first);
380 Client second_client(new_connection(), second);
381
382 EXPECT_CALL(first_client, handle_input(mt::PointerEnterEvent())).Times(AnyNumber());
383 EXPECT_CALL(first_client, handle_input(mt::PointerLeaveEvent())).Times(AnyNumber());
384 EXPECT_CALL(first_client, handle_input(mt::PointerMovementEvent())).Times(AnyNumber());
385 {
386 // We should only see one button event sequence.
387 InSequence seq;
388 EXPECT_CALL(first_client, handle_input(mt::ButtonDownEvent(501, 1)));
389 EXPECT_CALL(first_client, handle_input(mt::ButtonUpEvent(501, 1)))
390 .WillOnce(mt::WakeUp(&first_client.all_events_received));
391 }
392
393 EXPECT_CALL(second_client, handle_input(mt::PointerEnterEvent())).Times(AnyNumber());
394 EXPECT_CALL(second_client, handle_input(mt::PointerLeaveEvent())).Times(AnyNumber());
395 EXPECT_CALL(second_client, handle_input(mt::PointerMovementEvent())).Times(AnyNumber());
396 {
397 // Likewise we should only see one button sequence.
398 InSequence seq;
399 EXPECT_CALL(second_client, handle_input(mt::ButtonDownEvent(1, 1)));
400 EXPECT_CALL(second_client, handle_input(mt::ButtonUpEvent(1, 1)))
401 .WillOnce(mt::WakeUp(&second_client.all_events_received));
402 }
403
404 // First we will move the cursor in to the region where client 2 obscures client 1
405 fake_mouse->emit_event(mis::a_pointer_event().with_movement(1, 1));
406 fake_mouse->emit_event(
407 mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
408 fake_mouse->emit_event(mis::a_button_up_event().of_button(BTN_LEFT));
409 // Now we move to the unobscured region of client 1
410 fake_mouse->emit_event(mis::a_pointer_event().with_movement(500, 0));
411 fake_mouse->emit_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
412 fake_mouse->emit_event(mis::a_button_up_event().of_button(BTN_LEFT));
413
414 first_client.all_events_received.wait_for_at_most_seconds(5);
415 second_client.all_events_received.wait_for_at_most_seconds(5);
416}
417
418TEST_F(TestClientInput, hidden_clients_do_not_receive_pointer_events)
419{
420 depths[second] = ms::DepthId{1};
421 positions[second] = {{0,0}, {surface_width, surface_height}};
422
423 Client first_client(new_connection(), first);
424 Client second_client(new_connection(), second);
425
426 EXPECT_CALL(second_client, handle_input(mt::PointerEnterEvent())).Times(AnyNumber());
427 EXPECT_CALL(second_client, handle_input(mt::PointerLeaveEvent())).Times(AnyNumber());
428 EXPECT_CALL(second_client, handle_input(mt::PointerEventWithPosition(1, 1)))
429 .WillOnce(mt::WakeUp(&second_client.all_events_received));
430
431 EXPECT_CALL(first_client, handle_input(mt::PointerEnterEvent())).Times(AnyNumber());
432 EXPECT_CALL(first_client, handle_input(mt::PointerLeaveEvent())).Times(AnyNumber());
433 EXPECT_CALL(first_client, handle_input(mt::PointerEventWithPosition(2, 2)))
434 .WillOnce(mt::WakeUp(&first_client.all_events_received));
435
436 // We send one event and then hide the surface on top before sending the next.
437 // So we expect each of the two surfaces to receive one event
438 fake_mouse->emit_event(mis::a_pointer_event().with_movement(1,1));
439
440 second_client.all_events_received.wait_for_at_most_seconds(2);
441
442 server.the_shell()->focused_session()->hide();
443
444 fake_mouse->emit_event(mis::a_pointer_event().with_movement(1,1));
445 first_client.all_events_received.wait_for_at_most_seconds(2);
446}
447
448TEST_F(TestClientInput, clients_receive_pointer_within_coordinate_system_of_window)
449{
450 int const screen_width = screen_geometry.size.width.as_int();
451 int const screen_height = screen_geometry.size.height.as_int();
452 int const client_height = screen_height / 2;
453 int const client_width = screen_width / 2;
454
455 positions[first] = {{screen_width / 2, screen_height / 2}, {client_width, client_height}};
456
457 Client first_client(new_connection(), first);
458
459 InSequence seq;
460 EXPECT_CALL(first_client, handle_input(mt::PointerEnterEvent()));
461 EXPECT_CALL(first_client, handle_input(mt::PointerEventWithPosition(80, 170)))
462 .Times(AnyNumber())
463 .WillOnce(mt::WakeUp(&first_client.all_events_received));
464
465 server.the_shell()->focused_surface()->move_to(geom::Point{screen_width / 2 - 40, screen_height / 2 - 80});
466
467 fake_mouse->emit_event(mis::a_pointer_event().with_movement(screen_width / 2 + 40, screen_height / 2 + 90));
468
469 first_client.all_events_received.wait_for_at_most_seconds(2);
470}
471
472// TODO: Consider tests for more input devices with custom mapping (i.e. joysticks...)
473TEST_F(TestClientInput, usb_direct_input_devices_work)
474{
475 float const minimum_touch = mtf::FakeInputDevice::minimum_touch_axis_value;
476 float const maximum_touch = mtf::FakeInputDevice::maximum_touch_axis_value;
477 auto const display_width = screen_geometry.size.width.as_float();
478 auto const display_height = screen_geometry.size.height.as_float();
479
480 // We place a click 10% in to the touchscreens space in both axis,
481 // and a second at 0,0. Thus we expect to see a click at
482 // .1*screen_width/height and a second at zero zero.
483 float const abs_touch_x_1 = minimum_touch + (maximum_touch - minimum_touch) * 0.1f;
484 float const abs_touch_y_1 = minimum_touch + (maximum_touch - minimum_touch) * 0.1f;
485 float const abs_touch_x_2 = 0;
486 float const abs_touch_y_2 = 0;
487
488 float const expected_scale_x = display_width / (maximum_touch - minimum_touch + 1.0f);
489 float const expected_scale_y = display_height / (maximum_touch - minimum_touch + 1.0f);
490
491 float const expected_motion_x_1 = expected_scale_x * abs_touch_x_1;
492 float const expected_motion_y_1 = expected_scale_y * abs_touch_y_1;
493 float const expected_motion_x_2 = expected_scale_x * abs_touch_x_2;
494 float const expected_motion_y_2 = expected_scale_y * abs_touch_y_2;
495
496 positions[first] = screen_geometry;
497
498 Client first_client(new_connection(), first);
499
500 InSequence seq;
501 EXPECT_CALL(first_client, handle_input(
502 mt::TouchEvent(expected_motion_x_1, expected_motion_y_1)));
503 EXPECT_CALL(first_client, handle_input(
504 mt::TouchEventInDirection(expected_motion_x_1,
505 expected_motion_y_1,
506 expected_motion_x_2,
507 expected_motion_y_2)))
508 .Times(AnyNumber())
509 .WillOnce(mt::WakeUp(&first_client.all_events_received));
510
511 fake_touch_screen->emit_event(mis::a_touch_event()
512 .at_position({abs_touch_x_1, abs_touch_y_1}));
513 // Sleep here to trigger more failures (simulate slow machine)
514 // TODO why would that cause failures?b
515 std::this_thread::sleep_for(std::chrono::milliseconds(10));
516 fake_touch_screen->emit_event(mis::a_touch_event()
517 .with_action(mis::TouchParameters::Action::Move)
518 .at_position({abs_touch_x_2, abs_touch_y_2}));
519
520 first_client.all_events_received.wait_for_at_most_seconds(2);
521}
522
523TEST_F(TestClientInput, send_mir_input_events_through_surface)
524{
525 Client first_client(new_connection(), first);
526
527 EXPECT_CALL(first_client, handle_input(mt::KeyDownEvent()))
528 .WillOnce(mt::WakeUp(&first_client.all_events_received));
529
530 auto key_event = mir::events::make_event(MirInputDeviceId{0}, std::chrono::nanoseconds(0), mir_keyboard_action_down, 0, KEY_M,
531 mir_input_event_modifier_none);
532
533 server.the_shell()->focused_surface()->consume(*key_event);
534
535 first_client.all_events_received.wait_for_at_most_seconds(2);
536}
537
538TEST_F(TestClientInput, clients_receive_keymap_change_events)
539{
540 Client first_client(new_connection(), first);
541
542 xkb_rule_names names;
543 names.rules = "evdev";
544 names.model = "pc105";
545 names.layout = "dvorak";
546 names.variant = "";
547 names.options = "";
548
549 EXPECT_CALL(first_client, handle_keymap(mt::KeymapEventWithRules(names)))
550 .Times(1)
551 .WillOnce(mt::WakeUp(&first_client.all_events_received));
552
553 server.the_shell()->focused_surface()->set_keymap(names);
554 first_client.all_events_received.wait_for_at_most_seconds(2);
555}
556
557TEST_F(TestClientInput, keymap_changes_change_keycode_received)
558{
559 Client first_client(new_connection(), first);
560
561 xkb_rule_names names;
562 names.rules = "evdev";
563 names.model = "pc105";
564 names.layout = "us";
565 names.variant = "dvorak";
566 names.options = "";
567
568 mt::WaitCondition first_event_received,
569 client_sees_keymap_change;
570
571 InSequence seq;
572 EXPECT_CALL(first_client, handle_input(AllOf(mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_n))));
573 EXPECT_CALL(first_client, handle_input(mt::KeyUpEvent()))
574 .WillOnce(mt::WakeUp(&first_event_received));
575 EXPECT_CALL(first_client, handle_keymap(mt::KeymapEventWithRules(names)))
576 .WillOnce(mt::WakeUp(&client_sees_keymap_change));
577
578 EXPECT_CALL(first_client, handle_input(AllOf(mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_b))));
579 EXPECT_CALL(first_client, handle_input(mt::KeyUpEvent()))
580 .WillOnce(mt::WakeUp(&first_client.all_events_received));
581
582 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_N));
583 fake_keyboard->emit_event(mis::a_key_up_event().of_scancode(KEY_N));
584
585 first_event_received.wait_for_at_most_seconds(60);
586
587 server.the_shell()->focused_surface()->set_keymap(names);
588
589 client_sees_keymap_change.wait_for_at_most_seconds(60);
590
591 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_N));
592 fake_keyboard->emit_event(mis::a_key_up_event().of_scancode(KEY_N));
593
594 first_client.all_events_received.wait_for_at_most_seconds(5);
595}
596
597TEST_F(TestClientInput, event_filter_may_consume_events)
598{
153 std::shared_ptr<MockEventFilter> mock_event_filter = std::make_shared<MockEventFilter>();599 std::shared_ptr<MockEventFilter> mock_event_filter = std::make_shared<MockEventFilter>();
154};600 server.the_composite_event_filter()->append(mock_event_filter);
155}
156601
157TEST_F(TestClientInputNewEventFilter, event_filter_may_consume_events)602 Client first_client(new_connection(), first);
158{
159 using namespace ::testing;
160603
161 InSequence seq;604 InSequence seq;
162 EXPECT_CALL(*mock_event_filter, handle(_)).WillOnce(Return(true));605 EXPECT_CALL(*mock_event_filter, handle(_)).WillOnce(Return(true));
163 EXPECT_CALL(*mock_event_filter, handle(_)).WillOnce(606 EXPECT_CALL(*mock_event_filter, handle(_)).WillOnce(
164 DoAll(mt::WakeUp(&all_events_received), Return(true)));607 DoAll(mt::WakeUp(&first_client.all_events_received), Return(true)));
165608
166 // Since we handle the events in the filter the client should not receive them.609 // Since we handle the events in the filter the client should not receive them.
167 EXPECT_CALL(handler, handle_input(_)).Times(0);610 EXPECT_CALL(first_client, handle_input(_)).Times(0);
168
169 ready_to_accept_events.wait_for_at_most_seconds(5);
170611
171 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_M));612 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_M));
172 fake_keyboard->emit_event(mis::a_key_up_event().of_scancode(KEY_M));613 fake_keyboard->emit_event(mis::a_key_up_event().of_scancode(KEY_M));
173614
174 all_events_received.wait_for_at_most_seconds(10);615 first_client.all_events_received.wait_for_at_most_seconds(10);
175}616}
176617
=== modified file 'tests/acceptance-tests/test_surface_modifications.cpp'
--- tests/acceptance-tests/test_surface_modifications.cpp 2015-05-05 18:01:08 +0000
+++ tests/acceptance-tests/test_surface_modifications.cpp 2015-05-14 18:12:40 +0000
@@ -93,7 +93,6 @@
93 void generate_alt_click_at(Point const& click_position)93 void generate_alt_click_at(Point const& click_position)
94 {94 {
95 auto const modifiers = mir_input_event_modifier_alt;95 auto const modifiers = mir_input_event_modifier_alt;
96 std::vector<MirPointerButton> depressed_buttons{mir_pointer_button_tertiary};
9796
98 auto const x_axis_value = click_position.x.as_float();97 auto const x_axis_value = click_position.x.as_float();
99 auto const y_axis_value = click_position.y.as_float();98 auto const y_axis_value = click_position.y.as_float();
@@ -102,7 +101,7 @@
102 auto const action = mir_pointer_action_button_down;101 auto const action = mir_pointer_action_button_down;
103102
104 auto const click_event = mev::make_event(device_id, timestamp, modifiers,103 auto const click_event = mev::make_event(device_id, timestamp, modifiers,
105 action, depressed_buttons, x_axis_value, y_axis_value, hscroll_value, vscroll_value);104 action, mir_pointer_button_tertiary, x_axis_value, y_axis_value, hscroll_value, vscroll_value);
106105
107 server.the_shell()->handle(*click_event);106 server.the_shell()->handle(*click_event);
108 }107 }
@@ -110,7 +109,6 @@
110 void generate_alt_move_to(Point const& drag_position)109 void generate_alt_move_to(Point const& drag_position)
111 {110 {
112 auto const modifiers = mir_input_event_modifier_alt;111 auto const modifiers = mir_input_event_modifier_alt;
113 std::vector<MirPointerButton> depressed_buttons{mir_pointer_button_tertiary};
114112
115 auto const x_axis_value = drag_position.x.as_float();113 auto const x_axis_value = drag_position.x.as_float();
116 auto const y_axis_value = drag_position.y.as_float();114 auto const y_axis_value = drag_position.y.as_float();
@@ -119,7 +117,7 @@
119 auto const action = mir_pointer_action_motion;117 auto const action = mir_pointer_action_motion;
120118
121 auto const drag_event = mev::make_event(device_id, timestamp, modifiers,119 auto const drag_event = mev::make_event(device_id, timestamp, modifiers,
122 action, depressed_buttons, x_axis_value, y_axis_value, hscroll_value, vscroll_value);120 action, mir_pointer_button_tertiary, x_axis_value, y_axis_value, hscroll_value, vscroll_value);
123121
124 server.the_shell()->handle(*drag_event);122 server.the_shell()->handle(*drag_event);
125 }123 }
126124
=== modified file 'tests/acceptance-tests/test_surface_placement.cpp'
--- tests/acceptance-tests/test_surface_placement.cpp 2015-05-05 18:01:08 +0000
+++ tests/acceptance-tests/test_surface_placement.cpp 2015-05-14 18:12:40 +0000
@@ -121,7 +121,7 @@
121 MirInputDeviceId const device_id{7};121 MirInputDeviceId const device_id{7};
122122
123 auto const modifiers = mir_input_event_modifier_none;123 auto const modifiers = mir_input_event_modifier_none;
124 std::vector<MirPointerButton> depressed_buttons{mir_pointer_button_primary};124 auto const depressed_buttons = mir_pointer_button_primary;
125125
126 auto const x_axis_value = click_position.x.as_float();126 auto const x_axis_value = click_position.x.as_float();
127 auto const y_axis_value = click_position.y.as_float();127 auto const y_axis_value = click_position.y.as_float();
128128
=== modified file 'tests/acceptance-tests/throwback/CMakeLists.txt'
--- tests/acceptance-tests/throwback/CMakeLists.txt 2015-04-13 14:53:35 +0000
+++ tests/acceptance-tests/throwback/CMakeLists.txt 2015-05-14 18:12:40 +0000
@@ -9,7 +9,6 @@
99
10 clients.cpp10 clients.cpp
11 test_client_cursor_api.cpp11 test_client_cursor_api.cpp
12 test_client_input.cpp
13 test_custom_input_targeter.cpp12 test_custom_input_targeter.cpp
14 test_focus_selection.cpp13 test_focus_selection.cpp
15 test_touchspot_visualization.cpp14 test_touchspot_visualization.cpp
1615
=== removed file 'tests/acceptance-tests/throwback/test_client_input.cpp'
--- tests/acceptance-tests/throwback/test_client_input.cpp 2015-05-05 17:11:45 +0000
+++ tests/acceptance-tests/throwback/test_client_input.cpp 1970-01-01 00:00:00 +0000
@@ -1,704 +0,0 @@
1/*
2 * Copyright © 2013-2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 * Andreas Pokorny <andreas.pokorny@canonical.com>
18 * Alexandros Frantzis <alexandros.frantzis@canonical.com>
19 */
20
21#include "mir/events/event_private.h"
22#include "mir/shell/shell_wrapper.h"
23#include "mir/scene/surface_creation_parameters.h"
24#include "mir/scene/surface.h"
25#include "mir/scene/session.h"
26#include "src/server/scene/session_container.h"
27
28#include "mir_test_framework/in_process_server.h"
29#include "mir_test_framework/using_stub_client_platform.h"
30#include "mir_test_framework/fake_event_hub_server_configuration.h"
31#include "mir_test_framework/declarative_placement_strategy.h"
32#include "mir_test/wait_condition.h"
33#include "mir_test/fake_event_hub.h"
34#include "mir_test/event_matchers.h"
35#include "mir_test/spin_wait.h"
36
37#include "mir_toolkit/mir_client_library.h"
38
39#include <linux/input.h>
40
41#include <gtest/gtest.h>
42#include <gmock/gmock.h>
43#include <cstring>
44
45namespace mf = mir::frontend;
46namespace mt = mir::test;
47namespace mtf = mir_test_framework;
48namespace mis = mir::input::synthesis;
49namespace mia = mir::input::android;
50namespace msh = mir::shell;
51namespace ms = mir::scene;
52namespace geom = mir::geometry;
53
54namespace
55{
56
57struct MockInputHandler
58{
59 MOCK_METHOD1(handle_input, void(MirEvent const*));
60};
61
62struct InputClient
63{
64 InputClient(std::string const& connect_string, std::string const& client_name)
65 : connect_string{connect_string}, client_name{client_name}
66 {
67 }
68
69
70 ~InputClient()
71 {
72 if (client_thread.joinable())
73 client_thread.join();
74 }
75
76 void start()
77 {
78 client_thread = std::thread{[this] { run(); }};
79 ready_to_accept_events.wait_for_at_most_seconds(5);
80 }
81
82 void run()
83 {
84 auto const connection =
85 mir_connect_sync(connect_string.c_str(), client_name.c_str());
86
87 auto spec = mir_connection_create_spec_for_normal_surface(connection, surface_width,
88 surface_height, mir_pixel_format_bgr_888);
89 mir_surface_spec_set_name(spec, client_name.c_str());
90 surface = mir_surface_create_sync(spec);
91 mir_surface_spec_release(spec);
92
93 mir_surface_set_event_handler(surface, handle_input, this);
94 mir_buffer_stream_swap_buffers_sync(
95 mir_surface_get_buffer_stream(surface));
96
97 wait_for_surface_to_become_focused_and_exposed();
98
99 ready_to_accept_events.wake_up_everyone();
100 all_events_received.wait_for_at_most_seconds(10);
101
102 mir_surface_release_sync(surface);
103 mir_connection_release(connection);
104 }
105
106 static void handle_input(MirSurface*, MirEvent const* ev, void* context)
107 {
108 auto const client = static_cast<InputClient*>(context);
109
110 if (mir_event_get_type(ev) == mir_event_type_surface)
111 return;
112
113 client->handler.handle_input(ev);
114 }
115
116 void wait_for_surface_to_become_focused_and_exposed()
117 {
118 bool success = mt::spin_wait_for_condition_or_timeout(
119 [&]
120 {
121 return mir_surface_get_visibility(surface) == mir_surface_visibility_exposed &&
122 mir_surface_get_focus(surface) == mir_surface_focused;
123 },
124 std::chrono::seconds{5});
125
126 if (!success)
127 throw std::runtime_error("Timeout waiting for surface to become focused and exposed");
128 }
129
130 static int const surface_width = 100;
131 static int const surface_height = 100;
132
133 std::string const connect_string;
134 std::string const client_name;
135
136 std::thread client_thread;
137 MockInputHandler handler;
138 mir::test::WaitCondition all_events_received;
139 mir::test::WaitCondition ready_to_accept_events;
140
141 MirSurface* surface;
142};
143
144using ClientInputRegions = std::map<std::string, std::vector<geom::Rectangle>>;
145
146struct RegionApplyingShell : msh::ShellWrapper
147{
148 RegionApplyingShell(
149 std::shared_ptr<msh::Shell> wrapped_coordinator,
150 ClientInputRegions const& client_input_regions)
151 : msh::ShellWrapper(wrapped_coordinator),
152 client_input_regions(client_input_regions)
153 {
154 }
155
156 mf::SurfaceId create_surface(
157 std::shared_ptr<ms::Session> const& session,
158 ms::SurfaceCreationParameters const& params) override
159 {
160 auto const id = wrapped->create_surface(session, params);
161
162 auto const surface = session->surface(id);
163
164 if (client_input_regions.find(params.name) != client_input_regions.end())
165 surface->set_input_region(client_input_regions.at(params.name));
166
167 return id;
168 }
169
170 ClientInputRegions const& client_input_regions;
171};
172
173struct TestServerConfiguration : mtf::FakeEventHubServerConfiguration
174{
175 TestServerConfiguration(geom::Rectangle const& screen_geometry)
176 : mtf::FakeEventHubServerConfiguration(
177 std::vector<geom::Rectangle>{screen_geometry})
178 {
179 }
180
181 std::shared_ptr<mir::scene::PlacementStrategy> the_placement_strategy() override
182 {
183 return std::make_shared<mtf::DeclarativePlacementStrategy>(
184 FakeEventHubServerConfiguration::the_placement_strategy(),
185 client_geometries, client_depths);
186 }
187
188 std::shared_ptr<msh::Shell>
189 wrap_shell(std::shared_ptr<msh::Shell> const& wrapped) override
190 {
191 return std::make_shared<RegionApplyingShell>(
192 wrapped,
193 client_input_regions);
194 }
195
196 mtf::SurfaceGeometries client_geometries;
197 mtf::SurfaceDepths client_depths;
198 ClientInputRegions client_input_regions;
199};
200
201struct TestClientInput : mtf::InProcessServer
202{
203 mir::DefaultServerConfiguration& server_config() override
204 {
205 return server_configuration_;
206 }
207
208 TestServerConfiguration& test_server_config()
209 {
210 return server_configuration_;
211 }
212
213 std::shared_ptr<mir::input::android::FakeEventHub> fake_event_hub()
214 {
215 return server_configuration_.fake_event_hub;
216 }
217
218 std::string const test_client_name_1{"client1"};
219 std::string const test_client_name_2{"client2"};
220 geom::Rectangle const screen_geometry{{0, 0}, {1000, 800}};
221 TestServerConfiguration server_configuration_{screen_geometry};
222 mtf::UsingStubClientPlatform using_stub_client_platform;
223};
224
225}
226
227TEST_F(TestClientInput, clients_receive_key_input)
228{
229 using namespace testing;
230
231 InputClient client{new_connection(), test_client_name_1};
232
233 InSequence seq;
234 EXPECT_CALL(client.handler, handle_input(mt::KeyDownEvent())).Times(1);
235 EXPECT_CALL(client.handler, handle_input(mt::KeyRepeatEvent())).Times(1);
236 EXPECT_CALL(client.handler, handle_input(mt::KeyRepeatEvent()))
237 .WillOnce(mt::WakeUp(&client.all_events_received));
238
239 int const num_events_produced = 3;
240
241 client.start();
242
243 for (int i = 0; i < num_events_produced; i++)
244 fake_event_hub()->synthesize_event(
245 mis::a_key_down_event().of_scancode(KEY_ENTER));
246}
247
248TEST_F(TestClientInput, clients_receive_us_english_mapped_keys)
249{
250 using namespace testing;
251
252 InputClient client{new_connection(), test_client_name_1};
253
254 InSequence seq;
255
256 EXPECT_CALL(client.handler,
257 handle_input(
258 AllOf(mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_Shift_L))));
259 EXPECT_CALL(client.handler,
260 handle_input(
261 AllOf(mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_dollar))))
262 .WillOnce(mt::WakeUp(&client.all_events_received));
263
264 client.start();
265
266 fake_event_hub()->synthesize_event(
267 mis::a_key_down_event().of_scancode(KEY_LEFTSHIFT));
268 fake_event_hub()->synthesize_event(
269 mis::a_key_down_event().of_scancode(KEY_4));
270}
271
272TEST_F(TestClientInput, clients_receive_pointer_inside_window_and_crossing_events)
273{
274 using namespace testing;
275
276 InputClient client{new_connection(), test_client_name_1};
277
278 InSequence seq;
279
280 // We should see the cursor enter
281 EXPECT_CALL(client.handler, handle_input(mt::PointerEnterEvent()));
282 EXPECT_CALL(client.handler,
283 handle_input(
284 mt::PointerEventWithPosition(
285 InputClient::surface_width - 1,
286 InputClient::surface_height - 1)));
287 EXPECT_CALL(client.handler, handle_input(mt::PointerLeaveEvent()))
288 .WillOnce(mt::WakeUp(&client.all_events_received));
289 // But we should not receive an event for the second movement outside of our surface!
290
291 client.start();
292
293 fake_event_hub()->synthesize_event(
294 mis::a_pointer_event().with_movement(
295 InputClient::surface_width - 1,
296 InputClient::surface_height - 1));
297 fake_event_hub()->synthesize_event(mis::a_pointer_event().with_movement(2,2));
298}
299
300TEST_F(TestClientInput, clients_receive_button_events_inside_window)
301{
302 using namespace testing;
303
304 InputClient client{new_connection(), test_client_name_1};
305
306 // The cursor starts at (0, 0).
307 EXPECT_CALL(client.handler, handle_input(mt::ButtonDownEvent(0, 0)))
308 .WillOnce(mt::WakeUp(&client.all_events_received));
309
310 client.start();
311
312 fake_event_hub()->synthesize_event(
313 mis::a_button_down_event()
314 .of_button(BTN_LEFT)
315 .with_action(mis::EventAction::Down));
316}
317
318TEST_F(TestClientInput, multiple_clients_receive_pointer_inside_windows)
319{
320 using namespace testing;
321
322 int const screen_width = screen_geometry.size.width.as_int();
323 int const screen_height = screen_geometry.size.height.as_int();
324 int const client_height = screen_height / 2;
325 int const client_width = screen_width / 2;
326
327 test_server_config().client_geometries[test_client_name_1] =
328 {{0, 0}, {client_width, client_height}};
329 test_server_config().client_geometries[test_client_name_2] =
330 {{screen_width / 2, screen_height / 2}, {client_width, client_height}};
331
332 InputClient client1{new_connection(), test_client_name_1};
333 InputClient client2{new_connection(), test_client_name_2};
334
335 {
336 InSequence seq;
337 EXPECT_CALL(client1.handler, handle_input(mt::PointerEnterEvent()));
338 EXPECT_CALL(client1.handler,
339 handle_input(
340 mt::PointerEventWithPosition(client_width - 1, client_height - 1)));
341 EXPECT_CALL(client1.handler, handle_input(mt::PointerLeaveEvent()))
342 .WillOnce(mt::WakeUp(&client1.all_events_received));
343 }
344
345 {
346 InSequence seq;
347 EXPECT_CALL(client2.handler, handle_input(mt::PointerEnterEvent()));
348 EXPECT_CALL(client2.handler,
349 handle_input(
350 mt::PointerEventWithPosition(client_width - 1, client_height - 1)))
351 .WillOnce(mt::WakeUp(&client2.all_events_received));
352 }
353
354 client1.start();
355 client2.start();
356
357 // In the bounds of the first surface
358 fake_event_hub()->synthesize_event(
359 mis::a_pointer_event().with_movement(screen_width / 2 - 1, screen_height / 2 - 1));
360 // In the bounds of the second surface
361 fake_event_hub()->synthesize_event(
362 mis::a_pointer_event().with_movement(screen_width / 2, screen_height / 2));
363}
364
365TEST_F(TestClientInput, clients_do_not_receive_pointer_outside_input_region)
366{
367 using namespace testing;
368
369 int const client_height = InputClient::surface_height;
370 int const client_width = InputClient::surface_width;
371
372 test_server_config().client_input_regions[test_client_name_1] = {
373 {{0, 0}, {client_width - 80, client_height}},
374 {{client_width - 20, 0}, {client_width - 80, client_height}}};
375
376 InputClient client{new_connection(), test_client_name_1};
377
378 EXPECT_CALL(client.handler, handle_input(mt::PointerEnterEvent())).Times(AnyNumber());
379 EXPECT_CALL(client.handler, handle_input(mt::PointerLeaveEvent())).Times(AnyNumber());
380 EXPECT_CALL(client.handler, handle_input(mt::PointerMovementEvent())).Times(AnyNumber());
381
382 {
383 // We should see two of the three button pairs.
384 InSequence seq;
385 EXPECT_CALL(client.handler, handle_input(mt::ButtonDownEvent(1, 1)));
386 EXPECT_CALL(client.handler, handle_input(mt::ButtonUpEvent(1, 1)));
387 EXPECT_CALL(client.handler, handle_input(mt::ButtonDownEvent(99, 99)));
388 EXPECT_CALL(client.handler, handle_input(mt::ButtonUpEvent(99, 99)))
389 .WillOnce(mt::WakeUp(&client.all_events_received));
390 }
391
392 client.start();
393
394 // First we will move the cursor in to the input region on the left side of
395 // the window. We should see a click here.
396 fake_event_hub()->synthesize_event(mis::a_pointer_event().with_movement(1, 1));
397 fake_event_hub()->synthesize_event(
398 mis::a_button_down_event()
399 .of_button(BTN_LEFT)
400 .with_action(mis::EventAction::Down));
401 fake_event_hub()->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT));
402 // Now in to the dead zone in the center of the window. We should not see
403 // a click here.
404 fake_event_hub()->synthesize_event(mis::a_pointer_event().with_movement(49, 49));
405 fake_event_hub()->synthesize_event(
406 mis::a_button_down_event()
407 .of_button(BTN_LEFT)
408 .with_action(mis::EventAction::Down));
409 fake_event_hub()->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT));
410 // Now in to the right edge of the window, in the right input region.
411 // Again we should see a click.
412 fake_event_hub()->synthesize_event(mis::a_pointer_event().with_movement(49, 49));
413 fake_event_hub()->synthesize_event(
414 mis::a_button_down_event()
415 .of_button(BTN_LEFT)
416 .with_action(mis::EventAction::Down));
417 fake_event_hub()->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT));
418}
419
420TEST_F(TestClientInput, scene_obscure_motion_events_by_stacking)
421{
422 using namespace testing;
423
424 auto smaller_geometry = screen_geometry;
425 smaller_geometry.size.width =
426 geom::Width{screen_geometry.size.width.as_uint32_t() / 2};
427
428 test_server_config().client_geometries[test_client_name_1] = screen_geometry;
429 test_server_config().client_geometries[test_client_name_2] = smaller_geometry;
430 test_server_config().client_depths[test_client_name_1] = ms::DepthId{0};
431 test_server_config().client_depths[test_client_name_2] = ms::DepthId{1};
432
433 InputClient client1{new_connection(), test_client_name_1};
434 InputClient client2{new_connection(), test_client_name_2};
435
436 EXPECT_CALL(client1.handler, handle_input(mt::PointerEnterEvent())).Times(AnyNumber());
437 EXPECT_CALL(client1.handler, handle_input(mt::PointerLeaveEvent())).Times(AnyNumber());
438 EXPECT_CALL(client1.handler, handle_input(mt::PointerMovementEvent())).Times(AnyNumber());
439 {
440 // We should only see one button event sequence.
441 InSequence seq;
442 EXPECT_CALL(client1.handler, handle_input(mt::ButtonDownEvent(501, 1)));
443 EXPECT_CALL(client1.handler, handle_input(mt::ButtonUpEvent(501, 1)))
444 .WillOnce(mt::WakeUp(&client1.all_events_received));
445 }
446
447 EXPECT_CALL(client2.handler, handle_input(mt::PointerEnterEvent())).Times(AnyNumber());
448 EXPECT_CALL(client2.handler, handle_input(mt::PointerLeaveEvent())).Times(AnyNumber());
449 EXPECT_CALL(client2.handler, handle_input(mt::PointerMovementEvent())).Times(AnyNumber());
450 {
451 // Likewise we should only see one button sequence.
452 InSequence seq;
453 EXPECT_CALL(client2.handler, handle_input(mt::ButtonDownEvent(1, 1)));
454 EXPECT_CALL(client2.handler, handle_input(mt::ButtonUpEvent(1, 1)))
455 .WillOnce(mt::WakeUp(&client2.all_events_received));
456 }
457
458 client1.start();
459 client2.start();
460
461 // First we will move the cursor in to the region where client 2 obscures client 1
462 fake_event_hub()->synthesize_event(mis::a_pointer_event().with_movement(1, 1));
463 fake_event_hub()->synthesize_event(
464 mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
465 fake_event_hub()->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT));
466 // Now we move to the unobscured region of client 1
467 fake_event_hub()->synthesize_event(mis::a_pointer_event().with_movement(500, 0));
468 fake_event_hub()->synthesize_event(
469 mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
470 fake_event_hub()->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT));
471}
472
473TEST_F(TestClientInput, hidden_clients_do_not_receive_pointer_events)
474{
475 using namespace testing;
476
477 mt::WaitCondition second_client_done;
478
479 test_server_config().client_depths[test_client_name_1] = ms::DepthId{0};
480 test_server_config().client_depths[test_client_name_2] = ms::DepthId{1};
481
482 InputClient client1{new_connection(), test_client_name_1};
483 InputClient client2{new_connection(), test_client_name_2};
484
485 EXPECT_CALL(client1.handler, handle_input(mt::PointerEnterEvent())).Times(AnyNumber());
486 EXPECT_CALL(client1.handler, handle_input(mt::PointerLeaveEvent())).Times(AnyNumber());
487 EXPECT_CALL(client1.handler, handle_input(mt::PointerEventWithPosition(2, 2)))
488 .WillOnce(mt::WakeUp(&client1.all_events_received));
489
490 EXPECT_CALL(client2.handler, handle_input(mt::PointerEnterEvent())).Times(AnyNumber());
491 EXPECT_CALL(client2.handler, handle_input(mt::PointerLeaveEvent())).Times(AnyNumber());
492 EXPECT_CALL(client2.handler, handle_input(mt::PointerEventWithPosition(1, 1)))
493 .WillOnce(DoAll(mt::WakeUp(&second_client_done),
494 mt::WakeUp(&client2.all_events_received)));
495
496 client1.start();
497 client2.start();
498
499 // We send one event and then hide the surface on top before sending the next.
500 // So we expect each of the two surfaces to receive one even
501 fake_event_hub()->synthesize_event(mis::a_pointer_event().with_movement(1,1));
502 // We use a fence to ensure we do not hide the client
503 // before event dispatch occurs
504 second_client_done.wait_for_at_most_seconds(60);
505
506 server_config().the_session_container()->for_each(
507 [&](std::shared_ptr<ms::Session> const& session) -> void
508 {
509 if (session->name() == test_client_name_2)
510 session->hide();
511 });
512 // As the surface will not be unocludded immediately when the other surface is
513 // hidden (due to the compositor feedback approach used)
514 // See bug: https://bugs.launchpad.net/mir/+bug/1408168
515 client1.wait_for_surface_to_become_focused_and_exposed();
516
517 fake_event_hub()->synthesize_event(mis::a_pointer_event().with_movement(1,1));
518}
519
520TEST_F(TestClientInput, clients_receive_pointer_within_coordinate_system_of_window)
521{
522 using namespace testing;
523
524 int const screen_width = screen_geometry.size.width.as_int();
525 int const screen_height = screen_geometry.size.height.as_int();
526 int const client_height = screen_height / 2;
527 int const client_width = screen_width / 2;
528
529 test_server_config().client_geometries[test_client_name_1] =
530 {{screen_width / 2, screen_height / 2}, {client_width, client_height}};
531
532 InputClient client1{new_connection(), test_client_name_1};
533
534 InSequence seq;
535 EXPECT_CALL(client1.handler, handle_input(mt::PointerEnterEvent()));
536 EXPECT_CALL(client1.handler, handle_input(mt::PointerEventWithPosition(80, 170)))
537 .Times(AnyNumber())
538 .WillOnce(mt::WakeUp(&client1.all_events_received));
539
540 client1.start();
541
542 server_config().the_session_container()->for_each(
543 [&](std::shared_ptr<ms::Session> const& session) -> void
544 {
545 session->default_surface()->move_to(
546 geom::Point{screen_width / 2 - 40, screen_height / 2 - 80});
547 });
548
549 fake_event_hub()->synthesize_event(
550 mis::a_pointer_event().with_movement(screen_width / 2 + 40, screen_height / 2 + 90));
551}
552
553// TODO: Consider tests for more input devices with custom mapping (i.e. joysticks...)
554TEST_F(TestClientInput, usb_direct_input_devices_work)
555{
556 using namespace ::testing;
557
558 auto const minimum_touch = mia::FakeEventHub::TouchScreenMinAxisValue;
559 auto const maximum_touch = mia::FakeEventHub::TouchScreenMaxAxisValue;
560 auto const display_width = screen_geometry.size.width.as_uint32_t();
561 auto const display_height = screen_geometry.size.height.as_uint32_t();
562
563 // We place a click 10% in to the touchscreens space in both axis,
564 // and a second at 0,0. Thus we expect to see a click at
565 // .1*screen_width/height and a second at zero zero.
566 static int const abs_touch_x_1 = minimum_touch + (maximum_touch - minimum_touch) * 0.1;
567 static int const abs_touch_y_1 = minimum_touch + (maximum_touch - minimum_touch) * 0.1;
568 static int const abs_touch_x_2 = 0;
569 static int const abs_touch_y_2 = 0;
570
571 static float const expected_scale_x =
572 float(display_width) / (maximum_touch - minimum_touch + 1);
573 static float const expected_scale_y =
574 float(display_height) / (maximum_touch - minimum_touch + 1);
575
576 static float const expected_motion_x_1 = expected_scale_x * abs_touch_x_1;
577 static float const expected_motion_y_1 = expected_scale_y * abs_touch_y_1;
578 static float const expected_motion_x_2 = expected_scale_x * abs_touch_x_2;
579 static float const expected_motion_y_2 = expected_scale_y * abs_touch_y_2;
580
581 test_server_config().client_geometries[test_client_name_1] = screen_geometry;
582
583 InputClient client1{new_connection(), test_client_name_1};
584
585 InSequence seq;
586 EXPECT_CALL(client1.handler, handle_input(
587 mt::TouchEvent(expected_motion_x_1, expected_motion_y_1)));
588 EXPECT_CALL(client1.handler, handle_input(
589 mt::TouchEventInDirection(expected_motion_x_1,
590 expected_motion_y_1,
591 expected_motion_x_2,
592 expected_motion_y_2)))
593 .WillOnce(mt::WakeUp(&client1.all_events_received));
594
595 client1.start();
596
597 fake_event_hub()->synthesize_event(
598 mis::a_touch_event().at_position({abs_touch_x_1, abs_touch_y_1}));
599 // Sleep here to trigger more failures (simulate slow machine)
600 std::this_thread::sleep_for(std::chrono::milliseconds(10));
601 fake_event_hub()->synthesize_event(
602 mis::a_touch_event().at_position({abs_touch_x_2, abs_touch_y_2}));
603}
604
605TEST_F(TestClientInput, send_mir_input_events_through_surface)
606{
607 InputClient client1{new_connection(), test_client_name_1};
608
609 EXPECT_CALL(client1.handler, handle_input(mt::KeyDownEvent()))
610 .WillOnce(mt::WakeUp(&client1.all_events_received));
611
612 client1.start();
613
614 server_config().the_session_container()->for_each(
615 [] (std::shared_ptr<ms::Session> const& session) -> void
616 {
617 MirEvent key_event;
618 std::memset(&key_event, 0, sizeof key_event);
619 key_event.type = mir_event_type_key;
620 key_event.key.action = mir_keyboard_action_down;
621
622 session->default_surface()->consume(key_event);
623 });
624}
625
626TEST_F(TestClientInput, clients_receive_keymap_change_events)
627{
628 using namespace testing;
629
630 mt::WaitCondition first_event_received;
631 InputClient client{new_connection(), test_client_name_1};
632
633 xkb_rule_names names;
634 names.rules = "evdev";
635 names.model = "pc105";
636 names.layout = "dvorak";
637 names.variant = "";
638 names.options = "";
639
640 InSequence seq;
641 EXPECT_CALL(client.handler, handle_input(
642 mt::KeymapEventWithRules(names)))
643 .Times(1).WillOnce(mt::WakeUp(&client.all_events_received));
644
645 client.start();
646
647 server_config().the_session_container()->for_each(
648 [names] (std::shared_ptr<ms::Session> const& session) -> void
649 {
650 session->default_surface()->set_keymap(names);
651 });
652}
653
654
655TEST_F(TestClientInput, keymap_changes_change_keycode_received)
656{
657 using namespace testing;
658
659 xkb_rule_names names;
660 names.rules = "evdev";
661 names.model = "pc105";
662 names.layout = "us";
663 names.variant = "dvorak";
664 names.options = "";
665
666 mt::WaitCondition first_event_received,
667 client_sees_keymap_change;
668 InputClient client{new_connection(), test_client_name_1};
669
670 InSequence seq;
671 EXPECT_CALL(client.handler, handle_input(AllOf(
672 mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_n)))).Times(1);
673 EXPECT_CALL(client.handler, handle_input(mt::KeyUpEvent()))
674 .Times(1).WillOnce(mt::WakeUp(&first_event_received));
675 EXPECT_CALL(client.handler, handle_input(
676 mt::KeymapEventWithRules(names)))
677 .Times(1).WillOnce(mt::WakeUp(&client_sees_keymap_change));
678 EXPECT_CALL(client.handler, handle_input(AllOf(
679 mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_b)))).Times(1);
680 EXPECT_CALL(client.handler, handle_input(mt::KeyUpEvent()))
681 .Times(1).WillOnce(mt::WakeUp(&client.all_events_received));
682
683 client.start();
684
685 fake_event_hub()->synthesize_event(
686 mis::a_key_down_event().of_scancode(KEY_N));
687 fake_event_hub()->synthesize_event(
688 mis::a_key_up_event().of_scancode(KEY_N));
689
690 first_event_received.wait_for_at_most_seconds(60);
691
692 server_config().the_session_container()->for_each(
693 [&names] (std::shared_ptr<ms::Session> const& session) -> void
694 {
695 session->default_surface()->set_keymap(names);
696 });
697
698 client_sees_keymap_change.wait_for_at_most_seconds(60);
699
700 fake_event_hub()->synthesize_event(
701 mis::a_key_down_event().of_scancode(KEY_N));
702 fake_event_hub()->synthesize_event(
703 mis::a_key_up_event().of_scancode(KEY_N));
704}
7050
=== modified file 'tests/acceptance-tests/throwback/test_custom_input_targeter.cpp'
--- tests/acceptance-tests/throwback/test_custom_input_targeter.cpp 2015-05-07 07:07:20 +0000
+++ tests/acceptance-tests/throwback/test_custom_input_targeter.cpp 2015-05-14 18:12:40 +0000
@@ -40,7 +40,6 @@
40namespace ms = mir::scene;40namespace ms = mir::scene;
41namespace mi = mir::input;41namespace mi = mir::input;
42namespace mt = mir::test;42namespace mt = mir::test;
43namespace mtd = mt::doubles;
44namespace mt = mir::test;43namespace mt = mir::test;
45namespace mc = mir::compositor;44namespace mc = mir::compositor;
46namespace mtf = mir_test_framework;45namespace mtf = mir_test_framework;
4746
=== modified file 'tests/include/mir_test/event_matchers.h'
--- tests/include/mir_test/event_matchers.h 2015-05-07 07:07:20 +0000
+++ tests/include/mir_test/event_matchers.h 2015-05-14 18:12:40 +0000
@@ -135,10 +135,9 @@
135 return false;135 return false;
136 136
137 if(mir_keyboard_event_modifiers(kev) != modifiers)137 if(mir_keyboard_event_modifiers(kev) != modifiers)
138 {138 {
139 printf("modifiers: %d vs expected %d \n", mir_keyboard_event_modifiers(kev), modifiers);
140 return false;139 return false;
141 }140 }
142 141
143 return true;142 return true;
144}143}
@@ -229,36 +228,38 @@
229 return false;228 return false;
230}229}
231230
231inline bool button_event_matches(MirPointerEvent const* pev, float x, float y, MirPointerAction action, MirPointerButtons button_state,
232 bool check_action = true)
233{
234 if (pev == nullptr)
235 return false;
236 if (check_action && mir_pointer_event_action(pev) != action)
237 return false;
238 if (mir_pointer_event_buttons(pev) != button_state)
239 return false;
240 if (mir_pointer_event_axis_value(pev, mir_pointer_axis_x) != x)
241 return false;
242 if (mir_pointer_event_axis_value(pev, mir_pointer_axis_y) != y)
243 return false;
244 return true;
245}
246
232MATCHER_P2(ButtonDownEvent, x, y, "")247MATCHER_P2(ButtonDownEvent, x, y, "")
233{248{
234 auto pev = maybe_pointer_event(to_address(arg));249 auto pev = maybe_pointer_event(to_address(arg));
235 if (pev == nullptr)250 return button_event_matches(pev, x, y, mir_pointer_action_button_down, mir_pointer_button_primary);
236 return false;
237 if (mir_pointer_event_action(pev) != mir_pointer_action_button_down)
238 return false;
239 if (mir_pointer_event_button_state(pev, mir_pointer_button_primary) == false)
240 return false;
241 if (mir_pointer_event_axis_value(pev, mir_pointer_axis_x) != x)
242 return false;
243 if (mir_pointer_event_axis_value(pev, mir_pointer_axis_y) != y)
244 return false;
245 return true;
246}251}
247252
248MATCHER_P2(ButtonUpEvent, x, y, "")253MATCHER_P2(ButtonUpEvent, x, y, "")
249{254{
250 auto pev = maybe_pointer_event(to_address(arg));255 auto pev = maybe_pointer_event(to_address(arg));
251 if (pev == nullptr)256 return button_event_matches(pev, x, y, mir_pointer_action_button_up, 0);
252 return false;257}
253 if (mir_pointer_event_action(pev) != mir_pointer_action_button_up)258
254 return false;259MATCHER_P3(ButtonsDown, x, y, buttons, "")
255 if (mir_pointer_event_button_state(pev, mir_pointer_button_primary) == true)260{
256 return false;261 auto pev = maybe_pointer_event(to_address(arg));
257 if (mir_pointer_event_axis_value(pev, mir_pointer_axis_x) != x)262 return button_event_matches(pev, x, y, mir_pointer_action_button_down, buttons, false);
258 return false;
259 if (mir_pointer_event_axis_value(pev, mir_pointer_axis_y) != y)
260 return false;
261 return true;
262}263}
263264
264MATCHER_P2(TouchEvent, x, y, "")265MATCHER_P2(TouchEvent, x, y, "")
@@ -269,9 +270,9 @@
269270
270 if (mir_touch_event_action(tev, 0) != mir_touch_action_down)271 if (mir_touch_event_action(tev, 0) != mir_touch_action_down)
271 return false;272 return false;
272 if (mir_touch_event_axis_value(tev, 0, mir_touch_axis_x) != x)273 if (std::abs(mir_touch_event_axis_value(tev, 0, mir_touch_axis_x) - x) > 0.5f)
273 return false;274 return false;
274 if (mir_touch_event_axis_value(tev, 0, mir_touch_axis_y) != y)275 if (std::abs(mir_touch_event_axis_value(tev, 0, mir_touch_axis_y) - y) > 0.5f)
275 return false;276 return false;
276277
277 return true;278 return true;
278279
=== modified file 'tests/include/mir_test_framework/input_testing_server_configuration.h'
--- tests/include/mir_test_framework/input_testing_server_configuration.h 2015-03-31 09:10:52 +0000
+++ tests/include/mir_test_framework/input_testing_server_configuration.h 2015-05-14 18:12:40 +0000
@@ -31,24 +31,6 @@
31#include <atomic>31#include <atomic>
32#include <thread>32#include <thread>
3333
34namespace mir
35{
36namespace input
37{
38namespace android
39{
40class FakeEventHub;
41}
42}
43namespace test
44{
45namespace doubles
46{
47class FakeEventHubInputConfiguration;
48}
49}
50}
51
52namespace mir_test_framework34namespace mir_test_framework
53{35{
5436
@@ -61,20 +43,16 @@
61 void on_start() override;43 void on_start() override;
62 void on_exit() override;44 void on_exit() override;
6345
64 std::shared_ptr<droidinput::EventHubInterface> the_event_hub() override;
65 std::shared_ptr<mir::input::InputManager> the_input_manager() override;46 std::shared_ptr<mir::input::InputManager> the_input_manager() override;
66 std::shared_ptr<mir::input::InputDispatcher> the_input_dispatcher() override;47 std::shared_ptr<mir::input::InputDispatcher> the_input_dispatcher() override;
67 std::shared_ptr<mir::shell::InputTargeter> the_input_targeter() override;48 std::shared_ptr<mir::shell::InputTargeter> the_input_targeter() override;
68 std::shared_ptr<mir::input::InputSender> the_input_sender() override;49 std::shared_ptr<mir::input::InputSender> the_input_sender() override;
6950
70
71protected:51protected:
72 virtual void inject_input() = 0;52 virtual void inject_input() = 0;
7353
74 void wait_until_client_appears(std::string const& surface_name);54 void wait_until_client_appears(std::string const& surface_name);
7555
76private:
77 std::shared_ptr<mir::input::android::FakeEventHub> fake_event_hub;
78 std::thread input_injection_thread;56 std::thread input_injection_thread;
79};57};
8058
8159
=== added file 'tests/include/mir_test_framework/placement_applying_shell.h'
--- tests/include/mir_test_framework/placement_applying_shell.h 1970-01-01 00:00:00 +0000
+++ tests/include/mir_test_framework/placement_applying_shell.h 2015-05-14 18:12:40 +0000
@@ -0,0 +1,59 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
17 */
18
19#ifndef MIR_TEST_FRAMEWORK_PLACEMENT_APPLYING_SHELL_H_
20#define MIR_TEST_FRAMEWORK_PLACEMENT_APPLYING_SHELL_H_
21
22#include "mir/shell/shell_wrapper.h"
23#include "mir/geometry/rectangle.h"
24#include "mir/scene/depth_id.h"
25
26#include "mir/scene/session.h"
27#include "mir/scene/surface.h"
28#include "mir/scene/surface_creation_parameters.h"
29
30#include <vector>
31#include <string>
32#include <map>
33
34namespace mir_test_framework
35{
36using ClientInputRegions = std::map<std::string, std::vector<mir::geometry::Rectangle>>;
37using ClientPositions = std::map<std::string, mir::geometry::Rectangle>;
38using ClientDepths = std::map<std::string, mir::scene::DepthId>;
39
40struct PlacementApplyingShell : mir::shell::ShellWrapper
41{
42 PlacementApplyingShell(
43 std::shared_ptr<mir::shell::Shell> wrapped_coordinator,
44 ClientInputRegions const& client_input_regions,
45 ClientPositions const& client_positions,
46 ClientDepths const& client_depths);
47
48 mir::frontend::SurfaceId create_surface(
49 std::shared_ptr<mir::scene::Session> const& session,
50 mir::scene::SurfaceCreationParameters const& params) override;
51private:
52 ClientInputRegions const& client_input_regions;
53 ClientPositions const& client_positions;
54 ClientDepths const& client_depths;
55};
56
57}
58
59#endif
060
=== modified file 'tests/integration-tests/input/CMakeLists.txt'
--- tests/integration-tests/input/CMakeLists.txt 2015-04-16 22:11:07 +0000
+++ tests/integration-tests/input/CMakeLists.txt 2015-05-14 18:12:40 +0000
@@ -1,12 +1,9 @@
1list(1list(
2 APPEND INTEGRATION_TESTS_SRCS2 APPEND INTEGRATION_TESTS_SRCS
3 ${CMAKE_CURRENT_SOURCE_DIR}/test_configuring_input_manager.cpp3 ${CMAKE_CURRENT_SOURCE_DIR}/test_configuring_input_manager.cpp
4 ${CMAKE_CURRENT_SOURCE_DIR}/test_cursor_listener.cpp
4)5)
56
6if(NOT MIR_TEST_PLATFORM STREQUAL "android")
7 add_subdirectory(android)
8endif()
9
10set(7set(
11 INTEGRATION_TESTS_SRCS8 INTEGRATION_TESTS_SRCS
12 ${INTEGRATION_TESTS_SRCS}9 ${INTEGRATION_TESTS_SRCS}
1310
=== removed directory 'tests/integration-tests/input/android'
=== removed file 'tests/integration-tests/input/android/CMakeLists.txt'
--- tests/integration-tests/input/android/CMakeLists.txt 2015-05-06 12:57:11 +0000
+++ tests/integration-tests/input/android/CMakeLists.txt 1970-01-01 00:00:00 +0000
@@ -1,9 +0,0 @@
1list(
2 APPEND INTEGRATION_TESTS_SRCS
3 ${CMAKE_CURRENT_SOURCE_DIR}/test_android_cursor_listener.cpp
4)
5
6set(
7 INTEGRATION_TESTS_SRCS
8 ${INTEGRATION_TESTS_SRCS}
9 PARENT_SCOPE)
100
=== renamed file 'tests/integration-tests/input/android/test_android_cursor_listener.cpp' => 'tests/integration-tests/input/test_cursor_listener.cpp'
--- tests/integration-tests/input/android/test_android_cursor_listener.cpp 2015-04-20 20:07:52 +0000
+++ tests/integration-tests/input/test_cursor_listener.cpp 2015-05-14 18:12:40 +0000
@@ -20,8 +20,10 @@
20#include "mir/events/event_private.h"20#include "mir/events/event_private.h"
2121
22#include "mir_test/fake_shared.h"22#include "mir_test/fake_shared.h"
23#include "mir_test/fake_event_hub.h"23#include "mir_test_framework/fake_input_device.h"
24#include "mir_test_framework/fake_event_hub_server_configuration.h"24#include "mir_test_framework/stubbed_server_configuration.h"
25#include "mir_test_framework/stub_server_platform_factory.h"
26#include "mir_test_framework/temporary_environment_value.h"
25#include "mir_test_doubles/stub_input_enumerator.h"27#include "mir_test_doubles/stub_input_enumerator.h"
26#include "mir_test_doubles/stub_touch_visualizer.h"28#include "mir_test_doubles/stub_touch_visualizer.h"
27#include "mir_test/wait_condition.h"29#include "mir_test/wait_condition.h"
@@ -30,17 +32,18 @@
30#include "mir/input/cursor_listener.h"32#include "mir/input/cursor_listener.h"
31#include "mir/input/input_dispatcher.h"33#include "mir/input/input_dispatcher.h"
32#include "mir/input/input_manager.h"34#include "mir/input/input_manager.h"
35#include "mir/input/input_device_info.h"
36#include "mir_test_framework/executable_path.h"
3337
34#include <gmock/gmock.h>38#include <gmock/gmock.h>
35#include <gtest/gtest.h>39#include <gtest/gtest.h>
3640
37#include <thread>41#include <thread>
42#include <cstdlib>
3843
39namespace mi = mir::input;44namespace mi = mir::input;
40namespace mia = mir::input::android;
41namespace mis = mir::input::synthesis;45namespace mis = mir::input::synthesis;
42namespace mt = mir::test;46namespace mt = mir::test;
43namespace mtd = mir::test::doubles;
44namespace mtf = mir_test_framework;47namespace mtf = mir_test_framework;
4548
46namespace49namespace
@@ -54,8 +57,11 @@
54 ~MockCursorListener() noexcept {}57 ~MockCursorListener() noexcept {}
55};58};
5659
57struct AndroidCursorListenerIntegrationTest : testing::Test, mtf::FakeEventHubServerConfiguration60struct CursorListenerIntegrationTest : testing::Test, mtf::StubbedServerConfiguration
58{61{
62 mtf::TemporaryEnvironmentValue input_lib{"MIR_SERVER_PLATFORM_INPUT_LIB", mtf::server_platform("input-stub.so").c_str()};
63 mtf::TemporaryEnvironmentValue real_input{"MIR_SERVER_TESTS_USE_REAL_INPUT", "1"};
64
59 bool is_key_repeat_enabled() const override65 bool is_key_repeat_enabled() const override
60 {66 {
61 return false;67 return false;
@@ -83,11 +89,15 @@
83 MockCursorListener cursor_listener;89 MockCursorListener cursor_listener;
84 std::shared_ptr<mi::InputManager> input_manager;90 std::shared_ptr<mi::InputManager> input_manager;
85 std::shared_ptr<mi::InputDispatcher> input_dispatcher;91 std::shared_ptr<mi::InputDispatcher> input_dispatcher;
92
93 std::unique_ptr<mtf::FakeInputDevice> fake_mouse{
94 mtf::add_fake_input_device(mi::InputDeviceInfo{ 0, "mouse", "mouse-uid" , mi::DeviceCapability::pointer})
95 };
86};96};
8797
88}98}
8999
90TEST_F(AndroidCursorListenerIntegrationTest, cursor_listener_receives_motion)100TEST_F(CursorListenerIntegrationTest, cursor_listener_receives_motion)
91{101{
92 using namespace ::testing;102 using namespace ::testing;
93103
@@ -98,10 +108,7 @@
98108
99 EXPECT_CALL(cursor_listener, cursor_moved_to(x, y)).Times(1).WillOnce(mt::WakeUp(wait_condition));109 EXPECT_CALL(cursor_listener, cursor_moved_to(x, y)).Times(1).WillOnce(mt::WakeUp(wait_condition));
100110
101 fake_event_hub->synthesize_builtin_cursor_added();111 fake_mouse->emit_event(mis::a_pointer_event().with_movement(x, y));
102 fake_event_hub->synthesize_device_scan_complete();
103
104 fake_event_hub->synthesize_event(mis::a_pointer_event().with_movement(x, y));
105112
106 wait_condition->wait_for_at_most_seconds(10);113 wait_condition->wait_for_at_most_seconds(10);
107}114}
108115
=== modified file 'tests/mir_test_framework/CMakeLists.txt'
--- tests/mir_test_framework/CMakeLists.txt 2015-04-30 11:36:36 +0000
+++ tests/mir_test_framework/CMakeLists.txt 2015-05-14 18:12:40 +0000
@@ -46,6 +46,7 @@
46 fake_event_hub_server_configuration.cpp46 fake_event_hub_server_configuration.cpp
47 any_surface.cpp47 any_surface.cpp
48 headless_nested_server_runner.cpp48 headless_nested_server_runner.cpp
49 placement_applying_shell.cpp
49)50)
5051
51list(APPEND TEST_FRAMEWORK_SRCS52list(APPEND TEST_FRAMEWORK_SRCS
5253
=== modified file 'tests/mir_test_framework/fake_input_device_impl.cpp'
--- tests/mir_test_framework/fake_input_device_impl.cpp 2015-05-07 20:41:25 +0000
+++ tests/mir_test_framework/fake_input_device_impl.cpp 2015-05-14 18:12:40 +0000
@@ -144,7 +144,7 @@
144144
145mtf::FakeInputDeviceImpl::InputDevice::InputDevice(mi::InputDeviceInfo const& info,145mtf::FakeInputDeviceImpl::InputDevice::InputDevice(mi::InputDeviceInfo const& info,
146 std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchable)146 std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchable)
147 : info(info), queue{dispatchable}147 : info(info), queue{dispatchable}, buttons{0}
148{148{
149}149}
150150
@@ -197,12 +197,12 @@
197{197{
198 if (action == synthesis::EventAction::Down)198 if (action == synthesis::EventAction::Down)
199 {199 {
200 buttons.push_back(button);200 buttons |= button;
201 return mir_pointer_action_button_down;201 return mir_pointer_action_button_down;
202 }202 }
203 else203 else
204 {204 {
205 buttons.erase(remove(begin(buttons), end(buttons), button));205 buttons &= ~button;
206 return mir_pointer_action_button_up;206 return mir_pointer_action_button_up;
207 }207 }
208}208}
209209
=== modified file 'tests/mir_test_framework/fake_input_device_impl.h'
--- tests/mir_test_framework/fake_input_device_impl.h 2015-05-04 07:28:06 +0000
+++ tests/mir_test_framework/fake_input_device_impl.h 2015-05-14 18:12:40 +0000
@@ -25,8 +25,6 @@
25#include "mir/input/input_device_info.h"25#include "mir/input/input_device_info.h"
26#include "mir/geometry/point.h"26#include "mir/geometry/point.h"
2727
28#include <vector>
29
30namespace mir28namespace mir
31{29{
32namespace dispatch30namespace dispatch
@@ -76,7 +74,7 @@
76 std::shared_ptr<mir::dispatch::Dispatchable> const queue;74 std::shared_ptr<mir::dispatch::Dispatchable> const queue;
77 uint32_t modifiers{0};75 uint32_t modifiers{0};
78 mir::geometry::Point pos, scroll;76 mir::geometry::Point pos, scroll;
79 std::vector<MirPointerButton> buttons;77 MirPointerButtons buttons;
80 };78 };
81 std::shared_ptr<mir::dispatch::ActionQueue> queue;79 std::shared_ptr<mir::dispatch::ActionQueue> queue;
82 std::shared_ptr<InputDevice> device;80 std::shared_ptr<InputDevice> device;
8381
=== modified file 'tests/mir_test_framework/input_testing_server_options.cpp'
--- tests/mir_test_framework/input_testing_server_options.cpp 2015-03-31 02:35:42 +0000
+++ tests/mir_test_framework/input_testing_server_options.cpp 2015-05-14 18:12:40 +0000
@@ -24,7 +24,6 @@
24#include "mir/frontend/session.h"24#include "mir/frontend/session.h"
25#include "mir/input/composite_event_filter.h"25#include "mir/input/composite_event_filter.h"
2626
27#include "mir_test/fake_event_hub.h"
28#include "mir_test/wait_condition.h"27#include "mir_test/wait_condition.h"
2928
30#include <boost/throw_exception.hpp>29#include <boost/throw_exception.hpp>
@@ -41,7 +40,6 @@
41namespace ms = mir::shell;40namespace ms = mir::shell;
42namespace mia = mi::android;41namespace mia = mi::android;
43namespace geom = mir::geometry;42namespace geom = mir::geometry;
44namespace mtd = mir::test::doubles;
4543
46mtf::InputTestingServerConfiguration::InputTestingServerConfiguration()44mtf::InputTestingServerConfiguration::InputTestingServerConfiguration()
47{45{
@@ -96,18 +94,3 @@
96{94{
97 return DefaultServerConfiguration::the_input_sender();95 return DefaultServerConfiguration::the_input_sender();
98}96}
99
100std::shared_ptr<droidinput::EventHubInterface> mtf::InputTestingServerConfiguration::the_event_hub()
101{
102 if (!fake_event_hub)
103 {
104 fake_event_hub = std::make_shared<mia::FakeEventHub>();
105
106 fake_event_hub->synthesize_builtin_keyboard_added();
107 fake_event_hub->synthesize_builtin_cursor_added();
108 fake_event_hub->synthesize_usb_touchscreen_added();
109 fake_event_hub->synthesize_device_scan_complete();
110 }
111
112 return fake_event_hub;
113}
11497
=== added file 'tests/mir_test_framework/placement_applying_shell.cpp'
--- tests/mir_test_framework/placement_applying_shell.cpp 1970-01-01 00:00:00 +0000
+++ tests/mir_test_framework/placement_applying_shell.cpp 2015-05-14 18:12:40 +0000
@@ -0,0 +1,59 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
17 */
18
19#include "mir_test_framework/placement_applying_shell.h"
20
21namespace mtf = mir_test_framework;
22
23mtf::PlacementApplyingShell::PlacementApplyingShell(std::shared_ptr<mir::shell::Shell> wrapped_coordinator,
24 ClientInputRegions const& client_input_regions,
25 ClientPositions const& client_positions,
26 ClientDepths const& client_depths) :
27 mir::shell::ShellWrapper(wrapped_coordinator),
28 client_input_regions(client_input_regions),
29 client_positions(client_positions),
30 client_depths(client_depths)
31{
32}
33
34mir::frontend::SurfaceId mtf::PlacementApplyingShell::create_surface(
35 std::shared_ptr<mir::scene::Session> const& session,
36 mir::scene::SurfaceCreationParameters const& params)
37{
38 auto creation_parameters = params;
39
40 auto depth = client_depths.find(params.name);
41 if (depth != client_depths.end())
42 creation_parameters.depth = depth->second;
43
44 auto const id = wrapped->create_surface(session, creation_parameters);
45 auto const surface = session->surface(id);
46
47 auto position= client_positions.find(params.name);
48 if (position != client_positions.end())
49 {
50 surface->move_to(position->second.top_left);
51 surface->resize(position->second.size);
52 }
53
54 auto regions = client_input_regions.find(params.name);
55 if (regions != client_input_regions.end())
56 surface->set_input_region(regions->second);
57
58 return id;
59}
060
=== modified file 'tests/unit-tests/input/android/test_android_input_dispatcher.cpp'
--- tests/unit-tests/input/android/test_android_input_dispatcher.cpp 2015-05-05 18:01:08 +0000
+++ tests/unit-tests/input/android/test_android_input_dispatcher.cpp 2015-05-14 18:12:40 +0000
@@ -173,15 +173,16 @@
173 std::memset(expected_coords, 0, sizeof(expected_coords));173 std::memset(expected_coords, 0, sizeof(expected_coords));
174 std::memset(expected_properties, 0, sizeof(expected_properties));174 std::memset(expected_properties, 0, sizeof(expected_properties));
175 MirEvent event;175 MirEvent event;
176 std::memset(&event, 0, sizeof(event));
177
176 event.type = mir_event_type_motion;178 event.type = mir_event_type_motion;
177 event.motion.pointer_count = 1;179 event.motion.pointer_count = 1;
178 event.motion.event_time = std::chrono::nanoseconds(2);180 event.motion.event_time = std::chrono::nanoseconds(2);
179 event.motion.device_id = 3;181 event.motion.device_id = 3;
180 event.motion.source_id = 4;182 event.motion.source_id = 4;
181 event.motion.action = mir_motion_action_scroll;183 event.motion.action = mir_motion_action_scroll;
182 event.motion.modifiers = mir_input_event_modifier_shift,184 event.motion.modifiers = mir_input_event_modifier_shift;
183 event.motion.button_state =185 event.motion.buttons = mir_pointer_button_forward | mir_pointer_button_secondary;
184 static_cast<MirMotionButton>(mir_motion_button_forward | mir_motion_button_secondary);
185186
186 auto & pointer = event.motion.pointer_coordinates[0];187 auto & pointer = event.motion.pointer_coordinates[0];
187 pointer.id = 1;188 pointer.id = 1;
@@ -215,7 +216,7 @@
215 event.motion.action,216 event.motion.action,
216 0, /* flags */217 0, /* flags */
217 AMETA_SHIFT_ON,218 AMETA_SHIFT_ON,
218 event.motion.button_state,219 AMOTION_EVENT_BUTTON_FORWARD | AMOTION_EVENT_BUTTON_SECONDARY,
219 0, /* edge_flags */220 0, /* edge_flags */
220 event.motion.pointer_count,221 event.motion.pointer_count,
221 expected_properties,222 expected_properties,
222223
=== modified file 'tests/unit-tests/input/android/test_android_input_lexicon.cpp'
--- tests/unit-tests/input/android/test_android_input_lexicon.cpp 2015-05-05 18:01:08 +0000
+++ tests/unit-tests/input/android/test_android_input_lexicon.cpp 2015-05-14 18:12:40 +0000
@@ -78,7 +78,7 @@
78 const int32_t flags = 4;78 const int32_t flags = 4;
79 const int32_t edge_flags = 5;79 const int32_t edge_flags = 5;
80 const int32_t meta_state = 6;80 const int32_t meta_state = 6;
81 const int32_t button_state = 7;81 const int32_t button_state = 0;
82 const float x_offset = 8;82 const float x_offset = 8;
83 const float y_offset = 9;83 const float y_offset = 9;
84 const float x_precision = 10;84 const float x_precision = 10;
@@ -134,7 +134,6 @@
134134
135 auto mir_motion_ev = &mir_ev.motion;135 auto mir_motion_ev = &mir_ev.motion;
136136
137 EXPECT_EQ(mir_motion_ev->button_state, button_state);
138 EXPECT_EQ(mir_motion_ev->event_time, event_time);137 EXPECT_EQ(mir_motion_ev->event_time, event_time);
139138
140 EXPECT_EQ(mir_motion_ev->pointer_count, pointer_count);139 EXPECT_EQ(mir_motion_ev->pointer_count, pointer_count);
@@ -170,7 +169,6 @@
170 const int32_t flags = 4;169 const int32_t flags = 4;
171 const int32_t edge_flags = 5;170 const int32_t edge_flags = 5;
172 const int32_t meta_state = 6;171 const int32_t meta_state = 6;
173 const int32_t button_state = 7;
174 const float x_offset = 8;172 const float x_offset = 8;
175 const float y_offset = 9;173 const float y_offset = 9;
176 const float x_precision = 10;174 const float x_precision = 10;
@@ -223,7 +221,7 @@
223 }221 }
224222
225 android_motion_ev->initialize(device_id, source_id, action, flags,223 android_motion_ev->initialize(device_id, source_id, action, flags,
226 edge_flags, meta_state, button_state,224 edge_flags, meta_state, 0,
227 x_offset, y_offset, x_precision, y_precision,225 x_offset, y_offset, x_precision, y_precision,
228 down_time, event_time, pointer_count,226 down_time, event_time, pointer_count,
229 pointer_properties, pointer_coords);227 pointer_properties, pointer_coords);
@@ -241,7 +239,6 @@
241239
242 auto mir_motion_ev = &mir_ev.motion;240 auto mir_motion_ev = &mir_ev.motion;
243241
244 EXPECT_EQ(mir_motion_ev->button_state, button_state);
245 EXPECT_EQ(mir_motion_ev->event_time, event_time);242 EXPECT_EQ(mir_motion_ev->event_time, event_time);
246 EXPECT_EQ(mir_motion_ev->pointer_count, pointer_count);243 EXPECT_EQ(mir_motion_ev->pointer_count, pointer_count);
247244
248245
=== modified file 'tests/unit-tests/input/android/test_input_translator.cpp'
--- tests/unit-tests/input/android/test_input_translator.cpp 2015-05-07 19:43:49 +0000
+++ tests/unit-tests/input/android/test_input_translator.cpp 2015-05-14 18:12:40 +0000
@@ -266,8 +266,7 @@
266 expected.motion.source_id = 4;266 expected.motion.source_id = 4;
267 expected.motion.action = mir_motion_action_scroll;267 expected.motion.action = mir_motion_action_scroll;
268 expected.motion.modifiers = 6;268 expected.motion.modifiers = 6;
269 expected.motion.button_state =269 expected.motion.buttons = mir_pointer_button_forward | mir_pointer_button_secondary;
270 static_cast<MirMotionButton>(mir_motion_button_forward | mir_motion_button_secondary);
271270
272 auto & pointer = expected.motion.pointer_coordinates[0];271 auto & pointer = expected.motion.pointer_coordinates[0];
273 pointer.id = 1;272 pointer.id = 1;
@@ -303,7 +302,7 @@
303 expected.motion.action,302 expected.motion.action,
304 0, /* flags */303 0, /* flags */
305 expected.motion.modifiers,304 expected.motion.modifiers,
306 expected.motion.button_state,305 AMOTION_EVENT_BUTTON_FORWARD | AMOTION_EVENT_BUTTON_SECONDARY,
307 0, /* edge flags */306 0, /* edge flags */
308 expected.motion.pointer_count,307 expected.motion.pointer_count,
309 properties,308 properties,
310309
=== modified file 'tests/unit-tests/input/test_default_input_device_hub.cpp'
--- tests/unit-tests/input/test_default_input_device_hub.cpp 2015-05-07 20:41:25 +0000
+++ tests/unit-tests/input/test_default_input_device_hub.cpp 2015-05-14 18:12:40 +0000
@@ -31,6 +31,7 @@
31#include "mir/dispatch/multiplexing_dispatchable.h"31#include "mir/dispatch/multiplexing_dispatchable.h"
32#include "mir/dispatch/action_queue.h"32#include "mir/dispatch/action_queue.h"
33#include "mir/events/event_builders.h"33#include "mir/events/event_builders.h"
34#include "mir/input/cursor_listener.h"
3435
35#include <gmock/gmock.h>36#include <gmock/gmock.h>
36#include <gtest/gtest.h>37#include <gtest/gtest.h>
@@ -73,6 +74,13 @@
73 MOCK_METHOD0(changes_complete, void());74 MOCK_METHOD0(changes_complete, void());
74};75};
7576
77struct MockCursorListener : public mi::CursorListener
78{
79 MOCK_METHOD2(cursor_moved_to, void(float, float));
80
81 ~MockCursorListener() noexcept {}
82};
83
76struct MockInputDevice : public mi::InputDevice84struct MockInputDevice : public mi::InputDevice
77{85{
78 mir::dispatch::ActionQueue queue;86 mir::dispatch::ActionQueue queue;
@@ -90,11 +98,12 @@
90 mtd::TriggeredMainLoop observer_loop;98 mtd::TriggeredMainLoop observer_loop;
91 Nice<mtd::MockInputDispatcher> mock_dispatcher;99 Nice<mtd::MockInputDispatcher> mock_dispatcher;
92 Nice<mtd::MockInputRegion> mock_region;100 Nice<mtd::MockInputRegion> mock_region;
101 Nice<MockCursorListener> mock_cursor_listener;
93 Nice<MockTouchVisualizer> mock_visualizer;102 Nice<MockTouchVisualizer> mock_visualizer;
94 mir::dispatch::MultiplexingDispatchable multiplexer;103 mir::dispatch::MultiplexingDispatchable multiplexer;
95 mi::DefaultInputDeviceHub hub{mt::fake_shared(mock_dispatcher), mt::fake_shared(multiplexer),104 mi::DefaultInputDeviceHub hub{mt::fake_shared(mock_dispatcher), mt::fake_shared(multiplexer),
96 mt::fake_shared(observer_loop), mt::fake_shared(mock_visualizer),105 mt::fake_shared(observer_loop), mt::fake_shared(mock_visualizer),
97 mt::fake_shared(mock_region)};106 mt::fake_shared(mock_cursor_listener), mt::fake_shared(mock_region)};
98 Nice<MockInputDeviceObserver> mock_observer;107 Nice<MockInputDeviceObserver> mock_observer;
99 Nice<MockInputDevice> device;108 Nice<MockInputDevice> device;
100 Nice<MockInputDevice> another_device;109 Nice<MockInputDevice> another_device;
@@ -352,3 +361,21 @@
352 EXPECT_THAT(pos1, Eq(confined_pos));361 EXPECT_THAT(pos1, Eq(confined_pos));
353 EXPECT_THAT(pos2, Eq(confined_pos));362 EXPECT_THAT(pos2, Eq(confined_pos));
354}363}
364
365TEST_F(InputDeviceHubTest, forwards_pointer_updates_to_cursor_listener)
366{
367 using namespace ::testing;
368
369 auto x = 12.2f, y = 14.3f;
370 auto event = mir::events::make_event(0, std::chrono::nanoseconds(0),
371 mir_input_event_modifier_none, mir_pointer_action_motion, 0,
372 x, y, 0.0f, 0.0f);
373
374 EXPECT_CALL(mock_cursor_listener, cursor_moved_to(x, y)).Times(1);
375
376 mi::InputSink* sink;
377 capture_input_sink(device, sink);
378 hub.add_device(mt::fake_shared(device));
379
380 sink->handle_input(*event);
381}
355382
=== modified file 'tests/unit-tests/input/test_event_builders.cpp'
--- tests/unit-tests/input/test_event_builders.cpp 2015-05-08 20:54:52 +0000
+++ tests/unit-tests/input/test_event_builders.cpp 2015-05-14 18:12:40 +0000
@@ -99,8 +99,7 @@
99TEST_F(InputEventBuilder, makes_valid_pointer_event)99TEST_F(InputEventBuilder, makes_valid_pointer_event)
100{100{
101 MirPointerAction action = mir_pointer_action_enter;101 MirPointerAction action = mir_pointer_action_enter;
102 std::vector<MirPointerButton> depressed_buttons = 102 auto depressed_buttons = mir_pointer_button_back | mir_pointer_button_tertiary;
103 {mir_pointer_button_back, mir_pointer_button_tertiary};
104 float x_axis_value = 3.9, y_axis_value = 7.4, hscroll_value = .9, vscroll_value = .3;103 float x_axis_value = 3.9, y_axis_value = 7.4, hscroll_value = .9, vscroll_value = .3;
105 auto ev = mev::make_event(device_id, timestamp, modifiers, 104 auto ev = mev::make_event(device_id, timestamp, modifiers,
106 action, depressed_buttons, x_axis_value, y_axis_value, hscroll_value, vscroll_value);105 action, depressed_buttons, x_axis_value, y_axis_value, hscroll_value, vscroll_value);
@@ -162,11 +161,10 @@
162161
163TEST_F(InputEventBuilder, map_to_hover_if_no_button_pressed)162TEST_F(InputEventBuilder, map_to_hover_if_no_button_pressed)
164{163{
165 std::vector<MirPointerButton> no_pressed_buttons;
166 float x_axis_value = 3.9, y_axis_value = 7.4, hscroll_value = .9, vscroll_value = .3;164 float x_axis_value = 3.9, y_axis_value = 7.4, hscroll_value = .9, vscroll_value = .3;
167 MirPointerAction action = mir_pointer_action_motion;165 MirPointerAction action = mir_pointer_action_motion;
168 auto ev = mev::make_event(device_id, timestamp, modifiers,166 auto ev = mev::make_event(device_id, timestamp, modifiers,
169 action, no_pressed_buttons, x_axis_value, y_axis_value, hscroll_value, vscroll_value);167 action, 0, x_axis_value, y_axis_value, hscroll_value, vscroll_value);
170 auto e = ev.get();168 auto e = ev.get();
171169
172 auto ie = mir_event_get_input_event(e);170 auto ie = mir_event_get_input_event(e);
173171
=== modified file 'tests/unit-tests/input/test_input_event.cpp'
--- tests/unit-tests/input/test_input_event.cpp 2015-05-05 18:01:08 +0000
+++ tests/unit-tests/input/test_input_event.cpp 2015-05-14 18:12:40 +0000
@@ -61,15 +61,21 @@
61MirEvent a_key_ev()61MirEvent a_key_ev()
62{62{
63 MirEvent key_ev;63 MirEvent key_ev;
64 memset(&key_ev, 0, sizeof(key_ev));
65
64 key_ev.type = mir_event_type_key;66 key_ev.type = mir_event_type_key;
67
65 return key_ev;68 return key_ev;
66}69}
6770
68MirEvent a_motion_ev(int device_class = AINPUT_SOURCE_UNKNOWN)71MirEvent a_motion_ev(int device_class = AINPUT_SOURCE_UNKNOWN)
69{72{
70 MirEvent motion_ev;73 MirEvent motion_ev;
74 memset(&motion_ev, 0, sizeof(motion_ev));
75
71 motion_ev.type = mir_event_type_motion;76 motion_ev.type = mir_event_type_motion;
72 motion_ev.motion.source_id = device_class;77 motion_ev.motion.source_id = device_class;
78
73 return motion_ev;79 return motion_ev;
74}80}
7581
@@ -350,13 +356,13 @@
350{356{
351 auto old_ev = a_motion_ev(AINPUT_SOURCE_MOUSE);357 auto old_ev = a_motion_ev(AINPUT_SOURCE_MOUSE);
352358
353 old_ev.motion.button_state = mir_motion_button_primary;359 old_ev.motion.buttons = mir_pointer_button_primary;
354 auto pev = mir_input_event_get_pointer_event(mir_event_get_input_event(&old_ev));360 auto pev = mir_input_event_get_pointer_event(mir_event_get_input_event(&old_ev));
355 361
356 EXPECT_TRUE(mir_pointer_event_button_state(pev, mir_pointer_button_primary));362 EXPECT_TRUE(mir_pointer_event_button_state(pev, mir_pointer_button_primary));
357 EXPECT_FALSE(mir_pointer_event_button_state(pev, mir_pointer_button_secondary));363 EXPECT_FALSE(mir_pointer_event_button_state(pev, mir_pointer_button_secondary));
358364
359 old_ev.motion.button_state = static_cast<MirMotionButton>(old_ev.motion.button_state | (mir_motion_button_secondary));365 old_ev.motion.buttons |= mir_pointer_button_secondary;
360366
361 EXPECT_TRUE(mir_pointer_event_button_state(pev, mir_pointer_button_primary));367 EXPECT_TRUE(mir_pointer_event_button_state(pev, mir_pointer_button_primary));
362 EXPECT_TRUE(mir_pointer_event_button_state(pev, mir_pointer_button_secondary));368 EXPECT_TRUE(mir_pointer_event_button_state(pev, mir_pointer_button_secondary));
363369
=== modified file 'tests/unit-tests/scene/test_abstract_shell.cpp'
--- tests/unit-tests/scene/test_abstract_shell.cpp 2015-05-11 18:19:27 +0000
+++ tests/unit-tests/scene/test_abstract_shell.cpp 2015-05-14 18:12:40 +0000
@@ -283,7 +283,7 @@
283{283{
284 MirInputEventModifiers const modifiers{mir_input_event_modifier_none};284 MirInputEventModifiers const modifiers{mir_input_event_modifier_none};
285 MirPointerAction const action{mir_pointer_action_button_down};285 MirPointerAction const action{mir_pointer_action_button_down};
286 std::vector<MirPointerButton> const buttons_pressed{mir_pointer_button_primary};286 auto const buttons_pressed = mir_pointer_button_primary;
287 float const x_axis_value{0.0};287 float const x_axis_value{0.0};
288 float const y_axis_value{0.0};288 float const y_axis_value{0.0};
289 float const hscroll_value{0.0};289 float const hscroll_value{0.0};

Subscribers

People subscribed via source and target branches