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