Mir

Merge lp:~andreas-pokorny/mir/combine-modifier-state-accross-devices into lp:mir

Proposed by Andreas Pokorny
Status: Merged
Merged at revision: 3065
Proposed branch: lp:~andreas-pokorny/mir/combine-modifier-state-accross-devices
Merge into: lp:mir
Prerequisite: lp:~andreas-pokorny/mir/bump-input-platform-abi-for-0.18
Diff against target: 1512 lines (+615/-265)
24 files modified
include/client/mir/events/event_builders.h (+2/-0)
include/platform/mir/input/event_builder.h (+5/-7)
include/test/mir/test/event_matchers.h (+8/-0)
src/client/events/event_builders.cpp (+22/-0)
src/client/symbols.map (+8/-0)
src/platforms/evdev/CMakeLists.txt (+2/-3)
src/platforms/evdev/button_utils.cpp (+44/-0)
src/platforms/evdev/button_utils.h (+36/-0)
src/platforms/evdev/libinput_device.cpp (+12/-34)
src/platforms/evdev/libinput_device.h (+0/-1)
src/platforms/mesa/server/x11/input/input_platform.cpp (+6/-38)
src/server/input/CMakeLists.txt (+2/-0)
src/server/input/default_event_builder.cpp (+12/-14)
src/server/input/default_event_builder.h (+5/-7)
src/server/input/default_input_device_hub.cpp (+26/-58)
src/server/input/default_input_device_hub.h (+6/-10)
src/server/input/input_modifier_utils.cpp (+4/-22)
src/server/input/input_modifier_utils.h (+2/-7)
src/server/input/seat.cpp (+161/-0)
src/server/input/seat.h (+74/-0)
tests/mir_test_framework/fake_input_device_impl.cpp (+4/-16)
tests/mir_test_framework/fake_input_device_impl.h (+0/-1)
tests/unit-tests/input/evdev/test_libinput_device.cpp (+28/-33)
tests/unit-tests/input/test_default_input_device_hub.cpp (+146/-14)
To merge this branch: bzr merge lp:~andreas-pokorny/mir/combine-modifier-state-accross-devices
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Chris Halse Rogers Approve
Alan Griffiths Abstain
Review via email: mp+274412@code.launchpad.net

This proposal supersedes a proposal from 2015-10-14.

Commit message

Rework Modifier tracking to combine modifiers within

The platform is no longer in charge of the modifier. Instead the new input stack tracks it when the events are received. To reduce the complexity of InputDeviceHub this behavior and similar parts are moved to mir::input::Seat which represents a group of input devices that belong to a user session. (Currently all of them).

Collateral changes:
- allow changing the modifier of MirEvent after creation -> additional symbols to 'hidden' C++ client API
- reduction of EventBuilder interface
- moving of modifier utils to server

Description of the change

This fixes the problem that caused the revert of the input platform probing mp..

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

+MIR_CLIENT_DETAIL_v0.18.0 {

AIUI this should be MIR_CLIENT_DETAIL_unreleased? (and then become MIR_CLIENT_DETAIL_0.18)

review: Needs Fixing
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
Alan Griffiths (alan-griffiths) wrote :

I think this is OK, but not yet checked fully

review: Abstain
Revision history for this message
Chris Halse Rogers (raof) wrote :

Hm. The addition of Seat is great, but it looks like this will remove the ability to do per-keyboard modifiers? This isn't super-useful for things like <alt> or <ctrl>, but it's super-annoying for things like <num lock>.

Would it be possible to add the Seat interface, but still have keyboard devices handle their own modifiers? My understanding of the problem suggests that it is, but you've undoubtedly got a better understanding :)

review: Needs Information
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

> Hm. The addition of Seat is great, but it looks like this will remove the
> ability to do per-keyboard modifiers? This isn't super-useful for things like
> <alt> or <ctrl>, but it's super-annoying for things like <num lock>.
>
> Would it be possible to add the Seat interface, but still have keyboard
> devices handle their own modifiers? My understanding of the problem suggests
> that it is, but you've undoubtedly got a better understanding :)

I think we can achieve that in several ways.. and I think one of the options to do that looks robust: Have an additional keyboard device modifier property in MirEvent for keyboard events. The modifier which is currently stored per device in seat. After peeking into xkb_mapper. On the client side we would have to track the xkb state per keyboard device, and on every key event from a device inject potentially not experienced scan codes for caps lock and num lock (because it might have happened before the surface existed or when it was not focused) to ensure that the client has the right state..

We also discussed doing the xkb mapping on the server side.. and maybe per surface.. but thats would boil down to similar tasks.

Aaahnnd... we would have to find ways to tunnel that info through qt key events.. i believe..

Hmm why does this work at all right now?

Revision history for this message
Chris Halse Rogers (raof) wrote :

Hm. Couldn't you just keep the MirInputEventModifiers in the key_event() constructor and then not call mev::set_modifier(,seat->event_modifier()) on key events? That should then work just like it does today?

=============

+struct Seat

Class, surely? It has no public data members!

Otherwise looks good.

review: Needs Fixing
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

> Hm. Couldn't you just keep the MirInputEventModifiers in the key_event()
> constructor and then not call mev::set_modifier(,seat->event_modifier()) on
> key events? That should then work just like it does today?

Ah - so combine modifiers only for non key events, but keep per device modifers for key events..
So you cannot do for example ExternalKeyboard-Ctrl + BuiltinKeyboard-C to break stuff (which is what x11 currently does).

.... sounds good to me .. and simple to implement.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Chris Halse Rogers (raof) wrote :

Woot! Exactly what I was after.

review: Approve
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)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/client/mir/events/event_builders.h'
2--- include/client/mir/events/event_builders.h 2015-10-02 04:27:33 +0000
3+++ include/client/mir/events/event_builders.h 2015-10-26 14:13:05 +0000
4@@ -58,6 +58,8 @@
5 uint64_t mac, MirKeyboardAction action, xkb_keysym_t key_code,
6 int scan_code, MirInputEventModifiers modifiers);
7
8+void set_modifier(MirEvent& event, MirInputEventModifiers modifiers);
9+
10 // Deprecated version without mac
11 EventUPtr make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp,
12 MirKeyboardAction action, xkb_keysym_t key_code,
13
14=== modified file 'include/platform/mir/input/event_builder.h'
15--- include/platform/mir/input/event_builder.h 2015-08-24 23:25:00 +0000
16+++ include/platform/mir/input/event_builder.h 2015-10-26 14:13:05 +0000
17@@ -38,18 +38,16 @@
18 virtual ~EventBuilder() = default;
19 using Timestamp = std::chrono::nanoseconds;
20
21- virtual EventUPtr key_event(Timestamp timestamp, MirKeyboardAction action, xkb_keysym_t key_code, int scan_code,
22- MirInputEventModifiers modifiers) = 0;
23+ virtual EventUPtr key_event(Timestamp timestamp, MirKeyboardAction action, xkb_keysym_t key_code, int scan_code) = 0;
24
25- virtual EventUPtr touch_event(Timestamp timestamp, MirInputEventModifiers modifiers) = 0;
26+ virtual EventUPtr touch_event(Timestamp timestamp) = 0;
27 virtual void add_touch(MirEvent& event, MirTouchId touch_id, MirTouchAction action, MirTouchTooltype tooltype,
28 float x_axis_value, float y_axis_value, float pressure_value, float touch_major_value,
29 float touch_minor_value, float size_value) = 0;
30
31- virtual EventUPtr pointer_event(Timestamp timestamp, MirInputEventModifiers modifiers, MirPointerAction action,
32- MirPointerButtons buttons_pressed, float x_axis_value, float y_axis_value,
33- float hscroll_value, float vscroll_value, float relative_x_value,
34- float relative_y_value) = 0;
35+ virtual EventUPtr pointer_event(Timestamp timestamp, MirPointerAction action, MirPointerButtons buttons_pressed,
36+ float x_axis_value, float y_axis_value, float hscroll_value, float vscroll_value,
37+ float relative_x_value, float relative_y_value) = 0;
38
39 virtual EventUPtr configuration_event(Timestamp timestamp, MirInputConfigurationAction action) = 0;
40
41
42=== modified file 'include/test/mir/test/event_matchers.h'
43--- include/test/mir/test/event_matchers.h 2015-10-13 16:25:36 +0000
44+++ include/test/mir/test/event_matchers.h 2015-10-26 14:13:05 +0000
45@@ -353,6 +353,14 @@
46 return true;
47 }
48
49+MATCHER_P(PointerEventWithModifiers, modifiers, "")
50+{
51+ auto pev = maybe_pointer_event(to_address(arg));
52+ if (pev && mir_pointer_event_modifiers(pev) == modifiers)
53+ return true;
54+ return false;
55+}
56+
57 MATCHER_P2(PointerEventWithDiff, dx, dy, "")
58 {
59 auto pev = maybe_pointer_event(to_address(arg));
60
61=== modified file 'src/client/events/event_builders.cpp'
62--- src/client/events/event_builders.cpp 2015-10-07 12:07:00 +0000
63+++ src/client/events/event_builders.cpp 2015-10-26 14:13:05 +0000
64@@ -165,6 +165,28 @@
65 return make_event_uptr(e);
66 }
67
68+
69+void mev::set_modifier(MirEvent& event, MirInputEventModifiers modifiers)
70+{
71+ switch(event.type)
72+ {
73+ case mir_event_type_key:
74+ {
75+ auto& kev = event.key;
76+ kev.modifiers = modifiers;
77+ break;
78+ }
79+ case mir_event_type_motion:
80+ {
81+ auto& mev = event.motion;
82+ mev.modifiers = modifiers;
83+ break;
84+ }
85+ default:
86+ BOOST_THROW_EXCEPTION(std::invalid_argument("Input event modifiers are only valid for pointer, key and touch events."));
87+ }
88+}
89+
90 // Deprecated version without mac
91 mir::EventUPtr mev::make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp,
92 MirKeyboardAction action, xkb_keysym_t key_code,
93
94=== modified file 'src/client/symbols.map'
95--- src/client/symbols.map 2015-10-08 21:11:44 +0000
96+++ src/client/symbols.map 2015-10-26 14:13:05 +0000
97@@ -243,3 +243,11 @@
98 mir::operator???std::ostream???Mir*
99 };
100 };
101+
102+MIR_CLIENT_DETAIL_unreleased {
103+ global:
104+ extern "C++" {
105+ mir::events::set_modifier*;
106+ };
107+} MIR_CLIENT_DETAIL_9;
108+
109
110=== modified file 'src/platforms/evdev/CMakeLists.txt'
111--- src/platforms/evdev/CMakeLists.txt 2015-10-05 20:17:26 +0000
112+++ src/platforms/evdev/CMakeLists.txt 2015-10-26 14:13:05 +0000
113@@ -8,7 +8,7 @@
114
115 add_library(mirevdevutilsobjects OBJECT
116 evdev_device_detection.cpp
117- input_modifier_utils.cpp
118+ button_utils.cpp
119 )
120
121 add_library(mirplatforminputevdevobjects OBJECT
122@@ -34,8 +34,7 @@
123 )
124
125 target_link_libraries(mirplatforminputevdev
126- mirplatform
127- mirclient
128+ mirplatform # udev wrapper
129 ${Boost_PROGRAM_OPTIONS_LIBRARY}
130 ${LIBINPUT_LDFLAGS} ${LIBINPUT_LIBRARIES}
131 )
132
133=== added file 'src/platforms/evdev/button_utils.cpp'
134--- src/platforms/evdev/button_utils.cpp 1970-01-01 00:00:00 +0000
135+++ src/platforms/evdev/button_utils.cpp 2015-10-26 14:13:05 +0000
136@@ -0,0 +1,44 @@
137+/*
138+ * Copyright © 2015 Canonical Ltd.
139+ *
140+ * This program is free software: you can redistribute it and/or modify it
141+ * under the terms of the GNU General Public License version 3,
142+ * as published by the Free Software Foundation.
143+ *
144+ * This program is distributed in the hope that it will be useful,
145+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
146+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
147+ * GNU General Public License for more details.
148+ *
149+ * You should have received a copy of the GNU General Public License
150+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
151+ *
152+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
153+ */
154+
155+#include "button_utils.h"
156+#include "boost/throw_exception.hpp"
157+
158+#include "linux/input.h"
159+
160+#include <stdexcept>
161+
162+namespace mie = mir::input::evdev;
163+
164+MirPointerButton mie::to_pointer_button(int button, MirPointerHandedness handedness)
165+{
166+ switch(button)
167+ {
168+ case BTN_LEFT: return (handedness == mir_pointer_handedness_right)
169+ ? mir_pointer_button_primary
170+ : mir_pointer_button_secondary;
171+ case BTN_RIGHT: return (handedness == mir_pointer_handedness_right)
172+ ? mir_pointer_button_secondary
173+ : mir_pointer_button_primary;
174+ case BTN_MIDDLE: return mir_pointer_button_tertiary;
175+ case BTN_BACK: return mir_pointer_button_back;
176+ case BTN_FORWARD: return mir_pointer_button_forward;
177+ }
178+ BOOST_THROW_EXCEPTION(std::runtime_error("Invalid mouse button"));
179+}
180+
181
182=== added file 'src/platforms/evdev/button_utils.h'
183--- src/platforms/evdev/button_utils.h 1970-01-01 00:00:00 +0000
184+++ src/platforms/evdev/button_utils.h 2015-10-26 14:13:05 +0000
185@@ -0,0 +1,36 @@
186+/*
187+ * Copyright © 2015 Canonical Ltd.
188+ *
189+ * This program is free software: you can redistribute it and/or modify it
190+ * under the terms of the GNU General Public License version 3,
191+ * as published by the Free Software Foundation.
192+ *
193+ * This program is distributed in the hope that it will be useful,
194+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
195+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
196+ * GNU General Public License for more details.
197+ *
198+ * You should have received a copy of the GNU General Public License
199+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
200+ *
201+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
202+ */
203+
204+#ifndef MIR_INPUT_EVDEV_BUTTON_UTILS_H_
205+#define MIR_INPUT_EVDEV_BUTTON_UTILS_H_
206+
207+#include "mir_toolkit/event.h"
208+#include "mir_toolkit/mir_input_device.h"
209+
210+namespace mir
211+{
212+namespace input
213+{
214+namespace evdev
215+{
216+MirPointerButton to_pointer_button(int button, MirPointerHandedness handedness);
217+}
218+}
219+}
220+
221+#endif
222
223=== modified file 'src/platforms/evdev/libinput_device.cpp'
224--- src/platforms/evdev/libinput_device.cpp 2015-10-23 16:32:32 +0000
225+++ src/platforms/evdev/libinput_device.cpp 2015-10-26 14:13:05 +0000
226@@ -19,8 +19,8 @@
227 #include "libinput_device.h"
228 #include "libinput_ptr.h"
229 #include "libinput_device_ptr.h"
230-#include "input_modifier_utils.h"
231 #include "evdev_device_detection.h"
232+#include "button_utils.h"
233
234 #include "mir/input/input_sink.h"
235 #include "mir/input/input_report.h"
236@@ -55,8 +55,7 @@
237
238 mie::LibInputDevice::LibInputDevice(std::shared_ptr<mi::InputReport> const& report, char const* path,
239 LibInputDevicePtr dev)
240- : report{report}, accumulated_touch_event{nullptr, null_deleter}, pointer_pos{0, 0}, modifier_state{0},
241- button_state{0}
242+ : report{report}, accumulated_touch_event{nullptr, null_deleter}, pointer_pos{0, 0}, button_state{0}
243 {
244 add_device_of_group(path, std::move(dev));
245 }
246@@ -140,18 +139,7 @@
247 auto const code = libinput_event_keyboard_get_key(keyboard);
248 report->received_event_from_kernel(time.count(), EV_KEY, code, action);
249
250- auto event = builder->key_event(time,
251- action,
252- xkb_keysym_t{0},
253- code,
254- mie::expand_modifiers(modifier_state));
255-
256- if (action == mir_keyboard_action_down)
257- modifier_state |= mie::to_modifiers(code);
258- else
259- modifier_state &= ~mie::to_modifiers(code);
260-
261- return event;
262+ return builder->key_event(time, action, xkb_keysym_t{0}, code);
263 }
264
265 mir::EventUPtr mie::LibInputDevice::convert_button_event(libinput_event_pointer* pointer)
266@@ -175,11 +163,8 @@
267 else
268 button_state = MirPointerButton(button_state & ~uint32_t(pointer_button));
269
270- auto event = builder->pointer_event(time, mie::expand_modifiers(modifier_state), action, button_state,
271- pointer_pos.x.as_float(), pointer_pos.y.as_float(), hscroll_value,
272- vscroll_value, relative_x_value, relative_y_value);
273-
274- return event;
275+ return builder->pointer_event(time, action, button_state, pointer_pos.x.as_float(), pointer_pos.y.as_float(),
276+ hscroll_value, vscroll_value, relative_x_value, relative_y_value);
277 }
278
279 mir::EventUPtr mie::LibInputDevice::convert_motion_event(libinput_event_pointer* pointer)
280@@ -198,11 +183,8 @@
281
282 sink->confine_pointer(pointer_pos);
283
284- auto event = builder->pointer_event(time, mie::expand_modifiers(modifier_state), action, button_state,
285- pointer_pos.x.as_float(), pointer_pos.y.as_float(), hscroll_value,
286- vscroll_value, movement.dx.as_float(), movement.dy.as_float());
287-
288- return event;
289+ return builder->pointer_event(time, action, button_state, pointer_pos.x.as_float(), pointer_pos.y.as_float(),
290+ hscroll_value, vscroll_value, movement.dx.as_float(), movement.dy.as_float());
291 }
292
293 mir::EventUPtr mie::LibInputDevice::convert_absolute_motion_event(libinput_event_pointer* pointer)
294@@ -222,10 +204,8 @@
295
296 sink->confine_pointer(pointer_pos);
297
298- auto event = builder->pointer_event(time, mie::expand_modifiers(modifier_state), action, button_state,
299- pointer_pos.x.as_float(), pointer_pos.y.as_float(), hscroll_value,
300- vscroll_value, movement.dx.as_float(), movement.dy.as_float());
301- return event;
302+ return builder->pointer_event(time, action, button_state, pointer_pos.x.as_float(), pointer_pos.y.as_float(),
303+ hscroll_value, vscroll_value, movement.dx.as_float(), movement.dy.as_float());
304 }
305
306 mir::EventUPtr mie::LibInputDevice::convert_axis_event(libinput_event_pointer* pointer)
307@@ -244,10 +224,8 @@
308 : 0.0f;
309
310 report->received_event_from_kernel(time.count(), EV_REL, 0, 0);
311- auto event = builder->pointer_event(time, mie::expand_modifiers(modifier_state), action, button_state,
312- pointer_pos.x.as_float(), pointer_pos.y.as_float(), hscroll_value,
313- vscroll_value, relative_x_value, relative_y_value);
314- return event;
315+ return builder->pointer_event(time, action, button_state, pointer_pos.x.as_float(), pointer_pos.y.as_float(),
316+ hscroll_value, vscroll_value, relative_x_value, relative_y_value);
317 }
318
319 MirEvent& mie::LibInputDevice::get_accumulated_touch_event(std::chrono::nanoseconds timestamp)
320@@ -255,7 +233,7 @@
321 if (!accumulated_touch_event)
322 {
323 report->received_event_from_kernel(timestamp.count(), EV_SYN, 0, 0);
324- accumulated_touch_event = builder->touch_event(timestamp, mie::expand_modifiers(modifier_state));
325+ accumulated_touch_event = builder->touch_event(timestamp);
326 }
327
328 return *accumulated_touch_event;
329
330=== modified file 'src/platforms/evdev/libinput_device.h'
331--- src/platforms/evdev/libinput_device.h 2015-10-23 16:32:32 +0000
332+++ src/platforms/evdev/libinput_device.h 2015-10-26 14:13:05 +0000
333@@ -88,7 +88,6 @@
334
335 InputDeviceInfo info;
336 mir::geometry::Point pointer_pos;
337- MirInputEventModifiers modifier_state;
338 MirPointerButtons button_state;
339 double vertical_scroll_scale{1.0};
340 double horizontal_scroll_scale{1.0};
341
342=== modified file 'src/platforms/mesa/server/x11/input/input_platform.cpp'
343--- src/platforms/mesa/server/x11/input/input_platform.cpp 2015-10-15 16:56:07 +0000
344+++ src/platforms/mesa/server/x11/input/input_platform.cpp 2015-10-26 14:13:05 +0000
345@@ -127,16 +127,6 @@
346 #endif
347 XLookupString(&xkev, str, STRMAX, &keysym, NULL);
348
349- MirInputEventModifiers modifiers = mir_input_event_modifier_none;
350- if (xkev.state & ShiftMask)
351- modifiers |= mir_input_event_modifier_shift;
352- if (xkev.state & ControlMask)
353- modifiers |= mir_input_event_modifier_ctrl;
354- if (xkev.state & Mod1Mask)
355- modifiers |= mir_input_event_modifier_alt;
356- if (xkev.state & Mod4Mask)
357- modifiers |= mir_input_event_modifier_meta;
358-
359 auto event_time =
360 std::chrono::duration_cast<std::chrono::nanoseconds>(
361 std::chrono::milliseconds{xkev.time});
362@@ -155,8 +145,7 @@
363 mir_keyboard_action_down :
364 mir_keyboard_action_up,
365 keysym,
366- xkev.keycode-8,
367- modifiers
368+ xkev.keycode-8
369 )
370 );
371 break;
372@@ -185,16 +174,6 @@
373 #endif
374 break;
375 }
376- MirInputEventModifiers modifiers = mir_input_event_modifier_none;
377- if (xbev.state & ShiftMask)
378- modifiers |= mir_input_event_modifier_shift;
379- if (xbev.state & ControlMask)
380- modifiers |= mir_input_event_modifier_ctrl;
381- if (xbev.state & Mod1Mask)
382- modifiers |= mir_input_event_modifier_alt;
383- if (xbev.state & Mod4Mask)
384- modifiers |= mir_input_event_modifier_meta;
385-
386 auto event_time =
387 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds{xbev.time});
388
389@@ -215,15 +194,15 @@
390
391 #ifdef MIR_ON_X11_INPUT_VERBOSE
392 mir::log_info("Mir button event : x=%d, y=%d, "
393- "buttons_pressed=0x%0X, modifiers=0x%0X, event_time=%" PRId64,
394- xbev.x, xbev.y, buttons_pressed, modifiers, event_time);
395+ "buttons_pressed=0x%0X, event_time=%" PRId64,
396+ xbev.x, xbev.y, buttons_pressed, event_time);
397 #endif
398+
399 if ((xbev.button == Button4) || (xbev.button == Button5))
400 { // scroll event
401 core_pointer->sink->handle_input(
402 *core_pointer->builder->pointer_event(
403 event_time,
404- modifiers,
405 mir_pointer_action_motion,
406 0,
407 xbev.x,
408@@ -240,7 +219,6 @@
409 core_pointer->sink->handle_input(
410 *core_pointer->builder->pointer_event(
411 event_time,
412- modifiers,
413 xbev.type == ButtonPress ?
414 mir_pointer_action_button_down :
415 mir_pointer_action_button_up,
416@@ -270,15 +248,6 @@
417 xmev.root, xmev.subwindow, xmev.time, xmev.x, xmev.y, xmev.x_root,
418 xmev.y_root, xmev.state, xmev.is_hint == NotifyNormal ? "no" : "yes", xmev.same_screen);
419 #endif
420- MirInputEventModifiers modifiers = mir_input_event_modifier_none;
421- if (xmev.state & ShiftMask)
422- modifiers |= mir_input_event_modifier_shift;
423- if (xmev.state & ControlMask)
424- modifiers |= mir_input_event_modifier_ctrl;
425- if (xmev.state & Mod1Mask)
426- modifiers |= mir_input_event_modifier_alt;
427- if (xmev.state & Mod4Mask)
428- modifiers |= mir_input_event_modifier_meta;
429
430 auto event_time =
431 std::chrono::duration_cast<std::chrono::nanoseconds>(
432@@ -298,13 +267,12 @@
433
434 #ifdef MIR_ON_X11_INPUT_VERBOSE
435 mir::log_info("Mir pointer event : "
436- "x=%d, y=%d, buttons_pressed=0x%0X, modifiers=0x%0X, event_time=%" PRId64,
437- xmev.x, xmev.y, buttons_pressed, modifiers, event_time);
438+ "x=%d, y=%d, buttons_pressed=0x%0X, event_time=%" PRId64,
439+ xmev.x, xmev.y, buttons_pressed, event_time);
440 #endif
441 core_pointer->sink->handle_input(
442 *core_pointer->builder->pointer_event(
443 event_time,
444- modifiers,
445 mir_pointer_action_motion,
446 buttons_pressed,
447 xmev.x,
448
449=== modified file 'src/server/input/CMakeLists.txt'
450--- src/server/input/CMakeLists.txt 2015-10-12 19:30:14 +0000
451+++ src/server/input/CMakeLists.txt 2015-10-26 14:13:05 +0000
452@@ -8,6 +8,8 @@
453 default_event_builder.cpp
454 default_input_manager.cpp
455 default_input_device_hub.cpp
456+ input_modifier_utils.cpp
457+ seat.cpp
458
459 surface_input_dispatcher.cpp
460 event_filter_chain_dispatcher.cpp
461
462=== modified file 'src/server/input/default_event_builder.cpp'
463--- src/server/input/default_event_builder.cpp 2015-10-09 00:15:44 +0000
464+++ src/server/input/default_event_builder.cpp 2015-10-26 14:13:05 +0000
465@@ -33,21 +33,21 @@
466 }
467
468 mir::EventUPtr mi::DefaultEventBuilder::key_event(Timestamp timestamp, MirKeyboardAction action, xkb_keysym_t key_code,
469- int scan_code, MirInputEventModifiers modifiers)
470+ int scan_code)
471 {
472 uint64_t mac = cookie_factory->timestamp_to_cookie(timestamp.count()).mac;
473- return me::make_event(device_id, timestamp, mac, action, key_code, scan_code, modifiers);
474+ return me::make_event(device_id, timestamp, mac, action, key_code, scan_code, mir_input_event_modifier_none);
475 }
476
477-mir::EventUPtr mi::DefaultEventBuilder::touch_event(Timestamp timestamp, MirInputEventModifiers modifiers)
478+mir::EventUPtr mi::DefaultEventBuilder::touch_event(Timestamp timestamp)
479 {
480- return me::make_event(device_id, timestamp, 0, modifiers);
481+ return me::make_event(device_id, timestamp, 0, mir_input_event_modifier_none);
482 }
483
484 void mi::DefaultEventBuilder::add_touch(MirEvent& event, MirTouchId touch_id, MirTouchAction action,
485- MirTouchTooltype tooltype, float x_axis_value, float y_axis_value,
486- float pressure_value, float touch_major_value,
487- float touch_minor_value, float size_value)
488+ MirTouchTooltype tooltype, float x_axis_value, float y_axis_value,
489+ float pressure_value, float touch_major_value, float touch_minor_value,
490+ float size_value)
491 {
492 if (action == mir_touch_action_up || action == mir_touch_action_down)
493 {
494@@ -59,17 +59,15 @@
495 touch_minor_value, size_value);
496 }
497
498-mir::EventUPtr mi::DefaultEventBuilder::pointer_event(Timestamp timestamp, MirInputEventModifiers modifiers,
499- MirPointerAction action, MirPointerButtons buttons_pressed,
500- float x_axis_value, float y_axis_value, float hscroll_value,
501- float vscroll_value, float relative_x_value,
502- float relative_y_value)
503+mir::EventUPtr mi::DefaultEventBuilder::pointer_event(Timestamp timestamp, MirPointerAction action,
504+ MirPointerButtons buttons_pressed, float x_axis_value,
505+ float y_axis_value, float hscroll_value, float vscroll_value,
506+ float relative_x_value, float relative_y_value)
507 {
508 uint64_t mac = 0;
509 if (action == mir_pointer_action_button_up || action == mir_pointer_action_button_down)
510 mac = cookie_factory->timestamp_to_cookie(timestamp.count()).mac;
511-
512- return me::make_event(device_id, timestamp, mac, modifiers, action, buttons_pressed, x_axis_value, y_axis_value,
513+ return me::make_event(device_id, timestamp, mac, mir_input_event_modifier_none, action, buttons_pressed, x_axis_value, y_axis_value,
514 hscroll_value, vscroll_value, relative_x_value, relative_y_value);
515 }
516
517
518=== modified file 'src/server/input/default_event_builder.h'
519--- src/server/input/default_event_builder.h 2015-10-08 00:23:43 +0000
520+++ src/server/input/default_event_builder.h 2015-10-26 14:13:05 +0000
521@@ -37,18 +37,16 @@
522 explicit DefaultEventBuilder(MirInputDeviceId device_id,
523 std::shared_ptr<cookie::CookieFactory> const& cookie_factory);
524
525- EventUPtr key_event(Timestamp timestamp, MirKeyboardAction action, xkb_keysym_t key_code, int scan_code,
526- MirInputEventModifiers modifiers) override;
527+ EventUPtr key_event(Timestamp timestamp, MirKeyboardAction action, xkb_keysym_t key_code, int scan_code) override;
528
529- EventUPtr touch_event(Timestamp timestamp, MirInputEventModifiers modifiers) override;
530+ EventUPtr touch_event(Timestamp timestamp) override;
531 void add_touch(MirEvent& event, MirTouchId touch_id, MirTouchAction action, MirTouchTooltype tooltype,
532 float x_axis_value, float y_axis_value, float pressure_value, float touch_major_value,
533 float touch_minor_value, float size_value) override;
534
535- EventUPtr pointer_event(Timestamp timestamp, MirInputEventModifiers modifiers, MirPointerAction action,
536- MirPointerButtons buttons_pressed, float x_axis_value, float y_axis_value,
537- float hscroll_value, float vscroll_value, float relative_x_value,
538- float relative_y_value) override;
539+ EventUPtr pointer_event(Timestamp timestamp, MirPointerAction action, MirPointerButtons buttons_pressed,
540+ float x_axis_value, float y_axis_value, float hscroll_value, float vscroll_value,
541+ float relative_x_value, float relative_y_value) override;
542
543 EventUPtr configuration_event(Timestamp timestamp, MirInputConfigurationAction action) override;
544
545
546=== modified file 'src/server/input/default_input_device_hub.cpp'
547--- src/server/input/default_input_device_hub.cpp 2015-10-08 00:23:43 +0000
548+++ src/server/input/default_input_device_hub.cpp 2015-10-26 14:13:05 +0000
549@@ -19,11 +19,13 @@
550 #include "default_input_device_hub.h"
551 #include "device_handle.h"
552
553+#include "seat.h"
554 #include "mir/input/input_dispatcher.h"
555 #include "mir/input/input_device.h"
556 #include "mir/input/input_device_observer.h"
557-#include "mir/input/cursor_listener.h"
558 #include "mir/input/input_region.h"
559+#include "mir/geometry/point.h"
560+#include "mir/events/event_builders.h"
561 #include "mir/dispatch/multiplexing_dispatchable.h"
562 #include "mir/server_action_queue.h"
563 #include "mir/cookie_factory.h"
564@@ -36,6 +38,8 @@
565 #include <atomic>
566
567 namespace mi = mir::input;
568+namespace geom = mir::geometry;
569+namespace mev = mir::events;
570
571 mi::DefaultInputDeviceHub::DefaultInputDeviceHub(
572 std::shared_ptr<mi::InputDispatcher> const& input_dispatcher,
573@@ -45,9 +49,13 @@
574 std::shared_ptr<CursorListener> const& cursor_listener,
575 std::shared_ptr<InputRegion> const& input_region,
576 std::shared_ptr<mir::cookie::CookieFactory> const& cookie_factory)
577- : input_dispatcher(input_dispatcher), input_dispatchable{input_multiplexer}, observer_queue(observer_queue),
578- touch_visualizer(touch_visualizer), cursor_listener(cursor_listener), input_region(input_region),
579- cookie_factory(cookie_factory), device_id_generator{0}
580+ : input_dispatcher(input_dispatcher),
581+ input_dispatchable{input_multiplexer},
582+ observer_queue(observer_queue),
583+ input_region(input_region),
584+ cookie_factory(cookie_factory),
585+ seat(touch_visualizer, cursor_listener),
586+ device_id_generator{0}
587 {
588 }
589
590@@ -67,9 +75,10 @@
591 {
592 // send input device info to observer loop..
593 devices.push_back(std::make_unique<RegisteredDevice>(
594- device, create_new_device_id(), input_dispatcher, input_dispatchable, cookie_factory, this));
595+ device, create_new_device_id(), input_dispatcher, input_dispatchable, cookie_factory, this, &seat));
596
597 auto const& dev = devices.back();
598+ seat.add_device(dev->id());
599
600 auto handle = std::make_shared<DefaultDevice>(
601 dev->id(), device->get_device_info());
602@@ -104,6 +113,7 @@
603 if (item->device_matches(device))
604 {
605 item->stop();
606+ seat.remove_device(item->id());
607
608 // send input device info to observer queue..
609 observer_queue->enqueue(
610@@ -131,9 +141,10 @@
611 std::shared_ptr<InputDispatcher> const& dispatcher,
612 std::shared_ptr<dispatch::MultiplexingDispatchable> const& multiplexer,
613 std::shared_ptr<mir::cookie::CookieFactory> const& cookie_factory,
614- DefaultInputDeviceHub* hub)
615+ DefaultInputDeviceHub* hub,
616+ Seat* seat)
617 : device_id(device_id), builder(device_id, cookie_factory), device(dev), dispatcher(dispatcher),
618- multiplexer(multiplexer), hub(hub)
619+ multiplexer(multiplexer), hub(hub), seat(seat)
620 {
621 }
622
623@@ -154,50 +165,17 @@
624 if (type != mir_event_type_input)
625 BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid input event receivd from device"));
626
627- update_spots(mir_event_get_input_event(&event));
628- notify_cursor_listener(mir_event_get_input_event(&event));
629+ auto input_event = mir_event_get_input_event(&event);
630+ seat->update_seat_properties(input_event);
631+
632+ if (mir_input_event_type_key == mir_input_event_get_type(input_event))
633+ mev::set_modifier(event, seat->event_modifier(mir_input_event_get_device_id(input_event)));
634+ else
635+ mev::set_modifier(event, seat->event_modifier());
636+
637 dispatcher->dispatch(event);
638 }
639
640-void mi::DefaultInputDeviceHub::RegisteredDevice::notify_cursor_listener(MirInputEvent const* event)
641-{
642- if (mir_input_event_get_type(event) != mir_input_event_type_pointer)
643- return;
644-
645- auto pointer_ev = mir_input_event_get_pointer_event(event);
646- hub->cursor_listener->cursor_moved_to(
647- mir_pointer_event_axis_value(pointer_ev, mir_pointer_axis_x),
648- mir_pointer_event_axis_value(pointer_ev, mir_pointer_axis_y)
649- );
650-}
651-
652-void mi::DefaultInputDeviceHub::RegisteredDevice::update_spots(MirInputEvent const* event)
653-{
654- if (mir_input_event_get_type(event) != mir_input_event_type_touch)
655- return;
656-
657- auto const* touch_event = mir_input_event_get_touch_event(event);
658- auto count = mir_touch_event_point_count(touch_event);
659- touch_spots.reserve(count);
660- touch_spots.clear();
661- for (decltype(count) i = 0; i != count; ++i)
662- {
663- if (mir_touch_event_action(touch_event, i) == mir_touch_action_up)
664- continue;
665- touch_spots.push_back(mi::TouchVisualizer::Spot{
666- {mir_touch_event_axis_value(touch_event, i, mir_touch_axis_x),
667- mir_touch_event_axis_value(touch_event, i, mir_touch_axis_y)},
668- mir_touch_event_axis_value(touch_event, i, mir_touch_axis_pressure)});
669- }
670-
671- hub->update_spots();
672-}
673-
674-std::vector<mir::input::TouchVisualizer::Spot> const& mi::DefaultInputDeviceHub::RegisteredDevice::spots() const
675-{
676- return touch_spots;
677-}
678-
679 bool mi::DefaultInputDeviceHub::RegisteredDevice::device_matches(std::shared_ptr<InputDevice> const& dev) const
680 {
681 return dev == device;
682@@ -278,13 +256,3 @@
683
684 handles.erase(handle_it, end(handles));
685 }
686-
687-void mi::DefaultInputDeviceHub::update_spots()
688-{
689- std::vector<TouchVisualizer::Spot> spots;
690-
691- for (auto const& dev : devices)
692- spots.insert(end(spots), begin(dev->spots()), end(dev->spots()));
693-
694- touch_visualizer->visualize_touches(spots);
695-}
696
697=== modified file 'src/server/input/default_input_device_hub.h'
698--- src/server/input/default_input_device_hub.h 2015-10-08 00:23:43 +0000
699+++ src/server/input/default_input_device_hub.h 2015-10-26 14:13:05 +0000
700@@ -20,12 +20,12 @@
701 #define MIR_INPUT_DEFAULT_INPUT_DEVICE_HUB_H_
702
703 #include "default_event_builder.h"
704+#include "seat.h"
705
706 #include "mir/input/input_device_registry.h"
707 #include "mir/input/input_sink.h"
708 #include "mir/input/input_device_hub.h"
709 #include "mir/input/input_device_info.h"
710-#include "mir/input/touch_visualizer.h"
711
712 #include "mir_toolkit/event.h"
713
714@@ -82,10 +82,9 @@
715 std::shared_ptr<InputDispatcher> const input_dispatcher;
716 std::shared_ptr<dispatch::MultiplexingDispatchable> const input_dispatchable;
717 std::shared_ptr<ServerActionQueue> const observer_queue;
718- std::shared_ptr<TouchVisualizer> const touch_visualizer;
719- std::shared_ptr<CursorListener> const cursor_listener;
720 std::shared_ptr<InputRegion> const input_region;
721 std::shared_ptr<cookie::CookieFactory> const cookie_factory;
722+ Seat seat;
723
724 struct RegisteredDevice : public InputSink
725 {
726@@ -95,8 +94,8 @@
727 std::shared_ptr<InputDispatcher> const& dispatcher,
728 std::shared_ptr<dispatch::MultiplexingDispatchable> const& multiplexer,
729 std::shared_ptr<cookie::CookieFactory> const& cookie_factory,
730- DefaultInputDeviceHub* hub);
731-
732+ DefaultInputDeviceHub* hub,
733+ Seat* seat);
734 void handle_input(MirEvent& event) override;
735 void confine_pointer(mir::geometry::Point& position) override;
736 mir::geometry::Rectangle bounding_rectangle() const override;
737@@ -104,24 +103,21 @@
738 void start();
739 void stop();
740 MirInputDeviceId id();
741- std::vector<TouchVisualizer::Spot> const& spots() const;
742 private:
743- void update_spots(MirInputEvent const* event);
744- void notify_cursor_listener(MirInputEvent const* event);
745 MirInputDeviceId device_id;
746 DefaultEventBuilder builder;
747 std::shared_ptr<InputDevice> const device;
748 std::shared_ptr<InputDispatcher> const dispatcher;
749 std::shared_ptr<dispatch::MultiplexingDispatchable> const multiplexer;
750 DefaultInputDeviceHub* hub;
751- std::vector<TouchVisualizer::Spot> touch_spots;
752+ Seat* seat;
753 friend class DefaultInputDeviceHub;
754 };
755
756 std::vector<std::shared_ptr<DefaultDevice>> handles;
757 std::vector<std::unique_ptr<RegisteredDevice>> devices;
758 std::vector<std::shared_ptr<InputDeviceObserver>> observers;
759-
760+
761 MirInputDeviceId device_id_generator;
762 };
763
764
765=== renamed file 'src/platforms/evdev/input_modifier_utils.cpp' => 'src/server/input/input_modifier_utils.cpp'
766--- src/platforms/evdev/input_modifier_utils.cpp 2015-10-20 03:30:00 +0000
767+++ src/server/input/input_modifier_utils.cpp 2015-10-26 14:13:05 +0000
768@@ -25,26 +25,9 @@
769
770 #include <stdexcept>
771
772-namespace mie = mir::input::evdev;
773-
774-MirPointerButton mie::to_pointer_button(int button, MirPointerHandedness handedness)
775-{
776- switch(button)
777- {
778- case BTN_LEFT: return (handedness == mir_pointer_handedness_right)
779- ? mir_pointer_button_primary
780- : mir_pointer_button_secondary;
781- case BTN_RIGHT: return (handedness == mir_pointer_handedness_right)
782- ? mir_pointer_button_secondary
783- : mir_pointer_button_primary;
784- case BTN_MIDDLE: return mir_pointer_button_tertiary;
785- case BTN_BACK: return mir_pointer_button_back;
786- case BTN_FORWARD: return mir_pointer_button_forward;
787- }
788- BOOST_THROW_EXCEPTION(std::runtime_error("Invalid mouse button"));
789-}
790-
791-MirInputEventModifiers mie::to_modifiers(int32_t scan_code)
792+namespace mi = mir::input;
793+
794+MirInputEventModifiers mi::to_modifiers(int32_t scan_code)
795 {
796 switch(scan_code)
797 {
798@@ -75,7 +58,7 @@
799 }
800 }
801
802-MirInputEventModifiers mie::expand_modifiers(MirInputEventModifiers modifiers)
803+MirInputEventModifiers mi::expand_modifiers(MirInputEventModifiers modifiers)
804 {
805 if (modifiers == 0)
806 return mir_input_event_modifier_none;
807@@ -95,4 +78,3 @@
808 return modifiers;
809 }
810
811-
812
813=== renamed file 'src/platforms/evdev/input_modifier_utils.h' => 'src/server/input/input_modifier_utils.h'
814--- src/platforms/evdev/input_modifier_utils.h 2015-10-20 03:30:00 +0000
815+++ src/server/input/input_modifier_utils.h 2015-10-26 14:13:05 +0000
816@@ -16,23 +16,18 @@
817 * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
818 */
819
820-#ifndef MIR_INPUT_EVDEV_INPUT_MODIFIER_UTILS_H_
821-#define MIR_INPUT_EVDEV_INPUT_MODIFIER_UTILS_H_
822+#ifndef MIR_INPUT_INPUT_MODIFIER_UTILS_H_
823+#define MIR_INPUT_INPUT_MODIFIER_UTILS_H_
824
825 #include "mir_toolkit/event.h"
826-#include "mir_toolkit/mir_input_device.h"
827
828 namespace mir
829 {
830 namespace input
831 {
832-namespace evdev
833-{
834-MirPointerButton to_pointer_button(int button, MirPointerHandedness handedness);
835 MirInputEventModifiers to_modifiers(int32_t scan_code);
836 MirInputEventModifiers expand_modifiers(MirInputEventModifiers modifiers);
837 }
838 }
839-}
840
841 #endif
842
843=== added file 'src/server/input/seat.cpp'
844--- src/server/input/seat.cpp 1970-01-01 00:00:00 +0000
845+++ src/server/input/seat.cpp 2015-10-26 14:13:05 +0000
846@@ -0,0 +1,161 @@
847+/*
848+ * Copyright © 2015 Canonical Ltd.
849+ *
850+ * This program is free software: you can redistribute it and/or modify it
851+ * under the terms of the GNU General Public License version 3,
852+ * as published by the Free Software Foundation.
853+ *
854+ * This program is distributed in the hope that it will be useful,
855+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
856+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
857+ * GNU General Public License for more details.
858+ *
859+ * You should have received a copy of the GNU General Public License
860+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
861+ *
862+ * Authored by:
863+ * Andreas Pokorny <andreas.pokorny@canonical.com>
864+ */
865+
866+#include "seat.h"
867+#include "mir/input/device.h"
868+#include "mir/input/cursor_listener.h"
869+
870+#include "input_modifier_utils.h"
871+
872+#include <boost/throw_exception.hpp>
873+
874+#include <stdexcept>
875+#include <algorithm>
876+
877+namespace mi = mir::input;
878+
879+mi::Seat::Seat(std::shared_ptr<TouchVisualizer> const& touch_visualizer,
880+ std::shared_ptr<CursorListener> const& cursor_listener)
881+ : touch_visualizer{touch_visualizer}, cursor_listener{cursor_listener}, modifier{0}
882+{
883+}
884+
885+void mi::Seat::add_device(MirInputDeviceId id)
886+{
887+ device_data[id];
888+}
889+
890+void mi::Seat::remove_device(MirInputDeviceId id)
891+{
892+ auto stored_data = device_data.find(id);
893+
894+ if (stored_data == end(device_data))
895+ BOOST_THROW_EXCEPTION(std::logic_error("Modifier for unknown device changed"));
896+
897+ bool mod_update_needed = stored_data->second.mod != mir_input_event_modifier_none;
898+ bool spot_update_needed = !stored_data->second.spots.empty();
899+
900+ device_data.erase(stored_data);
901+
902+ if (mod_update_needed)
903+ update_modifier();
904+ if (spot_update_needed)
905+ update_spots();
906+}
907+
908+MirInputEventModifiers mi::Seat::event_modifier() const
909+{
910+ return expand_modifiers(modifier);
911+}
912+
913+MirInputEventModifiers mi::Seat::event_modifier(MirInputDeviceId id) const
914+{
915+ auto stored_data = device_data.find(id);
916+ if (stored_data == end(device_data))
917+ BOOST_THROW_EXCEPTION(std::logic_error("Modifier for unknown device requested"));
918+ return expand_modifiers(stored_data->second.mod);
919+}
920+
921+void mi::Seat::update_seat_properties(MirInputEvent const* event)
922+{
923+ auto id = mir_input_event_get_device_id(event);
924+
925+ auto stored_data = device_data.find(id);
926+
927+ if (stored_data == end(device_data))
928+ BOOST_THROW_EXCEPTION(std::logic_error("Modifier for unknown device changed"));
929+
930+ switch(mir_input_event_get_type(event))
931+ {
932+ case mir_input_event_type_key:
933+ {
934+ auto const* key = mir_input_event_get_keyboard_event(event);
935+ if (stored_data->second.update_modifier(mir_keyboard_event_action(key),
936+ mir_keyboard_event_scan_code(key)))
937+ update_modifier();
938+ break;
939+ }
940+ case mir_input_event_type_touch:
941+ if (stored_data->second.update_spots(mir_input_event_get_touch_event(event)))
942+ update_spots();
943+ break;
944+ case mir_input_event_type_pointer:
945+ update_cursor(mir_input_event_get_pointer_event(event));
946+ break;
947+ default:
948+ break;
949+ }
950+}
951+
952+bool mi::Seat::DeviceData::update_modifier(MirKeyboardAction key_action, int scan_code)
953+{
954+ auto mod_change = to_modifiers(scan_code);
955+
956+ if (mod_change == 0 || key_action == mir_keyboard_action_repeat)
957+ return false;
958+
959+ if (key_action == mir_keyboard_action_down)
960+ mod |= mod_change;
961+ else if (key_action == mir_keyboard_action_up)
962+ mod &= ~mod_change;
963+
964+ return true;
965+}
966+
967+bool mi::Seat::DeviceData::update_spots(MirTouchEvent const* event)
968+{
969+ auto count = mir_touch_event_point_count(event);
970+ spots.clear();
971+ for (decltype(count) i = 0; i != count; ++i)
972+ {
973+ if (mir_touch_event_action(event, i) == mir_touch_action_up)
974+ continue;
975+ spots.push_back({{mir_touch_event_axis_value(event, i, mir_touch_axis_x),
976+ mir_touch_event_axis_value(event, i, mir_touch_axis_y)},
977+ mir_touch_event_axis_value(event, i, mir_touch_axis_pressure)});
978+ }
979+ return true;
980+}
981+
982+void mi::Seat::update_spots()
983+{
984+ spots.clear();
985+ for (auto const& dev : device_data)
986+ spots.insert(end(spots), begin(dev.second.spots), end(dev.second.spots));
987+
988+ touch_visualizer->visualize_touches(spots);
989+}
990+
991+void mi::Seat::update_modifier()
992+{
993+ modifier = std::accumulate(begin(device_data),
994+ end(device_data),
995+ MirInputEventModifiers{0},
996+ [](auto const& acc, auto const& item)
997+ {
998+ return acc | item.second.mod;
999+ });
1000+}
1001+
1002+void mi::Seat::update_cursor(MirPointerEvent const* event)
1003+{
1004+ cursor_listener->cursor_moved_to(mir_pointer_event_axis_value(event, mir_pointer_axis_x),
1005+ mir_pointer_event_axis_value(event, mir_pointer_axis_y));
1006+}
1007+
1008
1009=== added file 'src/server/input/seat.h'
1010--- src/server/input/seat.h 1970-01-01 00:00:00 +0000
1011+++ src/server/input/seat.h 2015-10-26 14:13:05 +0000
1012@@ -0,0 +1,74 @@
1013+/*
1014+ * Copyright © 2015 Canonical Ltd.
1015+ *
1016+ * This program is free software: you can redistribute it and/or modify it
1017+ * under the terms of the GNU General Public License version 3,
1018+ * as published by the Free Software Foundation.
1019+ *
1020+ * This program is distributed in the hope that it will be useful,
1021+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1022+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1023+ * GNU General Public License for more details.
1024+ *
1025+ * You should have received a copy of the GNU General Public License
1026+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1027+ *
1028+ * Authored by:
1029+ * Andreas Pokorny <andreas.pokorny@canonical.com>
1030+ */
1031+
1032+#ifndef MIR_INPUT_DEFAULT_SEAT_H_
1033+#define MIR_INPUT_DEFAULT_SEAT_H_
1034+
1035+#include "mir/input/touch_visualizer.h"
1036+#include "mir_toolkit/event.h"
1037+#include <unordered_map>
1038+#include <memory>
1039+
1040+namespace mir
1041+{
1042+namespace input
1043+{
1044+class CursorListener;
1045+
1046+/*
1047+ * The seat bundles a group of devices. A cursor position, input event modifiers and the visible touch spots are properties
1048+ * controlled by this grouping of input devices.
1049+ */
1050+class Seat
1051+{
1052+public:
1053+ Seat(std::shared_ptr<TouchVisualizer> const& touch_visualizer, std::shared_ptr<CursorListener> const& cursor_listener);
1054+ void add_device(MirInputDeviceId);
1055+ void remove_device(MirInputDeviceId);
1056+
1057+ MirInputEventModifiers event_modifier() const;
1058+ MirInputEventModifiers event_modifier(MirInputDeviceId) const;
1059+ void update_seat_properties(MirInputEvent const* event);
1060+private:
1061+ void update_cursor(MirPointerEvent const* event);
1062+ void update_spots();
1063+ void update_modifier();
1064+
1065+ std::shared_ptr<TouchVisualizer> const touch_visualizer;
1066+ std::shared_ptr<CursorListener> const cursor_listener;
1067+
1068+ struct DeviceData
1069+ {
1070+ DeviceData() {}
1071+ bool update_modifier(MirKeyboardAction action, int scan_code);
1072+ bool update_spots(MirTouchEvent const* event);
1073+
1074+ MirInputEventModifiers mod{0};
1075+ std::vector<TouchVisualizer::Spot> spots;
1076+ };
1077+
1078+ MirInputEventModifiers modifier;
1079+ std::unordered_map<MirInputDeviceId, DeviceData> device_data;
1080+ std::vector<TouchVisualizer::Spot> spots;
1081+};
1082+
1083+}
1084+}
1085+
1086+#endif
1087
1088=== modified file 'tests/mir_test_framework/fake_input_device_impl.cpp'
1089--- tests/mir_test_framework/fake_input_device_impl.cpp 2015-10-23 16:32:32 +0000
1090+++ tests/mir_test_framework/fake_input_device_impl.cpp 2015-10-26 14:13:05 +0000
1091@@ -27,8 +27,7 @@
1092 #include "mir/input/event_builder.h"
1093 #include "mir/dispatch/action_queue.h"
1094 #include "mir/geometry/displacement.h"
1095-#include "mir/module_deleter.h"
1096-#include "src/platforms/evdev/input_modifier_utils.h"
1097+#include "src/platforms/evdev/button_utils.h"
1098
1099 #include "boost/throw_exception.hpp"
1100
1101@@ -103,13 +102,7 @@
1102 auto input_action =
1103 (key_params.action == synthesis::EventAction::Down) ? mir_keyboard_action_down : mir_keyboard_action_up;
1104
1105- auto event_modifiers = mie::expand_modifiers(modifiers);
1106- auto key_event = builder->key_event(event_time, input_action, key_code, key_params.scancode, event_modifiers);
1107-
1108- if (key_params.action == synthesis::EventAction::Down)
1109- modifiers |= mie::to_modifiers(key_params.scancode);
1110- else
1111- modifiers &= ~mie::to_modifiers(key_params.scancode);
1112+ auto key_event = builder->key_event(event_time, input_action, key_code, key_params.scancode);
1113
1114 if (!sink)
1115 BOOST_THROW_EXCEPTION(std::runtime_error("Device is not started."));
1116@@ -121,9 +114,7 @@
1117 auto event_time = std::chrono::duration_cast<std::chrono::nanoseconds>(
1118 std::chrono::system_clock::now().time_since_epoch());
1119 auto action = update_buttons(button.action, mie::to_pointer_button(button.button, settings.handedness));
1120- auto event_modifiers = mie::expand_modifiers(modifiers);
1121 auto button_event = builder->pointer_event(event_time,
1122- event_modifiers,
1123 action,
1124 buttons,
1125 pos.x.as_float(),
1126@@ -159,17 +150,15 @@
1127
1128 auto event_time = std::chrono::duration_cast<std::chrono::nanoseconds>(
1129 std::chrono::system_clock::now().time_since_epoch());
1130- auto event_modifiers = mie::expand_modifiers(modifiers);
1131 // constant scaling is used here to simplify checking for the
1132 // expected results. Default settings of the device lead to no
1133 // scaling at all.
1134 auto acceleration = (settings.cursor_acceleration_bias + 1.0);
1135 auto rel_x = pointer.rel_x * acceleration;
1136 auto rel_y = pointer.rel_y * acceleration;
1137-
1138+
1139 update_position(rel_x, rel_y);
1140 auto pointer_event = builder->pointer_event(event_time,
1141- event_modifiers,
1142 mir_pointer_action_motion,
1143 buttons,
1144 pos.x.as_float(),
1145@@ -195,9 +184,8 @@
1146
1147 auto event_time = std::chrono::duration_cast<std::chrono::nanoseconds>(
1148 std::chrono::system_clock::now().time_since_epoch());
1149- auto event_modifiers = mie::expand_modifiers(modifiers);
1150
1151- auto touch_event = builder->touch_event(event_time, event_modifiers);
1152+ auto touch_event = builder->touch_event(event_time);
1153
1154 auto touch_action = mir_touch_action_up;
1155 if (touch.action == synthesis::TouchParameters::Action::Tap)
1156
1157=== modified file 'tests/mir_test_framework/fake_input_device_impl.h'
1158--- tests/mir_test_framework/fake_input_device_impl.h 2015-10-23 16:32:32 +0000
1159+++ tests/mir_test_framework/fake_input_device_impl.h 2015-10-26 14:13:05 +0000
1160@@ -79,7 +79,6 @@
1161 mir::input::EventBuilder* builder{nullptr};
1162 mir::input::InputDeviceInfo info;
1163 std::shared_ptr<mir::dispatch::Dispatchable> const queue;
1164- uint32_t modifiers{0};
1165 mir::geometry::Point pos, scroll;
1166 MirPointerButtons buttons;
1167 mir::input::PointerSettings settings;
1168
1169=== modified file 'tests/unit-tests/input/evdev/test_libinput_device.cpp'
1170--- tests/unit-tests/input/evdev/test_libinput_device.cpp 2015-10-23 16:32:32 +0000
1171+++ tests/unit-tests/input/evdev/test_libinput_device.cpp 2015-10-26 14:13:05 +0000
1172@@ -78,16 +78,15 @@
1173 mi::DefaultEventBuilder builder{MirInputDeviceId{3}, cookie_factory};
1174 MockEventBuilder()
1175 {
1176- ON_CALL(*this, key_event(_,_,_,_,_))
1177- .WillByDefault(Invoke([this](Timestamp time, MirKeyboardAction action, xkb_keysym_t key, int scan_code,
1178- MirInputEventModifiers modifier)
1179+ ON_CALL(*this, key_event(_,_,_,_))
1180+ .WillByDefault(Invoke([this](Timestamp time, MirKeyboardAction action, xkb_keysym_t key, int scan_code)
1181 {
1182- return builder.key_event(time, action, key, scan_code, modifier);
1183+ return builder.key_event(time, action, key, scan_code);
1184 }));
1185- ON_CALL(*this, touch_event(_,_))
1186- .WillByDefault(Invoke([this](Timestamp time, MirInputEventModifiers modifier)
1187+ ON_CALL(*this, touch_event(_))
1188+ .WillByDefault(Invoke([this](Timestamp time)
1189 {
1190- return builder.touch_event(time, modifier);
1191+ return builder.touch_event(time);
1192 }));
1193 ON_CALL(*this, add_touch(_,_,_,_,_,_,_,_,_,_))
1194 .WillByDefault(Invoke([this](MirEvent& event, MirTouchId id, MirTouchAction action,
1195@@ -97,13 +96,12 @@
1196 return builder.add_touch(event, id, action, tooltype, x, y, major, minor,
1197 pressure, size);
1198 }));
1199- ON_CALL(*this, pointer_event(_,_,_,_,_,_,_,_,_,_))
1200- .WillByDefault(Invoke([this](Timestamp time, MirInputEventModifiers modifier, MirPointerAction action,
1201- MirPointerButtons buttons, float x, float y, float hscroll, float vscroll,
1202- float relative_x, float relative_y)
1203+ ON_CALL(*this, pointer_event(_, _, _, _, _, _, _, _, _))
1204+ .WillByDefault(Invoke([this](Timestamp time, MirPointerAction action, MirPointerButtons buttons, float x,
1205+ float y, float hscroll, float vscroll, float relative_x, float relative_y)
1206 {
1207- return builder.pointer_event(time, modifier, action, buttons, x, y, hscroll,
1208- vscroll, relative_x, relative_y);
1209+ return builder.pointer_event(time, action, buttons, x, y, hscroll, vscroll,
1210+ relative_x, relative_y);
1211 }));
1212 ON_CALL(*this, configuration_event(_,_))
1213 .WillByDefault(Invoke([this](Timestamp time, MirInputConfigurationAction action)
1214@@ -112,14 +110,14 @@
1215 }));
1216 }
1217 using EventBuilder::Timestamp;
1218- MOCK_METHOD5(key_event, mir::EventUPtr(Timestamp, MirKeyboardAction, xkb_keysym_t, int, MirInputEventModifiers));
1219+ MOCK_METHOD4(key_event, mir::EventUPtr(Timestamp, MirKeyboardAction, xkb_keysym_t, int));
1220
1221- MOCK_METHOD2(touch_event, mir::EventUPtr(Timestamp, MirInputEventModifiers));
1222+ MOCK_METHOD1(touch_event, mir::EventUPtr(Timestamp));
1223 MOCK_METHOD10(add_touch, void(MirEvent&, MirTouchId, MirTouchAction, MirTouchTooltype, float, float, float, float,
1224 float, float));
1225
1226- MOCK_METHOD10(pointer_event, mir::EventUPtr(Timestamp, MirInputEventModifiers, MirPointerAction, MirPointerButtons,
1227- float, float, float, float, float, float));
1228+ MOCK_METHOD9(pointer_event, mir::EventUPtr(Timestamp, MirPointerAction, MirPointerButtons, float, float, float,
1229+ float, float, float));
1230 MOCK_METHOD2(configuration_event, mir::EventUPtr(Timestamp, MirInputConfigurationAction));
1231 };
1232
1233@@ -478,9 +476,9 @@
1234 setup_key_event(fake_event_1, event_time_1, KEY_A, LIBINPUT_KEY_STATE_PRESSED);
1235 setup_key_event(fake_event_2, event_time_2, KEY_A, LIBINPUT_KEY_STATE_RELEASED);
1236
1237- EXPECT_CALL(mock_builder, key_event(time_stamp_1, mir_keyboard_action_down, _, KEY_A, mir_input_event_modifier_none));
1238+ EXPECT_CALL(mock_builder, key_event(time_stamp_1, mir_keyboard_action_down, _, KEY_A));
1239 EXPECT_CALL(mock_sink, handle_input(AllOf(mt::KeyOfScanCode(KEY_A),mt::KeyDownEvent())));
1240- EXPECT_CALL(mock_builder, key_event(time_stamp_2, mir_keyboard_action_up, _, KEY_A, mir_input_event_modifier_none));
1241+ EXPECT_CALL(mock_builder, key_event(time_stamp_2, mir_keyboard_action_up, _, KEY_A));
1242 EXPECT_CALL(mock_sink, handle_input(AllOf(mt::KeyOfScanCode(KEY_A),mt::KeyUpEvent())));
1243
1244 keyboard.start(&mock_sink, &mock_builder);
1245@@ -495,15 +493,12 @@
1246 setup_key_event(fake_event_3, event_time_3, KEY_C, LIBINPUT_KEY_STATE_RELEASED);
1247
1248 InSequence seq;
1249- EXPECT_CALL(mock_builder, key_event(time_stamp_1, mir_keyboard_action_down, _, KEY_C, mir_input_event_modifier_none));
1250+ EXPECT_CALL(mock_builder, key_event(time_stamp_1, mir_keyboard_action_down, _, KEY_C));
1251 EXPECT_CALL(mock_sink, handle_input(AllOf(mt::KeyOfScanCode(KEY_C),mt::KeyDownEvent())));
1252- EXPECT_CALL(mock_builder, key_event(time_stamp_2, mir_keyboard_action_down, _, KEY_LEFTALT, mir_input_event_modifier_none));
1253+ EXPECT_CALL(mock_builder, key_event(time_stamp_2, mir_keyboard_action_down, _, KEY_LEFTALT));
1254 EXPECT_CALL(mock_sink, handle_input(AllOf(mt::KeyOfScanCode(KEY_LEFTALT),mt::KeyDownEvent())));
1255- EXPECT_CALL(mock_builder, key_event(time_stamp_3, mir_keyboard_action_up, _, KEY_C,
1256- mir_input_event_modifier_alt | mir_input_event_modifier_alt_left));
1257+ EXPECT_CALL(mock_builder, key_event(time_stamp_3, mir_keyboard_action_up, _, KEY_C));
1258 EXPECT_CALL(mock_sink, handle_input(AllOf(mt::KeyOfScanCode(KEY_C),
1259- mt::KeyWithModifiers(MirInputEventModifiers{
1260- mir_input_event_modifier_alt | mir_input_event_modifier_alt_left}),
1261 mt::KeyUpEvent())));
1262
1263 keyboard.start(&mock_sink, &mock_builder);
1264@@ -583,11 +578,11 @@
1265
1266 InSequence seq;
1267 // expect two scroll events..
1268- EXPECT_CALL(mock_builder, pointer_event(time_stamp_1, mir_input_event_modifier_none, mir_pointer_action_motion, 0,
1269- 0.0f, 0.0f, 0.0f, 20.0f, 0.0f, 0.0f));
1270+ EXPECT_CALL(mock_builder,
1271+ pointer_event(time_stamp_1, mir_pointer_action_motion, 0, 0.0f, 0.0f, 0.0f, 20.0f, 0.0f, 0.0f));
1272 EXPECT_CALL(mock_sink, handle_input(mt::PointerAxisChange(mir_pointer_axis_vscroll, 20.0f)));
1273- EXPECT_CALL(mock_builder, pointer_event(time_stamp_2, mir_input_event_modifier_none, mir_pointer_action_motion, 0,
1274- 0.0f, 0.0f, 5.0f, 0.0f, 0.0f, 0.0f));
1275+ EXPECT_CALL(mock_builder,
1276+ pointer_event(time_stamp_2, mir_pointer_action_motion, 0, 0.0f, 0.0f, 5.0f, 0.0f, 0.0f, 0.0f));
1277 EXPECT_CALL(mock_sink, handle_input(mt::PointerAxisChange(mir_pointer_axis_hscroll, 5.0f)));
1278
1279 mouse.start(&mock_sink, &mock_builder);
1280@@ -608,7 +603,7 @@
1281 setup_touch_frame(fake_event_2);
1282
1283 InSequence seq;
1284- EXPECT_CALL(mock_builder, touch_event(time_stamp_1, mir_input_event_modifier_none));
1285+ EXPECT_CALL(mock_builder, touch_event(time_stamp_1));
1286 EXPECT_CALL(mock_builder, add_touch(_, MirTouchId{0}, mir_touch_action_down, mir_touch_tooltype_finger, x, y,
1287 pressure, major, minor, major));
1288 EXPECT_CALL(mock_sink, handle_input(mt::TouchEvent(x, y)));
1289@@ -631,7 +626,7 @@
1290 setup_touch_frame(fake_event_2);
1291
1292 InSequence seq;
1293- EXPECT_CALL(mock_builder, touch_event(time_stamp_1, mir_input_event_modifier_none));
1294+ EXPECT_CALL(mock_builder, touch_event(time_stamp_1));
1295 EXPECT_CALL(mock_builder, add_touch(_, MirTouchId{0}, mir_touch_action_change, mir_touch_tooltype_finger, x, y,
1296 pressure, major, minor, major));
1297 EXPECT_CALL(mock_sink, handle_input(mt::TouchMovementEvent()));
1298@@ -656,12 +651,12 @@
1299 setup_touch_frame(fake_event_4);
1300
1301 InSequence seq;
1302- EXPECT_CALL(mock_builder, touch_event(time_stamp_1, mir_input_event_modifier_none));
1303+ EXPECT_CALL(mock_builder, touch_event(time_stamp_1));
1304 EXPECT_CALL(mock_builder, add_touch(_, MirTouchId{slot}, mir_touch_action_down, mir_touch_tooltype_finger, x, y,
1305 pressure, major, minor, major));
1306 EXPECT_CALL(mock_sink, handle_input(mt::TouchEvent(x, y)));
1307
1308- EXPECT_CALL(mock_builder, touch_event(time_stamp_2, mir_input_event_modifier_none));
1309+ EXPECT_CALL(mock_builder, touch_event(time_stamp_2));
1310 EXPECT_CALL(mock_builder, add_touch(_, MirTouchId{slot}, mir_touch_action_up, mir_touch_tooltype_finger, x, y,
1311 pressure, major, minor, major));
1312 EXPECT_CALL(mock_sink, handle_input(mt::TouchUpEvent(x, y)));
1313
1314=== modified file 'tests/unit-tests/input/test_default_input_device_hub.cpp'
1315--- tests/unit-tests/input/test_default_input_device_hub.cpp 2015-10-23 16:32:32 +0000
1316+++ tests/unit-tests/input/test_default_input_device_hub.cpp 2015-10-26 14:13:05 +0000
1317@@ -274,7 +274,7 @@
1318 observer_loop.trigger_server_actions();
1319
1320 auto event = builder->key_event(arbitrary_timestamp, mir_keyboard_action_down, 0,
1321- KEY_A, mir_input_event_modifier_none);
1322+ KEY_A);
1323
1324 EXPECT_CALL(mock_dispatcher, dispatch(AllOf(mt::InputDeviceIdMatches(handle->id()), mt::MirKeyEventMatches(event.get()))));
1325
1326@@ -293,23 +293,23 @@
1327
1328 observer_loop.trigger_server_actions();
1329
1330- auto touch_event_1 = builder->touch_event(arbitrary_timestamp, mir_input_event_modifier_none);
1331+ auto touch_event_1 = builder->touch_event(arbitrary_timestamp);
1332 builder->add_touch(*touch_event_1, 0, mir_touch_action_down, mir_touch_tooltype_finger, 21.0f, 34.0f, 50.0f, 15.0f,
1333 5.0f, 4.0f);
1334
1335- auto touch_event_2 = builder->touch_event(arbitrary_timestamp, mir_input_event_modifier_none);
1336+ auto touch_event_2 = builder->touch_event(arbitrary_timestamp);
1337 builder->add_touch(*touch_event_2, 0, mir_touch_action_change, mir_touch_tooltype_finger, 24.0f, 34.0f, 50.0f,
1338 15.0f, 5.0f, 4.0f);
1339 builder->add_touch(*touch_event_2, 1, mir_touch_action_down, mir_touch_tooltype_finger, 60.0f, 34.0f, 50.0f, 15.0f,
1340 5.0f, 4.0f);
1341
1342- auto touch_event_3 = builder->touch_event(arbitrary_timestamp, mir_input_event_modifier_none);
1343+ auto touch_event_3 = builder->touch_event(arbitrary_timestamp);
1344 builder->add_touch(*touch_event_3, 0, mir_touch_action_up, mir_touch_tooltype_finger, 24.0f, 34.0f, 50.0f, 15.0f,
1345 5.0f, 4.0f);
1346 builder->add_touch(*touch_event_3, 1, mir_touch_action_change, mir_touch_tooltype_finger, 70.0f, 30.0f, 50.0f,
1347 15.0f, 5.0f, 4.0f);
1348
1349- auto touch_event_4 = builder->touch_event(arbitrary_timestamp, mir_input_event_modifier_none);
1350+ auto touch_event_4 = builder->touch_event(arbitrary_timestamp);
1351 builder->add_touch(*touch_event_4, 1, mir_touch_action_up, mir_touch_tooltype_finger, 70.0f, 35.0f, 50.0f, 15.0f,
1352 5.0f, 4.0f);
1353
1354@@ -378,17 +378,149 @@
1355 using namespace ::testing;
1356
1357 auto x = 12.2f, y = 14.3f;
1358- auto const mac = 0;
1359-
1360- auto event = mir::events::make_event(0, 0ns, mac, mir_input_event_modifier_none, mir_pointer_action_motion, 0,
1361- x, y, 0.0f, 0.0f, 0.0f, 0.0f);
1362+
1363+ mi::InputSink* sink;
1364+ mi::EventBuilder* builder;
1365+ capture_input_sink(device, sink, builder);
1366+ hub.add_device(mt::fake_shared(device));
1367+
1368+ auto event = builder->pointer_event(0ns, mir_pointer_action_motion, 0, x, y, 0.0f, 0.0f, 0.0f, 0.0f);
1369
1370 EXPECT_CALL(mock_cursor_listener, cursor_moved_to(x, y)).Times(1);
1371
1372- mi::InputSink* sink;
1373- mi::EventBuilder* builder;
1374- capture_input_sink(device, sink, builder);
1375- hub.add_device(mt::fake_shared(device));
1376-
1377 sink->handle_input(*event);
1378 }
1379+
1380+TEST_F(InputDeviceHubTest, input_sink_tracks_modifier)
1381+{
1382+ using namespace ::testing;
1383+
1384+ mi::InputSink* key_board_sink;
1385+ mi::EventBuilder* key_event_builder;
1386+ std::shared_ptr<mi::Device> key_handle;
1387+
1388+ capture_input_sink(device, key_board_sink, key_event_builder);
1389+
1390+ InSequence seq;
1391+ EXPECT_CALL(mock_observer,device_added(_))
1392+ .WillOnce(SaveArg<0>(&key_handle));
1393+
1394+ hub.add_observer(mt::fake_shared(mock_observer));
1395+ hub.add_device(mt::fake_shared(device));
1396+
1397+ observer_loop.trigger_server_actions();
1398+
1399+ const MirInputEventModifiers shift_left = mir_input_event_modifier_shift_left | mir_input_event_modifier_shift;
1400+ auto shift_down =
1401+ key_event_builder->key_event(arbitrary_timestamp, mir_keyboard_action_down, 0, KEY_LEFTSHIFT);
1402+ auto shift_up =
1403+ key_event_builder->key_event(arbitrary_timestamp, mir_keyboard_action_up, 0, KEY_LEFTSHIFT);
1404+
1405+ EXPECT_CALL(mock_dispatcher, dispatch(mt::KeyWithModifiers(shift_left)));
1406+ EXPECT_CALL(mock_dispatcher, dispatch(mt::KeyWithModifiers(mir_input_event_modifier_none)));
1407+
1408+ key_board_sink->handle_input(*shift_down);
1409+ key_board_sink->handle_input(*shift_up);
1410+}
1411+
1412+TEST_F(InputDeviceHubTest, input_sink_unifies_modifier_state_accross_devices)
1413+{
1414+ using namespace ::testing;
1415+
1416+ mi::InputSink* mouse_sink;
1417+ mi::EventBuilder* mouse_event_builder;
1418+ mi::InputSink* key_board_sink;
1419+ mi::EventBuilder* key_event_builder;
1420+ std::shared_ptr<mi::Device> mouse_handle;
1421+ std::shared_ptr<mi::Device> key_handle;
1422+
1423+ capture_input_sink(device, mouse_sink, mouse_event_builder);
1424+ capture_input_sink(another_device, key_board_sink, key_event_builder);
1425+
1426+ InSequence seq;
1427+ EXPECT_CALL(mock_observer,device_added(_))
1428+ .WillOnce(SaveArg<0>(&mouse_handle));
1429+ EXPECT_CALL(mock_observer,device_added(_))
1430+ .WillOnce(SaveArg<0>(&key_handle));
1431+
1432+ hub.add_observer(mt::fake_shared(mock_observer));
1433+ hub.add_device(mt::fake_shared(device));
1434+ hub.add_device(mt::fake_shared(another_device));
1435+
1436+ observer_loop.trigger_server_actions();
1437+
1438+ const MirInputEventModifiers r_alt_modifier = mir_input_event_modifier_alt_right | mir_input_event_modifier_alt;
1439+ auto key =
1440+ key_event_builder->key_event(arbitrary_timestamp, mir_keyboard_action_down, 0, KEY_RIGHTALT);
1441+ auto motion =
1442+ mouse_event_builder->pointer_event(arbitrary_timestamp, mir_pointer_action_motion, 0, 12, 40, 0, 0, 12, 40);
1443+
1444+ EXPECT_CALL(mock_dispatcher, dispatch(mt::KeyWithModifiers(r_alt_modifier)));
1445+ EXPECT_CALL(mock_dispatcher, dispatch(mt::PointerEventWithModifiers(r_alt_modifier)));
1446+
1447+ key_board_sink->handle_input(*key);
1448+ mouse_sink->handle_input(*motion);
1449+
1450+ EXPECT_THAT(key_handle->id(), Ne(mouse_handle->id()));
1451+}
1452+
1453+TEST_F(InputDeviceHubTest, input_sink_reduces_modifier_state_accross_devices)
1454+{
1455+ using namespace ::testing;
1456+
1457+ mi::InputSink* mouse_sink;
1458+ mi::EventBuilder* mouse_event_builder;
1459+ mi::InputSink* key_board_sink_1;
1460+ mi::EventBuilder* key_event_builder_1;
1461+ mi::InputSink* key_board_sink_2;
1462+ mi::EventBuilder* key_event_builder_2;
1463+ std::shared_ptr<mi::Device> mouse_handle;
1464+ std::shared_ptr<mi::Device> key_handle_1;
1465+ std::shared_ptr<mi::Device> key_handle_2;
1466+
1467+ capture_input_sink(device, mouse_sink, mouse_event_builder);
1468+ capture_input_sink(another_device, key_board_sink_1, key_event_builder_1);
1469+ capture_input_sink(third_device, key_board_sink_2, key_event_builder_2);
1470+
1471+ InSequence seq;
1472+ EXPECT_CALL(mock_observer, device_added(_))
1473+ .WillOnce(SaveArg<0>(&mouse_handle));
1474+ EXPECT_CALL(mock_observer, device_added(_))
1475+ .WillOnce(SaveArg<0>(&key_handle_1));
1476+ EXPECT_CALL(mock_observer, device_added(_))
1477+ .WillOnce(SaveArg<0>(&key_handle_2));
1478+
1479+ hub.add_observer(mt::fake_shared(mock_observer));
1480+ hub.add_device(mt::fake_shared(device));
1481+ hub.add_device(mt::fake_shared(another_device));
1482+ hub.add_device(mt::fake_shared(third_device));
1483+
1484+ const MirInputEventModifiers r_alt_modifier = mir_input_event_modifier_alt_right | mir_input_event_modifier_alt;
1485+ const MirInputEventModifiers l_ctrl_modifier = mir_input_event_modifier_ctrl_left | mir_input_event_modifier_ctrl;
1486+ const MirInputEventModifiers combined_modifier = r_alt_modifier | l_ctrl_modifier;
1487+
1488+ observer_loop.trigger_server_actions();
1489+
1490+ auto alt_down = key_event_builder_1->key_event(arbitrary_timestamp, mir_keyboard_action_down, 0, KEY_RIGHTALT);
1491+ auto ctrl_down = key_event_builder_2->key_event(arbitrary_timestamp, mir_keyboard_action_down, 0, KEY_LEFTCTRL);
1492+ auto ctrl_up = key_event_builder_2->key_event(arbitrary_timestamp, mir_keyboard_action_up, 0, KEY_LEFTCTRL);
1493+
1494+ auto motion_1 =
1495+ mouse_event_builder->pointer_event(arbitrary_timestamp, mir_pointer_action_motion, 0, 12, 40, 0, 0, 12, 40);
1496+ auto motion_2 =
1497+ mouse_event_builder->pointer_event(arbitrary_timestamp, mir_pointer_action_motion, 0, 30, 50, 0, 0, 18, 10);
1498+
1499+ EXPECT_CALL(mock_dispatcher, dispatch(mt::KeyWithModifiers(r_alt_modifier)));
1500+ EXPECT_CALL(mock_dispatcher, dispatch(mt::KeyWithModifiers(l_ctrl_modifier)));
1501+ EXPECT_CALL(mock_dispatcher, dispatch(mt::PointerEventWithModifiers(combined_modifier)));
1502+ EXPECT_CALL(mock_dispatcher, dispatch(mt::KeyWithModifiers(mir_input_event_modifier_none)));
1503+ EXPECT_CALL(mock_dispatcher, dispatch(mt::PointerEventWithModifiers(r_alt_modifier)));
1504+
1505+ key_board_sink_1->handle_input(*alt_down);
1506+ key_board_sink_2->handle_input(*ctrl_down);
1507+ mouse_sink->handle_input(*motion_1);
1508+ key_board_sink_2->handle_input(*ctrl_up);
1509+ mouse_sink->handle_input(*motion_2);
1510+
1511+ EXPECT_THAT(key_handle_1->id(), Ne(key_handle_2->id()));
1512+}

Subscribers

People subscribed via source and target branches