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