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