Flutter Windows Embedder
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 
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"
14 #include "flutter/shell/platform/windows/testing/engine_modifier.h"
15 #include "gtest/gtest.h"
16 
17 namespace flutter {
18 namespace testing {
19 
20 namespace {
21 
22 constexpr SHORT kStateMaskToggled = 0x01;
23 constexpr SHORT kStateMaskPressed = 0x80;
24 
25 class TestFlutterKeyEvent : public FlutterKeyEvent {
26  public:
27  TestFlutterKeyEvent(const FlutterKeyEvent& src,
28  FlutterKeyEventCallback callback,
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 
47  FlutterKeyEventCallback callback;
48  void* user_data;
49 
50  private:
51  const std::string character_str;
52 };
53 
54 class 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 
71 UINT DefaultMapVkToScan(UINT virtual_key, bool extended) {
72  return MapVirtualKey(virtual_key,
73  extended ? MAPVK_VK_TO_VSC_EX : MAPVK_VK_TO_VSC);
74 }
75 
76 constexpr uint64_t kScanCodeKeyA = 0x1e;
77 constexpr uint64_t kScanCodeAltLeft = 0x38;
78 constexpr uint64_t kScanCodeNumpad1 = 0x4f;
79 constexpr uint64_t kScanCodeNumLock = 0x45;
80 constexpr uint64_t kScanCodeControl = 0x1d;
81 constexpr uint64_t kScanCodeShiftLeft = 0x2a;
82 constexpr uint64_t kScanCodeShiftRight = 0x36;
83 
84 constexpr uint64_t kVirtualKeyA = 0x41;
85 
86 } // namespace
87 
88 using namespace ::flutter::testing::keycodes;
89 
90 TEST(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.
119 TEST(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,
128  FlutterKeyEventCallback callback, void* user_data) {
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.
187 TEST(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,
196  FlutterKeyEventCallback callback, void* user_data) {
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).
259 TEST(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,
268  FlutterKeyEventCallback callback, void* user_data) {
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.)
333 TEST(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,
342  FlutterKeyEventCallback callback, void* user_data) {
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.
426 TEST(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,
435  FlutterKeyEventCallback callback, void* user_data) {
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.
519 TEST(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,
529  FlutterKeyEventCallback callback, void* user_data) {
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.
562 TEST(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,
571  FlutterKeyEventCallback callback, void* user_data) {
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.
615 TEST(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,
624  FlutterKeyEventCallback callback, void* user_data) {
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.
696 TEST(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,
705  FlutterKeyEventCallback callback, void* user_data) {
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 
716 TEST(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,
725  FlutterKeyEventCallback callback, void* user_data) {
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 
777 TEST(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,
786  FlutterKeyEventCallback callback, void* user_data) {
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 
831 TEST(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,
840  FlutterKeyEventCallback callback, void* user_data) {
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 
864 TEST(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,
873  FlutterKeyEventCallback callback, void* user_data) {
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 
952 TEST(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,
961  FlutterKeyEventCallback callback, void* user_data) {
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 
1072 TEST(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,
1082  FlutterKeyEventCallback callback, void* user_data) {
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 
1132 TEST(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,
1144  FlutterKeyEventCallback callback, void* user_data) {
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 
1190 TEST(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,
1202  FlutterKeyEventCallback callback, void* user_data) {
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 
1226 TEST(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,
1235  FlutterKeyEventCallback callback, void* user_data) {
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
FlutterKeyEventCallback callback
bool pressed
bool toggled_on
enum flutter::testing::@98::KeyboardChange::Type type
TEST(AccessibilityBridgeWindows, GetParent)
constexpr int kShift
constexpr int kScanCodeShiftRight
constexpr int kScanCodeShiftLeft
constexpr int kScanCodeControlRight
std::string ConvertChar32ToUtf8(char32_t ch)
constexpr int kScanCodeControlLeft
constexpr int kControl