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