| Flutter Windows Embedder |

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