Flutter Engine
The Flutter Engine
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
5#include "flutter/shell/platform/windows/keyboard_key_embedder_handler.h"
6
7#include <string>
8#include <vector>
9
10#include "flutter/shell/platform/embedder/embedder.h"
11#include "flutter/shell/platform/embedder/test_utils/key_codes.g.h"
12#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
13#include "flutter/shell/platform/windows/keyboard_utils.h"
14#include "flutter/shell/platform/windows/testing/engine_modifier.h"
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)
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
94 EXPECT_EQ(result.length(), 1);
95 EXPECT_EQ(result[0], '\x24');
96
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 yield an empty event)
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, true);
756 EXPECT_EQ(results.size(), 1);
757 event = &results[0];
758 EXPECT_EQ(event->physical, 0);
759 EXPECT_EQ(event->logical, 0);
760 EXPECT_EQ(event->callback, nullptr);
761 results.clear();
762}
763
764TEST(KeyboardKeyEmbedderHandlerTest, AbruptRepeatIsConvertedToDown) {
765 TestKeystate key_state;
766 std::vector<TestFlutterKeyEvent> results;
767 TestFlutterKeyEvent* event;
768 bool last_handled = false;
769
770 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
771 std::make_unique<KeyboardKeyEmbedderHandler>(
772 [&results](const FlutterKeyEvent& event,
774 results.emplace_back(event, callback, user_data);
775 },
776 key_state.Getter(), DefaultMapVkToScan);
777 last_handled = false;
778
779 key_state.Set(kVirtualKeyA, true);
780
781 // Press A (with was_down true)
782 handler->KeyboardHook(
783 kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 'a', false, true,
784 [&last_handled](bool handled) { last_handled = handled; });
785 EXPECT_EQ(last_handled, false);
786 EXPECT_EQ(results.size(), 1);
787 event = &results[0];
788 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
789 EXPECT_EQ(event->physical, kPhysicalKeyA);
790 EXPECT_EQ(event->logical, kLogicalKeyA);
791 EXPECT_STREQ(event->character, "a");
792 EXPECT_EQ(event->synthesized, false);
793
794 event->callback(true, event->user_data);
795 EXPECT_EQ(last_handled, true);
796 results.clear();
797
798 // Release A
799 last_handled = false;
800 key_state.Set(kVirtualKeyA, false);
801 handler->KeyboardHook(
802 kVirtualKeyA, kScanCodeKeyA, WM_KEYUP, 'a', false, true,
803 [&last_handled](bool handled) { last_handled = handled; });
804 EXPECT_EQ(last_handled, false);
805 EXPECT_EQ(results.size(), 1);
806 event = &results[0];
807 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
808 EXPECT_EQ(event->physical, kPhysicalKeyA);
809 EXPECT_EQ(event->logical, kLogicalKeyA);
810 EXPECT_STREQ(event->character, "");
811 EXPECT_EQ(event->synthesized, false);
812
813 event->callback(true, event->user_data);
814 EXPECT_EQ(last_handled, true);
815 results.clear();
816}
817
818TEST(KeyboardKeyEmbedderHandlerTest, AbruptUpIsIgnored) {
819 TestKeystate key_state;
820 std::vector<TestFlutterKeyEvent> results;
821 TestFlutterKeyEvent* event;
822 bool last_handled = false;
823
824 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
825 std::make_unique<KeyboardKeyEmbedderHandler>(
826 [&results](const FlutterKeyEvent& event,
828 results.emplace_back(event, callback, user_data);
829 },
830 key_state.Getter(), DefaultMapVkToScan);
831 last_handled = false;
832
833 // KeyA's key down is missed.
834
835 key_state.Set(kVirtualKeyA, true);
836
837 // Press A again (should yield an empty event)
838 last_handled = false;
839 handler->KeyboardHook(
840 kVirtualKeyA, kScanCodeKeyA, WM_KEYUP, 'a', false, true,
841 [&last_handled](bool handled) { last_handled = handled; });
842 EXPECT_EQ(last_handled, true);
843 EXPECT_EQ(results.size(), 1);
844 event = &results[0];
845 EXPECT_EQ(event->physical, 0);
846 EXPECT_EQ(event->logical, 0);
847 EXPECT_EQ(event->callback, nullptr);
848 results.clear();
849}
850
851TEST(KeyboardKeyEmbedderHandlerTest, SynthesizeForDesyncPressingState) {
852 TestKeystate key_state;
853 std::vector<TestFlutterKeyEvent> results;
854 TestFlutterKeyEvent* event;
855 bool last_handled = false;
856
857 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
858 std::make_unique<KeyboardKeyEmbedderHandler>(
859 [&results](const FlutterKeyEvent& event,
861 results.emplace_back(event, callback, user_data);
862 },
863 key_state.Getter(), DefaultMapVkToScan);
864
865 // A key down of control left is missed.
866 key_state.Set(VK_LCONTROL, true);
867
868 // Send a normal event
869 key_state.Set(kVirtualKeyA, true);
870 handler->KeyboardHook(
871 kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 'a', false, false,
872 [&last_handled](bool handled) { last_handled = handled; });
873 EXPECT_EQ(last_handled, false);
874 EXPECT_EQ(results.size(), 2);
875 event = &results[0];
876 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
877 EXPECT_EQ(event->physical, kPhysicalControlLeft);
878 EXPECT_EQ(event->logical, kLogicalControlLeft);
879 EXPECT_STREQ(event->character, "");
880 EXPECT_EQ(event->synthesized, true);
881 EXPECT_EQ(event->callback, nullptr);
882
883 event = &results[1];
884 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
885 EXPECT_EQ(event->physical, kPhysicalKeyA);
886 EXPECT_EQ(event->logical, kLogicalKeyA);
887 EXPECT_STREQ(event->character, "a");
888 EXPECT_EQ(event->synthesized, false);
889
890 last_handled = true;
891 event->callback(false, event->user_data);
892 EXPECT_EQ(last_handled, false);
893 results.clear();
894
895 // A key down of control right is missed.
896 key_state.Set(VK_LCONTROL, false);
897
898 // Hold KeyA.
899 handler->KeyboardHook(
900 kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 'a', false, true,
901 [&last_handled](bool handled) { last_handled = handled; });
902 EXPECT_EQ(last_handled, false);
903 EXPECT_EQ(results.size(), 2);
904 event = &results[0];
905 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
906 EXPECT_EQ(event->physical, kPhysicalControlLeft);
907 EXPECT_EQ(event->logical, kLogicalControlLeft);
908 EXPECT_STREQ(event->character, "");
909 EXPECT_EQ(event->synthesized, true);
910 EXPECT_EQ(event->callback, nullptr);
911
912 event = &results[1];
913 EXPECT_EQ(event->type, kFlutterKeyEventTypeRepeat);
914 EXPECT_EQ(event->physical, kPhysicalKeyA);
915 EXPECT_EQ(event->logical, kLogicalKeyA);
916 EXPECT_STREQ(event->character, "a");
917 EXPECT_EQ(event->synthesized, false);
918
919 last_handled = true;
920 event->callback(false, event->user_data);
921 EXPECT_EQ(last_handled, false);
922 results.clear();
923
924 // Release KeyA.
925 key_state.Set(kVirtualKeyA, false);
926 handler->KeyboardHook(
927 kVirtualKeyA, kScanCodeKeyA, WM_KEYUP, 0, false, true,
928 [&last_handled](bool handled) { last_handled = handled; });
929 EXPECT_EQ(results.size(), 1);
930 event = &results[0];
931 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
932 EXPECT_EQ(event->physical, kPhysicalKeyA);
933 EXPECT_EQ(event->logical, kLogicalKeyA);
934 EXPECT_STREQ(event->character, "");
935 EXPECT_EQ(event->synthesized, false);
936 event->callback(false, event->user_data);
937}
938
939TEST(KeyboardKeyEmbedderHandlerTest, SynthesizeForDesyncToggledState) {
940 TestKeystate key_state;
941 std::vector<TestFlutterKeyEvent> results;
942 TestFlutterKeyEvent* event;
943 bool last_handled = false;
944
945 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
946 std::make_unique<KeyboardKeyEmbedderHandler>(
947 [&results](const FlutterKeyEvent& event,
949 results.emplace_back(event, callback, user_data);
950 },
951 key_state.Getter(), DefaultMapVkToScan);
952
953 // The NumLock is desynchronized by toggled on
954 key_state.Set(VK_NUMLOCK, false, true);
955
956 // Send a normal event
957 key_state.Set(kVirtualKeyA, true);
958 handler->KeyboardHook(
959 kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 'a', false, false,
960 [&last_handled](bool handled) { last_handled = handled; });
961 EXPECT_EQ(last_handled, false);
962 EXPECT_EQ(results.size(), 3);
963 event = &results[0];
964 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
965 EXPECT_EQ(event->physical, kPhysicalNumLock);
966 EXPECT_EQ(event->logical, kLogicalNumLock);
967 EXPECT_STREQ(event->character, "");
968 EXPECT_EQ(event->synthesized, true);
969
970 event = &results[1];
971 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
972 EXPECT_EQ(event->physical, kPhysicalNumLock);
973 EXPECT_EQ(event->logical, kLogicalNumLock);
974 EXPECT_STREQ(event->character, "");
975 EXPECT_EQ(event->synthesized, true);
976
977 event = &results[2];
978 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
979 EXPECT_EQ(event->physical, kPhysicalKeyA);
980 EXPECT_EQ(event->logical, kLogicalKeyA);
981 EXPECT_STREQ(event->character, "a");
982 EXPECT_EQ(event->synthesized, false);
983
984 event->callback(true, event->user_data);
985 EXPECT_EQ(last_handled, true);
986 results.clear();
987
988 // Test if the NumLock is mis-toggled while it should also be pressed
989 key_state.Set(VK_NUMLOCK, true, true);
990
991 // Send a normal event
992 handler->KeyboardHook(
993 kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 'a', false, true,
994 [&last_handled](bool handled) { last_handled = handled; });
995 EXPECT_EQ(last_handled, true);
996 EXPECT_EQ(results.size(), 2);
997 event = &results[0];
998 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
999 EXPECT_EQ(event->physical, kPhysicalNumLock);
1000 EXPECT_EQ(event->logical, kLogicalNumLock);
1001 EXPECT_STREQ(event->character, "");
1002 EXPECT_EQ(event->synthesized, true);
1003
1004 event = &results[1];
1005 EXPECT_EQ(event->type, kFlutterKeyEventTypeRepeat);
1006 EXPECT_EQ(event->physical, kPhysicalKeyA);
1007 EXPECT_EQ(event->logical, kLogicalKeyA);
1008 EXPECT_STREQ(event->character, "a");
1009 EXPECT_EQ(event->synthesized, false);
1010
1011 event->callback(false, event->user_data);
1012 EXPECT_EQ(last_handled, false);
1013 results.clear();
1014
1015 // Numlock is pressed at this moment.
1016
1017 // Test if the NumLock is mis-toggled while it should also be released
1018 key_state.Set(VK_NUMLOCK, false, false);
1019
1020 // Send a normal event
1021 key_state.Set(kVirtualKeyA, false);
1022 handler->KeyboardHook(
1023 kVirtualKeyA, kScanCodeKeyA, WM_KEYUP, 0, false, true,
1024 [&last_handled](bool handled) { last_handled = handled; });
1025 EXPECT_EQ(results.size(), 4);
1026 event = &results[0];
1027 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
1028 EXPECT_EQ(event->physical, kPhysicalNumLock);
1029 EXPECT_EQ(event->logical, kLogicalNumLock);
1030 EXPECT_STREQ(event->character, "");
1031 EXPECT_EQ(event->synthesized, true);
1032 EXPECT_EQ(event->callback, nullptr);
1033
1034 event = &results[1];
1035 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
1036 EXPECT_EQ(event->physical, kPhysicalNumLock);
1037 EXPECT_EQ(event->logical, kLogicalNumLock);
1038 EXPECT_STREQ(event->character, "");
1039 EXPECT_EQ(event->synthesized, true);
1040 EXPECT_EQ(event->callback, nullptr);
1041
1042 event = &results[2];
1043 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
1044 EXPECT_EQ(event->physical, kPhysicalNumLock);
1045 EXPECT_EQ(event->logical, kLogicalNumLock);
1046 EXPECT_STREQ(event->character, "");
1047 EXPECT_EQ(event->synthesized, true);
1048 EXPECT_EQ(event->callback, nullptr);
1049
1050 event = &results[3];
1051 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
1052 EXPECT_EQ(event->physical, kPhysicalKeyA);
1053 EXPECT_EQ(event->logical, kLogicalKeyA);
1054 EXPECT_STREQ(event->character, "");
1055 EXPECT_EQ(event->synthesized, false);
1056 event->callback(false, event->user_data);
1057}
1058
1059TEST(KeyboardKeyEmbedderHandlerTest,
1060 SynthesizeForDesyncToggledStateByItselfsUp) {
1061 TestKeystate key_state;
1062 std::vector<TestFlutterKeyEvent> results;
1063 TestFlutterKeyEvent* event;
1064 bool last_handled = false;
1065
1066 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
1067 std::make_unique<KeyboardKeyEmbedderHandler>(
1068 [&results](const FlutterKeyEvent& event,
1070 results.emplace_back(event, callback, user_data);
1071 },
1072 key_state.Getter(), DefaultMapVkToScan);
1073
1074 // When NumLock is down
1075 key_state.Set(VK_NUMLOCK, true, true);
1076 handler->KeyboardHook(
1077 VK_NUMLOCK, kScanCodeNumLock, WM_KEYDOWN, 0, true, false,
1078 [&last_handled](bool handled) { last_handled = handled; });
1079 event = &results.back();
1080 event->callback(false, event->user_data);
1081 results.clear();
1082
1083 // Numlock is desynchronized by being off and released
1084 key_state.Set(VK_NUMLOCK, false, false);
1085 // Send a NumLock key up
1086 handler->KeyboardHook(
1087 VK_NUMLOCK, kScanCodeNumLock, WM_KEYUP, 0, true, true,
1088 [&last_handled](bool handled) { last_handled = handled; });
1089 EXPECT_EQ(last_handled, false);
1090 EXPECT_EQ(results.size(), 3);
1091 event = &results[0];
1092 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
1093 EXPECT_EQ(event->physical, kPhysicalNumLock);
1094 EXPECT_EQ(event->logical, kLogicalNumLock);
1095 EXPECT_STREQ(event->character, "");
1096 EXPECT_EQ(event->synthesized, true);
1097 EXPECT_EQ(event->callback, nullptr);
1098
1099 event = &results[1];
1100 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
1101 EXPECT_EQ(event->physical, kPhysicalNumLock);
1102 EXPECT_EQ(event->logical, kLogicalNumLock);
1103 EXPECT_STREQ(event->character, "");
1104 EXPECT_EQ(event->synthesized, true);
1105 EXPECT_EQ(event->callback, nullptr);
1106
1107 event = &results[2];
1108 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
1109 EXPECT_EQ(event->physical, kPhysicalNumLock);
1110 EXPECT_EQ(event->logical, kLogicalNumLock);
1111 EXPECT_STREQ(event->character, "");
1112 EXPECT_EQ(event->synthesized, false);
1113
1114 last_handled = false;
1115 event->callback(true, event->user_data);
1116 EXPECT_EQ(last_handled, true);
1117}
1118
1119TEST(KeyboardKeyEmbedderHandlerTest,
1120 SynthesizeForDesyncToggledStateByItselfsDown) {
1121 TestKeystate key_state;
1122 std::vector<TestFlutterKeyEvent> results;
1123 TestFlutterKeyEvent* event;
1124 bool last_handled = false;
1125
1126 // NumLock is started up and disabled
1127 key_state.Set(VK_NUMLOCK, false, false);
1128 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
1129 std::make_unique<KeyboardKeyEmbedderHandler>(
1130 [&results](const FlutterKeyEvent& event,
1132 results.emplace_back(event, callback, user_data);
1133 },
1134 key_state.Getter(), DefaultMapVkToScan);
1135
1136 // NumLock is toggled somewhere else
1137 // key_state.Set(VK_NUMLOCK, false, true);
1138
1139 // NumLock is pressed
1140 key_state.Set(VK_NUMLOCK, true, false);
1141 handler->KeyboardHook(
1142 VK_NUMLOCK, kScanCodeNumLock, WM_KEYDOWN, 0, true, false,
1143 [&last_handled](bool handled) { last_handled = handled; });
1144 EXPECT_EQ(last_handled, false);
1145 // 4 total events should be fired:
1146 // Pre-synchronization toggle, pre-sync press,
1147 // main event, and post-sync press.
1148 EXPECT_EQ(results.size(), 4);
1149 event = &results[0];
1150 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
1151 EXPECT_EQ(event->physical, kPhysicalNumLock);
1152 EXPECT_EQ(event->logical, kLogicalNumLock);
1153 EXPECT_STREQ(event->character, "");
1154 EXPECT_EQ(event->synthesized, true);
1155 EXPECT_EQ(event->callback, nullptr);
1156
1157 event = &results[1];
1158 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
1159 EXPECT_EQ(event->physical, kPhysicalNumLock);
1160 EXPECT_EQ(event->logical, kLogicalNumLock);
1161 EXPECT_STREQ(event->character, "");
1162 EXPECT_EQ(event->synthesized, true);
1163 EXPECT_EQ(event->callback, nullptr);
1164
1165 event = &results[2];
1166 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
1167 EXPECT_EQ(event->physical, kPhysicalNumLock);
1168 EXPECT_EQ(event->logical, kLogicalNumLock);
1169 EXPECT_STREQ(event->character, "");
1170 EXPECT_EQ(event->synthesized, false);
1171
1172 last_handled = false;
1173 event->callback(true, event->user_data);
1174 EXPECT_EQ(last_handled, true);
1175}
1176
1177TEST(KeyboardKeyEmbedderHandlerTest, SynthesizeWithInitialTogglingState) {
1178 TestKeystate key_state;
1179 std::vector<TestFlutterKeyEvent> results;
1180 TestFlutterKeyEvent* event;
1181 bool last_handled = false;
1182
1183 // The app starts with NumLock toggled on
1184 key_state.Set(VK_NUMLOCK, false, true);
1185
1186 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
1187 std::make_unique<KeyboardKeyEmbedderHandler>(
1188 [&results](const FlutterKeyEvent& event,
1190 results.emplace_back(event, callback, user_data);
1191 },
1192 key_state.Getter(), DefaultMapVkToScan);
1193
1194 // NumLock key down
1195 key_state.Set(VK_NUMLOCK, true, false);
1196 handler->KeyboardHook(
1197 VK_NUMLOCK, kScanCodeNumLock, WM_KEYDOWN, 0, true, false,
1198 [&last_handled](bool handled) { last_handled = handled; });
1199 EXPECT_EQ(last_handled, false);
1200 EXPECT_EQ(results.size(), 1);
1201 event = &results[0];
1202 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
1203 EXPECT_EQ(event->physical, kPhysicalNumLock);
1204 EXPECT_EQ(event->logical, kLogicalNumLock);
1205 EXPECT_STREQ(event->character, "");
1206 EXPECT_EQ(event->synthesized, false);
1207
1208 event->callback(true, event->user_data);
1209 EXPECT_EQ(last_handled, true);
1210 results.clear();
1211}
1212
1213TEST(KeyboardKeyEmbedderHandlerTest, SysKeyPress) {
1214 TestKeystate key_state;
1215 std::vector<TestFlutterKeyEvent> results;
1216 TestFlutterKeyEvent* event;
1217 bool last_handled = false;
1218
1219 std::unique_ptr<KeyboardKeyEmbedderHandler> handler =
1220 std::make_unique<KeyboardKeyEmbedderHandler>(
1221 [&results](const FlutterKeyEvent& event,
1223 results.emplace_back(event, callback, user_data);
1224 },
1225 key_state.Getter(), DefaultMapVkToScan);
1226
1227 // Press KeyAltLeft.
1228 key_state.Set(VK_LMENU, true);
1229 handler->KeyboardHook(
1230 VK_LMENU, kScanCodeAltLeft, WM_SYSKEYDOWN, 0, false, false,
1231 [&last_handled](bool handled) { last_handled = handled; });
1232 EXPECT_EQ(last_handled, false);
1233 EXPECT_EQ(results.size(), 1);
1234 event = results.data();
1235 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
1236 EXPECT_EQ(event->physical, kPhysicalAltLeft);
1237 EXPECT_EQ(event->logical, kLogicalAltLeft);
1238 EXPECT_STREQ(event->character, "");
1239 EXPECT_EQ(event->synthesized, false);
1240
1241 event->callback(true, event->user_data);
1242 EXPECT_EQ(last_handled, true);
1243 results.clear();
1244
1245 // Release KeyAltLeft.
1246 key_state.Set(VK_LMENU, false);
1247 handler->KeyboardHook(
1248 VK_LMENU, kScanCodeAltLeft, WM_SYSKEYUP, 0, false, true,
1249 [&last_handled](bool handled) { last_handled = handled; });
1250 EXPECT_EQ(results.size(), 1);
1251 event = results.data();
1252 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
1253 EXPECT_EQ(event->physical, kPhysicalAltLeft);
1254 EXPECT_EQ(event->logical, kLogicalAltLeft);
1255 EXPECT_STREQ(event->character, "");
1256 EXPECT_EQ(event->synthesized, false);
1257 event->callback(false, event->user_data);
1258}
1259
1260} // namespace testing
1261} // namespace flutter
#define TEST(S, s, D, expected)
void(* FlutterKeyEventCallback)(bool, void *)
Definition embedder.h:1153
@ kFlutterKeyEventTypeDown
Definition embedder.h:1074
@ kFlutterKeyEventTypeUp
Definition embedder.h:1073
@ kFlutterKeyEventTypeRepeat
Definition embedder.h:1075
SkBitmap source
Definition examples.cpp:28
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
FlKeyEvent * event
GAsyncResult * result
bool pressed
bool toggled_on
const GrXPFactory * Get(SkBlendMode mode)
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:256
unsigned int UINT
short SHORT