Flutter Engine
The Flutter Engine
keyboard_unittest.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// Testing the stateful Fuchsia Input3 keyboard interactions. This test case
6// is not intended to be exhaustive: it is intended to capture the tests that
7// demonstrate how we think Input3 interaction should work, and possibly
8// regression tests if we catch some behavior that needs to be guarded long
9// term. Pragmatically, this should be enough to ensure no specific bug
10// happens twice.
11
12#include "flutter/shell/platform/fuchsia/flutter/keyboard.h"
13
14#include <fuchsia/input/cpp/fidl.h>
15#include <fuchsia/ui/input/cpp/fidl.h>
16#include <fuchsia/ui/input3/cpp/fidl.h>
17
18#include <gtest/gtest.h>
19#include <zircon/time.h>
20#include <vector>
21
22namespace flutter_runner {
23namespace {
24
26using fuchsia::ui::input::kModifierCapsLock;
27using fuchsia::ui::input::kModifierLeftAlt;
28using fuchsia::ui::input::kModifierLeftControl;
29using fuchsia::ui::input::kModifierLeftShift;
30using fuchsia::ui::input::kModifierNone;
31using fuchsia::ui::input::kModifierRightAlt;
32using fuchsia::ui::input::kModifierRightControl;
33using fuchsia::ui::input::kModifierRightShift;
34using fuchsia::ui::input3::KeyEvent;
36using fuchsia::ui::input3::KeyMeaning;
37
38class KeyboardTest : public testing::Test {
39 protected:
40 static void SetUpTestCase() { testing::Test::SetUpTestCase(); }
41
42 // Creates a new key event for testing.
43 KeyEvent NewKeyEvent(KeyEventType event_type, Key key) {
44 KeyEvent event;
45 // Assume events are delivered with correct timing.
46 event.set_timestamp(++timestamp_);
47 event.set_type(event_type);
48 event.set_key(key);
49 return event;
50 }
51
52 KeyEvent NewKeyEventWithMeaning(KeyEventType event_type,
53 KeyMeaning key_meaning) {
54 KeyEvent event;
55 // Assume events are delivered with correct timing.
56 event.set_timestamp(++timestamp_);
57 event.set_type(event_type);
58 event.set_key_meaning(std::move(key_meaning));
59 return event;
60 }
61
62 // Makes the keyboard consume all the provided `events`. The end state of
63 // the keyboard is as if all of the specified events happened between the
64 // start state of the keyboard and its end state. Returns false if any of
65 // the event was not consumed.
66 bool ConsumeEvents(Keyboard* keyboard, const std::vector<KeyEvent>& events) {
67 for (const auto& event : events) {
68 KeyEvent e;
69 event.Clone(&e);
70 if (keyboard->ConsumeEvent(std::move(e)) == false) {
71 return false;
72 }
73 }
74 return true;
75 }
76
77 // Converts a pressed key to usage value.
78 uint32_t ToUsage(Key key) { return static_cast<uint64_t>(key) & 0xFFFFFFFF; }
79
80 private:
81 zx_time_t timestamp_ = 0;
82};
83
84// Checks whether the HID usage, page and ID values are reported correctly.
85TEST_F(KeyboardTest, UsageValues) {
86 std::vector<KeyEvent> keys;
87 keys.emplace_back(NewKeyEvent(KeyEventType::SYNC, Key::CAPS_LOCK));
88 Keyboard keyboard;
89 ASSERT_TRUE(ConsumeEvents(&keyboard, keys));
90
91 // Values for Caps Lock.
92 // See spec at:
93 // https://cs.opensource.google/fuchsia/fuchsia/+/main:sdk/fidl/fuchsia.input/keys.fidl;l=177;drc=e3b39f2b57e720770773b857feca4f770ee0619e
94 EXPECT_EQ(0x07u, keyboard.LastHIDUsagePage());
95 EXPECT_EQ(0x39u, keyboard.LastHIDUsageID());
96 EXPECT_EQ(0x70039u, keyboard.LastHIDUsage());
97
98 // Try also an usage that is not on page 7. This one is on page 0x0C.
99 // See spec at:
100 // https://cs.opensource.google/fuchsia/fuchsia/+/main:sdk/fidl/fuchsia.input/keys.fidl;l=339;drc=e3b39f2b57e720770773b857feca4f770ee0619e
101 // Note that Fuchsia does not define constants for every key you may think of,
102 // rather only those that we had the need for. However it is not an issue
103 // to add more keys if needed.
104 keys.clear();
105 keys.emplace_back(NewKeyEvent(KeyEventType::SYNC, Key::MEDIA_MUTE));
106 ASSERT_TRUE(ConsumeEvents(&keyboard, keys));
107 EXPECT_EQ(0x0Cu, keyboard.LastHIDUsagePage());
108 EXPECT_EQ(0xE2u, keyboard.LastHIDUsageID());
109 EXPECT_EQ(0xC00E2u, keyboard.LastHIDUsage());
110
111 // Don't crash when a key with only a meaning comes in.
112 keys.clear();
113 keys.emplace_back(NewKeyEventWithMeaning(KeyEventType::SYNC,
114 KeyMeaning::WithCodepoint(32)));
115 ASSERT_TRUE(ConsumeEvents(&keyboard, keys));
116 EXPECT_EQ(0x0u, keyboard.LastHIDUsagePage());
117 EXPECT_EQ(0x0u, keyboard.LastHIDUsageID());
118 EXPECT_EQ(0x0u, keyboard.LastHIDUsage());
119 EXPECT_EQ(0x20u, keyboard.LastCodePoint());
120
121 keys.clear();
122 auto key =
123 NewKeyEventWithMeaning(KeyEventType::SYNC, KeyMeaning::WithCodepoint(65));
124 key.set_key(Key::A);
125 keys.emplace_back(std::move(key));
126 ASSERT_TRUE(ConsumeEvents(&keyboard, keys));
127 EXPECT_EQ(0x07u, keyboard.LastHIDUsagePage());
128 EXPECT_EQ(0x04u, keyboard.LastHIDUsageID());
129 EXPECT_EQ(0x70004u, keyboard.LastHIDUsage());
130 EXPECT_EQ(65u, keyboard.LastCodePoint());
131}
132
133// This test checks that if a caps lock has been pressed when we didn't have
134// focus, the effect of caps lock remains. Only this first test case is
135// commented to explain how the test case works.
136TEST_F(KeyboardTest, CapsLockSync) {
137 // Place the key events since the beginning of time into `keys`.
138 std::vector<KeyEvent> keys;
139 keys.emplace_back(NewKeyEvent(KeyEventType::SYNC, Key::CAPS_LOCK));
140
141 // Replay them on the keyboard.
142 Keyboard keyboard;
143 ASSERT_TRUE(ConsumeEvents(&keyboard, keys));
144
145 // Verify the state of the keyboard's public API:
146 // - check that the key sync had no code point (it was a caps lock press).
147 // - check that the registered usage was that of caps lock.
148 // - check that the net effect is that the caps lock modifier is locked
149 // active.
150 EXPECT_EQ(0u, keyboard.LastCodePoint());
151 EXPECT_EQ(ToUsage(Key::CAPS_LOCK), keyboard.LastHIDUsage());
152 EXPECT_EQ(kModifierCapsLock, keyboard.Modifiers());
153}
154
155TEST_F(KeyboardTest, CapsLockPress) {
156 std::vector<KeyEvent> keys;
157 keys.emplace_back(NewKeyEvent(KeyEventType::PRESSED, Key::CAPS_LOCK));
158
159 Keyboard keyboard;
160 ASSERT_TRUE(ConsumeEvents(&keyboard, keys));
161
162 EXPECT_EQ(0u, keyboard.LastCodePoint());
163 EXPECT_EQ(ToUsage(Key::CAPS_LOCK), keyboard.LastHIDUsage());
164 EXPECT_EQ(kModifierCapsLock, keyboard.Modifiers());
165}
166
167TEST_F(KeyboardTest, CapsLockPressRelease) {
168 std::vector<KeyEvent> keys;
169 keys.emplace_back(NewKeyEvent(KeyEventType::PRESSED, Key::CAPS_LOCK));
170 keys.emplace_back(NewKeyEvent(KeyEventType::RELEASED, Key::CAPS_LOCK));
171
172 Keyboard keyboard;
173 ASSERT_TRUE(ConsumeEvents(&keyboard, keys));
174
175 EXPECT_EQ(0u, keyboard.LastCodePoint());
176 EXPECT_EQ(ToUsage(Key::CAPS_LOCK), keyboard.LastHIDUsage());
177 EXPECT_EQ(kModifierCapsLock, keyboard.Modifiers());
178}
179
180TEST_F(KeyboardTest, ShiftA) {
181 std::vector<KeyEvent> keys;
182 keys.emplace_back(NewKeyEvent(KeyEventType::PRESSED, Key::LEFT_SHIFT));
183 keys.emplace_back(NewKeyEvent(KeyEventType::PRESSED, Key::A));
184
185 Keyboard keyboard;
186 ASSERT_TRUE(ConsumeEvents(&keyboard, keys));
187
188 EXPECT_EQ(static_cast<uint32_t>('A'), keyboard.LastCodePoint());
189 EXPECT_EQ(ToUsage(Key::A), keyboard.LastHIDUsage());
190 EXPECT_EQ(kModifierLeftShift, keyboard.Modifiers());
191}
192
193TEST_F(KeyboardTest, ShiftAWithRelease) {
194 std::vector<KeyEvent> keys;
195 keys.emplace_back(NewKeyEvent(KeyEventType::PRESSED, Key::LEFT_SHIFT));
196 keys.emplace_back(NewKeyEvent(KeyEventType::PRESSED, Key::A));
197 keys.emplace_back(NewKeyEvent(KeyEventType::RELEASED, Key::A));
198
199 Keyboard keyboard;
200 ASSERT_TRUE(ConsumeEvents(&keyboard, keys));
201
202 EXPECT_EQ(static_cast<uint32_t>('A'), keyboard.LastCodePoint());
203 EXPECT_EQ(ToUsage(Key::A), keyboard.LastHIDUsage());
204 EXPECT_EQ(kModifierLeftShift, keyboard.Modifiers());
205}
206
207TEST_F(KeyboardTest, ShiftAWithReleaseShift) {
208 std::vector<KeyEvent> keys;
209 keys.emplace_back(NewKeyEvent(KeyEventType::PRESSED, Key::LEFT_SHIFT));
210 keys.emplace_back(NewKeyEvent(KeyEventType::PRESSED, Key::A));
211 keys.emplace_back(NewKeyEvent(KeyEventType::RELEASED, Key::LEFT_SHIFT));
212 keys.emplace_back(NewKeyEvent(KeyEventType::RELEASED, Key::A));
213
214 Keyboard keyboard;
215 ASSERT_TRUE(ConsumeEvents(&keyboard, keys));
216
217 EXPECT_EQ(static_cast<uint32_t>('a'), keyboard.LastCodePoint());
218 EXPECT_EQ(ToUsage(Key::A), keyboard.LastHIDUsage());
219 EXPECT_EQ(kModifierNone, keyboard.Modifiers());
220}
221
222TEST_F(KeyboardTest, LowcaseA) {
223 std::vector<KeyEvent> keys;
224 keys.emplace_back(NewKeyEvent(KeyEventType::PRESSED, Key::A));
225 keys.emplace_back(NewKeyEvent(KeyEventType::RELEASED, Key::A));
226
227 Keyboard keyboard;
228 ASSERT_TRUE(ConsumeEvents(&keyboard, keys));
229
230 EXPECT_EQ(static_cast<uint32_t>('a'), keyboard.LastCodePoint());
231 EXPECT_EQ(ToUsage(Key::A), keyboard.LastHIDUsage());
232 EXPECT_EQ(kModifierNone, keyboard.Modifiers());
233}
234
235} // namespace
236} // namespace flutter_runner
TArray< uint32_t > Key
ax::mojom::Event event_type
FlKeyEvent * event
TEST_F(DisplayListTest, Defaults)
KeyEventType
Definition: key_data.h:22