Mir

Merge lp:~andreas-pokorny/mir/fix-1588237 into lp:mir

Proposed by Andreas Pokorny
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
Reviewer Review Type Date Requested Status
Alexandros Frantzis (community) Approve
Mir CI Bot continuous-integration Approve
Review via email: mp+299353@code.launchpad.net

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->set_keymap_for_all_devices(mir::input::Keymap{});
to the constructor of android_input_receiver.cpp

Launch "gedit -s" twice, and change num lock or caps lock in one gedit then type in the other.

To post a comment you must log in.
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:3534
https://mir-jenkins.ubuntu.com/job/mir-ci/1236/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/1438/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/1490
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1481
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1481
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1452
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1452/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1452/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1452
        deb: https://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
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1452
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1452/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1452/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/1236/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:3535
https://mir-jenkins.ubuntu.com/job/mir-ci/1240/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/1442/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/1494
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1485
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1485
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1456
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1456/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1456
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1456/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1456
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1456/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1456
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1456/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1456/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/1240/rebuild

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

[ FAILED ] TestClientInput.reestablishes_num_lock_state_in_client_with_surface_keymap (1450 ms)

review: Needs Fixing
Revision history for this message
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

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:3537
https://mir-jenkins.ubuntu.com/job/mir-ci/2877/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/3793/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/3872
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/3862
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/3862
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/3862
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/3820
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/3820/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/3820
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/3820/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/3820/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/3820
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/3820/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/3820
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/3820/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/3820/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/2877/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:3538
https://mir-jenkins.ubuntu.com/job/mir-ci/2878/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/3795/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/3874
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/3864
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/3864
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/3864
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/3822
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/3822/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/3822/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/3822
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/3822/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/3822
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/3822/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/3822
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/3822/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/3822
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/3822/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/2878/rebuild

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

Ok still the same ordering problem.. the device state event occurs to soon and lacks the pressed keys..

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:3540
https://mir-jenkins.ubuntu.com/job/mir-ci/2898/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/3830/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/3909
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/3899
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/3899
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/3899
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/3857
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/3857/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/3857
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/3857/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/3857/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/3857
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/3857/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/3857
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/3857/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/3857
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/3857/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/2898/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:3541
https://mir-jenkins.ubuntu.com/job/mir-ci/2899/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/3831/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/3910
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/3900
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/3900
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/3900
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/3858
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/3858/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/3858
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/3858/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/3858
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/3858/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/3858
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/3858/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/3858
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/3858/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/3858/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/2899/rebuild

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

NestedInput.* and in the last one there were two ClientLatency.* failures.

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3542
https://mir-jenkins.ubuntu.com/job/mir-ci/2945/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/3902
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/3981
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/3971
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/3971
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/3971
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/3929
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/3929/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/3929
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/3929/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/3929
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/3929/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/3929
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/3929/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/3929
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/3929/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/3929
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/3929/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/2945/rebuild

review: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/client/input/android/android_input_receiver.cpp'
--- src/client/input/android/android_input_receiver.cpp 2017-01-18 02:29:37 +0000
+++ src/client/input/android/android_input_receiver.cpp 2017-02-06 09:42:51 +0000
@@ -103,12 +103,28 @@
103103
104static void map_key_event(std::shared_ptr<mircv::XKBMapper> const& xkb_mapper, MirEvent &ev)104static void map_key_event(std::shared_ptr<mircv::XKBMapper> const& xkb_mapper, MirEvent &ev)
105{105{
106 // TODO: As XKBMapper is used to track modifier state we need to use a seperate instance106 auto const type = mir_event_get_type(&ev);
107 // of XKBMapper per device id (or modify XKBMapper semantics)107 if (type == mir_event_type_input)
108 if (mir_event_get_type(&ev) != mir_event_type_input)108 {
109 return;109 xkb_mapper->map_event(ev);
110110 }
111 xkb_mapper->map_event(ev);111 else if (type == mir_event_type_input_device_state)
112 {
113 auto device_state = mir_event_get_input_device_state_event(&ev);
114 std::vector<uint32_t> keys;
115
116 for (size_t index = 0, end_index = mir_input_device_state_event_device_count(device_state);
117 index != end_index; ++index)
118 {
119 auto device_id = mir_input_device_state_event_device_id(device_state, index);
120 auto key_count = mir_input_device_state_event_device_pressed_keys_count(device_state, index);
121 for (decltype(key_count) i = 0; i != key_count; ++i)
122 keys.push_back(
123 mir_input_device_state_event_device_pressed_keys_for_index(device_state, index, i));
124
125 xkb_mapper->set_key_state(device_id, keys);
126 }
127 }
112}128}
113129
114}130}
115131
=== modified file 'src/client/input/xkb_mapper.cpp'
--- src/client/input/xkb_mapper.cpp 2017-01-18 02:29:37 +0000
+++ src/client/input/xkb_mapper.cpp 2017-02-06 09:42:51 +0000
@@ -25,6 +25,7 @@
2525
26#include <sstream>26#include <sstream>
27#include <boost/throw_exception.hpp>27#include <boost/throw_exception.hpp>
28#include <unordered_set>
2829
29namespace mi = mir::input;30namespace mi = mir::input;
30namespace mev = mir::events;31namespace mev = mir::events;
@@ -59,10 +60,18 @@
59 case XKB_KEY_Super_R: return mir_input_event_modifier_meta_right;60 case XKB_KEY_Super_R: return mir_input_event_modifier_meta_right;
60 case XKB_KEY_Caps_Lock: return mir_input_event_modifier_caps_lock;61 case XKB_KEY_Caps_Lock: return mir_input_event_modifier_caps_lock;
61 case XKB_KEY_Scroll_Lock: return mir_input_event_modifier_scroll_lock;62 case XKB_KEY_Scroll_Lock: return mir_input_event_modifier_scroll_lock;
63 case XKB_KEY_Num_Lock: return mir_input_event_modifier_num_lock;
62 default: return MirInputEventModifiers{0};64 default: return MirInputEventModifiers{0};
63 }65 }
64}66}
6567
68bool is_toggle_modifier(MirInputEventModifiers key)
69{
70 return key == mir_input_event_modifier_caps_lock ||
71 key == mir_input_event_modifier_scroll_lock ||
72 key == mir_input_event_modifier_num_lock;
73}
74
66MirInputEventModifiers expand_modifiers(MirInputEventModifiers modifiers)75MirInputEventModifiers expand_modifiers(MirInputEventModifiers modifiers)
67{76{
68 if (modifiers == 0)77 if (modifiers == 0)
@@ -167,7 +176,7 @@
167 MirInputEventModifiers new_modifier = 0;176 MirInputEventModifiers new_modifier = 0;
168 for (auto const& mapping_state : device_mapping)177 for (auto const& mapping_state : device_mapping)
169 {178 {
170 new_modifier |= mapping_state.second->modifier_state;179 new_modifier |= mapping_state.second->modifiers();
171 }180 }
172181
173 modifier_state = new_modifier;182 modifier_state = new_modifier;
@@ -284,6 +293,16 @@
284 return mir_input_event_modifier_none;293 return mir_input_event_modifier_none;
285}294}
286295
296MirInputEventModifiers mircv::XKBMapper::device_modifiers(MirInputDeviceId id) const
297{
298 std::lock_guard<std::mutex> lg(guard);
299
300 auto it = device_mapping.find(id);
301 if (it == end(device_mapping))
302 return mir_input_event_modifier_none;
303 return expand_modifiers(it->second->modifiers());
304}
305
287mircv::XKBMapper::XkbMappingState::XkbMappingState(std::shared_ptr<xkb_keymap> const& keymap)306mircv::XKBMapper::XkbMappingState::XkbMappingState(std::shared_ptr<xkb_keymap> const& keymap)
288 : keymap{keymap}, state{make_unique_state(this->keymap.get())}307 : keymap{keymap}, state{make_unique_state(this->keymap.get())}
289{308{
@@ -293,8 +312,20 @@
293{312{
294 state = make_unique_state(keymap.get());313 state = make_unique_state(keymap.get());
295 modifier_state = mir_input_event_modifier_none;314 modifier_state = mir_input_event_modifier_none;
315 std::unordered_set<uint32_t> pressed_codes;
296 for (uint32_t scan_code : key_state)316 for (uint32_t scan_code : key_state)
297 update_state(to_xkb_scan_code(scan_code), mir_keyboard_action_down, nullptr);317 {
318 bool already_pressed = pressed_codes.count(scan_code) > 0;
319
320 update_state(to_xkb_scan_code(scan_code),
321 (already_pressed) ? mir_keyboard_action_up : mir_keyboard_action_down,
322 nullptr);
323
324 if (already_pressed)
325 pressed_codes.erase(scan_code);
326 else
327 pressed_codes.insert(scan_code);
328 }
298}329}
299330
300bool mircv::XKBMapper::XkbMappingState::update_and_map(MirEvent& event, mircv::XKBMapper::ComposeState* compose_state)331bool mircv::XKBMapper::XkbMappingState::update_and_map(MirEvent& event, mircv::XKBMapper::ComposeState* compose_state)
@@ -322,17 +353,26 @@
322 if (action == mir_keyboard_action_up)353 if (action == mir_keyboard_action_up)
323 {354 {
324 xkb_state_update_key(state.get(), scan_code, XKB_KEY_UP);355 xkb_state_update_key(state.get(), scan_code, XKB_KEY_UP);
325 modifier_state = modifier_state & ~mod_change;356 // TODO get the modifier state from xkbcommon and apply it
357 // for all other modifiers manually track them here:
358 release_modifier(mod_change);
326 }359 }
327 else if (action == mir_keyboard_action_down)360 else if (action == mir_keyboard_action_down)
328 {361 {
329 xkb_state_update_key(state.get(), scan_code, XKB_KEY_DOWN);362 xkb_state_update_key(state.get(), scan_code, XKB_KEY_DOWN);
330 modifier_state = modifier_state | mod_change;363 // TODO get the modifier state from xkbcommon and apply it
364 // for all other modifiers manually track them here:
365 press_modifier(mod_change);
331 }366 }
332367
333 return key_sym;368 return key_sym;
334}369}
335370
371MirInputEventModifiers mircv::XKBMapper::XkbMappingState::modifiers() const
372{
373 return modifier_state;
374}
375
336mircv::XKBMapper::ComposeState* mircv::XKBMapper::get_compose_state(MirInputDeviceId id)376mircv::XKBMapper::ComposeState* mircv::XKBMapper::get_compose_state(MirInputDeviceId id)
337{377{
338 auto dev_compose_state = device_composing.find(id);378 auto dev_compose_state = device_composing.find(id);
@@ -410,3 +450,18 @@
410450
411 return mapped_key;451 return mapped_key;
412}452}
453
454
455void mircv::XKBMapper::XkbMappingState::press_modifier(MirInputEventModifiers mod)
456{
457 if (is_toggle_modifier(mod))
458 modifier_state ^= mod;
459 else
460 modifier_state |= mod;
461}
462
463void mircv::XKBMapper::XkbMappingState::release_modifier(MirInputEventModifiers mod)
464{
465 if (!is_toggle_modifier(mod))
466 modifier_state &= ~mod;
467}
413468
=== modified file 'src/include/common/mir/input/key_mapper.h'
--- src/include/common/mir/input/key_mapper.h 2017-01-18 02:29:37 +0000
+++ src/include/common/mir/input/key_mapper.h 2017-02-06 09:42:51 +0000
@@ -88,6 +88,7 @@
88 */88 */
89 virtual void map_event(MirEvent& event) = 0;89 virtual void map_event(MirEvent& event) = 0;
90 virtual MirInputEventModifiers modifiers() const = 0;90 virtual MirInputEventModifiers modifiers() const = 0;
91 virtual MirInputEventModifiers device_modifiers(MirInputDeviceId id) const = 0;
9192
92protected:93protected:
93 KeyMapper(KeyMapper const&) = delete;94 KeyMapper(KeyMapper const&) = delete;
9495
=== modified file 'src/include/common/mir/input/xkb_mapper.h'
--- src/include/common/mir/input/xkb_mapper.h 2017-01-18 02:29:37 +0000
+++ src/include/common/mir/input/xkb_mapper.h 2017-02-06 09:42:51 +0000
@@ -63,6 +63,7 @@
63 void clear_all_keymaps() override;63 void clear_all_keymaps() override;
64 void map_event(MirEvent& event) override;64 void map_event(MirEvent& event) override;
65 MirInputEventModifiers modifiers() const override;65 MirInputEventModifiers modifiers() const override;
66 MirInputEventModifiers device_modifiers(MirInputDeviceId di) const override;
6667
67protected:68protected:
68 XKBMapper(XKBMapper const&) = delete;69 XKBMapper(XKBMapper const&) = delete;
@@ -89,8 +90,14 @@
89 {90 {
90 explicit XkbMappingState(std::shared_ptr<xkb_keymap> const& keymap);91 explicit XkbMappingState(std::shared_ptr<xkb_keymap> const& keymap);
91 void set_key_state(std::vector<uint32_t> const& key_state);92 void set_key_state(std::vector<uint32_t> const& key_state);
93
92 bool update_and_map(MirEvent& event, ComposeState* compose_state);94 bool update_and_map(MirEvent& event, ComposeState* compose_state);
93 xkb_keysym_t update_state(uint32_t scan_code, MirKeyboardAction direction, ComposeState* compose_state);95 xkb_keysym_t update_state(uint32_t scan_code, MirKeyboardAction direction, ComposeState* compose_state);
96 MirInputEventModifiers modifiers() const;
97 private:
98 void press_modifier(MirInputEventModifiers mod);
99 void release_modifier(MirInputEventModifiers mod);
100
94 std::shared_ptr<xkb_keymap> const keymap;101 std::shared_ptr<xkb_keymap> const keymap;
95 XKBStatePtr state;102 XKBStatePtr state;
96 MirInputEventModifiers modifier_state{0};103 MirInputEventModifiers modifier_state{0};
97104
=== modified file 'src/server/input/seat_input_device_tracker.cpp'
--- src/server/input/seat_input_device_tracker.cpp 2017-01-18 02:29:37 +0000
+++ src/server/input/seat_input_device_tracker.cpp 2017-02-06 09:42:51 +0000
@@ -31,6 +31,7 @@
31#include "input_modifier_utils.h"31#include "input_modifier_utils.h"
3232
33#include <boost/throw_exception.hpp>33#include <boost/throw_exception.hpp>
34#include <linux/input.h>
3435
35#include <stdexcept>36#include <stdexcept>
36#include <algorithm>37#include <algorithm>
@@ -115,7 +116,7 @@
115 if (stored_data == end(device_data))116 if (stored_data == end(device_data))
116 return true;117 return true;
117118
118 return !stored_data->second.allowed_scan_code_action(mir_input_event_get_keyboard_event(event));119 return !stored_data->second.allowed_scan_code_action(mir_input_event_get_keyboard_event(event));;
119 }120 }
120 return false;121 return false;
121}122}
@@ -251,8 +252,44 @@
251 std::vector<mev::InputDeviceState> devices;252 std::vector<mev::InputDeviceState> devices;
252 devices.reserve(device_data.size());253 devices.reserve(device_data.size());
253 for (auto const& item : device_data)254 for (auto const& item : device_data)
255 {
254 devices.push_back({item.first, item.second.scan_codes, item.second.buttons});256 devices.push_back({item.first, item.second.scan_codes, item.second.buttons});
255257 auto lock_state = key_mapper->device_modifiers(item.first);
258
259 bool caps_lock_active = (lock_state & mir_input_event_modifier_caps_lock);
260 bool scroll_lock_active = (lock_state & mir_input_event_modifier_scroll_lock);
261 bool num_lock_active = (lock_state & mir_input_event_modifier_num_lock);
262
263 bool contains_caps_lock_pressed = false;
264 bool contains_scroll_lock_pressed = false;
265 bool contains_num_lock_pressed = false;
266
267 for (uint32_t scan_code : item.second.scan_codes)
268 {
269 if (scan_code == KEY_CAPSLOCK)
270 contains_caps_lock_pressed = true;
271 else if (scan_code == KEY_SCROLLLOCK)
272 contains_scroll_lock_pressed = true;
273 else if (scan_code == KEY_NUMLOCK)
274 contains_num_lock_pressed = true;
275 }
276
277 if (caps_lock_active && !contains_caps_lock_pressed)
278 {
279 devices.back().pressed_keys.push_back(KEY_CAPSLOCK);
280 devices.back().pressed_keys.push_back(KEY_CAPSLOCK);
281 }
282 if (num_lock_active && !contains_num_lock_pressed)
283 {
284 devices.back().pressed_keys.push_back(KEY_NUMLOCK);
285 devices.back().pressed_keys.push_back(KEY_NUMLOCK);
286 }
287 if (scroll_lock_active && !contains_scroll_lock_pressed)
288 {
289 devices.back().pressed_keys.push_back(KEY_SCROLLLOCK);
290 devices.back().pressed_keys.push_back(KEY_SCROLLLOCK);
291 }
292 }
256 auto out_ev = mev::make_event(293 auto out_ev = mev::make_event(
257 clock->now().time_since_epoch(),294 clock->now().time_since_epoch(),
258 buttons,295 buttons,
259296
=== modified file 'tests/acceptance-tests/test_client_input.cpp'
--- tests/acceptance-tests/test_client_input.cpp 2017-02-06 03:54:54 +0000
+++ tests/acceptance-tests/test_client_input.cpp 2017-02-06 09:42:51 +0000
@@ -18,7 +18,10 @@
1818
19#include "mir/input/input_device_info.h"19#include "mir/input/input_device_info.h"
20#include "mir/input/event_filter.h"20#include "mir/input/event_filter.h"
21#include "mir/input/keymap.h"
21#include "mir/input/composite_event_filter.h"22#include "mir/input/composite_event_filter.h"
23#include "mir/scene/session.h"
24#include "mir/scene/surface.h"
22#include "mir/input/mir_touchpad_config.h"25#include "mir/input/mir_touchpad_config.h"
23#include "mir/input/mir_input_config.h"26#include "mir/input/mir_input_config.h"
2427
@@ -45,6 +48,7 @@
45#include <linux/input.h>48#include <linux/input.h>
4649
47#include <condition_variable>50#include <condition_variable>
51#include <unordered_map>
48#include <chrono>52#include <chrono>
49#include <atomic>53#include <atomic>
50#include <mutex>54#include <mutex>
@@ -98,12 +102,52 @@
98{102{
99}103}
100104
105struct SurfaceTrackingShell : mir::shell::ShellWrapper
106{
107 SurfaceTrackingShell(
108 std::shared_ptr<mir::shell::Shell> wrapped_shell)
109 : ShellWrapper{wrapped_shell}, wrapped_shell{wrapped_shell}
110 {}
111
112 mir::frontend::SurfaceId create_surface(
113 std::shared_ptr<mir::scene::Session> const& session,
114 mir::scene::SurfaceCreationParameters const& params,
115 std::shared_ptr<mir::frontend::EventSink> const& sink) override
116 {
117 auto surface_id = wrapped_shell->create_surface(session, params, sink);
118
119 tracked_surfaces[session->name()] = TrackedSurface{session, surface_id};
120
121 return surface_id;
122 }
123
124 std::shared_ptr<mir::scene::Surface> get_surface(std::string const& session_name)
125 {
126 if (end(tracked_surfaces) == tracked_surfaces.find(session_name))
127 return nullptr;
128 TrackedSurface & tracked_surface = tracked_surfaces[session_name];
129 auto session = tracked_surface.session.lock();
130 if (!session)
131 return nullptr;
132 return session->surface(tracked_surface.surface);
133 }
134
135 struct TrackedSurface
136 {
137 std::weak_ptr<mir::scene::Session> session;
138 mir::frontend::SurfaceId surface;
139 };
140 std::unordered_map<std::string, TrackedSurface> tracked_surfaces;
141 std::shared_ptr<mir::shell::Shell> wrapped_shell;
142};
143
101struct Client144struct Client
102{145{
103 MirWindow* window{nullptr};146 MirWindow* window{nullptr};
104147
105 MOCK_METHOD1(handle_input, void(MirEvent const*));148 MOCK_METHOD1(handle_input, void(MirEvent const*));
106 MOCK_METHOD1(handle_keymap, void(MirEvent const*));149 MOCK_METHOD1(handle_keymap, void(MirEvent const*));
150 MOCK_METHOD1(handle_input_device_state, void(MirEvent const*));
107151
108 Client(std::string const& con, std::string const& name)152 Client(std::string const& con, std::string const& name)
109 {153 {
@@ -146,7 +190,12 @@
146 mir_window_focus_state_focused == value)190 mir_window_focus_state_focused == value)
147 focused = true;191 focused = true;
148192
149 if (exposed && focused)193 test_and_raise();
194 }
195
196 void test_and_raise()
197 {
198 if (exposed && focused && input_device_state_received)
150 ready_to_accept_events.raise();199 ready_to_accept_events.raise();
151 }200 }
152201
@@ -164,6 +213,12 @@
164 client->handle_input(ev);213 client->handle_input(ev);
165 if (type == mir_event_type_keymap)214 if (type == mir_event_type_keymap)
166 client->handle_keymap(ev);215 client->handle_keymap(ev);
216 if (type == mir_event_type_input_device_state)
217 {
218 client->input_device_state_received = true;
219 client->test_and_raise();
220 client->handle_input_device_state(ev);
221 }
167 }222 }
168 ~Client()223 ~Client()
169 {224 {
@@ -181,6 +236,7 @@
181 mir::test::Signal all_events_received;236 mir::test::Signal all_events_received;
182 bool exposed = false;237 bool exposed = false;
183 bool focused = false;238 bool focused = false;
239 bool input_device_state_received = false;
184};240};
185241
186struct DeviceCounter : mi::InputDeviceObserver242struct DeviceCounter : mi::InputDeviceObserver
@@ -216,7 +272,8 @@
216 [this](std::shared_ptr<mir::shell::Shell> const& wrapped)272 [this](std::shared_ptr<mir::shell::Shell> const& wrapped)
217 {273 {
218 shell = std::make_shared<mtf::PlacementApplyingShell>(wrapped, input_regions, positions);274 shell = std::make_shared<mtf::PlacementApplyingShell>(wrapped, input_regions, positions);
219 return shell;275 surfaces = std::make_shared<SurfaceTrackingShell>(shell);
276 return surfaces;
220 });277 });
221 server.override_the_session_authorizer([this] { return mt::fake_shared(stub_authorizer); });278 server.override_the_session_authorizer([this] { return mt::fake_shared(stub_authorizer); });
222279
@@ -225,7 +282,13 @@
225 positions[first] = geom::Rectangle{{0,0}, {surface_width, surface_height}};282 positions[first] = geom::Rectangle{{0,0}, {surface_width, surface_height}};
226 }283 }
227284
285 std::shared_ptr<mir::scene::Surface> get_surface(std::string const& name)
286 {
287 return surfaces->get_surface(name);
288 }
289
228 std::shared_ptr<mtf::PlacementApplyingShell> shell;290 std::shared_ptr<mtf::PlacementApplyingShell> shell;
291 std::shared_ptr<SurfaceTrackingShell> surfaces;
229 std::string const keyboard_name = "keyboard";292 std::string const keyboard_name = "keyboard";
230 std::string const keyboard_unique_id = "keyboard-uid";293 std::string const keyboard_unique_id = "keyboard-uid";
231 std::string const mouse_name = "mouse";294 std::string const mouse_name = "mouse";
@@ -939,6 +1002,81 @@
939 mir_input_config_release(config);1002 mir_input_config_release(config);
940}1003}
9411004
1005TEST_F(TestClientInput, num_lock_is_off_on_startup)
1006{
1007 Client a_client(new_connection(), first);
1008
1009 EXPECT_CALL(a_client, handle_input(mt::KeyOfSymbol(XKB_KEY_KP_Left)))
1010 .WillOnce(mt::WakeUp(&a_client.all_events_received));
1011
1012 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_KP4));
1013 a_client.all_events_received.wait_for(10s);
1014}
1015
1016TEST_F(TestClientInput, keeps_num_lock_state_after_focus_change)
1017{
1018 Client first_client(new_connection(), first);
1019
1020 {
1021 Client second_client(new_connection(), second);
1022 EXPECT_CALL(second_client, handle_input(mt::KeyDownEvent()));
1023 EXPECT_CALL(second_client, handle_input(mt::KeyUpEvent()))
1024 .WillOnce(mt::WakeUp(&second_client.all_events_received));
1025
1026 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_NUMLOCK));
1027 fake_keyboard->emit_event(mis::a_key_up_event().of_scancode(KEY_NUMLOCK));
1028
1029 second_client.all_events_received.wait_for(10s);
1030 }
1031
1032 EXPECT_CALL(first_client, handle_input(mt::KeyOfSymbol(XKB_KEY_KP_4)))
1033 .WillOnce(mt::WakeUp(&first_client.all_events_received));
1034 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_KP4));
1035 first_client.all_events_received.wait_for(10s);
1036}
1037
1038TEST_F(TestClientInput, reestablishes_num_lock_state_in_client_with_surface_keymap)
1039{
1040 Client a_client_with_keymap(new_connection(), first);
1041
1042 mir::test::Signal keymap_received;
1043 mir::test::Signal device_state_received;
1044
1045 EXPECT_CALL(a_client_with_keymap, handle_keymap(_))
1046 .WillOnce(mt::WakeUp(&keymap_received));
1047 EXPECT_CALL(a_client_with_keymap,
1048 handle_input_device_state(
1049 mt::DeviceStateWithPressedKeys(std::vector<uint32_t>{KEY_NUMLOCK, KEY_NUMLOCK})))
1050 .WillOnce(mt::WakeUp(&device_state_received));
1051
1052 get_surface(first)->set_keymap(MirInputDeviceId{0}, "pc105", "de", "", "");
1053 keymap_received.wait_for(4s);
1054
1055 {
1056 Client a_client(new_connection(), second);
1057
1058 EXPECT_CALL(a_client, handle_input(mt::KeyDownEvent()));
1059 EXPECT_CALL(a_client, handle_input(mt::KeyUpEvent()));
1060 EXPECT_CALL(a_client, handle_input(AllOf(mt::KeyDownEvent(),mt::KeyOfSymbol(XKB_KEY_KP_4))));
1061 EXPECT_CALL(a_client, handle_input(AllOf(mt::KeyUpEvent(),mt::KeyOfSymbol(XKB_KEY_KP_4))))
1062 .WillOnce(mt::WakeUp(&a_client.all_events_received));
1063
1064 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_NUMLOCK));
1065 fake_keyboard->emit_event(mis::a_key_up_event().of_scancode(KEY_NUMLOCK));
1066 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_KP4));
1067 fake_keyboard->emit_event(mis::a_key_up_event().of_scancode(KEY_KP4));
1068
1069 a_client.all_events_received.wait_for(10s);
1070 }
1071 device_state_received.wait_for(4s);
1072 EXPECT_CALL(a_client_with_keymap, handle_input(mt::KeyOfSymbol(XKB_KEY_KP_4)))
1073 .WillOnce(mt::WakeUp(&a_client_with_keymap.all_events_received));
1074
1075 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_KP4));
1076
1077 a_client_with_keymap.all_events_received.wait_for(10s);
1078}
1079
942TEST_F(TestClientInput, initial_mouse_configuration_can_be_querried)1080TEST_F(TestClientInput, initial_mouse_configuration_can_be_querried)
943{1081{
944 wait_for_input_devices();1082 wait_for_input_devices();
9451083
=== modified file 'tests/include/mir/test/doubles/mock_key_mapper.h'
--- tests/include/mir/test/doubles/mock_key_mapper.h 2017-01-18 02:29:37 +0000
+++ tests/include/mir/test/doubles/mock_key_mapper.h 2017-02-06 09:42:51 +0000
@@ -41,6 +41,7 @@
41 MOCK_METHOD0(clear_all_keymaps, void());41 MOCK_METHOD0(clear_all_keymaps, void());
42 MOCK_METHOD1(map_event, void(MirEvent& event));42 MOCK_METHOD1(map_event, void(MirEvent& event));
43 MOCK_CONST_METHOD0(modifiers, MirInputEventModifiers());43 MOCK_CONST_METHOD0(modifiers, MirInputEventModifiers());
44 MOCK_CONST_METHOD1(device_modifiers, MirInputEventModifiers(MirInputDeviceId));
44};45};
4546
4647

Subscribers

People subscribed via source and target branches