Mir

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

Proposed by Andreas Pokorny
Status: Merged
Approved by: Daniel van Vugt
Approved revision: no longer in the source branch.
Merged at revision: 4041
Proposed branch: lp:~andreas-pokorny/mir/fix-1664610
Merge into: lp:mir
Diff against target: 392 lines (+187/-12)
12 files modified
include/client/mir_toolkit/events/input/keyboard_event.h (+12/-0)
include/test/mir/test/event_matchers.h (+12/-0)
src/capnproto/mir_event.capnp (+1/-0)
src/client/input/input_event.cpp (+5/-0)
src/client/input/xkb_mapper.cpp (+39/-7)
src/client/symbols.map (+1/-0)
src/common/events/keyboard_event.cpp (+8/-0)
src/common/symbols.map (+5/-3)
src/include/common/mir/events/keyboard_event.h (+3/-0)
src/include/common/mir/input/xkb_mapper.h (+3/-2)
tests/acceptance-tests/test_client_input.cpp (+37/-0)
tests/unit-tests/client/input/test_xkb_mapper.cpp (+61/-0)
To merge this branch: bzr merge lp:~andreas-pokorny/mir/fix-1664610
Reviewer Review Type Date Requested Status
Mir CI Bot continuous-integration Approve
Daniel van Vugt Approve
Brandon Schaefer (community) Approve
Review via email: mp+317440@code.launchpad.net

Commit message

mirclient: Offer a utf8 representation of the text a key press should produce (LP: #1664610)

The new client API mir_keyboard_event_key_text returns the text a key combination or key sequence generates in the current state of the keyboard.

Description of the change

To properly get the text of a key entry sequence the individual xkb key symbols do not contain enough information. The current xkb_state or xkb_compose_state is needed for that.

This change produces the key text within the XKBMapper and offers that information attached to each mir_keyboard event.

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

FAILED: Continuous integration, rev:4036
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~andreas-pokorny/mir/fix-1664610/+merge/317440/+edit-commit-message

https://mir-jenkins.ubuntu.com/job/mir-ci/3008/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4010
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4096
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4086
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4086
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4086
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4037
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4037/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/4037
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4037/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4037
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4037/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/4037
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4037/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/4037
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4037/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/4037
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4037/artifact/output/*zip*/output.zip

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

xkb_state_key_get_utf8(...)

All uses of this dont assign a null term on the end of the buffer when it is then assigned to a std::string which depends on a null term char*.

review: Needs Fixing
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

Actually mis-read the API. It'll always be null terminated.

review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Cool.

But why should Mir offer this at all?

Users could just call this:
   xkb_state_key_get_utf8(state, mir_keyboard_event_scan_code(e), buffer, sizeof(buffer));
if only they knew what 'state' was...?

review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

OK, I think you answered my question in the description.

Revision history for this message
Mir CI Bot (mir-ci-bot) :
review: Approve (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_toolkit/events/input/keyboard_event.h'
2--- include/client/mir_toolkit/events/input/keyboard_event.h 2017-01-18 02:29:37 +0000
3+++ include/client/mir_toolkit/events/input/keyboard_event.h 2017-02-16 10:52:53 +0000
4@@ -82,6 +82,18 @@
5 int mir_keyboard_event_scan_code(MirKeyboardEvent const* event);
6
7 /**
8+ * Retrieve the text the key press would emit as null terminated utf8 string.
9+ *
10+ * The text will only be available to key down and key repeat events.
11+ * For mir_keyboard_action_up or key presses that do produce text an empty
12+ * string will be returned.
13+ *
14+ * \param [in] event The key event
15+ * \return The text
16+ */
17+char const* mir_keyboard_event_key_text(MirKeyboardEvent const* event);
18+
19+/**
20 * Retrieve the modifier keys pressed when the key action occured.
21 *
22 * \param [in] event The key event
23
24=== modified file 'include/test/mir/test/event_matchers.h'
25--- include/test/mir/test/event_matchers.h 2017-01-27 04:57:53 +0000
26+++ include/test/mir/test/event_matchers.h 2017-02-16 10:52:53 +0000
27@@ -156,6 +156,18 @@
28 return true;
29 }
30
31+MATCHER_P(KeyWithText, text, "")
32+{
33+ auto kev = maybe_key_event(to_address(arg));
34+ if (kev == nullptr)
35+ return false;
36+
37+ if(strcmp(mir_keyboard_event_key_text(kev), text))
38+ return false;
39+
40+ return true;
41+}
42+
43 MATCHER_P(KeyOfScanCode, code, "")
44 {
45 auto kev = maybe_key_event(to_address(arg));
46
47=== modified file 'src/capnproto/mir_event.capnp'
48--- src/capnproto/mir_event.capnp 2017-02-15 13:36:35 +0000
49+++ src/capnproto/mir_event.capnp 2017-02-16 10:52:53 +0000
50@@ -52,6 +52,7 @@
51 down @1;
52 repeat @2;
53 }
54+ text @3 :Text;
55 }
56
57 struct TouchScreenEvent
58
59=== modified file 'src/client/input/input_event.cpp'
60--- src/client/input/input_event.cpp 2017-02-15 13:36:35 +0000
61+++ src/client/input/input_event.cpp 2017-02-16 10:52:53 +0000
62@@ -143,6 +143,11 @@
63 return kev->modifiers();
64 })
65
66+char const* mir_keyboard_event_key_text(MirKeyboardEvent const* kev) MIR_HANDLE_EVENT_EXCEPTION(
67+{
68+ return kev->text();
69+})
70+
71 /* Touch event accessors */
72
73 MirInputEventModifiers mir_touch_event_modifiers(MirTouchEvent const* tev) MIR_HANDLE_EVENT_EXCEPTION(
74
75=== modified file 'src/client/input/xkb_mapper.cpp'
76--- src/client/input/xkb_mapper.cpp 2017-02-15 07:38:33 +0000
77+++ src/client/input/xkb_mapper.cpp 2017-02-16 10:52:53 +0000
78@@ -313,13 +313,15 @@
79 state = make_unique_state(keymap.get());
80 modifier_state = mir_input_event_modifier_none;
81 std::unordered_set<uint32_t> pressed_codes;
82+ std::string t;
83 for (uint32_t scan_code : key_state)
84 {
85 bool already_pressed = pressed_codes.count(scan_code) > 0;
86
87 update_state(to_xkb_scan_code(scan_code),
88 (already_pressed) ? mir_keyboard_action_up : mir_keyboard_action_down,
89- nullptr);
90+ nullptr,
91+ t);
92
93 if (already_pressed)
94 pressed_codes.erase(scan_code);
95@@ -333,8 +335,12 @@
96 auto& key_ev = *event.to_input()->to_keyboard();
97 uint32_t xkb_scan_code = to_xkb_scan_code(key_ev.scan_code());
98 auto old_state = modifier_state;
99+ std::string key_text;
100+ xkb_keysym_t key_sym;
101+ key_sym = update_state(xkb_scan_code, key_ev.action(), compose_state, key_text);
102
103- key_ev.set_key_code(update_state(xkb_scan_code, key_ev.action(), compose_state));
104+ key_ev.set_key_code(key_sym);
105+ key_ev.set_text(key_text.c_str());
106 // TODO we should also indicate effective/consumed modifier state to properly
107 // implement short cuts with keys that are only reachable via modifier keys
108 key_ev.set_modifiers(expand_modifiers(modifier_state));
109@@ -342,13 +348,21 @@
110 return old_state != modifier_state;
111 }
112
113-xkb_keysym_t mircv::XKBMapper::XkbMappingState::update_state(uint32_t scan_code, MirKeyboardAction action, mircv::XKBMapper::ComposeState* compose_state)
114+xkb_keysym_t mircv::XKBMapper::XkbMappingState::update_state(uint32_t scan_code, MirKeyboardAction action, mircv::XKBMapper::ComposeState* compose_state, std::string& text)
115 {
116 auto key_sym = xkb_state_key_get_one_sym(state.get(), scan_code);
117 auto mod_change = xkb_key_code_to_modifier(key_sym);
118
119+ if(action == mir_keyboard_action_down || action == mir_keyboard_action_repeat)
120+ {
121+ char buffer[7];
122+ // scan code? really? not keysym?
123+ xkb_state_key_get_utf8(state.get(), scan_code, buffer, sizeof(buffer));
124+ text = buffer;
125+ }
126+
127 if (compose_state)
128- key_sym = compose_state->update_state(key_sym, action);
129+ key_sym = compose_state->update_state(key_sym, action, text);
130
131 if (action == mir_keyboard_action_up)
132 {
133@@ -405,25 +419,31 @@
134
135 auto const key_sym = key_ev.key_code();
136 auto const action = key_ev.action();
137- key_ev.set_key_code(update_state(key_sym, action));
138+ std::string text;
139+ key_ev.set_key_code(update_state(key_sym, action, text));
140+ key_ev.set_text(text.c_str());
141 }
142
143-xkb_keysym_t mircv::XKBMapper::ComposeState::update_state(xkb_keysym_t mapped_key, MirKeyboardAction action)
144+xkb_keysym_t mircv::XKBMapper::ComposeState::update_state(xkb_keysym_t mapped_key, MirKeyboardAction action, std::string& mapped_text)
145 {
146 // the state machine only cares about downs
147 if (action == mir_keyboard_action_down)
148 {
149 if (xkb_compose_state_feed(state.get(), mapped_key) == XKB_COMPOSE_FEED_ACCEPTED)
150 {
151- auto result = xkb_compose_state_get_status(state.get());
152+ auto result = xkb_compose_state_get_status(state.get());
153 if (result == XKB_COMPOSE_COMPOSED)
154 {
155+ char buffer[7];
156+ xkb_compose_state_get_utf8(state.get(), buffer, sizeof(buffer));
157+ mapped_text = buffer;
158 auto composed_key_sym = xkb_compose_state_get_one_sym(state.get());
159 last_composed_key = std::make_tuple(mapped_key, composed_key_sym);
160 return composed_key_sym;
161 }
162 else if (result == XKB_COMPOSE_COMPOSING)
163 {
164+ mapped_text = "";
165 consumed_keys.insert(mapped_key);
166 return XKB_KEY_NoSymbol;
167 }
168@@ -440,12 +460,24 @@
169 mapped_key == std::get<0>(last_composed_key.value()))
170 {
171 if (action == mir_keyboard_action_up)
172+ {
173+ mapped_text = "";
174 return std::get<1>(last_composed_key.consume());
175+ }
176 else
177+ {
178+ // on repeat get the text of the compose state
179+ char buffer[7];
180+ xkb_compose_state_get_utf8(state.get(), buffer, sizeof(buffer));
181+ mapped_text = buffer;
182 return std::get<1>(last_composed_key.value());
183+ }
184 }
185 if (consumed_keys.erase(mapped_key))
186+ {
187+ mapped_text = "";
188 return XKB_KEY_NoSymbol;
189+ }
190 }
191
192 return mapped_key;
193
194=== modified file 'src/client/symbols.map'
195--- src/client/symbols.map 2017-02-16 04:47:36 +0000
196+++ src/client/symbols.map 2017-02-16 10:52:53 +0000
197@@ -609,4 +609,5 @@
198 mir_connection_apply_session_input_config;
199 mir_connection_set_base_input_config;
200 mir_get_client_api_version;
201+ mir_keyboard_event_key_text;
202 } MIR_CLIENT_0.26.1;
203
204=== modified file 'src/common/events/keyboard_event.cpp'
205--- src/common/events/keyboard_event.cpp 2017-01-18 02:29:37 +0000
206+++ src/common/events/keyboard_event.cpp 2017-02-16 10:52:53 +0000
207@@ -55,4 +55,12 @@
208 event.getInput().getKey().setScanCode(scan_code);
209 }
210
211+char const* MirKeyboardEvent::text() const
212+{
213+ return event.asReader().getInput().getKey().getText().cStr();
214+}
215
216+void MirKeyboardEvent::set_text(char const* str)
217+{
218+ event.getInput().getKey().setText(str);
219+}
220
221=== modified file 'src/common/symbols.map'
222--- src/common/symbols.map 2017-02-15 14:45:41 +0000
223+++ src/common/symbols.map 2017-02-16 10:52:53 +0000
224@@ -445,9 +445,11 @@
225 MIR_COMMON_0.27 {
226 global:
227 extern "C++" {
228+ MirInputDeviceStateEvent::set_window_id*;
229+ MirInputDeviceStateEvent::window_id*;
230+ MirInputEvent::set_window_id*;
231 MirInputEvent::window_id*;
232- MirInputEvent::set_window_id*;
233- MirInputDeviceStateEvent::window_id*;
234- MirInputDeviceStateEvent::set_window_id*;
235+ MirKeyboardEvent::set_text*;
236+ MirKeyboardEvent::text*;
237 };
238 } MIR_COMMON_0.26;
239
240=== modified file 'src/include/common/mir/events/keyboard_event.h'
241--- src/include/common/mir/events/keyboard_event.h 2017-01-18 02:29:37 +0000
242+++ src/include/common/mir/events/keyboard_event.h 2017-02-16 10:52:53 +0000
243@@ -37,6 +37,9 @@
244
245 int32_t scan_code() const;
246 void set_scan_code(int32_t scan_code);
247+
248+ char const* text() const;
249+ void set_text(char const* str);
250 };
251
252 #endif /* MIR_COMMON_KEYBOARD_EVENT_H_ */
253
254=== modified file 'src/include/common/mir/input/xkb_mapper.h'
255--- src/include/common/mir/input/xkb_mapper.h 2017-02-15 07:38:33 +0000
256+++ src/include/common/mir/input/xkb_mapper.h 2017-02-16 10:52:53 +0000
257@@ -80,7 +80,8 @@
258 {
259 ComposeState(XKBComposeTablePtr const& table);
260 void update_and_map(MirEvent& event);
261- xkb_keysym_t update_state(xkb_keysym_t mapped_key, MirKeyboardAction action);
262+ xkb_keysym_t update_state(xkb_keysym_t mapped_key, MirKeyboardAction action, std::string& text);
263+ private:
264 XKBComposeStatePtr state;
265 std::unordered_set<xkb_keysym_t> consumed_keys;
266 mir::optional_value<std::tuple<xkb_keysym_t,xkb_keysym_t>> last_composed_key;
267@@ -92,7 +93,7 @@
268 void set_key_state(std::vector<uint32_t> const& key_state);
269
270 bool update_and_map(MirEvent& event, ComposeState* compose_state);
271- xkb_keysym_t update_state(uint32_t scan_code, MirKeyboardAction direction, ComposeState* compose_state);
272+ xkb_keysym_t update_state(uint32_t scan_code, MirKeyboardAction direction, ComposeState* compose_state, std::string& text);
273 MirInputEventModifiers modifiers() const;
274 private:
275 void press_modifier(MirInputEventModifiers mod);
276
277=== modified file 'tests/acceptance-tests/test_client_input.cpp'
278--- tests/acceptance-tests/test_client_input.cpp 2017-02-15 07:38:33 +0000
279+++ tests/acceptance-tests/test_client_input.cpp 2017-02-16 10:52:53 +0000
280@@ -1002,6 +1002,43 @@
281 mir_input_config_release(config);
282 }
283
284+TEST_F(TestClientInput, key_event_contains_text_to_append)
285+{
286+ Client a_client(new_connection(), first);
287+
288+ EXPECT_CALL(a_client, handle_input(mt::KeyWithText("x")))
289+ .WillOnce(mt::WakeUp(&a_client.all_events_received));
290+
291+ fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_X));
292+ a_client.all_events_received.wait_for(10s);
293+}
294+
295+TEST_F(TestClientInput, key_event_text_applies_shift_modifiers)
296+{
297+ Client a_client(new_connection(), first);
298+
299+ EXPECT_CALL(a_client, handle_input(AllOf(mt::KeyWithText(""), mt::KeyOfSymbol(XKB_KEY_Shift_L))));
300+ EXPECT_CALL(a_client, handle_input(mt::KeyWithText("W")))
301+ .WillOnce(mt::WakeUp(&a_client.all_events_received));
302+
303+ fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_LEFTSHIFT));
304+ fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_W));
305+ a_client.all_events_received.wait_for(10s);
306+}
307+
308+TEST_F(TestClientInput, on_ctrl_c_key_event_text_is_end_of_text)
309+{
310+ Client a_client(new_connection(), first);
311+
312+ EXPECT_CALL(a_client, handle_input(AllOf(mt::KeyWithText(""), mt::KeyOfSymbol(XKB_KEY_Control_R))));
313+ EXPECT_CALL(a_client, handle_input(mt::KeyWithText("\003")))
314+ .WillOnce(mt::WakeUp(&a_client.all_events_received));
315+
316+ fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_RIGHTCTRL));
317+ fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_C));
318+ a_client.all_events_received.wait_for(10s);
319+}
320+
321 TEST_F(TestClientInput, num_lock_is_off_on_startup)
322 {
323 Client a_client(new_connection(), first);
324
325=== modified file 'tests/unit-tests/client/input/test_xkb_mapper.cpp'
326--- tests/unit-tests/client/input/test_xkb_mapper.cpp 2017-01-18 02:29:37 +0000
327+++ tests/unit-tests/client/input/test_xkb_mapper.cpp 2017-02-16 10:52:53 +0000
328@@ -438,3 +438,64 @@
329 EXPECT_EQ(XKB_KEY_u, map_key(local_mapper, keyboard, mir_keyboard_action_down, KEY_U));
330 EXPECT_EQ(XKB_KEY_u, map_key(local_mapper, keyboard, mir_keyboard_action_up, KEY_U));
331 }
332+
333+namespace
334+{
335+struct XKBMapperWithUsKeymap : XKBMapper
336+{
337+ MirInputDeviceId keyboard = MirInputDeviceId{0};
338+ XKBMapperWithUsKeymap()
339+ {
340+ mapper.set_keymap_for_all_devices(mi::Keymap{"pc105", "us", "intl",""});
341+ }
342+};
343+}
344+
345+TEST_F(XKBMapperWithUsKeymap, key_event_contains_text_to_append)
346+{
347+ EXPECT_CALL(*this, mapped_event(mt::KeyWithText("u")));
348+ EXPECT_CALL(*this, mapped_event(mt::KeyWithText("")));
349+
350+ map_event(keyboard, mir_keyboard_action_down, KEY_U);
351+ map_event(keyboard, mir_keyboard_action_up, KEY_U);
352+}
353+
354+TEST_F(XKBMapperWithUsKeymap, key_event_text_applies_shift_modifiers)
355+{
356+ EXPECT_CALL(*this, mapped_event(AllOf(mt::KeyWithText(""), mt::KeyOfSymbol(XKB_KEY_Shift_L))));
357+ EXPECT_CALL(*this, mapped_event(mt::KeyWithText("U")));
358+ EXPECT_CALL(*this, mapped_event(AllOf(mt::KeyWithText(""), mt::KeyOfSymbol(XKB_KEY_U))));
359+
360+ map_event(keyboard, mir_keyboard_action_down, KEY_LEFTSHIFT);
361+ map_event(keyboard, mir_keyboard_action_down, KEY_U);
362+ map_event(keyboard, mir_keyboard_action_up, KEY_U);
363+}
364+
365+TEST_F(XKBMapperWithUsKeymap, on_ctrl_c_key_event_text_is_u0003)
366+{
367+ EXPECT_CALL(*this, mapped_event(AllOf(mt::KeyWithText(""), mt::KeyOfSymbol(XKB_KEY_Control_R))));
368+ EXPECT_CALL(*this, mapped_event(AllOf(mt::KeyWithText("\003"), mt::KeyOfSymbol(XKB_KEY_c))));
369+ EXPECT_CALL(*this, mapped_event(AllOf(mt::KeyWithText(""), mt::KeyOfSymbol(XKB_KEY_c))));
370+
371+ map_event(keyboard, mir_keyboard_action_down, KEY_RIGHTCTRL);
372+ map_event(keyboard, mir_keyboard_action_down, KEY_C);
373+ map_event(keyboard, mir_keyboard_action_up, KEY_C);
374+}
375+
376+TEST_F(XKBMapperWithUsKeymap, compose_key_sequence_contains_text_on_key_down)
377+{
378+ InSequence seq;
379+ EXPECT_CALL(*this, mapped_event(AllOf(mt::KeyWithText(""),mt::KeyOfSymbol(XKB_KEY_Shift_R))));
380+ EXPECT_CALL(*this, mapped_event(AllOf(mt::KeyWithText(""),mt::KeyOfSymbol(XKB_KEY_NoSymbol))));
381+ EXPECT_CALL(*this, mapped_event(AllOf(mt::KeyWithText(""),mt::KeyOfSymbol(XKB_KEY_NoSymbol))));
382+ EXPECT_CALL(*this, mapped_event(AllOf(mt::KeyWithText(""),mt::KeyOfSymbol(XKB_KEY_Shift_R))));
383+ EXPECT_CALL(*this, mapped_event(AllOf(mt::KeyWithText("ΓΌ"),mt::KeyOfSymbol(XKB_KEY_udiaeresis))));
384+ EXPECT_CALL(*this, mapped_event(AllOf(mt::KeyWithText(""),mt::KeyOfSymbol(XKB_KEY_udiaeresis))));
385+
386+ map_event(keyboard, mir_keyboard_action_down, KEY_RIGHTSHIFT);
387+ map_event(keyboard, mir_keyboard_action_down, KEY_APOSTROPHE);
388+ map_event(keyboard, mir_keyboard_action_up, KEY_APOSTROPHE);
389+ map_event(keyboard, mir_keyboard_action_up, KEY_RIGHTSHIFT);
390+ map_event(keyboard, mir_keyboard_action_down, KEY_U);
391+ map_event(keyboard, mir_keyboard_action_up, KEY_U);
392+}

Subscribers

People subscribed via source and target branches