Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
30using testing::_;
31using testing::Invoke;
32using testing::Return;
33using namespace ::flutter::testing::keycodes;
34
35namespace flutter {
36namespace testing {
37
38namespace {
39
40constexpr SHORT kStateMaskToggled = 0x01;
41constexpr SHORT kStateMaskPressed = 0x80;
42
43constexpr uint64_t kScanCodeBackquote = 0x29;
44constexpr uint64_t kScanCodeKeyA = 0x1e;
45constexpr uint64_t kScanCodeKeyB = 0x30;
46constexpr uint64_t kScanCodeKeyE = 0x12;
47constexpr uint64_t kScanCodeKeyF = 0x21;
48constexpr uint64_t kScanCodeKeyO = 0x18;
49constexpr uint64_t kScanCodeKeyQ = 0x10;
50constexpr uint64_t kScanCodeKeyW = 0x11;
51constexpr uint64_t kScanCodeDigit1 = 0x02;
52constexpr uint64_t kScanCodeDigit2 = 0x03;
53constexpr uint64_t kScanCodeDigit6 = 0x07;
54// constexpr uint64_t kScanCodeNumpad1 = 0x4f;
55// constexpr uint64_t kScanCodeNumLock = 0x45;
56constexpr uint64_t kScanCodeControl = 0x1d;
57constexpr uint64_t kScanCodeMetaLeft = 0x5b;
58constexpr uint64_t kScanCodeMetaRight = 0x5c;
59constexpr uint64_t kScanCodeAlt = 0x38;
60constexpr uint64_t kScanCodeShiftLeft = 0x2a;
61constexpr uint64_t kScanCodeShiftRight = 0x36;
62constexpr uint64_t kScanCodeBracketLeft = 0x1a;
63constexpr uint64_t kScanCodeArrowLeft = 0x4b;
64constexpr uint64_t kScanCodeEnter = 0x1c;
65constexpr uint64_t kScanCodeBackspace = 0x0e;
66
67constexpr uint64_t kVirtualDigit1 = 0x31;
68constexpr uint64_t kVirtualKeyA = 0x41;
69constexpr uint64_t kVirtualKeyB = 0x42;
70constexpr uint64_t kVirtualKeyE = 0x45;
71constexpr uint64_t kVirtualKeyF = 0x46;
72constexpr uint64_t kVirtualKeyO = 0x4f;
73constexpr uint64_t kVirtualKeyQ = 0x51;
74constexpr uint64_t kVirtualKeyW = 0x57;
75
76constexpr bool kSynthesized = true;
77constexpr bool kNotSynthesized = false;
78
79typedef UINT (*MapVirtualKeyLayout)(UINT uCode, UINT uMapType);
80typedef std::function<UINT(UINT)> MapVirtualKeyToChar;
81
82UINT LayoutDefault(UINT uCode, UINT uMapType) {
83 return MapVirtualKey(uCode, uMapType);
84}
85
86UINT 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
100class 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;
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.
124struct KeyStateChange {
125 uint32_t key;
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.
136struct ExpectForgedMessage {
137 explicit ExpectForgedMessage(Win32Message message) : message(message){};
138
139 Win32Message message;
140};
141
142struct 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,
163
164 union {
165 Win32Message message;
166 KeyStateChange key_state_change;
169};
170
171class 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
184class 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
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 :
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
323typedef 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.
337class 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
358class KeyboardTester {
359 public:
360 using ResponseHandler =
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(
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 =
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_;
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,
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 });
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
529 bool value) {
530 return [value](const FlutterKeyEvent* event,
532 callback(value);
533 };
534 }
535
536 private:
538};
539
540class 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
568TEST_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>{
579 kWmResultZero)});
580
581 EXPECT_EQ(tester.key_calls.size(), 1);
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>{
590 kWmResultZero)});
591
592 EXPECT_EQ(tester.key_calls.size(), 1);
594 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
595 tester.clear_key_calls();
596 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
597}
598
599TEST_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>{
610 kWmResultZero)});
611
612 EXPECT_EQ(tester.key_calls.size(), 2);
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>{
622 kWmResultZero)});
623
624 EXPECT_EQ(tester.key_calls.size(), 1);
626 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
627 tester.clear_key_calls();
628 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
629}
630
631TEST_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);
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);
656 kPhysicalArrowLeft, kLogicalArrowLeft, "",
657 kNotSynthesized);
658 tester.clear_key_calls();
659 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
660}
661
662TEST_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);
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);
687 kPhysicalArrowLeft, kLogicalArrowLeft, "",
688 kNotSynthesized);
689 tester.clear_key_calls();
690 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
691}
692
693TEST_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},
703 kWmResultZero)});
704
705 EXPECT_EQ(tester.key_calls.size(), 1);
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>{
715 kWmResultZero)});
716
717 EXPECT_EQ(tester.key_calls.size(), 1);
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},
728 kWmResultZero)});
729
730 EXPECT_EQ(tester.key_calls.size(), 1);
732 kPhysicalShiftLeft, kLogicalShiftLeft, "",
733 kNotSynthesized);
734 tester.clear_key_calls();
735 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
736}
737
738TEST_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},
748 kWmResultZero)});
749
750 EXPECT_EQ(tester.key_calls.size(), 1);
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},
761 kWmResultZero)});
762
763 EXPECT_EQ(tester.key_calls.size(), 1);
765 kPhysicalShiftRight, kLogicalShiftRight, "",
766 kNotSynthesized);
767 tester.clear_key_calls();
768 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
769}
770
771TEST_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);
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);
798 kPhysicalControlLeft, kLogicalControlLeft, "",
799 kNotSynthesized);
800 tester.clear_key_calls();
801 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
802}
803
804TEST_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);
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);
831 kPhysicalControlRight, kLogicalControlRight, "",
832 kNotSynthesized);
833 tester.clear_key_calls();
834 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
835}
836
837TEST_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);
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);
864 kPhysicalAltLeft, kLogicalAltLeft, "", kNotSynthesized);
865 tester.clear_key_calls();
866 // Don't redispatch sys messages.
867 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
868}
869
870TEST_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);
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);
898 kPhysicalAltRight, kLogicalAltRight, "",
899 kNotSynthesized);
900 tester.clear_key_calls();
901 // Don't redispatch sys messages.
902 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
903}
904
905TEST_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);
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);
931 kPhysicalMetaLeft, kLogicalMetaLeft, "",
932 kNotSynthesized);
933 tester.clear_key_calls();
934 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
935}
936
937TEST_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);
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);
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.
971TEST_F(KeyboardTest, RepeatA) {
972 KeyboardTester tester{GetContext()};
973 tester.Responding(true);
974
975 // Press A
976 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
980 kWmResultZero)});
981
982 // Hold A
983 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
987 kWmResultZero)});
988
989 EXPECT_EQ(tester.key_calls.size(), 2);
991 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
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.
1000TEST_F(KeyboardTest, RestartClearsKeyboardState) {
1001 KeyboardTester tester{GetContext()};
1002 tester.Responding(true);
1003
1004 // Press A
1005 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
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>{
1020 kWmResultZero)});
1021
1022 EXPECT_EQ(tester.key_calls.size(), 2);
1024 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
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.
1032TEST_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},
1042 kWmResultZero)});
1043
1044 EXPECT_EQ(tester.key_calls.size(), 1);
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>{
1056 kWmResultZero)});
1057
1058 EXPECT_EQ(tester.key_calls.size(), 2);
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},
1069 kWmResultZero)});
1070
1071 EXPECT_EQ(tester.key_calls.size(), 1);
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>{
1081 kWmResultZero)});
1082
1083 EXPECT_EQ(tester.key_calls.size(), 1);
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.
1092TEST_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);
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>{
1116 kWmResultZero)});
1117
1118 EXPECT_EQ(tester.key_calls.size(), 1);
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>{
1127 kWmResultZero)});
1128
1129 EXPECT_EQ(tester.key_calls.size(), 1);
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);
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.
1150TEST_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);
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);
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);
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);
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 '&'.
1207TEST_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}
1217 WmCharInfo{'&', kScanCodeDigit1, kNotExtended, kWasUp}.Build(
1218 kWmResultZero)});
1219
1220 EXPECT_EQ(tester.key_calls.size(), 2);
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);
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 '@'.
1240TEST_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(
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);
1257 kPhysicalControlLeft, kLogicalControlLeft, "",
1258 kNotSynthesized);
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(
1269 WmCharInfo{'@', kScanCodeKeyQ, kNotExtended, kWasUp}.Build(
1270 kWmResultZero)});
1271
1272 EXPECT_EQ(tester.key_calls.size(), 2);
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);
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(
1301
1302 EXPECT_EQ(tester.key_calls.size(), 2);
1304 kPhysicalControlLeft, kLogicalControlLeft, "",
1305 kNotSynthesized);
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).
1327TEST_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(
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);
1345 kPhysicalControlLeft, kLogicalControlLeft, "",
1346 kNotSynthesized);
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(
1364 EXPECT_EQ(tester.key_calls.size(), 2);
1366 kPhysicalControlLeft, kLogicalControlLeft, "",
1367 kNotSynthesized);
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(
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);
1387 kPhysicalControlLeft, kLogicalControlLeft, "",
1388 kNotSynthesized);
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(
1406 EXPECT_EQ(tester.key_calls.size(), 2);
1408 kPhysicalControlLeft, kLogicalControlLeft, "",
1409 kNotSynthesized);
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);
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 ê.
1430TEST_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(
1440 WmDeadCharInfo{'^', kScanCodeBracketLeft, kNotExtended, kWasUp}.Build(
1441 kWmResultZero)});
1442
1443 EXPECT_EQ(tester.key_calls.size(), 1);
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);
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(
1466 WmCharInfo{0xEA, kScanCodeKeyE, kNotExtended, kWasUp}.Build(
1467 kWmResultZero)});
1468
1469 EXPECT_EQ(tester.key_calls.size(), 2);
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);
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.
1493TEST_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},
1501 kWmResultZero)});
1502
1503 EXPECT_EQ(tester.key_calls.size(), 1);
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(
1514 WmDeadCharInfo{'^', kScanCodeDigit6, kNotExtended, kWasUp}.Build(
1515 kWmResultZero)});
1516
1517 EXPECT_EQ(tester.key_calls.size(), 1);
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);
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},
1537 kWmResultZero)});
1538
1539 EXPECT_EQ(tester.key_calls.size(), 1);
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(
1550 WmCharInfo{0xEA, kScanCodeKeyE, kNotExtended, kWasUp}.Build(
1551 kWmResultZero)});
1552
1553 EXPECT_EQ(tester.key_calls.size(), 2);
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);
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 "^&".
1574TEST_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(
1584 WmDeadCharInfo{'^', kScanCodeBracketLeft, kNotExtended, kWasUp}.Build(
1585 kWmResultZero)});
1586
1587 EXPECT_EQ(tester.key_calls.size(), 1);
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);
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}
1610 WmCharInfo{'^', kScanCodeDigit1, kNotExtended, kWasUp}.Build(
1612 WmCharInfo{'&', kScanCodeDigit1, kNotExtended, kWasUp}.Build(
1613 kWmResultZero)});
1614
1615 EXPECT_EQ(tester.key_calls.size(), 3);
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);
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 `è.
1643TEST_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(
1653 WmDeadCharInfo{'`', kScanCodeBackquote, kNotExtended, kWasUp}.Build(
1654 kWmResultZero)});
1655
1656 EXPECT_EQ(tester.key_calls.size(), 1);
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);
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,
1682 recorded_callbacks.push_back(callback);
1683 });
1684
1685 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1686 WmKeyDownInfo{0xC0, kScanCodeBackquote, kNotExtended, kWasUp}.Build(
1688 WmCharInfo{'`', kScanCodeBackquote, kNotExtended, kWasUp, kBeingReleased,
1689 kNoContext, 1, /*bit25*/ true}
1691 WmCharInfo{'`', kScanCodeBackquote, kNotExtended, kWasUp}.Build(
1692 kWmResultZero)});
1693
1694 EXPECT_EQ(recorded_callbacks.size(), 1);
1695 EXPECT_EQ(tester.key_calls.size(), 1);
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);
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.
1727TEST_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(
1738 WmCharInfo{0xd800, kScanCodeKeyW, kNotExtended, kWasUp}.Build(
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);
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);
1759 kPhysicalKeyW, kLogicalKeyW, "", kNotSynthesized);
1760 tester.clear_key_calls();
1761 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1762}
1763
1764TEST_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(
1772 Win32Message event2 =
1773 WmKeyUpInfo{VK_BACK, kScanCodeBackspace, kNotExtended}.Build(
1775
1776 // ShiftLeft
1777 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1778 KeyStateChange{VK_LSHIFT, true, true}, event1});
1779 EXPECT_EQ(tester.key_calls.size(), 2);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
1924 kPhysicalCapsLock, kLogicalCapsLock, "", kSynthesized);
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);
1934 kPhysicalCapsLock, kLogicalCapsLock, "", kSynthesized);
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);
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);
1954 kPhysicalScrollLock, kLogicalScrollLock, "",
1955 kSynthesized);
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);
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);
1979 kPhysicalNumLock, kLogicalNumLock, "", kSynthesized);
1981 kPhysicalNumLock, kLogicalNumLock, "", kSynthesized);
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 .
1992TEST_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);
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.
2020TEST_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},
2031 WmKeyDownInfo{VK_PROCESSKEY, kScanCodeDigit2, kNotExtended, kWasUp}.Build(
2033 KeyStateChange{VK_LSHIFT, false, true},
2036 WmKeyUpInfo{'2', kScanCodeDigit2, kNotExtended, kWasUp}.Build(
2037 kWmResultZero)});
2038
2039 EXPECT_EQ(tester.key_calls.size(), 4);
2041 kPhysicalShiftLeft, kLogicalShiftLeft, "",
2042 kNotSynthesized);
2044 kNotSynthesized);
2046 kPhysicalShiftLeft, kLogicalShiftLeft, "",
2047 kNotSynthesized);
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.
2059TEST_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,
2069 recorded_callbacks.push_back(callback);
2070 });
2071
2072 // Press A
2073 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2077 kWmResultZero)});
2078
2079 // Hold A
2080 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2084 kWmResultZero)});
2085
2086 EXPECT_EQ(tester.key_calls.size(), 1);
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");
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.
2122TEST_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,
2131 recorded_callbacks.push_back(callback);
2132 });
2133
2134 // Press A
2135 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2139 kWmResultZero)});
2140
2141 EXPECT_EQ(tester.key_calls.size(), 1);
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>{
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");
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>{
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);
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>{
2192 kWmResultZero)});
2193
2194 EXPECT_EQ(tester.key_calls.size(), 0);
2195 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2196}
2197
2198TEST_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"}])|");
2207
2208 // Press Enter
2209 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2210 WmKeyDownInfo{VK_RETURN, kScanCodeEnter, kNotExtended, kWasUp}.Build(
2212 WmCharInfo{'\n', kScanCodeEnter, kNotExtended, kWasUp}.Build(
2213 kWmResultZero)});
2214
2215 EXPECT_EQ(tester.key_calls.size(), 2);
2217 kPhysicalEnter, kLogicalEnter, "", kNotSynthesized);
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);
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>{
2247 kWmResultZero)});
2248
2249 EXPECT_EQ(tester.key_calls.size(), 2);
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>{
2258 kWmResultZero)});
2259
2260 EXPECT_EQ(tester.key_calls.size(), 1);
2262 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
2263 tester.clear_key_calls();
2264}
2265
2266TEST_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>{
2286 kWmResultZero)});
2287
2288 EXPECT_EQ(tester.key_calls.size(), 2);
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>{
2298 kWmResultZero)});
2299
2300 EXPECT_EQ(tester.key_calls.size(), 1);
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(
2312 WmCharInfo{0x8, kScanCodeBackspace, kNotExtended, kWasUp}.Build(
2314 WmKeyUpInfo{VK_BACK, kScanCodeBackspace, kNotExtended}.Build(
2317 WmCharInfo{0xe0 /*'à'*/, 0, kNotExtended, kWasUp}.Build(kWmResultZero),
2319
2320 EXPECT_EQ(tester.key_calls.size(), 3);
2322 kPhysicalBackspace, kLogicalBackspace, "",
2323 kNotSynthesized);
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);
2344 kNotSynthesized);
2345 tester.clear_key_calls();
2346 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2347}
2348
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>{
2370 kWmResultZero)});
2371
2372 EXPECT_EQ(tester.key_calls.size(), 2);
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>{
2382 kWmResultZero)});
2383
2384 EXPECT_EQ(tester.key_calls.size(), 1);
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,
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(
2404 WmCharInfo{0x8, kScanCodeBackspace, kNotExtended, kWasUp}.Build(
2406 WmKeyUpInfo{VK_BACK, kScanCodeBackspace, kNotExtended}.Build(
2409 WmCharInfo{0xe0 /*'à'*/, 0, kNotExtended, kWasUp}.Build(kWmResultZero),
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);
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);
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);
2451 kNotSynthesized);
2452 tester.clear_key_calls();
2453 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2454}
2455
2456TEST_F(KeyboardTest, VietnameseTelexAddDiacriticWithSlowFalseResponse) {
2458}
2459
2460TEST_F(KeyboardTest, VietnameseTelexAddDiacriticWithSlowTrueResponse) {
2462}
2463
2464// Ensure that the scancode-less key events issued by Narrator
2465// when toggling caps lock don't violate assert statements.
2466TEST_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
int count
static const JsonMessageCodec & GetInstance()
virtual void RedispatchEvent(std::unique_ptr< PendingEvent > event)
std::unique_ptr< std::vector< uint8_t > > EncodeMessage(const T &message) const
std::function< void(const FlutterKeyEvent *, ResponseCallback)> EmbedderCallbackHandler
std::function< void(bool)> ResponseCallback
BOOL Win32PeekMessage(LPMSG lpMsg, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
@ kFlutterKeyEventTypeDown
Definition embedder.h:1074
@ kFlutterKeyEventTypeUp
Definition embedder.h:1073
@ kFlutterKeyEventTypeRepeat
Definition embedder.h:1075
GLFWwindow * window
Definition main.cc:45
FlutterEngine engine
Definition main.cc:68
#define FATAL(error)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
FlKeyEvent * event
uint8_t value
#define FML_LOG(severity)
Definition logging.h:82
#define FML_DCHECK(condition)
Definition logging.h:103
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition macros.h:27
CallbackHandler callback_handler
std::string text_method_call
bool pressed
FlutterKeyEvent key_event
std::u16string text
#define EXPECT_CALL_IS_TEXT(_key_call, u16_string)
#define EXPECT_CALL_IS_TEXT_METHOD_CALL(_key_call, json_string)
std::list< KeyStateChange > state_changes_afterwards
std::vector< KeyCall > key_calls
KeyStateChange key_state_change
bool toggled_on
Win32Message expected_forged_message
union flutter::testing::@2838::KeyboardChange::@76 content
#define EXPECT_CALL_IS_EVENT(_key_call, _type, _physical, _logical, _character, _synthesized)
Win32Message message
const GrXPFactory * Get(SkBlendMode mode)
TEST_F(DisplayListTest, Defaults)
constexpr LRESULT kWmResultZero
Definition wm_builders.h:14
constexpr LRESULT kWmResultDefault
Definition wm_builders.h:15
void MockEmbedderApiForKeyboard(EngineModifier &modifier, std::shared_ptr< MockKeyResponseController > response_controller)
constexpr LRESULT kWmResultDontCheck
Definition wm_builders.h:16
char * clone_string(const char *string)
void VietnameseTelexAddDiacriticWithSlowResponse(WindowsTestContext &context, bool backspace_response)
constexpr int64_t kImplicitViewId
constexpr int kScanCodeShiftRight
constexpr int kScanCodeShiftLeft
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition switches.h:126
Definition ref_ptr.h:256
const char * character
Definition embedder.h:1135
Win32Message Build(LRESULT expected_result=kWmResultDontCheck)
Win32Message Build(LRESULT expected_result=kWmResultDontCheck)
Win32Message Build(LRESULT expected_result=kWmResultDontCheck)
Win32Message Build(LRESULT expected_result=kWmResultDontCheck)
Win32Message Build(LRESULT expected_result=kWmResultDontCheck)
Win32Message Build(LRESULT expected_result=kWmResultDontCheck)
int BOOL
struct tagMSG * LPMSG
LONG_PTR LRESULT
unsigned int UINT
LONG_PTR LPARAM
short SHORT
UINT_PTR WPARAM