Flutter Engine
keyboard_win32_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/common/json_message_codec.h"
6 #include "flutter/shell/platform/embedder/embedder.h"
7 #include "flutter/shell/platform/embedder/test_utils/key_codes.g.h"
8 #include "flutter/shell/platform/windows/flutter_windows_engine.h"
9 #include "flutter/shell/platform/windows/flutter_windows_view.h"
10 #include "flutter/shell/platform/windows/keyboard_key_channel_handler.h"
11 #include "flutter/shell/platform/windows/keyboard_key_embedder_handler.h"
12 #include "flutter/shell/platform/windows/keyboard_key_handler.h"
13 #include "flutter/shell/platform/windows/keyboard_manager_win32.h"
14 #include "flutter/shell/platform/windows/testing/engine_modifier.h"
15 #include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h"
16 #include "flutter/shell/platform/windows/testing/test_keyboard.h"
17 
18 #include "gmock/gmock.h"
19 #include "gtest/gtest.h"
20 #include "rapidjson/stringbuffer.h"
21 #include "rapidjson/writer.h"
22 
23 #include <functional>
24 #include <list>
25 #include <vector>
26 
27 using testing::_;
28 using testing::Invoke;
29 using testing::Return;
30 using namespace ::flutter::testing::keycodes;
31 
32 namespace flutter {
33 namespace testing {
34 
35 namespace {
36 
37 constexpr SHORT kStateMaskToggled = 0x01;
38 constexpr SHORT kStateMaskPressed = 0x80;
39 
40 constexpr uint64_t kScanCodeBackquote = 0x29;
41 constexpr uint64_t kScanCodeKeyA = 0x1e;
42 constexpr uint64_t kScanCodeKeyB = 0x30;
43 constexpr uint64_t kScanCodeKeyE = 0x12;
44 constexpr uint64_t kScanCodeKeyF = 0x21;
45 constexpr uint64_t kScanCodeKeyO = 0x18;
46 constexpr uint64_t kScanCodeKeyQ = 0x10;
47 constexpr uint64_t kScanCodeKeyW = 0x11;
48 constexpr uint64_t kScanCodeDigit1 = 0x02;
49 constexpr uint64_t kScanCodeDigit2 = 0x03;
50 constexpr uint64_t kScanCodeDigit6 = 0x07;
51 // constexpr uint64_t kScanCodeNumpad1 = 0x4f;
52 // constexpr uint64_t kScanCodeNumLock = 0x45;
53 constexpr uint64_t kScanCodeControl = 0x1d;
54 constexpr uint64_t kScanCodeMetaLeft = 0x5b;
55 constexpr uint64_t kScanCodeMetaRight = 0x5c;
56 constexpr uint64_t kScanCodeAlt = 0x38;
57 constexpr uint64_t kScanCodeShiftLeft = 0x2a;
58 constexpr uint64_t kScanCodeShiftRight = 0x36;
59 constexpr uint64_t kScanCodeBracketLeft = 0x1a;
60 constexpr uint64_t kScanCodeArrowLeft = 0x4b;
61 constexpr uint64_t kScanCodeEnter = 0x1c;
62 constexpr uint64_t kScanCodeBackspace = 0x0e;
63 
64 constexpr uint64_t kVirtualDigit1 = 0x31;
65 constexpr uint64_t kVirtualKeyA = 0x41;
66 constexpr uint64_t kVirtualKeyB = 0x42;
67 constexpr uint64_t kVirtualKeyE = 0x45;
68 constexpr uint64_t kVirtualKeyF = 0x46;
69 constexpr uint64_t kVirtualKeyO = 0x4f;
70 constexpr uint64_t kVirtualKeyQ = 0x51;
71 constexpr uint64_t kVirtualKeyW = 0x57;
72 
73 constexpr bool kSynthesized = true;
74 constexpr bool kNotSynthesized = false;
75 
76 typedef UINT (*MapVirtualKeyLayout)(UINT uCode, UINT uMapType);
77 typedef std::function<UINT(UINT)> MapVirtualKeyToChar;
78 
79 UINT LayoutDefault(UINT uCode, UINT uMapType) {
80  return MapVirtualKey(uCode, uMapType);
81 }
82 
83 UINT LayoutFrench(UINT uCode, UINT uMapType) {
84  switch (uMapType) {
85  case MAPVK_VK_TO_CHAR:
86  switch (uCode) {
87  case 0xDD:
88  return 0x8000005E;
89  default:
90  return MapVirtualKey(uCode, MAPVK_VK_TO_CHAR);
91  }
92  default:
93  return MapVirtualKey(uCode, uMapType);
94  }
95 }
96 
97 class TestKeyboardManagerWin32 : public KeyboardManagerWin32 {
98  public:
99  explicit TestKeyboardManagerWin32(WindowDelegate* delegate)
100  : KeyboardManagerWin32(delegate) {}
101 
102  bool DuringRedispatch() { return during_redispatch_; }
103 
104  protected:
105  void RedispatchEvent(std::unique_ptr<PendingEvent> event) override {
106  assert(!during_redispatch_);
107  during_redispatch_ = true;
108  KeyboardManagerWin32::RedispatchEvent(std::move(event));
109  during_redispatch_ = false;
110  }
111 
112  private:
113  bool during_redispatch_ = false;
114 };
115 
116 // Injecting this kind of keyboard change means that a key state (the true
117 // state for a key, typically a modifier) should be changed.
118 struct KeyStateChange {
119  uint32_t key;
120  bool pressed;
122 };
123 
124 // Injecting this kind of keyboard change does not make any changes to the
125 // keyboard system, but indicates that a forged event is expected here, and
126 // that `KeyStateChange`s after this will be applied only after the forged
127 // event.
128 //
129 // See `IsKeyDownAltRight` for explaination for foged events.
130 struct ExpectForgedMessage {
131  explicit ExpectForgedMessage(Win32Message message) : message(message){};
132 
133  Win32Message message;
134 };
135 
136 struct KeyboardChange {
137  // The constructors are intentionally for implicit conversion.
138 
139  KeyboardChange(Win32Message message) : type(kMessage) {
140  content.message = message;
141  }
142 
143  KeyboardChange(KeyStateChange change) : type(kKeyStateChange) {
144  content.key_state_change = change;
145  }
146 
147  KeyboardChange(ExpectForgedMessage forged_message)
148  : type(kExpectForgedMessage) {
149  content.expected_forged_message = forged_message.message;
150  }
151 
152  enum Type {
153  kMessage,
154  kKeyStateChange,
155  kExpectForgedMessage,
156  } type;
157 
158  union {
159  Win32Message message;
160  KeyStateChange key_state_change;
162  } content;
163 };
164 
165 class TestKeystate {
166  public:
167  void Set(uint32_t virtual_key, bool pressed, bool toggled_on = false) {
168  state_[virtual_key] = (pressed ? kStateMaskPressed : 0) |
169  (toggled_on ? kStateMaskToggled : 0);
170  }
171 
172  SHORT Get(uint32_t virtual_key) { return state_[virtual_key]; }
173 
174  private:
175  std::map<uint32_t, SHORT> state_;
176 };
177 
178 class MockKeyboardManagerWin32Delegate
179  : public KeyboardManagerWin32::WindowDelegate,
180  protected MockMessageQueue {
181  public:
182  MockKeyboardManagerWin32Delegate(WindowBindingHandlerDelegate* view,
183  MapVirtualKeyToChar map_vk_to_char)
184  : view_(view), map_vk_to_char_(std::move(map_vk_to_char)) {
185  keyboard_manager_ = std::make_unique<TestKeyboardManagerWin32>(this);
186  }
187  virtual ~MockKeyboardManagerWin32Delegate() {}
188 
189  // |KeyboardManagerWin32::WindowDelegate|
190  void OnKey(int key,
191  int scancode,
192  int action,
193  char32_t character,
194  bool extended,
195  bool was_down,
196  KeyEventCallback callback) override {
197  view_->OnKey(key, scancode, action, character, extended, was_down,
198  callback);
199  }
200 
201  // |KeyboardManagerWin32::WindowDelegate|
202  void OnText(const std::u16string& text) override { view_->OnText(text); }
203 
204  SHORT GetKeyState(int virtual_key) { return key_state_.Get(virtual_key); }
205 
206  void InjectKeyboardChanges(std::vector<KeyboardChange> changes) {
207  // First queue all messages to enable peeking.
208  for (const KeyboardChange& change : changes) {
209  switch (change.type) {
210  case KeyboardChange::kMessage:
211  PushBack(&change.content.message);
212  break;
213  default:
214  break;
215  }
216  }
217  for (const KeyboardChange& change : changes) {
218  switch (change.type) {
219  case KeyboardChange::kMessage:
220  DispatchFront();
221  break;
222  case KeyboardChange::kExpectForgedMessage:
223  forged_message_expectations_.push_back(ForgedMessageExpectation{
224  .message = change.content.expected_forged_message,
225  });
226  break;
227  case KeyboardChange::kKeyStateChange: {
228  const KeyStateChange& state_change = change.content.key_state_change;
229  if (forged_message_expectations_.empty()) {
230  key_state_.Set(state_change.key, state_change.pressed,
231  state_change.toggled_on);
232  } else {
233  forged_message_expectations_.back()
234  .state_changes_afterwards.push_back(state_change);
235  }
236  break;
237  }
238  default:
239  assert(false);
240  }
241  }
242  }
243 
244  std::list<Win32Message>& RedispatchedMessages() {
245  return redispatched_messages_;
246  }
247 
248  protected:
249  BOOL Win32PeekMessage(LPMSG lpMsg,
250  UINT wMsgFilterMin,
251  UINT wMsgFilterMax,
252  UINT wRemoveMsg) override {
253  return MockMessageQueue::Win32PeekMessage(lpMsg, wMsgFilterMin,
254  wMsgFilterMax, wRemoveMsg);
255  }
256 
257  uint32_t Win32MapVkToChar(uint32_t virtual_key) override {
258  return map_vk_to_char_(virtual_key);
259  }
260 
261  // This method is called for each message injected by test cases with
262  // `tester.InjectMessages`.
263  LRESULT Win32SendMessage(UINT const message,
264  WPARAM const wparam,
265  LPARAM const lparam) override {
266  return keyboard_manager_->HandleMessage(message, wparam, lparam)
267  ? 0
269  }
270 
271  // This method is called when the keyboard manager redispatches messages
272  // or forges messages (such as CtrlLeft up right before AltGr up).
273  UINT Win32DispatchMessage(UINT Msg, WPARAM wParam, LPARAM lParam) override {
274  bool handled = keyboard_manager_->HandleMessage(Msg, wParam, lParam);
275  if (keyboard_manager_->DuringRedispatch()) {
276  redispatched_messages_.push_back(Win32Message{
277  .message = Msg,
278  .wParam = wParam,
279  .lParam = lParam,
280  });
281  EXPECT_FALSE(handled);
282  } else {
283  EXPECT_FALSE(forged_message_expectations_.empty());
284  ForgedMessageExpectation expectation =
285  forged_message_expectations_.front();
286  forged_message_expectations_.pop_front();
287  EXPECT_EQ(expectation.message.message, Msg);
288  EXPECT_EQ(expectation.message.wParam, wParam);
289  EXPECT_EQ(expectation.message.lParam, lParam);
290  if (expectation.message.expected_result != kWmResultDontCheck) {
291  EXPECT_EQ(expectation.message.expected_result,
292  handled ? kWmResultZero : kWmResultDefault);
293  }
294  for (const KeyStateChange& change :
295  expectation.state_changes_afterwards) {
296  key_state_.Set(change.key, change.pressed, change.toggled_on);
297  }
298  }
299  return 0;
300  }
301 
302  private:
303  struct ForgedMessageExpectation {
304  Win32Message message;
305  std::list<KeyStateChange> state_changes_afterwards;
306  };
307 
308  WindowBindingHandlerDelegate* view_;
309  std::unique_ptr<TestKeyboardManagerWin32> keyboard_manager_;
310  std::list<ForgedMessageExpectation> forged_message_expectations_;
311  MapVirtualKeyToChar map_vk_to_char_;
312  TestKeystate key_state_;
313  std::list<Win32Message> redispatched_messages_;
314 };
315 
316 // A FlutterWindowsView that overrides the RegisterKeyboardHandlers function
317 // to register the keyboard hook handlers that can be spied upon.
318 class TestFlutterWindowsView : public FlutterWindowsView {
319  public:
320  typedef std::function<void(const std::u16string& text)> U16StringHandler;
321 
322  TestFlutterWindowsView(
323  U16StringHandler on_text,
326  // The WindowBindingHandler is used for window size and such, and doesn't
327  // affect keyboard.
328  : FlutterWindowsView(
329  std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>()),
330  get_keyboard_state_(std::move(get_keyboard_state)),
331  map_vk_to_scan_(std::move(map_vk_to_scan)),
332  on_text_(std::move(on_text)) {}
333 
334  void OnText(const std::u16string& text) override { on_text_(text); }
335 
336  void HandleMessage(const char* channel,
337  const char* method,
338  const char* args) {
339  rapidjson::Document args_doc;
340  args_doc.Parse(args);
341  assert(!args_doc.HasParseError());
342 
343  rapidjson::Document message_doc(rapidjson::kObjectType);
344  auto& allocator = message_doc.GetAllocator();
345  message_doc.AddMember("method", rapidjson::Value(method, allocator),
346  allocator);
347  message_doc.AddMember("args", args_doc, allocator);
348 
349  rapidjson::StringBuffer buffer;
350  rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
351  message_doc.Accept(writer);
352 
353  std::unique_ptr<std::vector<uint8_t>> data =
355  FlutterPlatformMessageResponseHandle response_handle;
357  sizeof(FlutterPlatformMessage), // struct_size
358  channel, // channel
359  data->data(), // message
360  data->size(), // message_size
361  &response_handle, // response_handle
362  };
363  GetEngine()->HandlePlatformMessage(&message);
364  }
365 
366  protected:
367  std::unique_ptr<KeyboardHandlerBase> CreateKeyboardKeyHandler(
368  BinaryMessenger* messenger,
371  override {
373  messenger,
374  [this](int virtual_key) { return get_keyboard_state_(virtual_key); },
375  [this](int virtual_key, bool extended) {
376  return map_vk_to_scan_(virtual_key, extended);
377  });
378  }
379 
380  private:
381  U16StringHandler on_text_;
384 };
385 
386 typedef struct {
387  enum {
388  kKeyCallOnKey,
389  kKeyCallOnText,
390  kKeyCallTextMethodCall,
391  } type;
392 
393  // Only one of the following fields should be assigned.
394  FlutterKeyEvent key_event; // For kKeyCallOnKey
395  std::u16string text; // For kKeyCallOnText
396  std::string text_method_call; // For kKeyCallTextMethodCall
397 } KeyCall;
398 
399 static std::vector<KeyCall> key_calls;
400 
401 void clear_key_calls() {
402  for (KeyCall& key_call : key_calls) {
403  if (key_call.type == KeyCall::kKeyCallOnKey &&
404  key_call.key_event.character != nullptr) {
405  delete[] key_call.key_event.character;
406  }
407  }
408  key_calls.clear();
409 }
410 
411 class KeyboardTester {
412  public:
413  using ResponseHandler =
414  std::function<void(MockKeyResponseController::ResponseCallback)>;
415 
416  explicit KeyboardTester()
417  : callback_handler_(RespondValue(false)),
418  map_virtual_key_layout_(LayoutDefault) {
419  view_ = std::make_unique<TestFlutterWindowsView>(
420  [](const std::u16string& text) {
421  key_calls.push_back(KeyCall{
422  .type = KeyCall::kKeyCallOnText,
423  .text = text,
424  });
425  },
426  [this](int virtual_key) -> SHORT {
427  // `window_` is not initialized yet when this callback is first
428  // called.
429  return window_ ? window_->GetKeyState(virtual_key) : 0;
430  },
431  [this](UINT virtual_key, bool extended) -> SHORT {
432  return map_virtual_key_layout_(
433  virtual_key, extended ? MAPVK_VK_TO_VSC_EX : MAPVK_VK_TO_VSC);
434  });
435  view_->SetEngine(GetTestEngine(
436  [&callback_handler = callback_handler_](
437  const FlutterKeyEvent* event,
439  FlutterKeyEvent clone_event = *event;
440  clone_event.character = event->character == nullptr
441  ? nullptr
442  : clone_string(event->character);
443  key_calls.push_back(KeyCall{
444  .type = KeyCall::kKeyCallOnKey,
445  .key_event = clone_event,
446  });
447  callback_handler(event, callback);
448  }));
449  window_ = std::make_unique<MockKeyboardManagerWin32Delegate>(
450  view_.get(), [this](UINT virtual_key) -> SHORT {
451  return map_virtual_key_layout_(virtual_key, MAPVK_VK_TO_CHAR);
452  });
453  }
454 
455  TestFlutterWindowsView& GetView() { return *view_; }
456  MockKeyboardManagerWin32Delegate& GetWindow() { return *window_; }
457 
458  // Set all events to be handled (true) or unhandled (false).
459  void Responding(bool response) { callback_handler_ = RespondValue(response); }
460 
461  // Manually handle event callback of the onKeyData embedder API.
462  //
463  // On every onKeyData call, the |handler| will be invoked with the target
464  // key data and the result callback. Immediately calling the callback with
465  // a boolean is equivalent to setting |Responding| with the boolean. However,
466  // |LateResponding| allows storing the callback to call later.
467  void LateResponding(
469  callback_handler_ = std::move(handler);
470  }
471 
472  void SetLayout(MapVirtualKeyLayout layout) {
473  map_virtual_key_layout_ = layout == nullptr ? LayoutDefault : layout;
474  }
475 
476  void InjectKeyboardChanges(std::vector<KeyboardChange> changes) {
477  assert(window_ != nullptr);
478  window_->InjectKeyboardChanges(changes);
479  }
480 
481  // Get the number of redispatched messages since the last clear, then clear
482  // the counter.
483  size_t RedispatchedMessageCountAndClear() {
484  auto& messages = window_->RedispatchedMessages();
485  size_t count = messages.size();
486  messages.clear();
487  return count;
488  }
489 
490  private:
491  std::unique_ptr<TestFlutterWindowsView> view_;
492  std::unique_ptr<MockKeyboardManagerWin32Delegate> window_;
494  MapVirtualKeyLayout map_virtual_key_layout_;
495 
496  // Returns an engine instance configured with dummy project path values, and
497  // overridden methods for sending platform messages, so that the engine can
498  // respond as if the framework were connected.
499  static std::unique_ptr<FlutterWindowsEngine> GetTestEngine(
501  embedder_callback_handler) {
502  FlutterDesktopEngineProperties properties = {};
503  properties.assets_path = L"C:\\foo\\flutter_assets";
504  properties.icu_data_path = L"C:\\foo\\icudtl.dat";
505  properties.aot_library_path = L"C:\\foo\\aot.so";
506  FlutterProjectBundle project(properties);
507  auto engine = std::make_unique<FlutterWindowsEngine>(project);
508 
509  EngineModifier modifier(engine.get());
510 
511  auto key_response_controller =
512  std::make_shared<MockKeyResponseController>();
513  key_response_controller->SetEmbedderResponse(
514  std::move(embedder_callback_handler));
515  key_response_controller->SetTextInputResponse(
516  [](std::unique_ptr<rapidjson::Document> document) {
517  rapidjson::StringBuffer buffer;
518  rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
519  document->Accept(writer);
520  key_calls.push_back(KeyCall{
521  .type = KeyCall::kKeyCallTextMethodCall,
522  .text_method_call = buffer.GetString(),
523  });
524  });
525 
526  MockEmbedderApiForKeyboard(modifier, key_response_controller);
527 
528  engine->RunWithEntrypoint(nullptr);
529  return engine;
530  }
531 
533  bool value) {
534  return [value](const FlutterKeyEvent* event,
536  callback(value);
537  };
538  }
539 };
540 
541 } // namespace
542 
543 // Define compound `expect` in macros. If they're defined in functions, the
544 // stacktrace wouldn't print where the function is called in the unit tests.
545 
546 #define EXPECT_CALL_IS_EVENT(_key_call, ...) \
547  EXPECT_EQ(_key_call.type, KeyCall::kKeyCallOnKey); \
548  EXPECT_EVENT_EQUALS(_key_call.key_event, __VA_ARGS__);
549 
550 #define EXPECT_CALL_IS_TEXT(_key_call, u16_string) \
551  EXPECT_EQ(_key_call.type, KeyCall::kKeyCallOnText); \
552  EXPECT_EQ(_key_call.text, u16_string);
553 
554 #define EXPECT_CALL_IS_TEXT_METHOD_CALL(_key_call, json_string) \
555  EXPECT_EQ(_key_call.type, KeyCall::kKeyCallTextMethodCall); \
556  EXPECT_STREQ(_key_call.text_method_call.c_str(), json_string);
557 
558 TEST(KeyboardTest, LowerCaseAHandled) {
559  KeyboardTester tester;
560  tester.Responding(true);
561 
562  // US Keyboard layout
563 
564  // Press A
565  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
567  kWmResultZero),
569  kWmResultZero)});
570 
571  EXPECT_EQ(key_calls.size(), 1);
573  kLogicalKeyA, "a", kNotSynthesized);
574  clear_key_calls();
575  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
576 
577  // Release A
578  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
580  kWmResultZero)});
581 
582  EXPECT_EQ(key_calls.size(), 1);
584  kLogicalKeyA, "", kNotSynthesized);
585  clear_key_calls();
586  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
587 }
588 
589 TEST(KeyboardTest, LowerCaseAUnhandled) {
590  KeyboardTester tester;
591  tester.Responding(false);
592 
593  // US Keyboard layout
594 
595  // Press A
596  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
598  kWmResultZero),
600  kWmResultZero)});
601 
602  EXPECT_EQ(key_calls.size(), 2);
604  kLogicalKeyA, "a", kNotSynthesized);
605  EXPECT_CALL_IS_TEXT(key_calls[1], u"a");
606  clear_key_calls();
607  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
608 
609  // Release A
610  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
612  kWmResultZero)});
613 
614  EXPECT_EQ(key_calls.size(), 1);
616  kLogicalKeyA, "", kNotSynthesized);
617  clear_key_calls();
618  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
619 }
620 
621 TEST(KeyboardTest, ArrowLeftHandled) {
622  KeyboardTester tester;
623  tester.Responding(true);
624 
625  // US Keyboard layout
626 
627  // Press ArrowLeft
628  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
629  WmKeyDownInfo{VK_LEFT, kScanCodeArrowLeft, kExtended, kWasUp}.Build(
630  kWmResultZero)});
631 
632  EXPECT_EQ(key_calls.size(), 1);
635  kNotSynthesized);
636  clear_key_calls();
637  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
638 
639  // Release ArrowLeft
640  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
641  WmKeyUpInfo{VK_LEFT, kScanCodeArrowLeft, kExtended}.Build(
642  kWmResultZero)});
643 
644  EXPECT_EQ(key_calls.size(), 1);
646  kLogicalArrowLeft, "", kNotSynthesized);
647  clear_key_calls();
648  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
649 }
650 
651 TEST(KeyboardTest, ArrowLeftUnhandled) {
652  KeyboardTester tester;
653  tester.Responding(false);
654 
655  // US Keyboard layout
656 
657  // Press ArrowLeft
658  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
659  WmKeyDownInfo{VK_LEFT, kScanCodeArrowLeft, kExtended, kWasUp}.Build(
660  kWmResultZero)});
661 
662  EXPECT_EQ(key_calls.size(), 1);
665  kNotSynthesized);
666  clear_key_calls();
667  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
668 
669  // Release ArrowLeft
670  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
671  WmKeyUpInfo{VK_LEFT, kScanCodeArrowLeft, kExtended}.Build(
672  kWmResultZero)});
673 
674  EXPECT_EQ(key_calls.size(), 1);
676  kLogicalArrowLeft, "", kNotSynthesized);
677  clear_key_calls();
678  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
679 }
680 
681 TEST(KeyboardTest, ShiftLeftUnhandled) {
682  KeyboardTester tester;
683  tester.Responding(false);
684 
685  // US Keyboard layout
686 
687  // Press ShiftLeft
688  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
689  KeyStateChange{VK_LSHIFT, true, false},
690  WmKeyDownInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended, kWasUp}.Build(
691  kWmResultZero)});
692 
693  EXPECT_EQ(key_calls.size(), 1);
696  kNotSynthesized);
697  clear_key_calls();
698  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
699 
700  // Release ShiftLeft
701  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
702  KeyStateChange{VK_LSHIFT, false, true},
703  WmKeyUpInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended}.Build(
704  kWmResultZero)});
705 
706  EXPECT_EQ(key_calls.size(), 1);
708  kLogicalShiftLeft, "", kNotSynthesized);
709  clear_key_calls();
710  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
711 }
712 
713 TEST(KeyboardTest, ShiftRightUnhandled) {
714  KeyboardTester tester;
715  tester.Responding(false);
716 
717  // US Keyboard layout
718 
719  // Press ShiftRight
720  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
721  KeyStateChange{VK_RSHIFT, true, false},
722  WmKeyDownInfo{VK_SHIFT, kScanCodeShiftRight, kNotExtended, kWasUp}.Build(
723  kWmResultZero)});
724 
725  EXPECT_EQ(key_calls.size(), 1);
728  kNotSynthesized);
729  clear_key_calls();
730  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
731 
732  // Release ShiftRight
733  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
734  KeyStateChange{VK_RSHIFT, false, true},
735  WmKeyUpInfo{VK_SHIFT, kScanCodeShiftRight, kNotExtended}.Build(
736  kWmResultZero)});
737 
738  EXPECT_EQ(key_calls.size(), 1);
741  kNotSynthesized);
742  clear_key_calls();
743  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
744 }
745 
746 TEST(KeyboardTest, CtrlLeftUnhandled) {
747  KeyboardTester tester;
748  tester.Responding(false);
749 
750  // US Keyboard layout
751 
752  // Press CtrlLeft
753  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
754  KeyStateChange{VK_LCONTROL, true, false},
755  WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build(
756  kWmResultZero)});
757 
758  EXPECT_EQ(key_calls.size(), 1);
761  kNotSynthesized);
762  clear_key_calls();
763  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
764 
765  // Release CtrlLeft
766  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
767  KeyStateChange{VK_LCONTROL, false, true},
768  WmKeyUpInfo{VK_SHIFT, kScanCodeControl, kNotExtended}.Build(
769  kWmResultZero)});
770 
771  EXPECT_EQ(key_calls.size(), 1);
774  kNotSynthesized);
775  clear_key_calls();
776  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
777 }
778 
779 TEST(KeyboardTest, CtrlRightUnhandled) {
780  KeyboardTester tester;
781  tester.Responding(false);
782 
783  // US Keyboard layout
784 
785  // Press CtrlRight
786  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
787  KeyStateChange{VK_RCONTROL, true, false},
788  WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kExtended, kWasUp}.Build(
789  kWmResultZero)});
790 
791  EXPECT_EQ(key_calls.size(), 1);
794  kNotSynthesized);
795  clear_key_calls();
796  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
797 
798  // Release CtrlRight
799  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
800  KeyStateChange{VK_RCONTROL, false, true},
801  WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kExtended}.Build(
802  kWmResultZero)});
803 
804  EXPECT_EQ(key_calls.size(), 1);
807  kNotSynthesized);
808  clear_key_calls();
809  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
810 }
811 
812 TEST(KeyboardTest, AltLeftUnhandled) {
813  KeyboardTester tester;
814  tester.Responding(false);
815 
816  // US Keyboard layout
817 
818  // Press AltLeft. AltLeft is a SysKeyDown event.
819  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
820  KeyStateChange{VK_LMENU, true, false},
821  WmSysKeyDownInfo{VK_MENU, kScanCodeAlt, kNotExtended, kWasUp}.Build(
822  kWmResultDefault)}); // Always pass to the default WndProc.
823 
824  EXPECT_EQ(key_calls.size(), 1);
826  kLogicalAltLeft, "", kNotSynthesized);
827  clear_key_calls();
828  // Don't redispatch sys messages.
829  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
830 
831  // Release AltLeft. AltLeft is a SysKeyUp event.
832  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
833  KeyStateChange{VK_LMENU, false, true},
834  WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kNotExtended}.Build(
835  kWmResultDefault)}); // Always pass to the default WndProc.
836 
837  EXPECT_EQ(key_calls.size(), 1);
839  kLogicalAltLeft, "", kNotSynthesized);
840  clear_key_calls();
841  // Don't redispatch sys messages.
842  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
843 }
844 
845 TEST(KeyboardTest, AltRightUnhandled) {
846  KeyboardTester tester;
847  tester.Responding(false);
848 
849  // US Keyboard layout
850 
851  // Press AltRight. AltRight is a SysKeyDown event.
852  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
853  KeyStateChange{VK_RMENU, true, false},
854  WmSysKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build(
855  kWmResultDefault)}); // Always pass to the default WndProc.
856 
857  EXPECT_EQ(key_calls.size(), 1);
860  kNotSynthesized);
861  clear_key_calls();
862  // Don't redispatch sys messages.
863  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
864 
865  // Release AltRight. AltRight is a SysKeyUp event.
866  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
867  KeyStateChange{VK_RMENU, false, true},
868  WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build(
869  kWmResultDefault)}); // Always pass to the default WndProc.
870 
871  EXPECT_EQ(key_calls.size(), 1);
873  kLogicalAltRight, "", kNotSynthesized);
874  clear_key_calls();
875  // Don't redispatch sys messages.
876  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
877 }
878 
879 TEST(KeyboardTest, MetaLeftUnhandled) {
880  KeyboardTester tester;
881  tester.Responding(false);
882 
883  // US Keyboard layout
884 
885  // Press MetaLeft
886  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
887  KeyStateChange{VK_LWIN, true, false},
888  WmKeyDownInfo{VK_LWIN, kScanCodeMetaLeft, kExtended, kWasUp}.Build(
889  kWmResultZero)});
890 
891  EXPECT_EQ(key_calls.size(), 1);
894  kNotSynthesized);
895  clear_key_calls();
896  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
897 
898  // Release MetaLeft
899  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
900  KeyStateChange{VK_LWIN, false, true},
901  WmKeyUpInfo{VK_LWIN, kScanCodeMetaLeft, kExtended}.Build(kWmResultZero)});
902 
903  EXPECT_EQ(key_calls.size(), 1);
905  kLogicalMetaLeft, "", kNotSynthesized);
906  clear_key_calls();
907  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
908 }
909 
910 TEST(KeyboardTest, MetaRightUnhandled) {
911  KeyboardTester tester;
912  tester.Responding(false);
913 
914  // US Keyboard layout
915 
916  // Press MetaRight
917  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
918  KeyStateChange{VK_RWIN, true, false},
919  WmKeyDownInfo{VK_RWIN, kScanCodeMetaRight, kExtended, kWasUp}.Build(
920  kWmResultZero)});
921 
922  EXPECT_EQ(key_calls.size(), 1);
925  kNotSynthesized);
926  clear_key_calls();
927  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
928 
929  // Release MetaRight
930  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
931  KeyStateChange{VK_RWIN, false, true},
932  WmKeyUpInfo{VK_RWIN, kScanCodeMetaRight, kExtended}.Build(
933  kWmResultZero)});
934 
935  EXPECT_EQ(key_calls.size(), 1);
937  kLogicalMetaRight, "", kNotSynthesized);
938  clear_key_calls();
939  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
940 }
941 
942 // Press Shift-A. This is special because Win32 gives 'A' as character for the
943 // KeyA press.
944 TEST(KeyboardTest, ShiftLeftKeyA) {
945  KeyboardTester tester;
946  tester.Responding(false);
947 
948  // US Keyboard layout
949 
950  // Press ShiftLeft
951  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
952  KeyStateChange{VK_LSHIFT, true, true},
953  WmKeyDownInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended, kWasUp}.Build(
954  kWmResultZero)});
955 
956  EXPECT_EQ(key_calls.size(), 1);
959  kNotSynthesized);
960  clear_key_calls();
961  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
962 
963  // Press A
964  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
966  kWmResultZero),
968  kWmResultZero)});
969 
970  EXPECT_EQ(key_calls.size(), 2);
972  kLogicalKeyA, "A", kNotSynthesized);
973  EXPECT_CALL_IS_TEXT(key_calls[1], u"A");
974  clear_key_calls();
975  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
976 
977  // Release ShiftLeft
978  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
979  KeyStateChange{VK_LSHIFT, false, true},
980  WmKeyUpInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended}.Build(
981  kWmResultZero)});
982 
983  EXPECT_EQ(key_calls.size(), 1);
985  kLogicalShiftLeft, "", kNotSynthesized);
986  clear_key_calls();
987  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
988 
989  // Release A
990  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
992  kWmResultZero)});
993 
994  EXPECT_EQ(key_calls.size(), 1);
996  kLogicalKeyA, "", kNotSynthesized);
997  clear_key_calls();
998  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
999 }
1000 
1001 // Press Ctrl-A. This is special because Win32 gives 0x01 as character for the
1002 // KeyA press.
1003 TEST(KeyboardTest, CtrlLeftKeyA) {
1004  KeyboardTester tester;
1005  tester.Responding(false);
1006 
1007  // US Keyboard layout
1008 
1009  // Press ControlLeft
1010  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1011  KeyStateChange{VK_LCONTROL, true, true},
1012  WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build(
1013  kWmResultZero)});
1014 
1015  EXPECT_EQ(key_calls.size(), 1);
1018  kNotSynthesized);
1019  clear_key_calls();
1020  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1021 
1022  // Press A
1023  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1025  kWmResultZero),
1027  kWmResultZero)});
1028 
1029  EXPECT_EQ(key_calls.size(), 1);
1031  kLogicalKeyA, "", kNotSynthesized);
1032  clear_key_calls();
1033  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1034 
1035  // Release A
1036  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1038  kWmResultZero)});
1039 
1040  EXPECT_EQ(key_calls.size(), 1);
1042  kLogicalKeyA, "", kNotSynthesized);
1043  clear_key_calls();
1044  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1045 
1046  // Release ControlLeft
1047  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1048  KeyStateChange{VK_LCONTROL, false, true},
1049  WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build(
1050  kWmResultZero)});
1051 
1052  EXPECT_EQ(key_calls.size(), 1);
1055  kNotSynthesized);
1056  clear_key_calls();
1057  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1058 }
1059 
1060 // Press Ctrl-1. This is special because it yields no WM_CHAR for the 1.
1061 TEST(KeyboardTest, CtrlLeftDigit1) {
1062  KeyboardTester tester;
1063  tester.Responding(false);
1064 
1065  // US Keyboard layout
1066 
1067  // Press ControlLeft
1068  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1069  KeyStateChange{VK_LCONTROL, true, true},
1070  WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build(
1071  kWmResultZero)});
1072 
1073  EXPECT_EQ(key_calls.size(), 1);
1076  kNotSynthesized);
1077  clear_key_calls();
1078  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1079 
1080  // Press 1
1081  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1082  WmKeyDownInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended, kWasUp}
1083  .Build(kWmResultZero)});
1084 
1085  EXPECT_EQ(key_calls.size(), 1);
1087  kLogicalDigit1, "", kNotSynthesized);
1088  clear_key_calls();
1089  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1090 
1091  // Release 1
1092  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1093  WmKeyUpInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended}.Build(
1094  kWmResultZero)});
1095 
1096  EXPECT_EQ(key_calls.size(), 1);
1098  kLogicalDigit1, "", kNotSynthesized);
1099  clear_key_calls();
1100  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1101 
1102  // Release ControlLeft
1103  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1104  KeyStateChange{VK_LCONTROL, false, true},
1105  WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build(
1106  kWmResultZero)});
1107 
1108  EXPECT_EQ(key_calls.size(), 1);
1111  kNotSynthesized);
1112  clear_key_calls();
1113  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1114 }
1115 
1116 // Press 1 on a French keyboard. This is special because it yields WM_CHAR
1117 // with char_code '&'.
1118 TEST(KeyboardTest, Digit1OnFrenchLayout) {
1119  KeyboardTester tester;
1120  tester.Responding(false);
1121 
1122  tester.SetLayout(LayoutFrench);
1123 
1124  // Press 1
1125  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1126  WmKeyDownInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended, kWasUp}
1127  .Build(kWmResultZero),
1128  WmCharInfo{'&', kScanCodeDigit1, kNotExtended, kWasUp}.Build(
1129  kWmResultZero)});
1130 
1131  EXPECT_EQ(key_calls.size(), 2);
1133  kLogicalDigit1, "&", kNotSynthesized);
1134  EXPECT_CALL_IS_TEXT(key_calls[1], u"&");
1135  clear_key_calls();
1136  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1137 
1138  // Release 1
1139  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1140  WmKeyUpInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended}.Build(
1141  kWmResultZero)});
1142 
1143  EXPECT_EQ(key_calls.size(), 1);
1145  kLogicalDigit1, "", kNotSynthesized);
1146  clear_key_calls();
1147  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1148 }
1149 
1150 // This tests AltGr-Q on a German keyboard, which should print '@'.
1151 TEST(KeyboardTest, AltGrModifiedKey) {
1152  KeyboardTester tester;
1153  tester.Responding(false);
1154 
1155  // German Keyboard layout
1156 
1157  // Press AltGr, which Win32 precedes with a ContrlLeft down.
1158  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1159  KeyStateChange{VK_LCONTROL, true, true},
1160  WmKeyDownInfo{VK_LCONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build(
1161  kWmResultZero),
1162  KeyStateChange{VK_RMENU, true, true},
1163  WmKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build(
1164  kWmResultZero)});
1165 
1166  EXPECT_EQ(key_calls.size(), 2);
1169  kNotSynthesized);
1172  kNotSynthesized);
1173  clear_key_calls();
1174  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1175 
1176  // Press Q
1177  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1178  WmKeyDownInfo{kVirtualKeyQ, kScanCodeKeyQ, kNotExtended, kWasUp}.Build(
1179  kWmResultZero),
1180  WmCharInfo{'@', kScanCodeKeyQ, kNotExtended, kWasUp}.Build(
1181  kWmResultZero)});
1182 
1183  EXPECT_EQ(key_calls.size(), 2);
1185  kLogicalKeyQ, "@", kNotSynthesized);
1186  EXPECT_CALL_IS_TEXT(key_calls[1], u"@");
1187  clear_key_calls();
1188  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1189 
1190  // Release Q
1191  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1192  WmKeyUpInfo{kVirtualKeyQ, kScanCodeKeyQ, kNotExtended}.Build(
1193  kWmResultZero)});
1194 
1195  EXPECT_EQ(key_calls.size(), 1);
1197  kLogicalKeyQ, "", kNotSynthesized);
1198  clear_key_calls();
1199  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1200 
1201  // Release AltGr. Win32 doesn't dispatch ControlLeft up. Instead Flutter will
1202  // forge one. The AltGr is a system key, therefore will be handled by Win32's
1203  // default WndProc.
1204  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1205  KeyStateChange{VK_LCONTROL, false, true},
1206  ExpectForgedMessage{
1207  WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build(
1208  kWmResultZero)},
1209  KeyStateChange{VK_RMENU, false, true},
1210  WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build(
1211  kWmResultDefault)});
1212 
1213  EXPECT_EQ(key_calls.size(), 2);
1216  kNotSynthesized);
1218  kLogicalAltRight, "", kNotSynthesized);
1219  clear_key_calls();
1220  // The sys key up must not be redispatched. The forged ControlLeft up will.
1221  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1222 }
1223 
1224 // Test the following two key sequences at the same time:
1225 //
1226 // 1. Tap AltGr, then tap AltGr.
1227 // 2. Tap AltGr, hold CtrlLeft, tap AltGr, release CtrlLeft.
1228 //
1229 // The two sequences are indistinguishable until the very end when a CtrlLeft
1230 // up event might or might not follow.
1231 //
1232 // Sequence 1: CtrlLeft down, AltRight down, AltRight up
1233 // Sequence 2: CtrlLeft down, AltRight down, AltRight up, CtrlLeft up
1234 //
1235 // This is because pressing AltGr alone causes Win32 to send a fake "CtrlLeft
1236 // down" event first (see |IsKeyDownAltRight| for detailed explanation).
1237 TEST(KeyboardTest, AltGrTwice) {
1238  KeyboardTester tester;
1239  tester.Responding(false);
1240 
1241  // 1. AltGr down.
1242 
1243  // The key down event causes a ControlLeft down and a AltRight (extended
1244  // AltLeft) down.
1245  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1246  KeyStateChange{VK_LCONTROL, true, true},
1247  WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build(
1248  kWmResultZero),
1249  KeyStateChange{VK_RMENU, true, true},
1250  WmKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build(
1251  kWmResultZero)});
1252 
1253  EXPECT_EQ(key_calls.size(), 2);
1256  kNotSynthesized);
1259  kNotSynthesized);
1260  clear_key_calls();
1261  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1262 
1263  // 2. AltGr up.
1264 
1265  // The key up event only causes a AltRight (extended AltLeft) up.
1266  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1267  KeyStateChange{VK_LCONTROL, false, true},
1268  ExpectForgedMessage{
1269  WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build(
1270  kWmResultZero)},
1271  KeyStateChange{VK_RMENU, false, true},
1272  WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build(
1273  kWmResultDefault)});
1274  EXPECT_EQ(key_calls.size(), 2);
1277  kNotSynthesized);
1279  kLogicalAltRight, "", kNotSynthesized);
1280  clear_key_calls();
1281  // The sys key up must not be redispatched. The forged ControlLeft up will.
1282  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1283 
1284  // 3. AltGr down (or: ControlLeft down then AltRight down.)
1285 
1286  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1287  KeyStateChange{VK_LCONTROL, true, false},
1288  WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build(
1289  kWmResultZero),
1290  KeyStateChange{VK_RMENU, true, true},
1291  WmKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build(
1292  kWmResultZero)});
1293 
1294  EXPECT_EQ(key_calls.size(), 2);
1297  kNotSynthesized);
1300  kNotSynthesized);
1301  clear_key_calls();
1302  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1303 
1304  // 4. AltGr up.
1305 
1306  // The key up event only causes a AltRight (extended AltLeft) up.
1307  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1308  KeyStateChange{VK_LCONTROL, false, false},
1309  ExpectForgedMessage{
1310  WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build(
1311  kWmResultZero)},
1312  KeyStateChange{VK_RMENU, false, false},
1313  WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build(
1314  kWmResultDefault)});
1315  EXPECT_EQ(key_calls.size(), 2);
1318  kNotSynthesized);
1320  kLogicalAltRight, "", kNotSynthesized);
1321  clear_key_calls();
1322  // The sys key up must not be redispatched. The forged ControlLeft up will.
1323  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1324 
1325  // 5. For key sequence 2: a real ControlLeft up.
1326  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1327  WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build(
1328  kWmResultZero)});
1329  EXPECT_EQ(key_calls.size(), 1);
1330  EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, 0, 0, "",
1331  kNotSynthesized);
1332  clear_key_calls();
1333  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
1334 }
1335 
1336 // This tests dead key ^ then E on a French keyboard, which should be combined
1337 // into ê.
1338 TEST(KeyboardTest, DeadKeyThatCombines) {
1339  KeyboardTester tester;
1340  tester.Responding(false);
1341 
1342  tester.SetLayout(LayoutFrench);
1343 
1344  // Press ^¨ (US: Left bracket)
1345  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1346  WmKeyDownInfo{0xDD, kScanCodeBracketLeft, kNotExtended, kWasUp}.Build(
1347  kWmResultZero),
1348  WmDeadCharInfo{'^', kScanCodeBracketLeft, kNotExtended, kWasUp}.Build(
1349  kWmResultZero)});
1350 
1351  EXPECT_EQ(key_calls.size(), 1);
1354  kNotSynthesized);
1355  clear_key_calls();
1356  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1357 
1358  // Release ^¨
1359  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1360  WmKeyUpInfo{0xDD, kScanCodeBracketLeft, kNotExtended}.Build(
1361  kWmResultZero)});
1362 
1363  EXPECT_EQ(key_calls.size(), 1);
1366  kNotSynthesized);
1367  clear_key_calls();
1368  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1369 
1370  // Press E
1371  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1372  WmKeyDownInfo{kVirtualKeyE, kScanCodeKeyE, kNotExtended, kWasUp}.Build(
1373  kWmResultZero),
1374  WmCharInfo{0xEA, kScanCodeKeyE, kNotExtended, kWasUp}.Build(
1375  kWmResultZero)});
1376 
1377  EXPECT_EQ(key_calls.size(), 2);
1379  kLogicalKeyE, "ê", kNotSynthesized);
1380  EXPECT_CALL_IS_TEXT(key_calls[1], u"ê");
1381  clear_key_calls();
1382  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1383 
1384  // Release E
1385  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1386  WmKeyUpInfo{kVirtualKeyE, kScanCodeKeyE, kNotExtended}.Build(
1387  kWmResultZero)});
1388 
1389  EXPECT_EQ(key_calls.size(), 1);
1391  kLogicalKeyE, "", kNotSynthesized);
1392  clear_key_calls();
1393  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1394 }
1395 
1396 // This tests dead key ^ then E on a US INTL keyboard, which should be combined
1397 // into ê.
1398 //
1399 // It is different from French AZERTY because the character that the ^ key is
1400 // mapped to does not contain the dead key character somehow.
1401 TEST(KeyboardTest, DeadKeyWithoutDeadMaskThatCombines) {
1402  KeyboardTester tester;
1403  tester.Responding(false);
1404 
1405  // Press ShiftLeft
1406  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1407  KeyStateChange{VK_LSHIFT, true, true},
1408  WmKeyDownInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended, kWasUp}.Build(
1409  kWmResultZero)});
1410 
1411  EXPECT_EQ(key_calls.size(), 1);
1414  kNotSynthesized);
1415  clear_key_calls();
1416  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1417 
1418  // Press 6^
1419  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1420  WmKeyDownInfo{'6', kScanCodeDigit6, kNotExtended, kWasUp}.Build(
1421  kWmResultZero),
1422  WmDeadCharInfo{'^', kScanCodeDigit6, kNotExtended, kWasUp}.Build(
1423  kWmResultZero)});
1424 
1425  EXPECT_EQ(key_calls.size(), 1);
1427  kLogicalDigit6, "6", kNotSynthesized);
1428  clear_key_calls();
1429  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1430 
1431  // Release 6^
1432  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1433  WmKeyUpInfo{'6', kScanCodeDigit6, kNotExtended}.Build(kWmResultZero)});
1434 
1435  EXPECT_EQ(key_calls.size(), 1);
1437  kLogicalDigit6, "", kNotSynthesized);
1438  clear_key_calls();
1439  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1440 
1441  // Release ShiftLeft
1442  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1443  KeyStateChange{VK_LSHIFT, false, true},
1444  WmKeyUpInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended}.Build(
1445  kWmResultZero)});
1446 
1447  EXPECT_EQ(key_calls.size(), 1);
1449  kLogicalShiftLeft, "", kNotSynthesized);
1450  clear_key_calls();
1451  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1452 
1453  // Press E
1454  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1455  WmKeyDownInfo{kVirtualKeyE, kScanCodeKeyE, kNotExtended, kWasUp}.Build(
1456  kWmResultZero),
1457  WmCharInfo{0xEA, kScanCodeKeyE, kNotExtended, kWasUp}.Build(
1458  kWmResultZero)});
1459 
1460  EXPECT_EQ(key_calls.size(), 2);
1462  kLogicalKeyE, "ê", kNotSynthesized);
1463  EXPECT_CALL_IS_TEXT(key_calls[1], u"ê");
1464  clear_key_calls();
1465  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1466 
1467  // Release E
1468  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1469  WmKeyUpInfo{kVirtualKeyE, kScanCodeKeyE, kNotExtended}.Build(
1470  kWmResultZero)});
1471 
1472  EXPECT_EQ(key_calls.size(), 1);
1474  kLogicalKeyE, "", kNotSynthesized);
1475  clear_key_calls();
1476  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1477 }
1478 
1479 // This tests dead key ^ then & (US: 1) on a French keyboard, which do not
1480 // combine and should output "^&".
1481 TEST(KeyboardTest, DeadKeyThatDoesNotCombine) {
1482  KeyboardTester tester;
1483  tester.Responding(false);
1484 
1485  tester.SetLayout(LayoutFrench);
1486 
1487  // Press ^¨ (US: Left bracket)
1488  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1489  WmKeyDownInfo{0xDD, kScanCodeBracketLeft, kNotExtended, kWasUp}.Build(
1490  kWmResultZero),
1491  WmDeadCharInfo{'^', kScanCodeBracketLeft, kNotExtended, kWasUp}.Build(
1492  kWmResultZero)});
1493 
1494  EXPECT_EQ(key_calls.size(), 1);
1497  kNotSynthesized);
1498  clear_key_calls();
1499  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1500 
1501  // Release ^¨
1502  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1503  WmKeyUpInfo{0xDD, kScanCodeBracketLeft, kNotExtended}.Build(
1504  kWmResultZero)});
1505 
1506  EXPECT_EQ(key_calls.size(), 1);
1509  kNotSynthesized);
1510  clear_key_calls();
1511  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1512 
1513  // Press 1
1514  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1515  WmKeyDownInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended, kWasUp}
1516  .Build(kWmResultZero),
1517  WmCharInfo{'^', kScanCodeDigit1, kNotExtended, kWasUp}.Build(
1518  kWmResultZero),
1519  WmCharInfo{'&', kScanCodeDigit1, kNotExtended, kWasUp}.Build(
1520  kWmResultZero)});
1521 
1522  EXPECT_EQ(key_calls.size(), 3);
1524  kLogicalDigit1, "^", kNotSynthesized);
1525  EXPECT_CALL_IS_TEXT(key_calls[1], u"^");
1526  EXPECT_CALL_IS_TEXT(key_calls[2], u"&");
1527  clear_key_calls();
1528  // TODO(dkwingsmt): This count should probably be 3. Currently the '^'
1529  // message is redispatched due to being part of the KeyDown session, which is
1530  // not handled by the framework, while the '&' message is not redispatched
1531  // for being a standalone message. We should resolve this inconsistency.
1532  // https://github.com/flutter/flutter/issues/98306
1533  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1534 
1535  // Release 1
1536  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1537  WmKeyUpInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended}.Build(
1538  kWmResultZero)});
1539 
1540  EXPECT_EQ(key_calls.size(), 1);
1542  kLogicalDigit1, "", kNotSynthesized);
1543  clear_key_calls();
1544  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1545 }
1546 
1547 // This tests dead key `, then dead key `, then e.
1548 //
1549 // It should output ``e, instead of `è.
1550 TEST(KeyboardTest, DeadKeyTwiceThenLetter) {
1551  KeyboardTester tester;
1552  tester.Responding(false);
1553 
1554  // US INTL layout.
1555 
1556  // Press `
1557  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1558  WmKeyDownInfo{0xC0, kScanCodeBackquote, kNotExtended, kWasUp}.Build(
1559  kWmResultZero),
1560  WmDeadCharInfo{'`', kScanCodeBackquote, kNotExtended, kWasUp}.Build(
1561  kWmResultZero)});
1562 
1563  EXPECT_EQ(key_calls.size(), 1);
1566  kNotSynthesized);
1567  clear_key_calls();
1568  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1569 
1570  // Release `
1571  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1572  WmKeyUpInfo{0xC0, kScanCodeBackquote, kNotExtended}.Build(
1573  kWmResultZero)});
1574 
1575  EXPECT_EQ(key_calls.size(), 1);
1577  kLogicalBackquote, "", kNotSynthesized);
1578  clear_key_calls();
1579  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1580 
1581  // Press ` again.
1582  // The response should be slow.
1583  std::vector<MockKeyResponseController::ResponseCallback> recorded_callbacks;
1584  tester.LateResponding(
1585  [&recorded_callbacks](
1586  const FlutterKeyEvent* event,
1588  recorded_callbacks.push_back(callback);
1589  });
1590 
1591  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1592  WmKeyDownInfo{0xC0, kScanCodeBackquote, kNotExtended, kWasUp}.Build(
1593  kWmResultZero),
1594  WmCharInfo{'`', kScanCodeBackquote, kNotExtended, kWasUp, kBeingReleased,
1595  kNoContext, 1, /*bit25*/ true}
1596  .Build(kWmResultZero),
1597  WmCharInfo{'`', kScanCodeBackquote, kNotExtended, kWasUp}.Build(
1598  kWmResultZero)});
1599 
1600  EXPECT_EQ(recorded_callbacks.size(), 1);
1601  EXPECT_EQ(key_calls.size(), 1);
1604  kNotSynthesized);
1605  clear_key_calls();
1606  // Key down event responded with false.
1607  recorded_callbacks.front()(false);
1608  EXPECT_EQ(key_calls.size(), 2);
1609  EXPECT_CALL_IS_TEXT(key_calls[0], u"`");
1610  EXPECT_CALL_IS_TEXT(key_calls[1], u"`");
1611  clear_key_calls();
1612  // TODO(dkwingsmt): This count should probably be 3. See the comment above
1613  // that is marked with the same issue.
1614  // https://github.com/flutter/flutter/issues/98306
1615  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1616 
1617  tester.Responding(false);
1618 
1619  // Release `
1620  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1621  WmKeyUpInfo{0xC0, kScanCodeBackquote, kNotExtended}.Build(
1622  kWmResultZero)});
1623 
1624  EXPECT_EQ(key_calls.size(), 1);
1626  kLogicalBackquote, "", kNotSynthesized);
1627  clear_key_calls();
1628  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1629 }
1630 
1631 // This tests when the resulting character needs to be combined with surrogates.
1632 TEST(KeyboardTest, MultibyteCharacter) {
1633  KeyboardTester tester;
1634  tester.Responding(false);
1635 
1636  // Gothic Keyboard layout. (We need a layout that yields non-BMP characters
1637  // without IME, which is actually very rare.)
1638 
1639  // Press key W of a US keyboard, which should yield character '𐍅'.
1640  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1641  WmKeyDownInfo{kVirtualKeyW, kScanCodeKeyW, kNotExtended, kWasUp}.Build(
1642  kWmResultZero),
1643  WmCharInfo{0xd800, kScanCodeKeyW, kNotExtended, kWasUp}.Build(
1644  kWmResultZero),
1645  WmCharInfo{0xdf45, kScanCodeKeyW, kNotExtended, kWasUp}.Build(
1646  kWmResultZero)});
1647 
1648  const char* st = key_calls[0].key_event.character;
1649 
1650  EXPECT_EQ(key_calls.size(), 2);
1652  kLogicalKeyW, "𐍅", kNotSynthesized);
1653  EXPECT_CALL_IS_TEXT(key_calls[1], u"𐍅");
1654  clear_key_calls();
1655  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 3);
1656 
1657  // Release W
1658  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1659  WmKeyUpInfo{kVirtualKeyW, kScanCodeKeyW, kNotExtended}.Build(
1660  kWmResultZero)});
1661 
1662  EXPECT_EQ(key_calls.size(), 1);
1664  kLogicalKeyW, "", kNotSynthesized);
1665  clear_key_calls();
1666  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1667 }
1668 
1669 TEST(KeyboardTest, SynthesizeModifiers) {
1670  KeyboardTester tester;
1671  tester.Responding(false);
1672 
1673  // Two dummy events used to trigger synthesization.
1674  Win32Message event1 =
1675  WmKeyDownInfo{VK_BACK, kScanCodeBackspace, kNotExtended, kWasUp}.Build(
1676  kWmResultZero);
1677  Win32Message event2 =
1678  WmKeyUpInfo{VK_BACK, kScanCodeBackspace, kNotExtended}.Build(
1679  kWmResultZero);
1680 
1681  // ShiftLeft
1682  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1683  KeyStateChange{VK_LSHIFT, true, true}, event1});
1684  EXPECT_EQ(key_calls.size(), 2);
1686  kPhysicalShiftLeft, kLogicalShiftLeft, "", kSynthesized);
1687  clear_key_calls();
1688  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1689 
1690  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1691  KeyStateChange{VK_LSHIFT, false, true}, event2});
1692  EXPECT_EQ(key_calls.size(), 2);
1694  kLogicalShiftLeft, "", kSynthesized);
1695  clear_key_calls();
1696  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1697 
1698  // ShiftRight
1699  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1700  KeyStateChange{VK_RSHIFT, true, true}, event1});
1701  EXPECT_EQ(key_calls.size(), 2);
1704  kSynthesized);
1705  clear_key_calls();
1706  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1707 
1708  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1709  KeyStateChange{VK_RSHIFT, false, true}, event2});
1710  EXPECT_EQ(key_calls.size(), 2);
1713  kSynthesized);
1714  clear_key_calls();
1715  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1716 
1717  // ControlLeft
1718  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1719  KeyStateChange{VK_LCONTROL, true, true}, event1});
1720  EXPECT_EQ(key_calls.size(), 2);
1723  kSynthesized);
1724  clear_key_calls();
1725  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1726 
1727  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1728  KeyStateChange{VK_LCONTROL, false, true}, event2});
1729  EXPECT_EQ(key_calls.size(), 2);
1732  kSynthesized);
1733  clear_key_calls();
1734  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1735 
1736  // ControlRight
1737  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1738  KeyStateChange{VK_RCONTROL, true, true}, event1});
1739  EXPECT_EQ(key_calls.size(), 2);
1742  kSynthesized);
1743  clear_key_calls();
1744  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1745 
1746  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1747  KeyStateChange{VK_RCONTROL, false, true}, event2});
1748  EXPECT_EQ(key_calls.size(), 2);
1751  kSynthesized);
1752  clear_key_calls();
1753  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1754 
1755  // AltLeft
1756  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1757  KeyStateChange{VK_LMENU, true, true}, event1});
1758  EXPECT_EQ(key_calls.size(), 2);
1760  kLogicalAltLeft, "", kSynthesized);
1761  clear_key_calls();
1762  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1763 
1764  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1765  KeyStateChange{VK_LMENU, false, true}, event2});
1766  EXPECT_EQ(key_calls.size(), 2);
1768  kLogicalAltLeft, "", kSynthesized);
1769  clear_key_calls();
1770  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1771 
1772  // AltRight
1773  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1774  KeyStateChange{VK_RMENU, true, true}, event1});
1775  EXPECT_EQ(key_calls.size(), 2);
1777  kPhysicalAltRight, kLogicalAltRight, "", kSynthesized);
1778  clear_key_calls();
1779  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1780 
1781  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1782  KeyStateChange{VK_RMENU, false, true}, event2});
1783  EXPECT_EQ(key_calls.size(), 2);
1785  kLogicalAltRight, "", kSynthesized);
1786  clear_key_calls();
1787  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1788 
1789  // MetaLeft
1790  tester.InjectKeyboardChanges(
1791  std::vector<KeyboardChange>{KeyStateChange{VK_LWIN, true, true}, event1});
1792  EXPECT_EQ(key_calls.size(), 2);
1794  kPhysicalMetaLeft, kLogicalMetaLeft, "", kSynthesized);
1795  clear_key_calls();
1796  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1797 
1798  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1799  KeyStateChange{VK_LWIN, false, true}, event2});
1800  EXPECT_EQ(key_calls.size(), 2);
1802  kLogicalMetaLeft, "", kSynthesized);
1803  clear_key_calls();
1804  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1805 
1806  // MetaRight
1807  tester.InjectKeyboardChanges(
1808  std::vector<KeyboardChange>{KeyStateChange{VK_RWIN, true, true}, event1});
1809  EXPECT_EQ(key_calls.size(), 2);
1811  kPhysicalMetaRight, kLogicalMetaRight, "", kSynthesized);
1812  clear_key_calls();
1813  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1814 
1815  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1816  KeyStateChange{VK_RWIN, false, true}, event2});
1817  EXPECT_EQ(key_calls.size(), 2);
1819  kLogicalMetaRight, "", kSynthesized);
1820  clear_key_calls();
1821  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1822 
1823  // CapsLock, phase 0 -> 2 -> 0.
1824  // (For phases, see |SynchronizeCritialToggledStates|.)
1825  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1826  KeyStateChange{VK_CAPITAL, false, true}, event1});
1827  EXPECT_EQ(key_calls.size(), 3);
1829  kPhysicalCapsLock, kLogicalCapsLock, "", kSynthesized);
1831  kLogicalCapsLock, "", kSynthesized);
1832  clear_key_calls();
1833  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1834 
1835  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1836  KeyStateChange{VK_CAPITAL, false, false}, event2});
1837  EXPECT_EQ(key_calls.size(), 3);
1839  kPhysicalCapsLock, kLogicalCapsLock, "", kSynthesized);
1841  kLogicalCapsLock, "", kSynthesized);
1842  clear_key_calls();
1843  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1844 
1845  // ScrollLock, phase 0 -> 1 -> 3
1846  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1847  KeyStateChange{VK_SCROLL, true, true}, event1});
1848  EXPECT_EQ(key_calls.size(), 2);
1851  kSynthesized);
1852  clear_key_calls();
1853  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1854 
1855  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1856  KeyStateChange{VK_SCROLL, true, false}, event2});
1857  EXPECT_EQ(key_calls.size(), 3);
1860  kSynthesized);
1863  kSynthesized);
1864  clear_key_calls();
1865  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1866 
1867  // NumLock, phase 0 -> 3 -> 2
1868  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1869  KeyStateChange{VK_NUMLOCK, true, false}, event1});
1870  // TODO(dkwingsmt): Synthesizing from phase 0 to 3 should yield a full key
1871  // tap and a key down. Fix the algorithm so that the following result becomes
1872  // 4 keycalls with an extra pair of key down and up.
1873  // https://github.com/flutter/flutter/issues/98533
1874  EXPECT_EQ(key_calls.size(), 2);
1876  kLogicalNumLock, "", kSynthesized);
1877  clear_key_calls();
1878  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1879 
1880  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1881  KeyStateChange{VK_NUMLOCK, false, true}, event2});
1882  EXPECT_EQ(key_calls.size(), 4);
1884  kLogicalNumLock, "", kSynthesized);
1886  kLogicalNumLock, "", kSynthesized);
1888  kLogicalNumLock, "", kSynthesized);
1889  clear_key_calls();
1890  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1891 }
1892 
1893 // Pressing extended keys during IME events should work properly by not sending
1894 // any events.
1895 //
1896 // Regression test for https://github.com/flutter/flutter/issues/95888 .
1897 TEST(KeyboardTest, ImeExtendedEventsAreIgnored) {
1898  KeyboardTester tester;
1899  tester.Responding(false);
1900 
1901  // US Keyboard layout.
1902 
1903  // There should be preceding key events to make the keyboard into IME mode.
1904  // Omit them in this test since they are not relavent.
1905 
1906  // Press CtrlRight in IME mode.
1907  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1908  KeyStateChange{VK_RCONTROL, true, false},
1909  WmKeyDownInfo{VK_PROCESSKEY, kScanCodeControl, kExtended, kWasUp}.Build(
1910  kWmResultZero)});
1911 
1912  EXPECT_EQ(key_calls.size(), 1);
1913  EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, 0, 0, "",
1914  kNotSynthesized);
1915  clear_key_calls();
1916  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
1917 }
1918 
1919 // Ensures that synthesization works correctly when a Shift key is pressed and
1920 // (only) its up event is labeled as an IME event (VK_PROCESSKEY).
1921 //
1922 // Regression test for https://github.com/flutter/flutter/issues/104169. These
1923 // are real messages recorded when pressing Shift-2 using Microsoft Pinyin IME
1924 // on Win 10 Enterprise, which crashed the app before the fix.
1925 TEST(KeyboardTest, UpOnlyImeEventsAreCorrectlyHandled) {
1926  KeyboardTester tester;
1927  tester.Responding(true);
1928 
1929  // US Keyboard layout.
1930 
1931  // Press CtrlRight in IME mode.
1932  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1933  KeyStateChange{VK_LSHIFT, true, false},
1934  WmKeyDownInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended, kWasUp}.Build(
1935  kWmResultZero),
1936  WmKeyDownInfo{VK_PROCESSKEY, kScanCodeDigit2, kNotExtended, kWasUp}.Build(
1937  kWmResultZero),
1938  KeyStateChange{VK_LSHIFT, false, true},
1939  WmKeyUpInfo{VK_PROCESSKEY, kScanCodeShiftLeft, kNotExtended}.Build(
1940  kWmResultZero),
1941  WmKeyUpInfo{'2', kScanCodeDigit2, kNotExtended, kWasUp}.Build(
1942  kWmResultZero)});
1943 
1944  EXPECT_EQ(key_calls.size(), 4);
1947  kNotSynthesized);
1948  EXPECT_CALL_IS_EVENT(key_calls[1], kFlutterKeyEventTypeDown, 0, 0, "",
1949  kNotSynthesized);
1951  kLogicalShiftLeft, "", kNotSynthesized);
1952  EXPECT_CALL_IS_EVENT(key_calls[3], kFlutterKeyEventTypeDown, 0, 0, "",
1953  kNotSynthesized);
1954  clear_key_calls();
1955 }
1956 
1957 TEST(KeyboardTest, DisorderlyRespondedEvents) {
1958  KeyboardTester tester;
1959 
1960  // Store callbacks to manually call them.
1961  std::vector<MockKeyResponseController::ResponseCallback> recorded_callbacks;
1962  tester.LateResponding(
1963  [&recorded_callbacks](
1964  const FlutterKeyEvent* event,
1966  recorded_callbacks.push_back(callback);
1967  });
1968 
1969  // Press A
1970  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1972  kWmResultZero),
1974  kWmResultZero)});
1975 
1976  // Press B
1977  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1978  WmKeyDownInfo{kVirtualKeyB, kScanCodeKeyB, kNotExtended, kWasUp}.Build(
1979  kWmResultZero),
1980  WmCharInfo{'b', kScanCodeKeyB, kNotExtended, kWasUp}.Build(
1981  kWmResultZero)});
1982 
1983  EXPECT_EQ(key_calls.size(), 2);
1984  EXPECT_EQ(recorded_callbacks.size(), 2);
1985  clear_key_calls();
1986  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
1987 
1988  // Resolve the second event first to test disordered responses.
1989  recorded_callbacks.back()(false);
1990 
1991  EXPECT_EQ(key_calls.size(), 0);
1992  clear_key_calls();
1993  // TODO(dkwingsmt): This should probably be 0. Redispatching the messages of
1994  // the second event this early means that the messages are not redispatched
1995  // in the order of arrival. https://github.com/flutter/flutter/issues/98308
1996  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1997 
1998  // Resolve the first event.
1999  recorded_callbacks.front()(false);
2000 
2001  EXPECT_EQ(key_calls.size(), 2);
2002  EXPECT_CALL_IS_TEXT(key_calls[0], u"a");
2003  EXPECT_CALL_IS_TEXT(key_calls[1], u"b");
2004  clear_key_calls();
2005  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2006 }
2007 
2008 // Regression test for a crash in an earlier implementation.
2009 //
2010 // In real life, the framework responds slowly. The next real event might
2011 // arrive earlier than the framework response, and if the 2nd event has an
2012 // identical hash as the one waiting for response, an earlier implementation
2013 // will crash upon the response.
2014 TEST(KeyboardTest, SlowFrameworkResponse) {
2015  KeyboardTester tester;
2016 
2017  std::vector<MockKeyResponseController::ResponseCallback> recorded_callbacks;
2018 
2019  // Store callbacks to manually call them.
2020  tester.LateResponding(
2021  [&recorded_callbacks](
2022  const FlutterKeyEvent* event,
2024  recorded_callbacks.push_back(callback);
2025  });
2026 
2027  // Press A
2028  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2030  kWmResultZero),
2032  kWmResultZero)});
2033 
2034  // Hold A
2035  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2037  kWmResultZero),
2039  kWmResultZero)});
2040 
2041  EXPECT_EQ(key_calls.size(), 2);
2042  EXPECT_EQ(recorded_callbacks.size(), 2);
2043  clear_key_calls();
2044  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2045 
2046  // The first response.
2047  recorded_callbacks.front()(false);
2048 
2049  EXPECT_EQ(key_calls.size(), 1);
2050  EXPECT_CALL_IS_TEXT(key_calls[0], u"a");
2051  clear_key_calls();
2052  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2053 
2054  // The second response.
2055  recorded_callbacks.back()(false);
2056 
2057  EXPECT_EQ(key_calls.size(), 1);
2058  EXPECT_CALL_IS_TEXT(key_calls[0], u"a");
2059  clear_key_calls();
2060  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2061 }
2062 
2063 // Regression test for https://github.com/flutter/flutter/issues/84210.
2064 //
2065 // When the framework response is slow during a sequence of identical messages,
2066 // make sure the real messages are not mistaken as redispatched messages,
2067 // in order to not mess up the order of events.
2068 //
2069 // In this test we use:
2070 //
2071 // KeyA down, KeyA up, (down event responded with false), KeyA down, KeyA up,
2072 //
2073 // The code must not take the 2nd real key down events as a redispatched event.
2074 TEST(KeyboardTest, SlowFrameworkResponseForIdenticalEvents) {
2075  KeyboardTester tester;
2076 
2077  std::vector<MockKeyResponseController::ResponseCallback> recorded_callbacks;
2078 
2079  // Store callbacks to manually call them.
2080  tester.LateResponding(
2081  [&recorded_callbacks](
2082  const FlutterKeyEvent* event,
2084  recorded_callbacks.push_back(callback);
2085  });
2086 
2087  // Press A
2088  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2090  kWmResultZero),
2092  kWmResultZero)});
2093 
2094  EXPECT_EQ(key_calls.size(), 1);
2096  kLogicalKeyA, "a", kNotSynthesized);
2097  clear_key_calls();
2098  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2099 
2100  // Release A
2101  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2103  kWmResultZero)});
2104 
2105  EXPECT_EQ(key_calls.size(), 1);
2107  kLogicalKeyA, "", kNotSynthesized);
2108  clear_key_calls();
2109  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2110 
2111  // The first down event responded with false.
2112  EXPECT_EQ(recorded_callbacks.size(), 2);
2113  recorded_callbacks.front()(false);
2114 
2115  EXPECT_EQ(key_calls.size(), 1);
2116  EXPECT_CALL_IS_TEXT(key_calls[0], u"a");
2117  clear_key_calls();
2118  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2119 
2120  // Press A again
2121  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2123  kWmResultZero),
2125  kWmResultZero)});
2126 
2127  EXPECT_EQ(key_calls.size(), 1);
2129  kLogicalKeyA, "a", kNotSynthesized);
2130  clear_key_calls();
2131  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2132 
2133  // Release A again
2134  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2136  kWmResultZero)});
2137 
2138  EXPECT_EQ(key_calls.size(), 1);
2140  kLogicalKeyA, "", kNotSynthesized);
2141  clear_key_calls();
2142  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2143 }
2144 
2145 TEST(KeyboardTest, TextInputSubmit) {
2146  KeyboardTester tester;
2147  tester.Responding(false);
2148 
2149  // US Keyboard layout
2150 
2151  tester.GetView().HandleMessage(
2152  "flutter/textinput", "TextInput.setClient",
2153  R"|([108, {"inputAction": "TextInputAction.none"}])|");
2154 
2155  // Press Enter
2156  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2157  WmKeyDownInfo{VK_RETURN, kScanCodeEnter, kNotExtended, kWasUp}.Build(
2158  kWmResultZero),
2159  WmCharInfo{'\n', kScanCodeEnter, kNotExtended, kWasUp}.Build(
2160  kWmResultZero)});
2161 
2162  EXPECT_EQ(key_calls.size(), 2);
2164  kLogicalEnter, "", kNotSynthesized);
2166  key_calls[1],
2167  "{"
2168  R"|("method":"TextInputClient.performAction",)|"
2169  R"|("args":[108,"TextInputAction.none"])|"
2170  "}");
2171  clear_key_calls();
2172  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2173 
2174  // Release Enter
2175  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2176  WmKeyUpInfo{VK_RETURN, kScanCodeEnter, kNotExtended}.Build(
2177  kWmResultZero)});
2178 
2179  EXPECT_EQ(key_calls.size(), 1);
2181  kLogicalEnter, "", kNotSynthesized);
2182  clear_key_calls();
2183  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
2184 
2185  // Make sure OnText is not obstructed after pressing Enter.
2186  //
2187  // Regression test for https://github.com/flutter/flutter/issues/97706.
2188 
2189  // Press A
2190  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2192  kWmResultZero),
2194  kWmResultZero)});
2195 
2196  EXPECT_EQ(key_calls.size(), 2);
2198  kLogicalKeyA, "a", kNotSynthesized);
2199  EXPECT_CALL_IS_TEXT(key_calls[1], u"a");
2200  clear_key_calls();
2201 
2202  // Release A
2203  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2205  kWmResultZero)});
2206 
2207  EXPECT_EQ(key_calls.size(), 1);
2209  kLogicalKeyA, "", kNotSynthesized);
2210  clear_key_calls();
2211 }
2212 
2213 TEST(KeyboardTest, VietnameseTelexAddDiacriticWithFastResponse) {
2214  // In this test, the user presses the folloing keys:
2215  //
2216  // Key Current text
2217  // ===========================
2218  // A a
2219  // F à
2220  //
2221  // And the Backspace event is responded immediately.
2222 
2223  KeyboardTester tester;
2224  tester.Responding(false);
2225 
2226  // US Keyboard layout
2227 
2228  // Press A
2229  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2231  kWmResultZero),
2233  kWmResultZero)});
2234 
2235  EXPECT_EQ(key_calls.size(), 2);
2237  kLogicalKeyA, "a", kNotSynthesized);
2238  EXPECT_CALL_IS_TEXT(key_calls[1], u"a");
2239  clear_key_calls();
2240  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2241 
2242  // Release A
2243  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2245  kWmResultZero)});
2246 
2247  EXPECT_EQ(key_calls.size(), 1);
2249  kLogicalKeyA, "", kNotSynthesized);
2250  clear_key_calls();
2251  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
2252 
2253  // Press F, which is translated to:
2254  //
2255  // Backspace down, char & up, then VK_PACKET('à').
2256  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2257  WmKeyDownInfo{VK_BACK, kScanCodeBackspace, kNotExtended, kWasUp}.Build(
2258  kWmResultZero),
2259  WmCharInfo{0x8, kScanCodeBackspace, kNotExtended, kWasUp}.Build(
2260  kWmResultZero),
2261  WmKeyUpInfo{VK_BACK, kScanCodeBackspace, kNotExtended}.Build(
2262  kWmResultZero),
2263  WmKeyDownInfo{VK_PACKET, 0, kNotExtended, kWasUp}.Build(kWmResultDefault),
2264  WmCharInfo{0xe0 /*'à'*/, 0, kNotExtended, kWasUp}.Build(kWmResultZero),
2265  WmKeyUpInfo{VK_PACKET, 0, kNotExtended}.Build(kWmResultDefault)});
2266 
2267  EXPECT_EQ(key_calls.size(), 3);
2270  kNotSynthesized);
2272  kLogicalBackspace, "", kNotSynthesized);
2273  EXPECT_CALL_IS_TEXT(key_calls[2], u"à");
2274  clear_key_calls();
2275  // TODO(dkwingsmt): This count should probably be 4. Currently the CHAR 0x8
2276  // message is redispatched due to being part of the KeyDown session, which is
2277  // not handled by the framework, while the 'à' message is not redispatched
2278  // for being a standalone message. We should resolve this inconsistency.
2279  // https://github.com/flutter/flutter/issues/98306
2280  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 3);
2281 
2282  // Release F
2283  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2284  WmKeyUpInfo{kVirtualKeyF, kScanCodeKeyF, kNotExtended,
2285  /* overwrite_prev_state_0 */ true}
2286  .Build(kWmResultZero)});
2287 
2288  EXPECT_EQ(key_calls.size(), 1);
2289  EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, 0, 0, "",
2290  kNotSynthesized);
2291  clear_key_calls();
2292  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2293 }
2294 
2295 void VietnameseTelexAddDiacriticWithSlowResponse(bool backspace_response) {
2296  // In this test, the user presses the folloing keys:
2297  //
2298  // Key Current text
2299  // ===========================
2300  // A a
2301  // F à
2302  //
2303  // And the Backspace down event is responded slowly with `backspace_response`.
2304 
2305  KeyboardTester tester;
2306  tester.Responding(false);
2307 
2308  // US Keyboard layout
2309 
2310  // Press A
2311  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2313  kWmResultZero),
2315  kWmResultZero)});
2316 
2317  EXPECT_EQ(key_calls.size(), 2);
2319  kLogicalKeyA, "a", kNotSynthesized);
2320  EXPECT_CALL_IS_TEXT(key_calls[1], u"a");
2321  clear_key_calls();
2322  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2323 
2324  // Release A
2325  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2327  kWmResultZero)});
2328 
2329  EXPECT_EQ(key_calls.size(), 1);
2331  kLogicalKeyA, "", kNotSynthesized);
2332  clear_key_calls();
2333  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
2334 
2335  std::vector<MockKeyResponseController::ResponseCallback> recorded_callbacks;
2336  tester.LateResponding(
2337  [&recorded_callbacks](
2338  const FlutterKeyEvent* event,
2340  recorded_callbacks.push_back(callback);
2341  });
2342 
2343  // Press F, which is translated to:
2344  //
2345  // Backspace down, char & up, VK_PACKET('à').
2346  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2347  WmKeyDownInfo{VK_BACK, kScanCodeBackspace, kNotExtended, kWasUp}.Build(
2348  kWmResultZero),
2349  WmCharInfo{0x8, kScanCodeBackspace, kNotExtended, kWasUp}.Build(
2350  kWmResultZero),
2351  WmKeyUpInfo{VK_BACK, kScanCodeBackspace, kNotExtended}.Build(
2352  kWmResultZero),
2353  WmKeyDownInfo{VK_PACKET, 0, kNotExtended, kWasUp}.Build(kWmResultDefault),
2354  WmCharInfo{0xe0 /*'à'*/, 0, kNotExtended, kWasUp}.Build(kWmResultZero),
2355  WmKeyUpInfo{VK_PACKET, 0, kNotExtended}.Build(kWmResultDefault)});
2356 
2357  // The Backspace event has not responded yet, therefore the char message must
2358  // hold. This is because when the framework is handling the Backspace event,
2359  // it will send a setEditingState message that updates the text state that has
2360  // the last character deleted (denoted by `string1`). Processing the char
2361  // message before then will cause the final text to set to `string1`.
2362  EXPECT_EQ(key_calls.size(), 2);
2365  kNotSynthesized);
2367  kLogicalBackspace, "", kNotSynthesized);
2368  clear_key_calls();
2369  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2370 
2371  EXPECT_EQ(recorded_callbacks.size(), 2);
2372  recorded_callbacks[0](backspace_response);
2373 
2374  EXPECT_EQ(key_calls.size(), 1);
2375  EXPECT_CALL_IS_TEXT(key_calls[0], u"à");
2376  clear_key_calls();
2377  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(),
2378  backspace_response ? 0 : 2);
2379 
2380  recorded_callbacks[1](false);
2381  EXPECT_EQ(key_calls.size(), 0);
2382  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
2383 
2384  tester.Responding(false);
2385 
2386  // Release F
2387  tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2388  WmKeyUpInfo{kVirtualKeyF, kScanCodeKeyF, kNotExtended,
2389  /* overwrite_prev_state_0 */ true}
2390  .Build(kWmResultZero)});
2391 
2392  EXPECT_EQ(key_calls.size(), 1);
2393  EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, 0, 0, "",
2394  kNotSynthesized);
2395  clear_key_calls();
2396  EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2397 }
2398 
2399 TEST(KeyboardTest, VietnameseTelexAddDiacriticWithSlowFalseResponse) {
2401 }
2402 
2403 TEST(KeyboardTest, VietnameseTelexAddDiacriticWithSlowTrueResponse) {
2405 }
2406 
2407 } // namespace testing
2408 } // namespace flutter
G_BEGIN_DECLS FlValue * args
Win32Message expected_forged_message
char * clone_string(const char *string)
constexpr uint64_t kPhysicalAltLeft
Definition: key_codes.g.h:226
#define EXPECT_CALL_IS_TEXT(_key_call, u16_string)
BOOL Win32PeekMessage(LPMSG lpMsg, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
constexpr uint64_t kPhysicalKeyE
Definition: key_codes.g.h:81
union flutter::testing::@1969::KeyboardChange::@58 content
std::function< void(bool)> ResponseCallback
Definition: test_keyboard.h:51
constexpr uint64_t kLogicalNumLock
Definition: key_codes.g.h:381
TEST(DisplayListColorFilter, BuilderSetGet)
constexpr uint64_t kPhysicalKeyW
Definition: key_codes.g.h:99
constexpr uint64_t kLogicalAltRight
Definition: key_codes.g.h:686
constexpr uint64_t kPhysicalEnter
Definition: key_codes.g.h:113
const char * character
Definition: embedder.h:871
FlutterEngine engine
Definition: main.cc:66
constexpr uint64_t kLogicalShiftRight
Definition: key_codes.g.h:684
struct tagMSG * LPMSG
constexpr uint64_t kPhysicalKeyA
Definition: key_codes.g.h:77
enum flutter::testing::@1969::KeyboardChange::Type type
constexpr uint64_t kPhysicalShiftLeft
Definition: key_codes.g.h:225
constexpr uint64_t kPhysicalBackspace
Definition: key_codes.g.h:115
constexpr uint64_t kLogicalKeyA
Definition: key_codes.g.h:339
constexpr uint64_t kPhysicalScrollLock
Definition: key_codes.g.h:143
char32_t character
constexpr uint64_t kPhysicalMetaRight
Definition: key_codes.g.h:231
Win32Message message
constexpr uint64_t kPhysicalDigit1
Definition: key_codes.g.h:103
constexpr uint64_t kLogicalBracketRight
Definition: key_codes.g.h:335
constexpr uint64_t kLogicalBackspace
Definition: key_codes.g.h:370
constexpr uint64_t kLogicalKeyW
Definition: key_codes.g.h:361
constexpr uint64_t kLogicalAltLeft
Definition: key_codes.g.h:685
LONG_PTR LRESULT
Definition: windows_types.h:61
constexpr uint64_t kLogicalMetaLeft
Definition: key_codes.g.h:687
constexpr uint64_t kLogicalEnter
Definition: key_codes.g.h:372
constexpr uint64_t kPhysicalControlLeft
Definition: key_codes.g.h:224
KeyStateChange key_state_change
constexpr uint64_t kLogicalControlRight
Definition: key_codes.g.h:682
UINT_PTR WPARAM
Definition: windows_types.h:59
std::string text_method_call
constexpr uint64_t kPhysicalKeyQ
Definition: key_codes.g.h:93
constexpr LRESULT kWmResultZero
Definition: wm_builders.h:15
FlKeyEvent * event
constexpr uint64_t kPhysicalMetaLeft
Definition: key_codes.g.h:227
constexpr uint64_t kLogicalKeyQ
Definition: key_codes.g.h:355
std::function< void(const FlutterKeyEvent *, ResponseCallback)> EmbedderCallbackHandler
Definition: test_keyboard.h:53
constexpr uint64_t kLogicalKeyE
Definition: key_codes.g.h:343
constexpr LRESULT kWmResultDontCheck
Definition: wm_builders.h:17
virtual void RedispatchEvent(std::unique_ptr< PendingEvent > event)
gchar gchar gchar gchar ** modifier
Definition: fl_engine.cc:81
#define EXPECT_CALL_IS_TEXT_METHOD_CALL(_key_call, json_string)
constexpr uint64_t kPhysicalBracketLeft
Definition: key_codes.g.h:120
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition: switches.h:41
FlutterKeyEvent key_event
uint8_t value
constexpr uint64_t kLogicalMetaRight
Definition: key_codes.g.h:688
constexpr uint64_t kLogicalScrollLock
Definition: key_codes.g.h:382
constexpr uint64_t kLogicalArrowLeft
Definition: key_codes.g.h:388
SemanticsAction action
constexpr uint64_t kLogicalBackquote
Definition: key_codes.g.h:338
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data observatory The hostname IP address on which the Dart Observatory should be served If not defaults to or::depending on whether ipv6 is specified disable Disable the Dart Observatory The observatory is never available in release mode Bind to the IPv6 localhost address for the Dart Observatory Ignored if observatory host is set endless trace buffer
Definition: switches.h:98
void VietnameseTelexAddDiacriticWithSlowResponse(bool backspace_response)
constexpr uint64_t kLogicalDigit6
Definition: key_codes.g.h:322
constexpr uint64_t kLogicalShiftLeft
Definition: key_codes.g.h:683
std::function< SHORT(UINT, bool)> MapVirtualKeyToScanCode
short SHORT
Definition: windows_types.h:29
constexpr uint64_t kLogicalCapsLock
Definition: key_codes.g.h:377
constexpr uint64_t kPhysicalBackquote
Definition: key_codes.g.h:125
static const JsonMessageCodec & GetInstance()
constexpr uint64_t kPhysicalNumLock
Definition: key_codes.g.h:155
int BOOL
Definition: windows_types.h:37
constexpr uint64_t kPhysicalControlRight
Definition: key_codes.g.h:228
LONG_PTR LPARAM
Definition: windows_types.h:60
constexpr uint64_t kLogicalControlLeft
Definition: key_codes.g.h:681
uint32_t key
void MockEmbedderApiForKeyboard(EngineModifier &modifier, std::shared_ptr< MockKeyResponseController > response_controller)
std::u16string text
constexpr uint64_t kPhysicalAltRight
Definition: key_codes.g.h:230
CallbackHandler callback_handler
constexpr LRESULT kWmResultDefault
Definition: wm_builders.h:16
unsigned int UINT
Definition: windows_types.h:32
virtual std::unique_ptr< KeyboardHandlerBase > CreateKeyboardKeyHandler(BinaryMessenger *messenger, KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state, KeyboardKeyEmbedderHandler::MapVirtualKeyToScanCode map_vk_to_scan)
std::list< KeyStateChange > state_changes_afterwards
constexpr uint64_t kLogicalDigit1
Definition: key_codes.g.h:317
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
std::unique_ptr< std::vector< uint8_t > > EncodeMessage(const T &message) const
Definition: message_codec.h:45
constexpr uint64_t kPhysicalShiftRight
Definition: key_codes.g.h:229
constexpr uint64_t kPhysicalCapsLock
Definition: key_codes.g.h:129
#define EXPECT_CALL_IS_EVENT(_key_call,...)
constexpr uint64_t kPhysicalDigit6
Definition: key_codes.g.h:108
constexpr uint64_t kPhysicalArrowLeft
Definition: key_codes.g.h:152