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