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