Flutter Engine
The Flutter Engine
keyboard.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "flutter/shell/platform/fuchsia/flutter/keyboard.h"
6
7#include <fuchsia/input/cpp/fidl.h>
8#include <fuchsia/ui/input/cpp/fidl.h>
9#include <fuchsia/ui/input3/cpp/fidl.h>
10
11#include <iostream>
12
13namespace flutter_runner {
14
16using fuchsia::ui::input::kModifierCapsLock;
17using fuchsia::ui::input::kModifierLeftAlt;
18using fuchsia::ui::input::kModifierLeftControl;
19using fuchsia::ui::input::kModifierLeftShift;
20using fuchsia::ui::input::kModifierNone;
21using fuchsia::ui::input::kModifierRightAlt;
22using fuchsia::ui::input::kModifierRightControl;
23using fuchsia::ui::input::kModifierRightShift;
24using fuchsia::ui::input3::KeyEvent;
26
27namespace {
28
29// A simple keymap from a QWERTY keyboard to code points. A value 0 means no
30// code point has been assigned for the respective keypress. Column 0 is the
31// code point without a level modifier active, and Column 1 is the code point
32// with a level modifier (e.g. Shift key) active.
33static const uint32_t QWERTY_TO_CODE_POINTS[][2] = {
34 // 0x00
35 {},
36 {},
37 {},
38 {},
39 // 0x04,
40 {'a', 'A'},
41 {'b', 'B'},
42 {'c', 'C'},
43 {'d', 'D'},
44 // 0x08
45 {'e', 'E'},
46 {'f', 'F'},
47 {'g', 'G'},
48 {'h', 'H'},
49 // 0x0c
50 {'i', 'I'},
51 {'j', 'J'},
52 {'k', 'K'},
53 {'l', 'L'},
54 // 0x10
55 {'m', 'M'},
56 {'n', 'N'},
57 {'o', 'O'},
58 {'p', 'P'},
59 // 0x14
60 {'q', 'Q'},
61 {'r', 'R'},
62 {'s', 'S'},
63 {'t', 'T'},
64 // 0x18
65 {'u', 'U'},
66 {'v', 'V'},
67 {'w', 'W'},
68 {'x', 'X'},
69 // 0x1c
70 {'y', 'Y'},
71 {'z', 'Z'},
72 {'1', '!'},
73 {'2', '@'},
74 // 0x20
75 {'3', '#'},
76 {'4', '$'},
77 {'5', '%'},
78 {'6', '^'},
79 // 0x24
80 {'7', '&'},
81 {'8', '*'},
82 {'9', '('},
83 {'0', ')'},
84 // 0x28
85 {},
86 {},
87 {},
88 {},
89 // 0x2c
90 {' ', ' '},
91 {'-', '_'},
92 {'=', '+'},
93 {'[', '{'},
94 // 0x30
95 {']', '}'},
96 {'\\', '|'},
97 {},
98 {';', ':'},
99 // 0x34
100 {'\'', '"'},
101 {'`', '~'},
102 {',', '<'},
103 {'.', '>'},
104 // 0x38
105 {'/', '?'},
106 {},
107 {},
108 {},
109 // 0x3c
110 {},
111 {},
112 {},
113 {},
114 // 0x40
115 {},
116 {},
117 {},
118 {},
119 // 0x44
120 {},
121 {},
122 {},
123 {},
124 // 0x48
125 {},
126 {},
127 {},
128 {},
129 // 0x4c
130 {},
131 {},
132 {},
133 {},
134 // 0x50
135 {},
136 {},
137 {},
138 {},
139 // 0x54
140 {'/', 0},
141 {'*', 0},
142 {'-', 0},
143 {'+', 0},
144 // 0x58
145 {},
146 {'1', 0},
147 {'2', 0},
148 {'3', 0},
149 // 0x5c
150 {'4', 0},
151 {'5', 0},
152 {'6', 0},
153 {'7', 0},
154 // 0x60
155 {'8', 0},
156 {'9', 0},
157 {'0', 0},
158 {'.', 0},
159};
160
161} // namespace
162
164 : any_events_received_(false),
165 stateful_caps_lock_(false),
166 left_shift_(false),
167 right_shift_(false),
168 left_alt_(false),
169 right_alt_(false),
170 left_ctrl_(false),
171 right_ctrl_(false),
172 last_event_() {}
173
175 if (!event.has_type()) {
176 return false;
177 }
178 if (!event.has_key() && !event.has_key_meaning()) {
179 return false;
180 }
181 // Check if the time sequence of the events is correct.
182 last_event_ = std::move(event);
183 any_events_received_ = true;
184
185 if (!event.has_key()) {
186 // The key only has key meaning. Key meaning currently can not
187 // update the modifier state, so we just short-circuit the table
188 // below.
189 return true;
190 }
191
192 const Key& key = last_event_.key();
193 const KeyEventType& event_type = last_event_.type();
194 switch (event_type) {
195 // For modifier keys, a SYNC is the same as a press.
196 case KeyEventType::SYNC:
197 switch (key) {
198 case Key::CAPS_LOCK:
199 stateful_caps_lock_ = true;
200 break;
201 case Key::LEFT_ALT:
202 left_alt_ = true;
203 break;
204 case Key::LEFT_CTRL:
205 left_ctrl_ = true;
206 break;
207 case Key::LEFT_SHIFT:
208 left_shift_ = true;
209 break;
210 case Key::RIGHT_ALT:
211 right_alt_ = true;
212 break;
213 case Key::RIGHT_CTRL:
214 right_ctrl_ = true;
215 break;
216 case Key::RIGHT_SHIFT:
217 right_shift_ = true;
218 break;
219 default:
220 // no-op
221 break;
222 }
223 break;
224 case KeyEventType::PRESSED:
225 switch (key) {
226 case Key::CAPS_LOCK:
227 stateful_caps_lock_ = !stateful_caps_lock_;
228 break;
229 case Key::LEFT_ALT:
230 left_alt_ = true;
231 break;
232 case Key::LEFT_CTRL:
233 left_ctrl_ = true;
234 break;
235 case Key::LEFT_SHIFT:
236 left_shift_ = true;
237 break;
238 case Key::RIGHT_ALT:
239 right_alt_ = true;
240 break;
241 case Key::RIGHT_CTRL:
242 right_ctrl_ = true;
243 break;
244 case Key::RIGHT_SHIFT:
245 right_shift_ = true;
246 break;
247 default:
248 // No-op
249 break;
250 }
251 break;
252 case KeyEventType::RELEASED:
253 switch (key) {
254 case Key::CAPS_LOCK:
255 // No-op.
256 break;
257 case Key::LEFT_ALT:
258 left_alt_ = false;
259 break;
260 case Key::LEFT_CTRL:
261 left_ctrl_ = false;
262 break;
263 case Key::LEFT_SHIFT:
264 left_shift_ = false;
265 break;
266 case Key::RIGHT_ALT:
267 right_alt_ = false;
268 break;
269 case Key::RIGHT_CTRL:
270 right_ctrl_ = false;
271 break;
272 case Key::RIGHT_SHIFT:
273 right_shift_ = false;
274 break;
275 default:
276 // No-op
277 break;
278 }
279 break;
280 case KeyEventType::CANCEL:
281 // No-op?
282 break;
283 default:
284 // No-op
285 break;
286 }
287 return true;
288}
289
290bool Keyboard::IsShift() {
291 return left_shift_ | right_shift_ | stateful_caps_lock_;
292}
293
294bool Keyboard::IsKeys() {
295 return LastHIDUsagePage() == 0x7;
296}
297
299 return kModifierNone + (kModifierLeftShift * left_shift_) +
300 (kModifierLeftAlt * left_alt_) + (kModifierLeftControl * left_ctrl_) +
301 (kModifierRightShift * right_shift_) +
302 (kModifierRightAlt * right_alt_) +
303 (kModifierRightControl * right_ctrl_) +
304 (kModifierCapsLock * stateful_caps_lock_);
305}
306
308 // If the key has a meaning, and if the meaning is a code point, always have
309 // that code point take precedence over any other keymap.
310 if (last_event_.has_key_meaning()) {
311 const auto& key_meaning = last_event_.key_meaning();
312 if (key_meaning.is_codepoint()) {
313 return key_meaning.codepoint();
314 }
315 }
316 static const int qwerty_map_size =
317 sizeof(QWERTY_TO_CODE_POINTS) / sizeof(QWERTY_TO_CODE_POINTS[0]);
318 if (!IsKeys()) {
319 return 0;
320 }
321 const auto usage = LastHIDUsageID();
322 if (usage < qwerty_map_size) {
323 return QWERTY_TO_CODE_POINTS[usage][IsShift() & 1];
324 }
325 // Any other keys don't have a code point.
326 return 0;
327}
328
329uint32_t Keyboard::GetLastKey() {
330 // For logical key determination, the physical key does not matter as long
331 // as code point is set.
332 // https://github.com/flutter/flutter/blob/570e39d38b799e91abe4f73f120ce494049c4ff0/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart#L71
333 // It is not quite clear what happens to the physical key, though:
334 // https://github.com/flutter/flutter/blob/570e39d38b799e91abe4f73f120ce494049c4ff0/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart#L88
335 if (!last_event_.has_key()) {
336 return 0;
337 }
338 return static_cast<uint32_t>(last_event_.key());
339}
340
342 return GetLastKey() & 0xFFFFFFFF;
343}
344
346 return GetLastKey() & 0xFFFF;
347}
348
350 return (GetLastKey() >> 16) & 0xFFFF;
351}
352
353} // namespace flutter_runner
TArray< uint32_t > Key
ax::mojom::Event event_type
uint16_t LastHIDUsagePage()
Definition: keyboard.cc:349
uint32_t LastCodePoint()
Definition: keyboard.cc:307
uint16_t LastHIDUsageID()
Definition: keyboard.cc:345
bool ConsumeEvent(fuchsia::ui::input3::KeyEvent event)
Definition: keyboard.cc:174
FlKeyEvent * event
KeyEventType
Definition: key_data.h:22
static void usage(char *argv0)