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