Mir

Merge lp:~mir-team/mir/relative-pointer-events into lp:mir

Proposed by Robert Carr
Status: Superseded
Proposed branch: lp:~mir-team/mir/relative-pointer-events
Merge into: lp:mir
Diff against target: 369 lines (+127/-16)
17 files modified
3rd_party/android-input/android/frameworks/base/services/input/InputReader.cpp (+3/-0)
3rd_party/android-input/android/frameworks/base/services/input/InputTransport.cpp (+12/-1)
include/client/mir/events/event_builders.h (+8/-0)
include/client/mir_toolkit/events/input/pointer_event.h (+6/-1)
include/test/mir/test/event_matchers.h (+14/-0)
src/client/event_printer.cpp (+2/-0)
src/client/events/event_builders.cpp (+14/-1)
src/client/input/android/android_input_lexicon.cpp (+3/-1)
src/client/input/input_event.cpp (+4/-0)
src/include/common/mir/events/event_private.h (+2/-0)
src/server/input/android/input_sender.cpp (+2/-0)
src/server/input/android/input_translator.cpp (+11/-7)
src/server/input/surface_input_dispatcher.cpp (+3/-2)
tests/acceptance-tests/test_client_input.cpp (+32/-0)
tests/mir_test_framework/fake_input_device_impl.cpp (+3/-1)
tests/unit-tests/input/android/test_android_input_sender.cpp (+1/-1)
tests/unit-tests/input/android/test_input_translator.cpp (+7/-1)
To merge this branch: bzr merge lp:~mir-team/mir/relative-pointer-events
Reviewer Review Type Date Requested Status
Andreas Pokorny (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+264929@code.launchpad.net

This proposal has been superseded by a proposal from 2015-07-16.

Commit message

Provide relative cursor axes as a way to allow Unity8 to draw the pointer.
(LP: #1276322)

Description of the change

Provide relative cursor axes as a way to allow Unity8 to draw the cursor.

This is provided in lieu of the full raw events API we have discussed. The raw events API may still come at a later time other use cases. I wanted to avoid hacking up the android input layer too much when we are intending to replace it soon though.

I have a concern with this branch in that it leaks the location of clients in some cases. If a client receives a stream of input events where dx/dy is changing but x/y is constant then they now know they are on the edge of the screen. I wonder if this is a real problem? If so we could only allow fullscreen surfaces to receive relative coordinates...or brainstorm for more solutions!

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

It would be nice to also have a test case that moves the mouse beyond the border of the screen, and verify that even when - from the pov of the pointer controller - the mouse did not move due to the screen boundaries we still send out relative position changes.

From a short dive through our pointer controller - we seem to override that position related filtering.

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

Good idea Andreas I manually tested this but something came up in doing the automated testing! Notably it turns out we are batching pointer events which made verifying large streams of events difficult (e.g. sometimes I would get (0,0) -> (1, 1) -> (2, 2) and sometimes (0, 0) -> (2, 2)).

I've updated the test to feature your suggestion and proposed a dependency branch which ensures only touch events are batched.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '3rd_party/android-input/android/frameworks/base/services/input/InputReader.cpp'
2--- 3rd_party/android-input/android/frameworks/base/services/input/InputReader.cpp 2015-06-17 05:20:42 +0000
3+++ 3rd_party/android-input/android/frameworks/base/services/input/InputReader.cpp 2015-07-16 21:29:50 +0000
4@@ -2445,6 +2445,9 @@
5
6 mPointerVelocityControl.move(when, &deltaX, &deltaY);
7
8+ pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RX, deltaX);
9+ pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RY, deltaY);
10+
11 if (mPointerController != NULL) {
12 if (moved || scrolled || buttonsChanged) {
13 mPointerController->setPresentation(
14
15=== modified file '3rd_party/android-input/android/frameworks/base/services/input/InputTransport.cpp'
16--- 3rd_party/android-input/android/frameworks/base/services/input/InputTransport.cpp 2015-04-28 07:54:10 +0000
17+++ 3rd_party/android-input/android/frameworks/base/services/input/InputTransport.cpp 2015-07-16 21:29:50 +0000
18@@ -61,6 +61,16 @@
19 return a + alpha * (b - a);
20 }
21
22+namespace
23+{
24+bool source_is_cursor(int32_t source)
25+{
26+ return source == AINPUT_SOURCE_MOUSE || source == AINPUT_SOURCE_TRACKBALL || source == AINPUT_SOURCE_TOUCHPAD;
27+}
28+}
29+
30+
31+
32 // --- InputMessage ---
33
34 InputMessage::InputMessage()
35@@ -463,7 +473,8 @@
36
37 // Start a new batch if needed.
38 if (mMsg.body.motion.action == AMOTION_EVENT_ACTION_MOVE
39- || mMsg.body.motion.action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
40+ || mMsg.body.motion.action == AMOTION_EVENT_ACTION_HOVER_MOVE
41+ && !source_is_cursor(mMsg.body.motion.source)) {
42 mBatches.push();
43 Batch& batch = mBatches.editTop();
44 batch.samples.push(mMsg);
45
46=== modified file 'include/client/mir/events/event_builders.h'
47--- include/client/mir/events/event_builders.h 2015-06-18 02:46:16 +0000
48+++ include/client/mir/events/event_builders.h 2015-07-16 21:29:50 +0000
49@@ -60,12 +60,20 @@
50 float pressure_value, float touch_major_value, float touch_minor_value, float size_value);
51
52 // Pointer event
53+// Deprecated version without relative axis
54 EventUPtr make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp,
55 MirInputEventModifiers modifiers, MirPointerAction action,
56 MirPointerButtons buttons_pressed,
57 float x_axis_value, float y_axis_value,
58 float hscroll_value, float vscroll_value);
59
60+EventUPtr make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp,
61+ MirInputEventModifiers modifiers, MirPointerAction action,
62+ MirPointerButtons buttons_pressed,
63+ float x_axis_value, float y_axis_value,
64+ float hscroll_value, float vscroll_value,
65+ float relative_x_value, float relative_y_value);
66+
67 // Input configuration event
68 EventUPtr make_event(MirInputConfigurationAction action,
69 MirInputDeviceId id, std::chrono::nanoseconds time);
70
71=== modified file 'include/client/mir_toolkit/events/input/pointer_event.h'
72--- include/client/mir_toolkit/events/input/pointer_event.h 2015-06-25 11:26:34 +0000
73+++ include/client/mir_toolkit/events/input/pointer_event.h 2015-07-16 21:29:50 +0000
74@@ -61,7 +61,12 @@
75 /* Relative axis containing ticks reported by the vertical scroll wheel */
76 mir_pointer_axis_vscroll = 2,
77 /* Relative axis containing ticks reported by the horizontal scroll wheel */
78- mir_pointer_axis_hscroll = 3
79+ mir_pointer_axis_hscroll = 3,
80+/* Relative axis containing the last reported x differential from the pointer */
81+ mir_pointer_axis_relative_x = 4,
82+/* Relative axis containing the last reported y differential from the pointer */
83+ mir_pointer_axis_relative_y = 5
84+
85 } MirPointerAxis;
86
87 /*
88
89=== modified file 'include/test/mir/test/event_matchers.h'
90--- include/test/mir/test/event_matchers.h 2015-06-22 03:03:59 +0000
91+++ include/test/mir/test/event_matchers.h 2015-07-16 21:29:50 +0000
92@@ -308,6 +308,20 @@
93 return true;
94 }
95
96+MATCHER_P2(PointerEventWithDiff, dx, dy, "")
97+{
98+ auto pev = maybe_pointer_event(to_address(arg));
99+ if (pev == nullptr)
100+ return false;
101+ if (mir_pointer_event_action(pev) != mir_pointer_action_motion)
102+ return false;
103+ if (mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_x) != dx)
104+ return false;
105+ if (mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_y) != dy)
106+ return false;
107+ return true;
108+}
109+
110 MATCHER_P4(TouchEventInDirection, x0, y0, x1, y1, "")
111 {
112 auto tev = maybe_touch_event(to_address(arg));
113
114=== modified file 'src/client/event_printer.cpp'
115--- src/client/event_printer.cpp 2015-05-19 21:34:34 +0000
116+++ src/client/event_printer.cpp 2015-07-16 21:29:50 +0000
117@@ -249,6 +249,8 @@
118 << mir_pointer_event_action(pointer_event) << ", button_state=" << button_state
119 << ", x=" << mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_x)
120 << ", y=" << mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y)
121+ << ", dx=" << mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_x)
122+ << ", dy=" << mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_y)
123 << ", vscroll=" << mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll)
124 << ", hscroll=" << mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll)
125 << ", modifiers=" << mir_pointer_event_modifiers(pointer_event) << ')';
126
127=== modified file 'src/client/events/event_builders.cpp'
128--- src/client/events/event_builders.cpp 2015-06-18 02:46:16 +0000
129+++ src/client/events/event_builders.cpp 2015-07-16 21:29:50 +0000
130@@ -183,7 +183,8 @@
131 MirInputEventModifiers modifiers, MirPointerAction action,
132 MirPointerButtons buttons_pressed,
133 float x_axis_value, float y_axis_value,
134- float hscroll_value, float vscroll_value)
135+ float hscroll_value, float vscroll_value,
136+ float relative_x_value, float relative_y_value)
137 {
138 auto e = new MirEvent;
139 memset(e, 0, sizeof (MirEvent));
140@@ -201,12 +202,24 @@
141 mev.pointer_coordinates[0].action = action;
142 pc.x = x_axis_value;
143 pc.y = y_axis_value;
144+ pc.dx = relative_x_value;
145+ pc.dy = relative_y_value;
146 pc.hscroll = hscroll_value;
147 pc.vscroll = vscroll_value;
148
149 return make_event_uptr(e);
150 }
151
152+mir::EventUPtr mev::make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp,
153+ MirInputEventModifiers modifiers, MirPointerAction action,
154+ MirPointerButtons buttons_pressed,
155+ float x_axis_value, float y_axis_value,
156+ float hscroll_value, float vscroll_value)
157+{
158+ return make_event(device_id, timestamp, modifiers, action, buttons_pressed,
159+ x_axis_value, y_axis_value, hscroll_value, vscroll_value, 0, 0);
160+}
161+
162 mir::EventUPtr mev::make_event(mf::SurfaceId const& surface_id, xkb_rule_names const& rules)
163 {
164 auto e = new MirEvent;
165
166=== modified file 'src/client/input/android/android_input_lexicon.cpp'
167--- src/client/input/android/android_input_lexicon.cpp 2015-06-17 05:20:42 +0000
168+++ src/client/input/android/android_input_lexicon.cpp 2015-07-16 21:29:50 +0000
169@@ -57,7 +57,9 @@
170 mia::mir_pointer_buttons_from_android(mev->getButtonState()),
171 mev->getX(0), mev->getY(0),
172 mev->getRawAxisValue(AMOTION_EVENT_AXIS_HSCROLL, 0),
173- mev->getRawAxisValue(AMOTION_EVENT_AXIS_VSCROLL, 0));
174+ mev->getRawAxisValue(AMOTION_EVENT_AXIS_VSCROLL, 0),
175+ mev->getRawAxisValue(AMOTION_EVENT_AXIS_RX, 0),
176+ mev->getRawAxisValue(AMOTION_EVENT_AXIS_RY, 0));
177 }
178 else
179 {
180
181=== modified file 'src/client/input/input_event.cpp'
182--- src/client/input/input_event.cpp 2015-06-29 03:29:31 +0000
183+++ src/client/input/input_event.cpp 2015-07-16 21:29:50 +0000
184@@ -399,6 +399,10 @@
185 return old_mev.pointer_coordinates[0].x;
186 case mir_pointer_axis_y:
187 return old_mev.pointer_coordinates[0].y;
188+ case mir_pointer_axis_relative_x:
189+ return old_mev.pointer_coordinates[0].dx;
190+ case mir_pointer_axis_relative_y:
191+ return old_mev.pointer_coordinates[0].dy;
192 case mir_pointer_axis_vscroll:
193 return old_mev.pointer_coordinates[0].vscroll;
194 case mir_pointer_axis_hscroll:
195
196=== modified file 'src/include/common/mir/events/event_private.h'
197--- src/include/common/mir/events/event_private.h 2015-06-18 02:46:16 +0000
198+++ src/include/common/mir/events/event_private.h 2015-07-16 21:29:50 +0000
199@@ -68,6 +68,8 @@
200 int id;
201 float x;
202 float y;
203+ float dx;
204+ float dy;
205 float touch_major;
206 float touch_minor;
207 float size;
208
209=== modified file 'src/server/input/android/input_sender.cpp'
210--- src/server/input/android/input_sender.cpp 2015-06-26 08:00:59 +0000
211+++ src/server/input/android/input_sender.cpp 2015-07-16 21:29:50 +0000
212@@ -277,6 +277,8 @@
213 // here x, y is used instead of the raw co-ordinates and offset is set to zero
214 coords[i].setAxisValue(AMOTION_EVENT_AXIS_X, event.pointer_coordinates[i].x);
215 coords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, event.pointer_coordinates[i].y);
216+ coords[i].setAxisValue(AMOTION_EVENT_AXIS_RX, event.pointer_coordinates[i].dx);
217+ coords[i].setAxisValue(AMOTION_EVENT_AXIS_RY, event.pointer_coordinates[i].dy);
218
219 coords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, event.pointer_coordinates[i].touch_major);
220 coords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, event.pointer_coordinates[i].touch_minor);
221
222=== modified file 'src/server/input/android/input_translator.cpp'
223--- src/server/input/android/input_translator.cpp 2015-06-17 05:20:42 +0000
224+++ src/server/input/android/input_translator.cpp 2015-07-16 21:29:50 +0000
225@@ -112,14 +112,18 @@
226
227 if (mia::android_source_id_is_pointer_device(args->source))
228 {
229+ auto const& pc = args->pointerCoords[0];
230 auto mir_event = mev::make_event(MirInputDeviceId(args->deviceId),
231- args->eventTime,
232- mia::mir_modifiers_from_android(args->metaState),
233- mia::mir_pointer_action_from_masked_android(args->action & AMOTION_EVENT_ACTION_MASK),
234- mia::mir_pointer_buttons_from_android(args->buttonState),
235- args->pointerCoords[0].getX(), args->pointerCoords[0].getY(),
236- args->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_HSCROLL),
237- args->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_VSCROLL));
238+ args->eventTime,
239+ mia::mir_modifiers_from_android(args->metaState),
240+ mia::mir_pointer_action_from_masked_android(args->action & AMOTION_EVENT_ACTION_MASK),
241+ mia::mir_pointer_buttons_from_android(args->buttonState),
242+ pc.getX(), pc.getY(),
243+ pc.getAxisValue(AMOTION_EVENT_AXIS_HSCROLL),
244+ pc.getAxisValue(AMOTION_EVENT_AXIS_VSCROLL),
245+ pc.getAxisValue(AMOTION_EVENT_AXIS_RX),
246+ pc.getAxisValue(AMOTION_EVENT_AXIS_RY)
247+ );
248
249 if (!valid_motion_event(mir_event->motion))
250 return;
251
252=== modified file 'src/server/input/surface_input_dispatcher.cpp'
253--- src/server/input/surface_input_dispatcher.cpp 2015-06-24 20:46:14 +0000
254+++ src/server/input/surface_input_dispatcher.cpp 2015-07-16 21:29:50 +0000
255@@ -225,7 +225,9 @@
256 mir_pointer_event_axis_value(pev,mir_pointer_axis_x),
257 mir_pointer_event_axis_value(pev,mir_pointer_axis_y),
258 mir_pointer_event_axis_value(pev,mir_pointer_axis_hscroll),
259- mir_pointer_event_axis_value(pev,mir_pointer_axis_vscroll)));
260+ mir_pointer_event_axis_value(pev,mir_pointer_axis_vscroll),
261+ mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_x),
262+ mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_y)));
263 }
264
265 mi::SurfaceInputDispatcher::PointerInputState& mi::SurfaceInputDispatcher::ensure_pointer_state(MirInputDeviceId id)
266@@ -299,7 +301,6 @@
267 {
268 pointer_state.gesture_owner = target;
269 }
270-
271 deliver(target, pev);
272 return true;
273 }
274
275=== modified file 'tests/acceptance-tests/test_client_input.cpp'
276--- tests/acceptance-tests/test_client_input.cpp 2015-06-26 08:00:59 +0000
277+++ tests/acceptance-tests/test_client_input.cpp 2015-07-16 21:29:50 +0000
278@@ -239,6 +239,38 @@
279 first_client.all_events_received.wait_for_at_most_seconds(120);
280 }
281
282+TEST_F(TestClientInput, clients_receive_relative_pointer_events)
283+{
284+ using namespace ::testing;
285+
286+ positions[first] = geom::Rectangle{{0,0}, {surface_width, surface_height}};
287+ Client first_client(new_connection(), first);
288+
289+ InSequence seq;
290+ EXPECT_CALL(first_client, handle_input(mt::PointerEnterEvent()));
291+ EXPECT_CALL(first_client, handle_input(AllOf(mt::PointerEventWithPosition(1, 1), mt::PointerEventWithDiff(1, 1))));
292+ EXPECT_CALL(first_client, handle_input(AllOf(mt::PointerEventWithPosition(2, 2), mt::PointerEventWithDiff(1, 1))));
293+ EXPECT_CALL(first_client, handle_input(AllOf(mt::PointerEventWithPosition(3, 3), mt::PointerEventWithDiff(1, 1))));
294+ EXPECT_CALL(first_client, handle_input(AllOf(mt::PointerEventWithPosition(2, 2), mt::PointerEventWithDiff(-1, -1))));
295+ EXPECT_CALL(first_client, handle_input(AllOf(mt::PointerEventWithPosition(1, 1), mt::PointerEventWithDiff(-1, -1))));
296+ // Ensure we continue to receive relative moement even when absolute movement is constrained.
297+ EXPECT_CALL(first_client, handle_input(AllOf(mt::PointerEventWithPosition(0, 0), mt::PointerEventWithDiff(-1, -1))));
298+ EXPECT_CALL(first_client, handle_input(AllOf(mt::PointerEventWithPosition(0, 0), mt::PointerEventWithDiff(-1, -1))));
299+ EXPECT_CALL(first_client, handle_input(AllOf(mt::PointerEventWithPosition(0, 0), mt::PointerEventWithDiff(-1, -1))))
300+ .WillOnce(mt::WakeUp(&first_client.all_events_received));
301+
302+ fake_mouse->emit_event(mis::a_pointer_event().with_movement(1, 1));
303+ fake_mouse->emit_event(mis::a_pointer_event().with_movement(1, 1));
304+ fake_mouse->emit_event(mis::a_pointer_event().with_movement(1, 1));
305+ fake_mouse->emit_event(mis::a_pointer_event().with_movement(-1, -1));
306+ fake_mouse->emit_event(mis::a_pointer_event().with_movement(-1, -1));
307+ fake_mouse->emit_event(mis::a_pointer_event().with_movement(-1, -1));
308+ fake_mouse->emit_event(mis::a_pointer_event().with_movement(-1, -1));
309+ fake_mouse->emit_event(mis::a_pointer_event().with_movement(-1, -1));
310+
311+ first_client.all_events_received.wait_for_at_most_seconds(120);
312+}
313+
314 TEST_F(TestClientInput, clients_receive_button_events_inside_window)
315 {
316 Client first_client(new_connection(), first);
317
318=== modified file 'tests/mir_test_framework/fake_input_device_impl.cpp'
319--- tests/mir_test_framework/fake_input_device_impl.cpp 2015-06-17 05:20:42 +0000
320+++ tests/mir_test_framework/fake_input_device_impl.cpp 2015-07-16 21:29:50 +0000
321@@ -224,7 +224,9 @@
322 pos.x.as_float(),
323 pos.y.as_float(),
324 scroll.x.as_float(),
325- scroll.y.as_float());
326+ scroll.y.as_float(),
327+ pointer.rel_x,
328+ pointer.rel_y);
329
330 sink->handle_input(*pointer_event);
331 }
332
333=== modified file 'tests/unit-tests/input/android/test_android_input_sender.cpp'
334--- tests/unit-tests/input/android/test_android_input_sender.cpp 2015-06-25 03:00:08 +0000
335+++ tests/unit-tests/input/android/test_android_input_sender.cpp 2015-07-16 21:29:50 +0000
336@@ -103,7 +103,7 @@
337 float test_y_coord[2] = {17, 9};
338
339 AndroidInputSender()
340- : key_event(mev::make_event(MirInputDeviceId(), std::chrono::nanoseconds(1), mir_keyboard_action_down,
341+ : key_event(mev::make_event(MirInputDeviceId(), std::chrono::nanoseconds(1), mir_keyboard_action_down,
342 7, test_scan_code, mir_input_event_modifier_none)),
343 motion_event(mev::make_event(MirInputDeviceId(), std::chrono::nanoseconds(-1), mir_input_event_modifier_none))
344 {
345
346=== modified file 'tests/unit-tests/input/android/test_input_translator.cpp'
347--- tests/unit-tests/input/android/test_input_translator.cpp 2015-06-26 08:00:59 +0000
348+++ tests/unit-tests/input/android/test_input_translator.cpp 2015-07-16 21:29:50 +0000
349@@ -167,13 +167,19 @@
350
351 const float x_pos = 12.0f;
352 const float y_pos = 30.0f;
353- EXPECT_CALL(dispatcher, dispatch(mt::PointerEventWithPosition(x_pos, y_pos))).Times(1);
354+ const float dx = 7.0f;
355+ const float dy = 9.3f;
356+ EXPECT_CALL(dispatcher, dispatch(AllOf(
357+ mt::PointerEventWithPosition(x_pos, y_pos),
358+ mt::PointerEventWithDiff(dx, dy)))).Times(1);
359
360 const uint32_t one_pointer = 1;
361
362 properties[0].id = 23;
363 coords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x_pos);
364 coords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y_pos);
365+ coords[0].setAxisValue(AMOTION_EVENT_AXIS_RX, dx);
366+ coords[0].setAxisValue(AMOTION_EVENT_AXIS_RY, dy);
367
368 droidinput::NotifyMotionArgs motion(some_time, device_id, AINPUT_SOURCE_MOUSE, 0, motion_action, no_flags,
369 meta_state, button_state, edge_flags, one_pointer, properties, coords,

Subscribers

People subscribed via source and target branches