Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
keyboard_key_embedder_handler_unittests.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
6
7#include <string>
8#include <vector>
9
15#include "gtest/gtest.h"
16
17namespace flutter {
18namespace testing {
19
20namespace {
21
22constexpr SHORT kStateMaskToggled = 0x01;
23constexpr SHORT kStateMaskPressed = 0x80;
24
25class TestFlutterKeyEvent : public FlutterKeyEvent {
26 public:
27 TestFlutterKeyEvent(const FlutterKeyEvent& src,
29 void* user_data)
30 : character_str(src.character), callback(callback), user_data(user_data) {
31 struct_size = src.struct_size;
32 timestamp = src.timestamp;
33 type = src.type;
34 physical = src.physical;
35 logical = src.logical;
36 character = character_str.c_str();
37 synthesized = src.synthesized;
38 }
39
40 TestFlutterKeyEvent(TestFlutterKeyEvent&& source)
41 : FlutterKeyEvent(source),
42 callback(std::move(source.callback)),
43 user_data(source.user_data) {
44 character = character_str.c_str();
45 }
46
48 void* user_data;
49
50 private:
51 const std::string character_str;
52};
53
54class TestKeystate {
55 public:
56 void Set(int virtual_key, bool pressed, bool toggled_on = false) {
57 state_[virtual_key] = (pressed ? kStateMaskPressed : 0) |
58 (toggled_on ? kStateMaskToggled : 0);
59 }
60
61 SHORT Get(int virtual_key) { return state_[virtual_key]; }
62
64 return [this](int virtual_key) { return Get(virtual_key); };
65 }
66
67 private:
68 std::map<int, SHORT> state_;
69};
70
71UINT DefaultMapVkToScan(UINT virtual_key, bool extended) {
72 return MapVirtualKey(virtual_key,
73 extended ? MAPVK_VK_TO_VSC_EX : MAPVK_VK_TO_VSC);
74}
75
76constexpr uint64_t kScanCodeKeyA = 0x1e;
77constexpr uint64_t kScanCodeAltLeft = 0x38;
78constexpr uint64_t kScanCodeNumpad1 = 0x4f;
79constexpr uint64_t kScanCodeNumLock = 0x45;
80constexpr uint64_t kScanCodeControl = 0x1d;
81constexpr uint64_t kScanCodeShiftLeft = 0x2a;
82constexpr uint64_t kScanCodeShiftRight = 0x36;
83
84constexpr uint64_t kVirtualKeyA = 0x41;
85
86} // namespace
87
88using namespace ::flutter::testing::keycodes;
89
90TEST(KeyboardKeyEmbedderHandlerTest, ConvertChar32ToUtf8) {
91 std::string result;
92
93 result = ConvertChar32ToUtf8(0x0024);
94 EXPECT_EQ(result.length(), 1);
95 EXPECT_EQ(result[0], '\x24');
96
97 result = ConvertChar32ToUtf8(0x00A2);
98 EXPECT_EQ(result.length(), 2);
99 EXPECT_EQ(result[0], '\xC2');
100 EXPECT_EQ(result[1], '\xA2');
101
102 result = ConvertChar32ToUtf8(0x0939);
103 EXPECT_EQ(result.length(), 3);
104 EXPECT_EQ(result[0], '\xE0');
105 EXPECT_EQ(result[1], '\xA4');
106 EXPECT_EQ(result[2], '\xB9');
107
108 result = ConvertChar32ToUtf8(0x10348);
109 EXPECT_EQ(result.length(), 4);
110 EXPECT_EQ(result[0], '\xF0');
111 EXPECT_EQ(result[1], '\x90');
112 EXPECT_EQ(result[2], '\x8D');
113 EXPECT_EQ(result[3], '\x88');
114}
115
116// Test the most basic key events.
117//
118// Press, hold, and release key A on an US keyboard.
119TEST(KeyboardKeyEmbedderHandlerTest, BasicKeyPressingAndHolding) {
120 TestKeystate key_state;
121 std::vector<TestFlutterKeyEvent> results;
122 TestFlutterKeyEvent* event;
123 bool last_handled = false;
124
125 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
126 std::make_unique<KeyboardKeyEmbedderHandler>(
127 [&results](const FlutterKeyEvent& event,
129 results.emplace_back(event, callback, user_data);
130 },
131 key_state.Getter(), DefaultMapVkToScan);
132
133 // Press KeyA.
134 handler->KeyboardHook(
135 kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 'a', false, false,
136 [&last_handled](bool handled) { last_handled = handled; });
137 EXPECT_EQ(last_handled, false);
138 EXPECT_EQ(results.size(), 1);
139 event = &results[0];
140 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
141 EXPECT_EQ(event->physical, kPhysicalKeyA);
142 EXPECT_EQ(event->logical, kLogicalKeyA);
143 EXPECT_STREQ(event->character, "a");
144 EXPECT_EQ(event->synthesized, false);
145
146 event->callback(true, event->user_data);
147 EXPECT_EQ(last_handled, true);
148 results.clear();
149 key_state.Set(kVirtualKeyA, true);
150
151 // Hold KeyA.
152 handler->KeyboardHook(
153 kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 'a', false, true,
154 [&last_handled](bool handled) { last_handled = handled; });
155 EXPECT_EQ(last_handled, true);
156 EXPECT_EQ(results.size(), 1);
157 event = &results[0];
158 EXPECT_EQ(event->type, kFlutterKeyEventTypeRepeat);
159 EXPECT_EQ(event->physical, kPhysicalKeyA);
160 EXPECT_EQ(event->logical, kLogicalKeyA);
161 EXPECT_STREQ(event->character, "a");
162 EXPECT_EQ(event->synthesized, false);
163
164 event->callback(false, event->user_data);
165 EXPECT_EQ(last_handled, false);
166 results.clear();
167
168 // Release KeyA.
169 handler->KeyboardHook(
170 kVirtualKeyA, kScanCodeKeyA, WM_KEYUP, 0, false, true,
171 [&last_handled](bool handled) { last_handled = handled; });
172 EXPECT_EQ(results.size(), 1);
173 event = &results[0];
174 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
175 EXPECT_EQ(event->physical, kPhysicalKeyA);
176 EXPECT_EQ(event->logical, kLogicalKeyA);
177 EXPECT_STREQ(event->character, "");
178 EXPECT_EQ(event->synthesized, false);
179 event->callback(false, event->user_data);
180}
181
182// Press numpad 1, toggle NumLock, and release numpad 1 on an US
183// keyboard.
184//
185// This is special because the virtual key for numpad 1 will
186// change in this process.
187TEST(KeyboardKeyEmbedderHandlerTest, ToggleNumLockDuringNumpadPress) {
188 TestKeystate key_state;
189 std::vector<TestFlutterKeyEvent> results;
190 TestFlutterKeyEvent* event;
191 bool last_handled = false;
192
193 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
194 std::make_unique<KeyboardKeyEmbedderHandler>(
195 [&results](const FlutterKeyEvent& event,
197 results.emplace_back(event, callback, user_data);
198 },
199 key_state.Getter(), DefaultMapVkToScan);
200
201 // Press NumPad1.
202 key_state.Set(VK_NUMPAD1, true);
203 handler->KeyboardHook(
204 VK_NUMPAD1, kScanCodeNumpad1, WM_KEYDOWN, 0, false, false,
205 [&last_handled](bool handled) { last_handled = handled; });
206 EXPECT_EQ(results.size(), 1);
207 event = &results[0];
208 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
209 EXPECT_EQ(event->physical, kPhysicalNumpad1);
210 EXPECT_EQ(event->logical, kLogicalNumpad1);
211 // EXPECT_STREQ(event->character, "1"); // TODO
212 EXPECT_EQ(event->synthesized, false);
213 results.clear();
214
215 // Press NumLock.
216 key_state.Set(VK_NUMLOCK, true, true);
217 handler->KeyboardHook(
218 VK_NUMLOCK, kScanCodeNumLock, WM_KEYDOWN, 0, true, false,
219 [&last_handled](bool handled) { last_handled = handled; });
220 EXPECT_EQ(results.size(), 1);
221 event = &results[0];
222 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
223 EXPECT_EQ(event->physical, kPhysicalNumLock);
224 EXPECT_EQ(event->logical, kLogicalNumLock);
225 EXPECT_STREQ(event->character, "");
226 EXPECT_EQ(event->synthesized, false);
227 results.clear();
228
229 // Release NumLock.
230 key_state.Set(VK_NUMLOCK, false, true);
231 handler->KeyboardHook(
232 VK_NUMLOCK, kScanCodeNumLock, WM_KEYUP, 0, true, true,
233 [&last_handled](bool handled) { last_handled = handled; });
234 EXPECT_EQ(results.size(), 1);
235 event = &results[0];
236 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
237 EXPECT_EQ(event->physical, kPhysicalNumLock);
238 EXPECT_EQ(event->logical, kLogicalNumLock);
239 EXPECT_STREQ(event->character, "");
240 EXPECT_EQ(event->synthesized, false);
241 results.clear();
242
243 // Release NumPad1. (The logical key is now NumpadEnd)
244 handler->KeyboardHook(
245 VK_END, kScanCodeNumpad1, WM_KEYUP, 0, false, true,
246 [&last_handled](bool handled) { last_handled = handled; });
247 EXPECT_EQ(results.size(), 1);
248 event = &results[0];
249 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
250 EXPECT_EQ(event->physical, kPhysicalNumpad1);
251 EXPECT_EQ(event->logical, kLogicalNumpad1);
252 EXPECT_STREQ(event->character, "");
253 EXPECT_EQ(event->synthesized, false);
254 results.clear();
255}
256
257// Key presses that trigger IME should be ignored by this API (and handled by
258// compose API).
259TEST(KeyboardKeyEmbedderHandlerTest, ImeEventsAreIgnored) {
260 TestKeystate key_state;
261 std::vector<TestFlutterKeyEvent> results;
262 TestFlutterKeyEvent* event;
263 bool last_handled = false;
264
265 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
266 std::make_unique<KeyboardKeyEmbedderHandler>(
267 [&results](const FlutterKeyEvent& event,
269 results.emplace_back(event, callback, user_data);
270 },
271 key_state.Getter(), DefaultMapVkToScan);
272
273 // Press A in an IME
274 last_handled = false;
275 handler->KeyboardHook(
276 VK_PROCESSKEY, kScanCodeKeyA, WM_KEYDOWN, 0, true, false,
277 [&last_handled](bool handled) { last_handled = handled; });
278 EXPECT_EQ(last_handled, true);
279
280 // The A key down should yield an empty event.
281 EXPECT_EQ(results.size(), 1);
282 event = &results[0];
283 EXPECT_EQ(event->physical, 0);
284 EXPECT_EQ(event->logical, 0);
285 EXPECT_EQ(event->callback, nullptr);
286 results.clear();
287
288 // Release A in an IME
289 last_handled = false;
290 handler->KeyboardHook(
291 // The up event for an IME press has a normal virtual key.
292 kVirtualKeyA, kScanCodeKeyA, WM_KEYUP, 0, true, true,
293 [&last_handled](bool handled) { last_handled = handled; });
294 EXPECT_EQ(last_handled, true);
295
296 // The A key up should yield an empty event.
297 EXPECT_EQ(results.size(), 1);
298 event = &results[0];
299 EXPECT_EQ(event->physical, 0);
300 EXPECT_EQ(event->logical, 0);
301 EXPECT_EQ(event->callback, nullptr);
302 results.clear();
303
304 // Press A out of an IME
305 key_state.Set(kVirtualKeyA, true);
306 last_handled = false;
307 handler->KeyboardHook(
308 kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 0, true, false,
309 [&last_handled](bool handled) { last_handled = handled; });
310 // Not decided yet
311 EXPECT_EQ(last_handled, false);
312 EXPECT_EQ(results.size(), 1);
313 event = &results[0];
314 event->callback(true, event->user_data);
315 EXPECT_EQ(last_handled, true);
316 results.clear();
317
318 last_handled = false;
319 key_state.Set(kVirtualKeyA, false);
320 handler->KeyboardHook(
321 kVirtualKeyA, kScanCodeKeyA, WM_KEYUP, 0, true, false,
322 [&last_handled](bool handled) { last_handled = handled; });
323 EXPECT_EQ(last_handled, false);
324 EXPECT_EQ(results.size(), 1);
325 event = &results[0];
326 event->callback(true, event->user_data);
327 EXPECT_EQ(last_handled, true);
328}
329
330// Test if modifier keys that are told apart by the extended bit can be
331// identified. (Their physical keys must be searched with the extended bit
332// considered.)
333TEST(KeyboardKeyEmbedderHandlerTest, ModifierKeysByExtendedBit) {
334 TestKeystate key_state;
335 std::vector<TestFlutterKeyEvent> results;
336 TestFlutterKeyEvent* event;
337 bool last_handled = false;
338
339 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
340 std::make_unique<KeyboardKeyEmbedderHandler>(
341 [&results](const FlutterKeyEvent& event,
343 results.emplace_back(event, callback, user_data);
344 },
345 key_state.Getter(), DefaultMapVkToScan);
346
347 // Press Ctrl left.
348 last_handled = false;
349 key_state.Set(VK_LCONTROL, true);
350 handler->KeyboardHook(
351 VK_LCONTROL, kScanCodeControl, WM_KEYDOWN, 0, false, false,
352 [&last_handled](bool handled) { last_handled = handled; });
353 EXPECT_EQ(last_handled, false);
354 EXPECT_EQ(results.size(), 1);
355 event = &results[0];
356 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
357 EXPECT_EQ(event->physical, kPhysicalControlLeft);
358 EXPECT_EQ(event->logical, kLogicalControlLeft);
359 EXPECT_STREQ(event->character, "");
360 EXPECT_EQ(event->synthesized, false);
361
362 event->callback(true, event->user_data);
363 EXPECT_EQ(last_handled, true);
364 results.clear();
365
366 // Press Ctrl right.
367 last_handled = false;
368 key_state.Set(VK_RCONTROL, true);
369 handler->KeyboardHook(
370 VK_RCONTROL, kScanCodeControl, WM_KEYDOWN, 0, true, true,
371 [&last_handled](bool handled) { last_handled = handled; });
372 EXPECT_EQ(last_handled, false);
373 EXPECT_EQ(results.size(), 1);
374 event = &results[0];
375 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
376 EXPECT_EQ(event->physical, kPhysicalControlRight);
377 EXPECT_EQ(event->logical, kLogicalControlRight);
378 EXPECT_STREQ(event->character, "");
379 EXPECT_EQ(event->synthesized, false);
380
381 event->callback(true, event->user_data);
382 EXPECT_EQ(last_handled, true);
383 results.clear();
384
385 // Release Ctrl left.
386 last_handled = false;
387 key_state.Set(VK_LCONTROL, false);
388 handler->KeyboardHook(
389 VK_LCONTROL, kScanCodeControl, WM_KEYUP, 0, false, true,
390 [&last_handled](bool handled) { last_handled = handled; });
391 EXPECT_EQ(last_handled, false);
392 EXPECT_EQ(results.size(), 1);
393 event = &results[0];
394 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
395 EXPECT_EQ(event->physical, kPhysicalControlLeft);
396 EXPECT_EQ(event->logical, kLogicalControlLeft);
397 EXPECT_STREQ(event->character, "");
398 EXPECT_EQ(event->synthesized, false);
399
400 event->callback(true, event->user_data);
401 EXPECT_EQ(last_handled, true);
402 results.clear();
403
404 // Release Ctrl right.
405 last_handled = false;
406 key_state.Set(VK_RCONTROL, false);
407 handler->KeyboardHook(
408 VK_RCONTROL, kScanCodeControl, WM_KEYUP, 0, true, true,
409 [&last_handled](bool handled) { last_handled = handled; });
410 EXPECT_EQ(last_handled, false);
411 EXPECT_EQ(results.size(), 1);
412 event = &results[0];
413 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
414 EXPECT_EQ(event->physical, kPhysicalControlRight);
415 EXPECT_EQ(event->logical, kLogicalControlRight);
416 EXPECT_STREQ(event->character, "");
417 EXPECT_EQ(event->synthesized, false);
418
419 event->callback(true, event->user_data);
420 EXPECT_EQ(last_handled, true);
421 results.clear();
422}
423
424// Test if modifier keys that are told apart by the virtual key
425// can be identified.
426TEST(KeyboardKeyEmbedderHandlerTest, ModifierKeysByVirtualKey) {
427 TestKeystate key_state;
428 std::vector<TestFlutterKeyEvent> results;
429 TestFlutterKeyEvent* event;
430 bool last_handled = false;
431
432 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
433 std::make_unique<KeyboardKeyEmbedderHandler>(
434 [&results](const FlutterKeyEvent& event,
436 results.emplace_back(event, callback, user_data);
437 },
438 key_state.Getter(), DefaultMapVkToScan);
439
440 // Press Shift left.
441 last_handled = false;
442 key_state.Set(VK_LSHIFT, true);
443 handler->KeyboardHook(
444 VK_LSHIFT, kScanCodeShiftLeft, WM_KEYDOWN, 0, false, false,
445 [&last_handled](bool handled) { last_handled = handled; });
446 EXPECT_EQ(last_handled, false);
447 EXPECT_EQ(results.size(), 1);
448 event = &results[0];
449 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
450 EXPECT_EQ(event->physical, kPhysicalShiftLeft);
451 EXPECT_EQ(event->logical, kLogicalShiftLeft);
452 EXPECT_STREQ(event->character, "");
453 EXPECT_EQ(event->synthesized, false);
454
455 event->callback(true, event->user_data);
456 EXPECT_EQ(last_handled, true);
457 results.clear();
458
459 // Press Shift right.
460 last_handled = false;
461 key_state.Set(VK_RSHIFT, true);
462 handler->KeyboardHook(
463 VK_RSHIFT, kScanCodeShiftRight, WM_KEYDOWN, 0, false, false,
464 [&last_handled](bool handled) { last_handled = handled; });
465 EXPECT_EQ(last_handled, false);
466 EXPECT_EQ(results.size(), 1);
467 event = &results[0];
468 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
469 EXPECT_EQ(event->physical, kPhysicalShiftRight);
470 EXPECT_EQ(event->logical, kLogicalShiftRight);
471 EXPECT_STREQ(event->character, "");
472 EXPECT_EQ(event->synthesized, false);
473
474 event->callback(true, event->user_data);
475 EXPECT_EQ(last_handled, true);
476 results.clear();
477
478 // Release Shift left.
479 last_handled = false;
480 key_state.Set(VK_LSHIFT, false);
481 handler->KeyboardHook(
482 VK_LSHIFT, kScanCodeShiftLeft, WM_KEYUP, 0, false, true,
483 [&last_handled](bool handled) { last_handled = handled; });
484 EXPECT_EQ(last_handled, false);
485 EXPECT_EQ(results.size(), 1);
486 event = &results[0];
487 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
488 EXPECT_EQ(event->physical, kPhysicalShiftLeft);
489 EXPECT_EQ(event->logical, kLogicalShiftLeft);
490 EXPECT_STREQ(event->character, "");
491 EXPECT_EQ(event->synthesized, false);
492
493 event->callback(true, event->user_data);
494 EXPECT_EQ(last_handled, true);
495 results.clear();
496
497 // Release Shift right.
498 last_handled = false;
499 key_state.Set(VK_RSHIFT, false);
500 handler->KeyboardHook(
501 VK_RSHIFT, kScanCodeShiftRight, WM_KEYUP, 0, false, true,
502 [&last_handled](bool handled) { last_handled = handled; });
503 EXPECT_EQ(last_handled, false);
504 EXPECT_EQ(results.size(), 1);
505 event = &results[0];
506 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
507 EXPECT_EQ(event->physical, kPhysicalShiftRight);
508 EXPECT_EQ(event->logical, kLogicalShiftRight);
509 EXPECT_STREQ(event->character, "");
510 EXPECT_EQ(event->synthesized, false);
511
512 event->callback(true, event->user_data);
513 EXPECT_EQ(last_handled, true);
514 results.clear();
515}
516
517// Test if modifiers left key down events are synthesized when left or right
518// keys are not pressed.
519TEST(KeyboardKeyEmbedderHandlerTest,
520 SynthesizeModifierLeftKeyDownWhenNotPressed) {
521 TestKeystate key_state;
522 std::vector<TestFlutterKeyEvent> results;
523 TestFlutterKeyEvent* event;
524 bool last_handled = false;
525
526 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
527 std::make_unique<KeyboardKeyEmbedderHandler>(
528 [&results](const FlutterKeyEvent& event,
530 results.emplace_back(event, callback, user_data);
531 },
532 key_state.Getter(), DefaultMapVkToScan);
533
534 // Should synthesize shift left key down event.
535 handler->SyncModifiersIfNeeded(kShift);
536 EXPECT_EQ(results.size(), 1);
537 event = &results[0];
538 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
539 EXPECT_EQ(event->physical, kPhysicalShiftLeft);
540 EXPECT_EQ(event->logical, kLogicalShiftLeft);
541 EXPECT_STREQ(event->character, "");
542 EXPECT_EQ(event->synthesized, true);
543 results.clear();
544
545 // Clear the pressing state.
546 handler->SyncModifiersIfNeeded(0);
547 results.clear();
548
549 // Should synthesize control left key down event.
550 handler->SyncModifiersIfNeeded(kControl);
551 EXPECT_EQ(results.size(), 1);
552 event = &results[0];
553 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
554 EXPECT_EQ(event->physical, kPhysicalControlLeft);
555 EXPECT_EQ(event->logical, kLogicalControlLeft);
556 EXPECT_STREQ(event->character, "");
557 EXPECT_EQ(event->synthesized, true);
558}
559
560// Test if modifiers left key down events are not synthesized when left or right
561// keys are pressed.
562TEST(KeyboardKeyEmbedderHandlerTest, DoNotSynthesizeModifierDownWhenPressed) {
563 TestKeystate key_state;
564 std::vector<TestFlutterKeyEvent> results;
565 TestFlutterKeyEvent* event;
566 bool last_handled = false;
567
568 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
569 std::make_unique<KeyboardKeyEmbedderHandler>(
570 [&results](const FlutterKeyEvent& event,
572 results.emplace_back(event, callback, user_data);
573 },
574 key_state.Getter(), DefaultMapVkToScan);
575
576 // Should not synthesize shift left key down event when shift left key
577 // is already pressed.
578 handler->KeyboardHook(
579 VK_LSHIFT, kScanCodeShiftLeft, WM_KEYDOWN, 0, false, true,
580 [&last_handled](bool handled) { last_handled = handled; });
581 results.clear();
582 handler->SyncModifiersIfNeeded(kShift);
583 EXPECT_EQ(results.size(), 0);
584
585 // Should not synthesize shift left key down event when shift right key
586 // is already pressed.
587 handler->KeyboardHook(
588 VK_RSHIFT, kScanCodeShiftRight, WM_KEYDOWN, 0, false, true,
589 [&last_handled](bool handled) { last_handled = handled; });
590 results.clear();
591 handler->SyncModifiersIfNeeded(kShift);
592 EXPECT_EQ(results.size(), 0);
593
594 // Should not synthesize control left key down event when control left key
595 // is already pressed.
596 handler->KeyboardHook(
597 VK_LCONTROL, kScanCodeControlLeft, WM_KEYDOWN, 0, false, true,
598 [&last_handled](bool handled) { last_handled = handled; });
599 results.clear();
600 handler->SyncModifiersIfNeeded(kControl);
601 EXPECT_EQ(results.size(), 0);
602
603 // Should not synthesize control left key down event when control right key
604 // is already pressed .
605 handler->KeyboardHook(
606 VK_RCONTROL, kScanCodeControlRight, WM_KEYDOWN, 0, true, true,
607 [&last_handled](bool handled) { last_handled = handled; });
608 results.clear();
609 handler->SyncModifiersIfNeeded(kControl);
610 EXPECT_EQ(results.size(), 0);
611}
612
613// Test if modifiers keys up events are synthesized when left or right keys
614// are pressed.
615TEST(KeyboardKeyEmbedderHandlerTest, SynthesizeModifierUpWhenPressed) {
616 TestKeystate key_state;
617 std::vector<TestFlutterKeyEvent> results;
618 TestFlutterKeyEvent* event;
619 bool last_handled = false;
620
621 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
622 std::make_unique<KeyboardKeyEmbedderHandler>(
623 [&results](const FlutterKeyEvent& event,
625 results.emplace_back(event, callback, user_data);
626 },
627 key_state.Getter(), DefaultMapVkToScan);
628
629 // Should synthesize shift left key up event when shift left key is
630 // already pressed and modifiers state is zero.
631 handler->KeyboardHook(
632 VK_LSHIFT, kScanCodeShiftLeft, WM_KEYDOWN, 0, false, true,
633 [&last_handled](bool handled) { last_handled = handled; });
634 results.clear();
635 handler->SyncModifiersIfNeeded(0);
636 EXPECT_EQ(results.size(), 1);
637 event = &results[0];
638 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
639 EXPECT_EQ(event->physical, kPhysicalShiftLeft);
640 EXPECT_EQ(event->logical, kLogicalShiftLeft);
641 EXPECT_STREQ(event->character, "");
642 EXPECT_EQ(event->synthesized, true);
643 results.clear();
644
645 // Should synthesize shift right key up event when shift right key is
646 // already pressed and modifiers state is zero.
647 handler->KeyboardHook(
648 VK_RSHIFT, kScanCodeShiftRight, WM_KEYDOWN, 0, false, true,
649 [&last_handled](bool handled) { last_handled = handled; });
650 results.clear();
651 handler->SyncModifiersIfNeeded(0);
652 EXPECT_EQ(results.size(), 1);
653 event = &results[0];
654 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
655 EXPECT_EQ(event->physical, kPhysicalShiftRight);
656 EXPECT_EQ(event->logical, kLogicalShiftRight);
657 EXPECT_STREQ(event->character, "");
658 EXPECT_EQ(event->synthesized, true);
659 results.clear();
660
661 // Should synthesize control left key up event when control left key is
662 // already pressed and modifiers state is zero.
663 handler->KeyboardHook(
664 VK_LCONTROL, kScanCodeControlLeft, WM_KEYDOWN, 0, false, true,
665 [&last_handled](bool handled) { last_handled = handled; });
666 results.clear();
667 handler->SyncModifiersIfNeeded(0);
668 EXPECT_EQ(results.size(), 1);
669 event = &results[0];
670 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
671 EXPECT_EQ(event->physical, kPhysicalControlLeft);
672 EXPECT_EQ(event->logical, kLogicalControlLeft);
673 EXPECT_STREQ(event->character, "");
674 EXPECT_EQ(event->synthesized, true);
675 results.clear();
676
677 // Should synthesize control right key up event when control right key is
678 // already pressed and modifiers state is zero.
679 handler->KeyboardHook(
680 VK_RCONTROL, kScanCodeControlRight, WM_KEYDOWN, 0, true, true,
681 [&last_handled](bool handled) { last_handled = handled; });
682 results.clear();
683 handler->SyncModifiersIfNeeded(0);
684 EXPECT_EQ(results.size(), 1);
685 event = &results[0];
686 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
687 EXPECT_EQ(event->physical, kPhysicalControlRight);
688 EXPECT_EQ(event->logical, kLogicalControlRight);
689 EXPECT_STREQ(event->character, "");
690 EXPECT_EQ(event->synthesized, true);
691 results.clear();
692}
693
694// Test if modifiers key up events are not synthesized when left or right
695// keys are not pressed.
696TEST(KeyboardKeyEmbedderHandlerTest, DoNotSynthesizeModifierUpWhenNotPressed) {
697 TestKeystate key_state;
698 std::vector<TestFlutterKeyEvent> results;
699 TestFlutterKeyEvent* event;
700 bool last_handled = false;
701
702 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
703 std::make_unique<KeyboardKeyEmbedderHandler>(
704 [&results](const FlutterKeyEvent& event,
706 results.emplace_back(event, callback, user_data);
707 },
708 key_state.Getter(), DefaultMapVkToScan);
709
710 // Should not synthesize up events when no modifier key is pressed
711 // in pressing state and modifiers state is zero.
712 handler->SyncModifiersIfNeeded(0);
713 EXPECT_EQ(results.size(), 0);
714}
715
716TEST(KeyboardKeyEmbedderHandlerTest, RepeatedDownIsIgnored) {
717 TestKeystate key_state;
718 std::vector<TestFlutterKeyEvent> results;
719 TestFlutterKeyEvent* event;
720 bool last_handled = false;
721
722 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
723 std::make_unique<KeyboardKeyEmbedderHandler>(
724 [&results](const FlutterKeyEvent& event,
726 results.emplace_back(event, callback, user_data);
727 },
728 key_state.Getter(), DefaultMapVkToScan);
729 last_handled = false;
730
731 // Press A (should yield a normal event)
732 handler->KeyboardHook(
733 kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 'a', false, false,
734 [&last_handled](bool handled) { last_handled = handled; });
735 EXPECT_EQ(last_handled, false);
736 EXPECT_EQ(results.size(), 1);
737 event = &results[0];
738 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
739 EXPECT_EQ(event->physical, kPhysicalKeyA);
740 EXPECT_EQ(event->logical, kLogicalKeyA);
741 EXPECT_STREQ(event->character, "a");
742 EXPECT_EQ(event->synthesized, false);
743
744 event->callback(true, event->user_data);
745 EXPECT_EQ(last_handled, true);
746 results.clear();
747
748 // KeyA's key up is missed.
749
750 // Press A again (should synthesize an up event followed by a new down).
751 last_handled = false;
752 handler->KeyboardHook(
753 kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 'a', false, false,
754 [&last_handled](bool handled) { last_handled = handled; });
755 EXPECT_EQ(last_handled, false);
756 ASSERT_EQ(results.size(), 2u);
757
758 event = &results[0];
759 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
760 EXPECT_EQ(event->physical, kPhysicalKeyA);
761 EXPECT_EQ(event->logical, kLogicalKeyA);
762 EXPECT_STREQ(event->character, "");
763 EXPECT_EQ(event->synthesized, true);
764 EXPECT_EQ(event->callback, nullptr);
765
766 event = &results[1];
767 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
768 EXPECT_EQ(event->physical, kPhysicalKeyA);
769 EXPECT_EQ(event->logical, kLogicalKeyA);
770 EXPECT_STREQ(event->character, "a");
771 EXPECT_EQ(event->synthesized, false);
772 event->callback(true, event->user_data);
773 EXPECT_EQ(last_handled, true);
774 results.clear();
775}
776
777TEST(KeyboardKeyEmbedderHandlerTest, AbruptRepeatIsConvertedToDown) {
778 TestKeystate key_state;
779 std::vector<TestFlutterKeyEvent> results;
780 TestFlutterKeyEvent* event;
781 bool last_handled = false;
782
783 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
784 std::make_unique<KeyboardKeyEmbedderHandler>(
785 [&results](const FlutterKeyEvent& event,
787 results.emplace_back(event, callback, user_data);
788 },
789 key_state.Getter(), DefaultMapVkToScan);
790 last_handled = false;
791
792 key_state.Set(kVirtualKeyA, true);
793
794 // Press A (with was_down true)
795 handler->KeyboardHook(
796 kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 'a', false, true,
797 [&last_handled](bool handled) { last_handled = handled; });
798 EXPECT_EQ(last_handled, false);
799 EXPECT_EQ(results.size(), 1);
800 event = &results[0];
801 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
802 EXPECT_EQ(event->physical, kPhysicalKeyA);
803 EXPECT_EQ(event->logical, kLogicalKeyA);
804 EXPECT_STREQ(event->character, "a");
805 EXPECT_EQ(event->synthesized, false);
806
807 event->callback(true, event->user_data);
808 EXPECT_EQ(last_handled, true);
809 results.clear();
810
811 // Release A
812 last_handled = false;
813 key_state.Set(kVirtualKeyA, false);
814 handler->KeyboardHook(
815 kVirtualKeyA, kScanCodeKeyA, WM_KEYUP, 'a', false, true,
816 [&last_handled](bool handled) { last_handled = handled; });
817 EXPECT_EQ(last_handled, false);
818 EXPECT_EQ(results.size(), 1);
819 event = &results[0];
820 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
821 EXPECT_EQ(event->physical, kPhysicalKeyA);
822 EXPECT_EQ(event->logical, kLogicalKeyA);
823 EXPECT_STREQ(event->character, "");
824 EXPECT_EQ(event->synthesized, false);
825
826 event->callback(true, event->user_data);
827 EXPECT_EQ(last_handled, true);
828 results.clear();
829}
830
831TEST(KeyboardKeyEmbedderHandlerTest, AbruptUpIsIgnored) {
832 TestKeystate key_state;
833 std::vector<TestFlutterKeyEvent> results;
834 TestFlutterKeyEvent* event;
835 bool last_handled = false;
836
837 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
838 std::make_unique<KeyboardKeyEmbedderHandler>(
839 [&results](const FlutterKeyEvent& event,
841 results.emplace_back(event, callback, user_data);
842 },
843 key_state.Getter(), DefaultMapVkToScan);
844 last_handled = false;
845
846 // KeyA's key down is missed.
847
848 key_state.Set(kVirtualKeyA, true);
849
850 // Press A again (should yield an empty event)
851 last_handled = false;
852 handler->KeyboardHook(
853 kVirtualKeyA, kScanCodeKeyA, WM_KEYUP, 'a', false, true,
854 [&last_handled](bool handled) { last_handled = handled; });
855 EXPECT_EQ(last_handled, true);
856 EXPECT_EQ(results.size(), 1);
857 event = &results[0];
858 EXPECT_EQ(event->physical, 0);
859 EXPECT_EQ(event->logical, 0);
860 EXPECT_EQ(event->callback, nullptr);
861 results.clear();
862}
863
864TEST(KeyboardKeyEmbedderHandlerTest, SynthesizeForDesyncPressingState) {
865 TestKeystate key_state;
866 std::vector<TestFlutterKeyEvent> results;
867 TestFlutterKeyEvent* event;
868 bool last_handled = false;
869
870 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
871 std::make_unique<KeyboardKeyEmbedderHandler>(
872 [&results](const FlutterKeyEvent& event,
874 results.emplace_back(event, callback, user_data);
875 },
876 key_state.Getter(), DefaultMapVkToScan);
877
878 // A key down of control left is missed.
879 key_state.Set(VK_LCONTROL, true);
880
881 // Send a normal event
882 key_state.Set(kVirtualKeyA, true);
883 handler->KeyboardHook(
884 kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 'a', false, false,
885 [&last_handled](bool handled) { last_handled = handled; });
886 EXPECT_EQ(last_handled, false);
887 EXPECT_EQ(results.size(), 2);
888 event = &results[0];
889 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
890 EXPECT_EQ(event->physical, kPhysicalControlLeft);
891 EXPECT_EQ(event->logical, kLogicalControlLeft);
892 EXPECT_STREQ(event->character, "");
893 EXPECT_EQ(event->synthesized, true);
894 EXPECT_EQ(event->callback, nullptr);
895
896 event = &results[1];
897 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
898 EXPECT_EQ(event->physical, kPhysicalKeyA);
899 EXPECT_EQ(event->logical, kLogicalKeyA);
900 EXPECT_STREQ(event->character, "a");
901 EXPECT_EQ(event->synthesized, false);
902
903 last_handled = true;
904 event->callback(false, event->user_data);
905 EXPECT_EQ(last_handled, false);
906 results.clear();
907
908 // A key down of control right is missed.
909 key_state.Set(VK_LCONTROL, false);
910
911 // Hold KeyA.
912 handler->KeyboardHook(
913 kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 'a', false, true,
914 [&last_handled](bool handled) { last_handled = handled; });
915 EXPECT_EQ(last_handled, false);
916 EXPECT_EQ(results.size(), 2);
917 event = &results[0];
918 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
919 EXPECT_EQ(event->physical, kPhysicalControlLeft);
920 EXPECT_EQ(event->logical, kLogicalControlLeft);
921 EXPECT_STREQ(event->character, "");
922 EXPECT_EQ(event->synthesized, true);
923 EXPECT_EQ(event->callback, nullptr);
924
925 event = &results[1];
926 EXPECT_EQ(event->type, kFlutterKeyEventTypeRepeat);
927 EXPECT_EQ(event->physical, kPhysicalKeyA);
928 EXPECT_EQ(event->logical, kLogicalKeyA);
929 EXPECT_STREQ(event->character, "a");
930 EXPECT_EQ(event->synthesized, false);
931
932 last_handled = true;
933 event->callback(false, event->user_data);
934 EXPECT_EQ(last_handled, false);
935 results.clear();
936
937 // Release KeyA.
938 key_state.Set(kVirtualKeyA, false);
939 handler->KeyboardHook(
940 kVirtualKeyA, kScanCodeKeyA, WM_KEYUP, 0, false, true,
941 [&last_handled](bool handled) { last_handled = handled; });
942 EXPECT_EQ(results.size(), 1);
943 event = &results[0];
944 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
945 EXPECT_EQ(event->physical, kPhysicalKeyA);
946 EXPECT_EQ(event->logical, kLogicalKeyA);
947 EXPECT_STREQ(event->character, "");
948 EXPECT_EQ(event->synthesized, false);
949 event->callback(false, event->user_data);
950}
951
952TEST(KeyboardKeyEmbedderHandlerTest, SynthesizeForDesyncToggledState) {
953 TestKeystate key_state;
954 std::vector<TestFlutterKeyEvent> results;
955 TestFlutterKeyEvent* event;
956 bool last_handled = false;
957
958 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
959 std::make_unique<KeyboardKeyEmbedderHandler>(
960 [&results](const FlutterKeyEvent& event,
962 results.emplace_back(event, callback, user_data);
963 },
964 key_state.Getter(), DefaultMapVkToScan);
965
966 // The NumLock is desynchronized by toggled on
967 key_state.Set(VK_NUMLOCK, false, true);
968
969 // Send a normal event
970 key_state.Set(kVirtualKeyA, true);
971 handler->KeyboardHook(
972 kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 'a', false, false,
973 [&last_handled](bool handled) { last_handled = handled; });
974 EXPECT_EQ(last_handled, false);
975 EXPECT_EQ(results.size(), 3);
976 event = &results[0];
977 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
978 EXPECT_EQ(event->physical, kPhysicalNumLock);
979 EXPECT_EQ(event->logical, kLogicalNumLock);
980 EXPECT_STREQ(event->character, "");
981 EXPECT_EQ(event->synthesized, true);
982
983 event = &results[1];
984 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
985 EXPECT_EQ(event->physical, kPhysicalNumLock);
986 EXPECT_EQ(event->logical, kLogicalNumLock);
987 EXPECT_STREQ(event->character, "");
988 EXPECT_EQ(event->synthesized, true);
989
990 event = &results[2];
991 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
992 EXPECT_EQ(event->physical, kPhysicalKeyA);
993 EXPECT_EQ(event->logical, kLogicalKeyA);
994 EXPECT_STREQ(event->character, "a");
995 EXPECT_EQ(event->synthesized, false);
996
997 event->callback(true, event->user_data);
998 EXPECT_EQ(last_handled, true);
999 results.clear();
1000
1001 // Test if the NumLock is mis-toggled while it should also be pressed
1002 key_state.Set(VK_NUMLOCK, true, true);
1003
1004 // Send a normal event
1005 handler->KeyboardHook(
1006 kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 'a', false, true,
1007 [&last_handled](bool handled) { last_handled = handled; });
1008 EXPECT_EQ(last_handled, true);
1009 EXPECT_EQ(results.size(), 2);
1010 event = &results[0];
1011 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
1012 EXPECT_EQ(event->physical, kPhysicalNumLock);
1013 EXPECT_EQ(event->logical, kLogicalNumLock);
1014 EXPECT_STREQ(event->character, "");
1015 EXPECT_EQ(event->synthesized, true);
1016
1017 event = &results[1];
1018 EXPECT_EQ(event->type, kFlutterKeyEventTypeRepeat);
1019 EXPECT_EQ(event->physical, kPhysicalKeyA);
1020 EXPECT_EQ(event->logical, kLogicalKeyA);
1021 EXPECT_STREQ(event->character, "a");
1022 EXPECT_EQ(event->synthesized, false);
1023
1024 event->callback(false, event->user_data);
1025 EXPECT_EQ(last_handled, false);
1026 results.clear();
1027
1028 // Numlock is pressed at this moment.
1029
1030 // Test if the NumLock is mis-toggled while it should also be released
1031 key_state.Set(VK_NUMLOCK, false, false);
1032
1033 // Send a normal event
1034 key_state.Set(kVirtualKeyA, false);
1035 handler->KeyboardHook(
1036 kVirtualKeyA, kScanCodeKeyA, WM_KEYUP, 0, false, true,
1037 [&last_handled](bool handled) { last_handled = handled; });
1038 EXPECT_EQ(results.size(), 4);
1039 event = &results[0];
1040 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
1041 EXPECT_EQ(event->physical, kPhysicalNumLock);
1042 EXPECT_EQ(event->logical, kLogicalNumLock);
1043 EXPECT_STREQ(event->character, "");
1044 EXPECT_EQ(event->synthesized, true);
1045 EXPECT_EQ(event->callback, nullptr);
1046
1047 event = &results[1];
1048 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
1049 EXPECT_EQ(event->physical, kPhysicalNumLock);
1050 EXPECT_EQ(event->logical, kLogicalNumLock);
1051 EXPECT_STREQ(event->character, "");
1052 EXPECT_EQ(event->synthesized, true);
1053 EXPECT_EQ(event->callback, nullptr);
1054
1055 event = &results[2];
1056 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
1057 EXPECT_EQ(event->physical, kPhysicalNumLock);
1058 EXPECT_EQ(event->logical, kLogicalNumLock);
1059 EXPECT_STREQ(event->character, "");
1060 EXPECT_EQ(event->synthesized, true);
1061 EXPECT_EQ(event->callback, nullptr);
1062
1063 event = &results[3];
1064 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
1065 EXPECT_EQ(event->physical, kPhysicalKeyA);
1066 EXPECT_EQ(event->logical, kLogicalKeyA);
1067 EXPECT_STREQ(event->character, "");
1068 EXPECT_EQ(event->synthesized, false);
1069 event->callback(false, event->user_data);
1070}
1071
1072TEST(KeyboardKeyEmbedderHandlerTest,
1073 SynthesizeForDesyncToggledStateByItselfsUp) {
1074 TestKeystate key_state;
1075 std::vector<TestFlutterKeyEvent> results;
1076 TestFlutterKeyEvent* event;
1077 bool last_handled = false;
1078
1079 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
1080 std::make_unique<KeyboardKeyEmbedderHandler>(
1081 [&results](const FlutterKeyEvent& event,
1083 results.emplace_back(event, callback, user_data);
1084 },
1085 key_state.Getter(), DefaultMapVkToScan);
1086
1087 // When NumLock is down
1088 key_state.Set(VK_NUMLOCK, true, true);
1089 handler->KeyboardHook(
1090 VK_NUMLOCK, kScanCodeNumLock, WM_KEYDOWN, 0, true, false,
1091 [&last_handled](bool handled) { last_handled = handled; });
1092 event = &results.back();
1093 event->callback(false, event->user_data);
1094 results.clear();
1095
1096 // Numlock is desynchronized by being off and released
1097 key_state.Set(VK_NUMLOCK, false, false);
1098 // Send a NumLock key up
1099 handler->KeyboardHook(
1100 VK_NUMLOCK, kScanCodeNumLock, WM_KEYUP, 0, true, true,
1101 [&last_handled](bool handled) { last_handled = handled; });
1102 EXPECT_EQ(last_handled, false);
1103 EXPECT_EQ(results.size(), 3);
1104 event = &results[0];
1105 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
1106 EXPECT_EQ(event->physical, kPhysicalNumLock);
1107 EXPECT_EQ(event->logical, kLogicalNumLock);
1108 EXPECT_STREQ(event->character, "");
1109 EXPECT_EQ(event->synthesized, true);
1110 EXPECT_EQ(event->callback, nullptr);
1111
1112 event = &results[1];
1113 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
1114 EXPECT_EQ(event->physical, kPhysicalNumLock);
1115 EXPECT_EQ(event->logical, kLogicalNumLock);
1116 EXPECT_STREQ(event->character, "");
1117 EXPECT_EQ(event->synthesized, true);
1118 EXPECT_EQ(event->callback, nullptr);
1119
1120 event = &results[2];
1121 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
1122 EXPECT_EQ(event->physical, kPhysicalNumLock);
1123 EXPECT_EQ(event->logical, kLogicalNumLock);
1124 EXPECT_STREQ(event->character, "");
1125 EXPECT_EQ(event->synthesized, false);
1126
1127 last_handled = false;
1128 event->callback(true, event->user_data);
1129 EXPECT_EQ(last_handled, true);
1130}
1131
1132TEST(KeyboardKeyEmbedderHandlerTest,
1133 SynthesizeForDesyncToggledStateByItselfsDown) {
1134 TestKeystate key_state;
1135 std::vector<TestFlutterKeyEvent> results;
1136 TestFlutterKeyEvent* event;
1137 bool last_handled = false;
1138
1139 // NumLock is started up and disabled
1140 key_state.Set(VK_NUMLOCK, false, false);
1141 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
1142 std::make_unique<KeyboardKeyEmbedderHandler>(
1143 [&results](const FlutterKeyEvent& event,
1145 results.emplace_back(event, callback, user_data);
1146 },
1147 key_state.Getter(), DefaultMapVkToScan);
1148
1149 // NumLock is toggled somewhere else
1150 // key_state.Set(VK_NUMLOCK, false, true);
1151
1152 // NumLock is pressed
1153 key_state.Set(VK_NUMLOCK, true, false);
1154 handler->KeyboardHook(
1155 VK_NUMLOCK, kScanCodeNumLock, WM_KEYDOWN, 0, true, false,
1156 [&last_handled](bool handled) { last_handled = handled; });
1157 EXPECT_EQ(last_handled, false);
1158 // 4 total events should be fired:
1159 // Pre-synchronization toggle, pre-sync press,
1160 // main event, and post-sync press.
1161 EXPECT_EQ(results.size(), 4);
1162 event = &results[0];
1163 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
1164 EXPECT_EQ(event->physical, kPhysicalNumLock);
1165 EXPECT_EQ(event->logical, kLogicalNumLock);
1166 EXPECT_STREQ(event->character, "");
1167 EXPECT_EQ(event->synthesized, true);
1168 EXPECT_EQ(event->callback, nullptr);
1169
1170 event = &results[1];
1171 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
1172 EXPECT_EQ(event->physical, kPhysicalNumLock);
1173 EXPECT_EQ(event->logical, kLogicalNumLock);
1174 EXPECT_STREQ(event->character, "");
1175 EXPECT_EQ(event->synthesized, true);
1176 EXPECT_EQ(event->callback, nullptr);
1177
1178 event = &results[2];
1179 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
1180 EXPECT_EQ(event->physical, kPhysicalNumLock);
1181 EXPECT_EQ(event->logical, kLogicalNumLock);
1182 EXPECT_STREQ(event->character, "");
1183 EXPECT_EQ(event->synthesized, false);
1184
1185 last_handled = false;
1186 event->callback(true, event->user_data);
1187 EXPECT_EQ(last_handled, true);
1188}
1189
1190TEST(KeyboardKeyEmbedderHandlerTest, SynthesizeWithInitialTogglingState) {
1191 TestKeystate key_state;
1192 std::vector<TestFlutterKeyEvent> results;
1193 TestFlutterKeyEvent* event;
1194 bool last_handled = false;
1195
1196 // The app starts with NumLock toggled on
1197 key_state.Set(VK_NUMLOCK, false, true);
1198
1199 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
1200 std::make_unique<KeyboardKeyEmbedderHandler>(
1201 [&results](const FlutterKeyEvent& event,
1203 results.emplace_back(event, callback, user_data);
1204 },
1205 key_state.Getter(), DefaultMapVkToScan);
1206
1207 // NumLock key down
1208 key_state.Set(VK_NUMLOCK, true, false);
1209 handler->KeyboardHook(
1210 VK_NUMLOCK, kScanCodeNumLock, WM_KEYDOWN, 0, true, false,
1211 [&last_handled](bool handled) { last_handled = handled; });
1212 EXPECT_EQ(last_handled, false);
1213 EXPECT_EQ(results.size(), 1);
1214 event = &results[0];
1215 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
1216 EXPECT_EQ(event->physical, kPhysicalNumLock);
1217 EXPECT_EQ(event->logical, kLogicalNumLock);
1218 EXPECT_STREQ(event->character, "");
1219 EXPECT_EQ(event->synthesized, false);
1220
1221 event->callback(true, event->user_data);
1222 EXPECT_EQ(last_handled, true);
1223 results.clear();
1224}
1225
1226TEST(KeyboardKeyEmbedderHandlerTest, SysKeyPress) {
1227 TestKeystate key_state;
1228 std::vector<TestFlutterKeyEvent> results;
1229 TestFlutterKeyEvent* event;
1230 bool last_handled = false;
1231
1232 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
1233 std::make_unique<KeyboardKeyEmbedderHandler>(
1234 [&results](const FlutterKeyEvent& event,
1236 results.emplace_back(event, callback, user_data);
1237 },
1238 key_state.Getter(), DefaultMapVkToScan);
1239
1240 // Press KeyAltLeft.
1241 key_state.Set(VK_LMENU, true);
1242 handler->KeyboardHook(
1243 VK_LMENU, kScanCodeAltLeft, WM_SYSKEYDOWN, 0, false, false,
1244 [&last_handled](bool handled) { last_handled = handled; });
1245 EXPECT_EQ(last_handled, false);
1246 EXPECT_EQ(results.size(), 1);
1247 event = results.data();
1248 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
1249 EXPECT_EQ(event->physical, kPhysicalAltLeft);
1250 EXPECT_EQ(event->logical, kLogicalAltLeft);
1251 EXPECT_STREQ(event->character, "");
1252 EXPECT_EQ(event->synthesized, false);
1253
1254 event->callback(true, event->user_data);
1255 EXPECT_EQ(last_handled, true);
1256 results.clear();
1257
1258 // Release KeyAltLeft.
1259 key_state.Set(VK_LMENU, false);
1260 handler->KeyboardHook(
1261 VK_LMENU, kScanCodeAltLeft, WM_SYSKEYUP, 0, false, true,
1262 [&last_handled](bool handled) { last_handled = handled; });
1263 EXPECT_EQ(results.size(), 1);
1264 event = results.data();
1265 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
1266 EXPECT_EQ(event->physical, kPhysicalAltLeft);
1267 EXPECT_EQ(event->logical, kLogicalAltLeft);
1268 EXPECT_STREQ(event->character, "");
1269 EXPECT_EQ(event->synthesized, false);
1270 event->callback(false, event->user_data);
1271}
1272
1273} // namespace testing
1274} // namespace flutter
GLenum type
void(* FlutterKeyEventCallback)(bool, void *)
Definition embedder.h:1427
@ kFlutterKeyEventTypeDown
Definition embedder.h:1348
@ kFlutterKeyEventTypeUp
Definition embedder.h:1347
@ kFlutterKeyEventTypeRepeat
Definition embedder.h:1349
const gchar FlBinaryMessengerMessageHandler handler
FlutterDesktopBinaryReply callback
bool pressed
bool toggled_on
TEST(NativeAssetsManagerTest, NoAvailableAssets)
constexpr int kShift
constexpr int kScanCodeShiftRight
constexpr int kScanCodeShiftLeft
constexpr int kScanCodeControlRight
std::string ConvertChar32ToUtf8(char32_t ch)
constexpr int kScanCodeControlLeft
constexpr int kControl
Definition ref_ptr.h:261
uint64_t logical
Definition embedder.h:1406
size_t struct_size
The size of this struct. Must be sizeof(FlutterKeyEvent).
Definition embedder.h:1384
uint64_t physical
Definition embedder.h:1398
FlutterKeyEventType type
The event kind.
Definition embedder.h:1390
unsigned int UINT
short SHORT