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