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