Merge lp:~andreas-pokorny/mir/fix-1588237 into lp:mir
- fix-1588237
- Merge into development-branch
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Andreas Pokorny | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 4016 | ||||
Proposed branch: | lp:~andreas-pokorny/mir/fix-1588237 | ||||
Merge into: | lp:mir | ||||
Prerequisite: | lp:~andreas-pokorny/mir/send-input-device-state-event | ||||
Diff against target: |
498 lines (+269/-14) 7 files modified
src/client/input/android/android_input_receiver.cpp (+22/-6) src/client/input/xkb_mapper.cpp (+59/-4) src/include/common/mir/input/key_mapper.h (+1/-0) src/include/common/mir/input/xkb_mapper.h (+7/-0) src/server/input/seat_input_device_tracker.cpp (+39/-2) tests/acceptance-tests/test_client_input.cpp (+140/-2) tests/include/mir/test/doubles/mock_key_mapper.h (+1/-0) |
||||
To merge this branch: | bzr merge lp:~andreas-pokorny/mir/fix-1588237 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexandros Frantzis (community) | Approve | ||
Mir CI Bot | continuous-integration | Approve | |
Review via email:
|
Commit message
Fix behavior of numlock and related modifier keys (LP: #1588237)
Corrects the tracking of modifiers that can be toggled. The input device state event now transfers the state of the toggled modifiers via double entries in the scan code array. Finally this change adds some missing wiring to forward the input device state event to the client side XkbMapper.
Description of the change
Three small changes that add all missing pieces to fix client side key mapping.
First of all the modifier tracking for toggling modifiers had to be fixed. Then those modifiers need special treatment to transfer them from the server to the upcoming focused client. The client needs that status to feed that back into xkb. This is done via scan codes - with that we also handle the case that the client keymap configuration remapped that toggling modifier.
When and where is that relevant?
If we do all scan code to key mapping in the server this change is not really necessary. The server keeps the key state separate from the currently focused window. So the modifier state stays correct when input focus is switched between surfaces. Because of Xmir/X11 we still have to support client side key mapping. So clients have to be informed about modifier state beyond the list of depressed keys.
Note on testing:
In mir/miral the default is to do server side key mapping only.
But his can be easily changed:
Add
xkb_mapper-
to the constructor of android_
Launch "gedit -s" twice, and change num lock or caps lock in one gedit then type in the other.

Mir CI Bot (mir-ci-bot) wrote : | # |

Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3535
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/

Alexandros Frantzis (afrantzis) wrote : | # |
[ FAILED ] TestClientInput

Andreas Pokorny (andreas-pokorny) wrote : | # |
still working on gtk and now also systemd to make a fix.. so putting that down for a week or so

Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3537
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/

Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3538
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/

Andreas Pokorny (andreas-pokorny) wrote : | # |
Ok still the same ordering problem.. the device state event occurs to soon and lacks the pressed keys..

Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3540
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/

Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3541
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/

Andreas Pokorny (andreas-pokorny) wrote : | # |
NestedInput.* and in the last one there were two ClientLatency.* failures.

Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:3542
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/

Alexandros Frantzis (afrantzis) wrote : | # |
Looks good.
Preview Diff
1 | === modified file 'src/client/input/android/android_input_receiver.cpp' |
2 | --- src/client/input/android/android_input_receiver.cpp 2017-01-18 02:29:37 +0000 |
3 | +++ src/client/input/android/android_input_receiver.cpp 2017-02-06 09:42:51 +0000 |
4 | @@ -103,12 +103,28 @@ |
5 | |
6 | static void map_key_event(std::shared_ptr<mircv::XKBMapper> const& xkb_mapper, MirEvent &ev) |
7 | { |
8 | - // TODO: As XKBMapper is used to track modifier state we need to use a seperate instance |
9 | - // of XKBMapper per device id (or modify XKBMapper semantics) |
10 | - if (mir_event_get_type(&ev) != mir_event_type_input) |
11 | - return; |
12 | - |
13 | - xkb_mapper->map_event(ev); |
14 | + auto const type = mir_event_get_type(&ev); |
15 | + if (type == mir_event_type_input) |
16 | + { |
17 | + xkb_mapper->map_event(ev); |
18 | + } |
19 | + else if (type == mir_event_type_input_device_state) |
20 | + { |
21 | + auto device_state = mir_event_get_input_device_state_event(&ev); |
22 | + std::vector<uint32_t> keys; |
23 | + |
24 | + for (size_t index = 0, end_index = mir_input_device_state_event_device_count(device_state); |
25 | + index != end_index; ++index) |
26 | + { |
27 | + auto device_id = mir_input_device_state_event_device_id(device_state, index); |
28 | + auto key_count = mir_input_device_state_event_device_pressed_keys_count(device_state, index); |
29 | + for (decltype(key_count) i = 0; i != key_count; ++i) |
30 | + keys.push_back( |
31 | + mir_input_device_state_event_device_pressed_keys_for_index(device_state, index, i)); |
32 | + |
33 | + xkb_mapper->set_key_state(device_id, keys); |
34 | + } |
35 | + } |
36 | } |
37 | |
38 | } |
39 | |
40 | === modified file 'src/client/input/xkb_mapper.cpp' |
41 | --- src/client/input/xkb_mapper.cpp 2017-01-18 02:29:37 +0000 |
42 | +++ src/client/input/xkb_mapper.cpp 2017-02-06 09:42:51 +0000 |
43 | @@ -25,6 +25,7 @@ |
44 | |
45 | #include <sstream> |
46 | #include <boost/throw_exception.hpp> |
47 | +#include <unordered_set> |
48 | |
49 | namespace mi = mir::input; |
50 | namespace mev = mir::events; |
51 | @@ -59,10 +60,18 @@ |
52 | case XKB_KEY_Super_R: return mir_input_event_modifier_meta_right; |
53 | case XKB_KEY_Caps_Lock: return mir_input_event_modifier_caps_lock; |
54 | case XKB_KEY_Scroll_Lock: return mir_input_event_modifier_scroll_lock; |
55 | + case XKB_KEY_Num_Lock: return mir_input_event_modifier_num_lock; |
56 | default: return MirInputEventModifiers{0}; |
57 | } |
58 | } |
59 | |
60 | +bool is_toggle_modifier(MirInputEventModifiers key) |
61 | +{ |
62 | + return key == mir_input_event_modifier_caps_lock || |
63 | + key == mir_input_event_modifier_scroll_lock || |
64 | + key == mir_input_event_modifier_num_lock; |
65 | +} |
66 | + |
67 | MirInputEventModifiers expand_modifiers(MirInputEventModifiers modifiers) |
68 | { |
69 | if (modifiers == 0) |
70 | @@ -167,7 +176,7 @@ |
71 | MirInputEventModifiers new_modifier = 0; |
72 | for (auto const& mapping_state : device_mapping) |
73 | { |
74 | - new_modifier |= mapping_state.second->modifier_state; |
75 | + new_modifier |= mapping_state.second->modifiers(); |
76 | } |
77 | |
78 | modifier_state = new_modifier; |
79 | @@ -284,6 +293,16 @@ |
80 | return mir_input_event_modifier_none; |
81 | } |
82 | |
83 | +MirInputEventModifiers mircv::XKBMapper::device_modifiers(MirInputDeviceId id) const |
84 | +{ |
85 | + std::lock_guard<std::mutex> lg(guard); |
86 | + |
87 | + auto it = device_mapping.find(id); |
88 | + if (it == end(device_mapping)) |
89 | + return mir_input_event_modifier_none; |
90 | + return expand_modifiers(it->second->modifiers()); |
91 | +} |
92 | + |
93 | mircv::XKBMapper::XkbMappingState::XkbMappingState(std::shared_ptr<xkb_keymap> const& keymap) |
94 | : keymap{keymap}, state{make_unique_state(this->keymap.get())} |
95 | { |
96 | @@ -293,8 +312,20 @@ |
97 | { |
98 | state = make_unique_state(keymap.get()); |
99 | modifier_state = mir_input_event_modifier_none; |
100 | + std::unordered_set<uint32_t> pressed_codes; |
101 | for (uint32_t scan_code : key_state) |
102 | - update_state(to_xkb_scan_code(scan_code), mir_keyboard_action_down, nullptr); |
103 | + { |
104 | + bool already_pressed = pressed_codes.count(scan_code) > 0; |
105 | + |
106 | + update_state(to_xkb_scan_code(scan_code), |
107 | + (already_pressed) ? mir_keyboard_action_up : mir_keyboard_action_down, |
108 | + nullptr); |
109 | + |
110 | + if (already_pressed) |
111 | + pressed_codes.erase(scan_code); |
112 | + else |
113 | + pressed_codes.insert(scan_code); |
114 | + } |
115 | } |
116 | |
117 | bool mircv::XKBMapper::XkbMappingState::update_and_map(MirEvent& event, mircv::XKBMapper::ComposeState* compose_state) |
118 | @@ -322,17 +353,26 @@ |
119 | if (action == mir_keyboard_action_up) |
120 | { |
121 | xkb_state_update_key(state.get(), scan_code, XKB_KEY_UP); |
122 | - modifier_state = modifier_state & ~mod_change; |
123 | + // TODO get the modifier state from xkbcommon and apply it |
124 | + // for all other modifiers manually track them here: |
125 | + release_modifier(mod_change); |
126 | } |
127 | else if (action == mir_keyboard_action_down) |
128 | { |
129 | xkb_state_update_key(state.get(), scan_code, XKB_KEY_DOWN); |
130 | - modifier_state = modifier_state | mod_change; |
131 | + // TODO get the modifier state from xkbcommon and apply it |
132 | + // for all other modifiers manually track them here: |
133 | + press_modifier(mod_change); |
134 | } |
135 | |
136 | return key_sym; |
137 | } |
138 | |
139 | +MirInputEventModifiers mircv::XKBMapper::XkbMappingState::modifiers() const |
140 | +{ |
141 | + return modifier_state; |
142 | +} |
143 | + |
144 | mircv::XKBMapper::ComposeState* mircv::XKBMapper::get_compose_state(MirInputDeviceId id) |
145 | { |
146 | auto dev_compose_state = device_composing.find(id); |
147 | @@ -410,3 +450,18 @@ |
148 | |
149 | return mapped_key; |
150 | } |
151 | + |
152 | + |
153 | +void mircv::XKBMapper::XkbMappingState::press_modifier(MirInputEventModifiers mod) |
154 | +{ |
155 | + if (is_toggle_modifier(mod)) |
156 | + modifier_state ^= mod; |
157 | + else |
158 | + modifier_state |= mod; |
159 | +} |
160 | + |
161 | +void mircv::XKBMapper::XkbMappingState::release_modifier(MirInputEventModifiers mod) |
162 | +{ |
163 | + if (!is_toggle_modifier(mod)) |
164 | + modifier_state &= ~mod; |
165 | +} |
166 | |
167 | === modified file 'src/include/common/mir/input/key_mapper.h' |
168 | --- src/include/common/mir/input/key_mapper.h 2017-01-18 02:29:37 +0000 |
169 | +++ src/include/common/mir/input/key_mapper.h 2017-02-06 09:42:51 +0000 |
170 | @@ -88,6 +88,7 @@ |
171 | */ |
172 | virtual void map_event(MirEvent& event) = 0; |
173 | virtual MirInputEventModifiers modifiers() const = 0; |
174 | + virtual MirInputEventModifiers device_modifiers(MirInputDeviceId id) const = 0; |
175 | |
176 | protected: |
177 | KeyMapper(KeyMapper const&) = delete; |
178 | |
179 | === modified file 'src/include/common/mir/input/xkb_mapper.h' |
180 | --- src/include/common/mir/input/xkb_mapper.h 2017-01-18 02:29:37 +0000 |
181 | +++ src/include/common/mir/input/xkb_mapper.h 2017-02-06 09:42:51 +0000 |
182 | @@ -63,6 +63,7 @@ |
183 | void clear_all_keymaps() override; |
184 | void map_event(MirEvent& event) override; |
185 | MirInputEventModifiers modifiers() const override; |
186 | + MirInputEventModifiers device_modifiers(MirInputDeviceId di) const override; |
187 | |
188 | protected: |
189 | XKBMapper(XKBMapper const&) = delete; |
190 | @@ -89,8 +90,14 @@ |
191 | { |
192 | explicit XkbMappingState(std::shared_ptr<xkb_keymap> const& keymap); |
193 | void set_key_state(std::vector<uint32_t> const& key_state); |
194 | + |
195 | bool update_and_map(MirEvent& event, ComposeState* compose_state); |
196 | xkb_keysym_t update_state(uint32_t scan_code, MirKeyboardAction direction, ComposeState* compose_state); |
197 | + MirInputEventModifiers modifiers() const; |
198 | + private: |
199 | + void press_modifier(MirInputEventModifiers mod); |
200 | + void release_modifier(MirInputEventModifiers mod); |
201 | + |
202 | std::shared_ptr<xkb_keymap> const keymap; |
203 | XKBStatePtr state; |
204 | MirInputEventModifiers modifier_state{0}; |
205 | |
206 | === modified file 'src/server/input/seat_input_device_tracker.cpp' |
207 | --- src/server/input/seat_input_device_tracker.cpp 2017-01-18 02:29:37 +0000 |
208 | +++ src/server/input/seat_input_device_tracker.cpp 2017-02-06 09:42:51 +0000 |
209 | @@ -31,6 +31,7 @@ |
210 | #include "input_modifier_utils.h" |
211 | |
212 | #include <boost/throw_exception.hpp> |
213 | +#include <linux/input.h> |
214 | |
215 | #include <stdexcept> |
216 | #include <algorithm> |
217 | @@ -115,7 +116,7 @@ |
218 | if (stored_data == end(device_data)) |
219 | return true; |
220 | |
221 | - return !stored_data->second.allowed_scan_code_action(mir_input_event_get_keyboard_event(event)); |
222 | + return !stored_data->second.allowed_scan_code_action(mir_input_event_get_keyboard_event(event));; |
223 | } |
224 | return false; |
225 | } |
226 | @@ -251,8 +252,44 @@ |
227 | std::vector<mev::InputDeviceState> devices; |
228 | devices.reserve(device_data.size()); |
229 | for (auto const& item : device_data) |
230 | + { |
231 | devices.push_back({item.first, item.second.scan_codes, item.second.buttons}); |
232 | - |
233 | + auto lock_state = key_mapper->device_modifiers(item.first); |
234 | + |
235 | + bool caps_lock_active = (lock_state & mir_input_event_modifier_caps_lock); |
236 | + bool scroll_lock_active = (lock_state & mir_input_event_modifier_scroll_lock); |
237 | + bool num_lock_active = (lock_state & mir_input_event_modifier_num_lock); |
238 | + |
239 | + bool contains_caps_lock_pressed = false; |
240 | + bool contains_scroll_lock_pressed = false; |
241 | + bool contains_num_lock_pressed = false; |
242 | + |
243 | + for (uint32_t scan_code : item.second.scan_codes) |
244 | + { |
245 | + if (scan_code == KEY_CAPSLOCK) |
246 | + contains_caps_lock_pressed = true; |
247 | + else if (scan_code == KEY_SCROLLLOCK) |
248 | + contains_scroll_lock_pressed = true; |
249 | + else if (scan_code == KEY_NUMLOCK) |
250 | + contains_num_lock_pressed = true; |
251 | + } |
252 | + |
253 | + if (caps_lock_active && !contains_caps_lock_pressed) |
254 | + { |
255 | + devices.back().pressed_keys.push_back(KEY_CAPSLOCK); |
256 | + devices.back().pressed_keys.push_back(KEY_CAPSLOCK); |
257 | + } |
258 | + if (num_lock_active && !contains_num_lock_pressed) |
259 | + { |
260 | + devices.back().pressed_keys.push_back(KEY_NUMLOCK); |
261 | + devices.back().pressed_keys.push_back(KEY_NUMLOCK); |
262 | + } |
263 | + if (scroll_lock_active && !contains_scroll_lock_pressed) |
264 | + { |
265 | + devices.back().pressed_keys.push_back(KEY_SCROLLLOCK); |
266 | + devices.back().pressed_keys.push_back(KEY_SCROLLLOCK); |
267 | + } |
268 | + } |
269 | auto out_ev = mev::make_event( |
270 | clock->now().time_since_epoch(), |
271 | buttons, |
272 | |
273 | === modified file 'tests/acceptance-tests/test_client_input.cpp' |
274 | --- tests/acceptance-tests/test_client_input.cpp 2017-02-06 03:54:54 +0000 |
275 | +++ tests/acceptance-tests/test_client_input.cpp 2017-02-06 09:42:51 +0000 |
276 | @@ -18,7 +18,10 @@ |
277 | |
278 | #include "mir/input/input_device_info.h" |
279 | #include "mir/input/event_filter.h" |
280 | +#include "mir/input/keymap.h" |
281 | #include "mir/input/composite_event_filter.h" |
282 | +#include "mir/scene/session.h" |
283 | +#include "mir/scene/surface.h" |
284 | #include "mir/input/mir_touchpad_config.h" |
285 | #include "mir/input/mir_input_config.h" |
286 | |
287 | @@ -45,6 +48,7 @@ |
288 | #include <linux/input.h> |
289 | |
290 | #include <condition_variable> |
291 | +#include <unordered_map> |
292 | #include <chrono> |
293 | #include <atomic> |
294 | #include <mutex> |
295 | @@ -98,12 +102,52 @@ |
296 | { |
297 | } |
298 | |
299 | +struct SurfaceTrackingShell : mir::shell::ShellWrapper |
300 | +{ |
301 | + SurfaceTrackingShell( |
302 | + std::shared_ptr<mir::shell::Shell> wrapped_shell) |
303 | + : ShellWrapper{wrapped_shell}, wrapped_shell{wrapped_shell} |
304 | + {} |
305 | + |
306 | + mir::frontend::SurfaceId create_surface( |
307 | + std::shared_ptr<mir::scene::Session> const& session, |
308 | + mir::scene::SurfaceCreationParameters const& params, |
309 | + std::shared_ptr<mir::frontend::EventSink> const& sink) override |
310 | + { |
311 | + auto surface_id = wrapped_shell->create_surface(session, params, sink); |
312 | + |
313 | + tracked_surfaces[session->name()] = TrackedSurface{session, surface_id}; |
314 | + |
315 | + return surface_id; |
316 | + } |
317 | + |
318 | + std::shared_ptr<mir::scene::Surface> get_surface(std::string const& session_name) |
319 | + { |
320 | + if (end(tracked_surfaces) == tracked_surfaces.find(session_name)) |
321 | + return nullptr; |
322 | + TrackedSurface & tracked_surface = tracked_surfaces[session_name]; |
323 | + auto session = tracked_surface.session.lock(); |
324 | + if (!session) |
325 | + return nullptr; |
326 | + return session->surface(tracked_surface.surface); |
327 | + } |
328 | + |
329 | + struct TrackedSurface |
330 | + { |
331 | + std::weak_ptr<mir::scene::Session> session; |
332 | + mir::frontend::SurfaceId surface; |
333 | + }; |
334 | + std::unordered_map<std::string, TrackedSurface> tracked_surfaces; |
335 | + std::shared_ptr<mir::shell::Shell> wrapped_shell; |
336 | +}; |
337 | + |
338 | struct Client |
339 | { |
340 | MirWindow* window{nullptr}; |
341 | |
342 | MOCK_METHOD1(handle_input, void(MirEvent const*)); |
343 | MOCK_METHOD1(handle_keymap, void(MirEvent const*)); |
344 | + MOCK_METHOD1(handle_input_device_state, void(MirEvent const*)); |
345 | |
346 | Client(std::string const& con, std::string const& name) |
347 | { |
348 | @@ -146,7 +190,12 @@ |
349 | mir_window_focus_state_focused == value) |
350 | focused = true; |
351 | |
352 | - if (exposed && focused) |
353 | + test_and_raise(); |
354 | + } |
355 | + |
356 | + void test_and_raise() |
357 | + { |
358 | + if (exposed && focused && input_device_state_received) |
359 | ready_to_accept_events.raise(); |
360 | } |
361 | |
362 | @@ -164,6 +213,12 @@ |
363 | client->handle_input(ev); |
364 | if (type == mir_event_type_keymap) |
365 | client->handle_keymap(ev); |
366 | + if (type == mir_event_type_input_device_state) |
367 | + { |
368 | + client->input_device_state_received = true; |
369 | + client->test_and_raise(); |
370 | + client->handle_input_device_state(ev); |
371 | + } |
372 | } |
373 | ~Client() |
374 | { |
375 | @@ -181,6 +236,7 @@ |
376 | mir::test::Signal all_events_received; |
377 | bool exposed = false; |
378 | bool focused = false; |
379 | + bool input_device_state_received = false; |
380 | }; |
381 | |
382 | struct DeviceCounter : mi::InputDeviceObserver |
383 | @@ -216,7 +272,8 @@ |
384 | [this](std::shared_ptr<mir::shell::Shell> const& wrapped) |
385 | { |
386 | shell = std::make_shared<mtf::PlacementApplyingShell>(wrapped, input_regions, positions); |
387 | - return shell; |
388 | + surfaces = std::make_shared<SurfaceTrackingShell>(shell); |
389 | + return surfaces; |
390 | }); |
391 | server.override_the_session_authorizer([this] { return mt::fake_shared(stub_authorizer); }); |
392 | |
393 | @@ -225,7 +282,13 @@ |
394 | positions[first] = geom::Rectangle{{0,0}, {surface_width, surface_height}}; |
395 | } |
396 | |
397 | + std::shared_ptr<mir::scene::Surface> get_surface(std::string const& name) |
398 | + { |
399 | + return surfaces->get_surface(name); |
400 | + } |
401 | + |
402 | std::shared_ptr<mtf::PlacementApplyingShell> shell; |
403 | + std::shared_ptr<SurfaceTrackingShell> surfaces; |
404 | std::string const keyboard_name = "keyboard"; |
405 | std::string const keyboard_unique_id = "keyboard-uid"; |
406 | std::string const mouse_name = "mouse"; |
407 | @@ -939,6 +1002,81 @@ |
408 | mir_input_config_release(config); |
409 | } |
410 | |
411 | +TEST_F(TestClientInput, num_lock_is_off_on_startup) |
412 | +{ |
413 | + Client a_client(new_connection(), first); |
414 | + |
415 | + EXPECT_CALL(a_client, handle_input(mt::KeyOfSymbol(XKB_KEY_KP_Left))) |
416 | + .WillOnce(mt::WakeUp(&a_client.all_events_received)); |
417 | + |
418 | + fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_KP4)); |
419 | + a_client.all_events_received.wait_for(10s); |
420 | +} |
421 | + |
422 | +TEST_F(TestClientInput, keeps_num_lock_state_after_focus_change) |
423 | +{ |
424 | + Client first_client(new_connection(), first); |
425 | + |
426 | + { |
427 | + Client second_client(new_connection(), second); |
428 | + EXPECT_CALL(second_client, handle_input(mt::KeyDownEvent())); |
429 | + EXPECT_CALL(second_client, handle_input(mt::KeyUpEvent())) |
430 | + .WillOnce(mt::WakeUp(&second_client.all_events_received)); |
431 | + |
432 | + fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_NUMLOCK)); |
433 | + fake_keyboard->emit_event(mis::a_key_up_event().of_scancode(KEY_NUMLOCK)); |
434 | + |
435 | + second_client.all_events_received.wait_for(10s); |
436 | + } |
437 | + |
438 | + EXPECT_CALL(first_client, handle_input(mt::KeyOfSymbol(XKB_KEY_KP_4))) |
439 | + .WillOnce(mt::WakeUp(&first_client.all_events_received)); |
440 | + fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_KP4)); |
441 | + first_client.all_events_received.wait_for(10s); |
442 | +} |
443 | + |
444 | +TEST_F(TestClientInput, reestablishes_num_lock_state_in_client_with_surface_keymap) |
445 | +{ |
446 | + Client a_client_with_keymap(new_connection(), first); |
447 | + |
448 | + mir::test::Signal keymap_received; |
449 | + mir::test::Signal device_state_received; |
450 | + |
451 | + EXPECT_CALL(a_client_with_keymap, handle_keymap(_)) |
452 | + .WillOnce(mt::WakeUp(&keymap_received)); |
453 | + EXPECT_CALL(a_client_with_keymap, |
454 | + handle_input_device_state( |
455 | + mt::DeviceStateWithPressedKeys(std::vector<uint32_t>{KEY_NUMLOCK, KEY_NUMLOCK}))) |
456 | + .WillOnce(mt::WakeUp(&device_state_received)); |
457 | + |
458 | + get_surface(first)->set_keymap(MirInputDeviceId{0}, "pc105", "de", "", ""); |
459 | + keymap_received.wait_for(4s); |
460 | + |
461 | + { |
462 | + Client a_client(new_connection(), second); |
463 | + |
464 | + EXPECT_CALL(a_client, handle_input(mt::KeyDownEvent())); |
465 | + EXPECT_CALL(a_client, handle_input(mt::KeyUpEvent())); |
466 | + EXPECT_CALL(a_client, handle_input(AllOf(mt::KeyDownEvent(),mt::KeyOfSymbol(XKB_KEY_KP_4)))); |
467 | + EXPECT_CALL(a_client, handle_input(AllOf(mt::KeyUpEvent(),mt::KeyOfSymbol(XKB_KEY_KP_4)))) |
468 | + .WillOnce(mt::WakeUp(&a_client.all_events_received)); |
469 | + |
470 | + fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_NUMLOCK)); |
471 | + fake_keyboard->emit_event(mis::a_key_up_event().of_scancode(KEY_NUMLOCK)); |
472 | + fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_KP4)); |
473 | + fake_keyboard->emit_event(mis::a_key_up_event().of_scancode(KEY_KP4)); |
474 | + |
475 | + a_client.all_events_received.wait_for(10s); |
476 | + } |
477 | + device_state_received.wait_for(4s); |
478 | + EXPECT_CALL(a_client_with_keymap, handle_input(mt::KeyOfSymbol(XKB_KEY_KP_4))) |
479 | + .WillOnce(mt::WakeUp(&a_client_with_keymap.all_events_received)); |
480 | + |
481 | + fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_KP4)); |
482 | + |
483 | + a_client_with_keymap.all_events_received.wait_for(10s); |
484 | +} |
485 | + |
486 | TEST_F(TestClientInput, initial_mouse_configuration_can_be_querried) |
487 | { |
488 | wait_for_input_devices(); |
489 | |
490 | === modified file 'tests/include/mir/test/doubles/mock_key_mapper.h' |
491 | --- tests/include/mir/test/doubles/mock_key_mapper.h 2017-01-18 02:29:37 +0000 |
492 | +++ tests/include/mir/test/doubles/mock_key_mapper.h 2017-02-06 09:42:51 +0000 |
493 | @@ -41,6 +41,7 @@ |
494 | MOCK_METHOD0(clear_all_keymaps, void()); |
495 | MOCK_METHOD1(map_event, void(MirEvent& event)); |
496 | MOCK_CONST_METHOD0(modifiers, MirInputEventModifiers()); |
497 | + MOCK_CONST_METHOD1(device_modifiers, MirInputEventModifiers(MirInputDeviceId)); |
498 | }; |
499 | |
500 |
FAILED: Continuous integration, rev:3534 /mir-jenkins. ubuntu. com/job/ mir-ci/ 1236/ /mir-jenkins. ubuntu. com/job/ build-mir/ 1438/console /mir-jenkins. ubuntu. com/job/ build-0- fetch/1490 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= vivid+overlay/ 1481 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= xenial/ 1481 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= vivid+overlay/ 1452 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= vivid+overlay/ 1452/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial/ 1452/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 1452 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 1452/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 1452 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 1452/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial/ 1452/console
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild: /mir-jenkins. ubuntu. com/job/ mir-ci/ 1236/rebuild
https:/