5 #include <Carbon/Carbon.h>
6 #import <Foundation/Foundation.h>
7 #import <OCMock/OCMock.h>
10 #include "flutter/shell/platform/embedder/test_utils/key_codes.g.h"
11 #import "flutter/testing/testing.h"
12 #include "third_party/googletest/googletest/include/gtest/gtest.h"
17 using flutter::testing::keycodes::kLogicalKeyQ;
19 NSEvent* keyEvent(NSEventType type,
20 NSEventModifierFlags modifierFlags,
22 NSString* charactersIgnoringModifiers,
24 unsigned short keyCode) {
25 return [NSEvent keyEventWithType:type
27 modifierFlags:modifierFlags
32 charactersIgnoringModifiers:charactersIgnoringModifiers
38 TEST(FlutterChannelKeyResponderUnittests, BasicKeyEvent) {
39 __block NSMutableArray<id>* messages = [[NSMutableArray<id> alloc] init];
40 __block BOOL next_response = TRUE;
41 __block NSMutableArray<NSNumber*>* responses = [[NSMutableArray<NSNumber*> alloc] init];
44 OCMStub([mockKeyEventChannel sendMessage:[OCMArg any] reply:[OCMArg any]])
45 .andDo((^(NSInvocation* invocation) {
46 [invocation retainArguments];
47 NSDictionary* message;
48 [invocation getArgument:&message atIndex:2];
49 [messages addObject:message];
52 [invocation getArgument:&callback atIndex:3];
53 NSDictionary* keyMessage = @{
54 @"handled" : @(next_response),
66 [responder handleEvent:keyEvent(NSEventTypeFlagsChanged, 0x100,
@"",
@"", FALSE, 60)
67 callback:^(BOOL handled) {
68 [responses addObject:@(handled)];
71 EXPECT_EQ([messages count], 0u);
72 EXPECT_EQ([responses count], 1u);
73 EXPECT_EQ([responses[0] boolValue], TRUE);
74 [responses removeAllObjects];
77 [responder handleEvent:keyEvent(NSEventTypeKeyDown, 0x100,
@"a",
@"a", FALSE, 0)
78 callback:^(BOOL handled) {
79 [responses addObject:@(handled)];
82 EXPECT_EQ([messages count], 1u);
83 EXPECT_STREQ([[messages lastObject][
@"keymap"] UTF8String],
"macos");
84 EXPECT_STREQ([[messages lastObject][
@"type"] UTF8String],
"keydown");
85 EXPECT_EQ([[messages lastObject][
@"keyCode"] intValue], 0);
86 EXPECT_EQ([[messages lastObject][
@"modifiers"] intValue], 0x0);
87 EXPECT_STREQ([[messages lastObject][
@"characters"] UTF8String],
"a");
88 EXPECT_STREQ([[messages lastObject][
@"charactersIgnoringModifiers"] UTF8String],
"a");
90 EXPECT_EQ([responses count], 1u);
91 EXPECT_EQ([[responses lastObject] boolValue], TRUE);
93 [messages removeAllObjects];
94 [responses removeAllObjects];
97 next_response = FALSE;
98 [responder handleEvent:keyEvent(NSEventTypeKeyUp, 0x100,
@"a",
@"a", FALSE, 0)
99 callback:^(BOOL handled) {
100 [responses addObject:@(handled)];
103 EXPECT_EQ([messages count], 1u);
104 EXPECT_STREQ([[messages lastObject][
@"keymap"] UTF8String],
"macos");
105 EXPECT_STREQ([[messages lastObject][
@"type"] UTF8String],
"keyup");
106 EXPECT_EQ([[messages lastObject][
@"keyCode"] intValue], 0);
107 EXPECT_EQ([[messages lastObject][
@"modifiers"] intValue], 0);
108 EXPECT_STREQ([[messages lastObject][
@"characters"] UTF8String],
"a");
109 EXPECT_STREQ([[messages lastObject][
@"charactersIgnoringModifiers"] UTF8String],
"a");
111 EXPECT_EQ([responses count], 1u);
112 EXPECT_EQ([[responses lastObject] boolValue], FALSE);
114 [messages removeAllObjects];
115 [responses removeAllObjects];
118 next_response = TRUE;
119 [responder handleEvent:keyEvent(NSEventTypeFlagsChanged, 0x20102,
@"",
@"", FALSE, 56)
120 callback:^(BOOL handled) {
121 [responses addObject:@(handled)];
124 EXPECT_EQ([messages count], 1u);
125 EXPECT_STREQ([[messages lastObject][
@"keymap"] UTF8String],
"macos");
126 EXPECT_STREQ([[messages lastObject][
@"type"] UTF8String],
"keydown");
127 EXPECT_EQ([[messages lastObject][
@"keyCode"] intValue], 56);
128 EXPECT_EQ([[messages lastObject][
@"modifiers"] intValue], 0x20002);
130 EXPECT_EQ([responses count], 1u);
131 EXPECT_EQ([[responses lastObject] boolValue], TRUE);
133 [messages removeAllObjects];
134 [responses removeAllObjects];
137 next_response =
false;
138 [responder handleEvent:keyEvent(NSEventTypeFlagsChanged, 0x20006,
@"",
@"", FALSE, 60)
139 callback:^(BOOL handled) {
140 [responses addObject:@(handled)];
143 EXPECT_EQ([messages count], 1u);
144 EXPECT_STREQ([[messages lastObject][
@"keymap"] UTF8String],
"macos");
145 EXPECT_STREQ([[messages lastObject][
@"type"] UTF8String],
"keydown");
146 EXPECT_EQ([[messages lastObject][
@"keyCode"] intValue], 60);
147 EXPECT_EQ([[messages lastObject][
@"modifiers"] intValue], 0x20006);
149 EXPECT_EQ([responses count], 1u);
150 EXPECT_EQ([[responses lastObject] boolValue], FALSE);
152 [messages removeAllObjects];
153 [responses removeAllObjects];
156 next_response =
false;
157 [responder handleEvent:keyEvent(NSEventTypeFlagsChanged, 0x20104,
@"",
@"", FALSE, 56)
158 callback:^(BOOL handled) {
159 [responses addObject:@(handled)];
162 EXPECT_EQ([messages count], 1u);
163 EXPECT_STREQ([[messages lastObject][
@"keymap"] UTF8String],
"macos");
164 EXPECT_STREQ([[messages lastObject][
@"type"] UTF8String],
"keyup");
165 EXPECT_EQ([[messages lastObject][
@"keyCode"] intValue], 56);
166 EXPECT_EQ([[messages lastObject][
@"modifiers"] intValue], 0x20004);
168 EXPECT_EQ([responses count], 1u);
169 EXPECT_EQ([[responses lastObject] boolValue], FALSE);
171 [messages removeAllObjects];
172 [responses removeAllObjects];
175 next_response =
false;
176 [responder handleEvent:keyEvent(NSEventTypeFlagsChanged, 0,
@"",
@"", FALSE, 60)
177 callback:^(BOOL handled) {
178 [responses addObject:@(handled)];
181 EXPECT_EQ([messages count], 1u);
182 EXPECT_STREQ([[messages lastObject][
@"keymap"] UTF8String],
"macos");
183 EXPECT_STREQ([[messages lastObject][
@"type"] UTF8String],
"keyup");
184 EXPECT_EQ([[messages lastObject][
@"keyCode"] intValue], 60);
185 EXPECT_EQ([[messages lastObject][
@"modifiers"] intValue], 0);
187 EXPECT_EQ([responses count], 1u);
188 EXPECT_EQ([[responses lastObject] boolValue], FALSE);
190 [messages removeAllObjects];
191 [responses removeAllObjects];
195 next_response =
false;
196 [responder handleEvent:keyEvent(NSEventTypeFlagsChanged, 0x100,
@"",
@"", FALSE, 60)
197 callback:^(BOOL handled) {
198 [responses addObject:@(handled)];
201 EXPECT_EQ([messages count], 0u);
202 EXPECT_EQ([responses count], 1u);
203 EXPECT_EQ([responses[0] boolValue], TRUE);
206 TEST(FlutterChannelKeyResponderUnittests, EmptyResponseIsTakenAsHandled) {
207 __block NSMutableArray<id>* messages = [[NSMutableArray<id> alloc] init];
208 __block NSMutableArray<NSNumber*>* responses = [[NSMutableArray<NSNumber*> alloc] init];
211 OCMStub([mockKeyEventChannel sendMessage:[OCMArg any] reply:[OCMArg any]])
212 .andDo((^(NSInvocation* invocation) {
213 [invocation retainArguments];
214 NSDictionary* message;
215 [invocation getArgument:&message atIndex:2];
216 [messages addObject:message];
219 [invocation getArgument:&callback atIndex:3];
225 [responder handleEvent:keyEvent(NSEventTypeKeyDown, 0x100,
@"a",
@"a", FALSE, 0)
226 callback:^(BOOL handled) {
227 [responses addObject:@(handled)];
230 EXPECT_EQ([messages count], 1u);
231 EXPECT_STREQ([[messages lastObject][
@"keymap"] UTF8String],
"macos");
232 EXPECT_STREQ([[messages lastObject][
@"type"] UTF8String],
"keydown");
233 EXPECT_EQ([[messages lastObject][
@"keyCode"] intValue], 0);
234 EXPECT_EQ([[messages lastObject][
@"modifiers"] intValue], 0);
235 EXPECT_STREQ([[messages lastObject][
@"characters"] UTF8String],
"a");
236 EXPECT_STREQ([[messages lastObject][
@"charactersIgnoringModifiers"] UTF8String],
"a");
238 EXPECT_EQ([responses count], 1u);
239 EXPECT_EQ([[responses lastObject] boolValue], TRUE);
242 TEST(FlutterChannelKeyResponderUnittests, FollowsLayoutMap) {
243 __block NSMutableArray<id>* messages = [[NSMutableArray<id> alloc] init];
244 __block BOOL next_response = TRUE;
245 __block NSMutableArray<NSNumber*>* responses = [[NSMutableArray<NSNumber*> alloc] init];
248 OCMStub([mockKeyEventChannel sendMessage:[OCMArg any] reply:[OCMArg any]])
249 .andDo((^(NSInvocation* invocation) {
250 [invocation retainArguments];
251 NSDictionary* message;
252 [invocation getArgument:&message atIndex:2];
253 [messages addObject:message];
256 [invocation getArgument:&callback atIndex:3];
257 NSDictionary* keyMessage = @{
258 @"handled" : @(next_response),
260 callback(keyMessage);
266 NSMutableDictionary<NSNumber*, NSNumber*>* layoutMap =
267 [NSMutableDictionary<NSNumber*, NSNumber*> dictionary];
270 layoutMap[@(kVK_ANSI_A)] = @(kLogicalKeyQ);
272 [responder handleEvent:keyEvent(NSEventTypeKeyDown, kVK_ANSI_A,
@"q",
@"q", FALSE, 0)
273 callback:^(BOOL handled) {
274 [responses addObject:@(handled)];
277 EXPECT_EQ([messages count], 1u);
278 EXPECT_STREQ([[messages lastObject][
@"keymap"] UTF8String],
"macos");
279 EXPECT_STREQ([[messages lastObject][
@"type"] UTF8String],
"keydown");
280 EXPECT_EQ([[messages lastObject][
@"keyCode"] intValue], 0);
281 EXPECT_EQ([[messages lastObject][
@"modifiers"] intValue], 0x0);
282 EXPECT_STREQ([[messages lastObject][
@"characters"] UTF8String],
"q");
283 EXPECT_STREQ([[messages lastObject][
@"charactersIgnoringModifiers"] UTF8String],
"q");
284 EXPECT_EQ([messages lastObject][
@"specifiedLogicalKey"], @(kLogicalKeyQ));
286 EXPECT_EQ([responses count], 1u);
287 EXPECT_EQ([[responses lastObject] boolValue], TRUE);
289 [messages removeAllObjects];
290 [responses removeAllObjects];