1package io.flutter.embedding.android;
3import static android.view.KeyEvent.*;
4import static io.flutter.embedding.android.KeyData.Type;
5import static io.flutter.util.KeyCodes.*;
6import static org.junit.Assert.assertEquals;
7import static org.junit.Assert.assertNotNull;
8import static org.junit.Assert.assertNull;
9import static org.junit.Assert.assertTrue;
10import static org.mockito.Mockito.any;
11import static org.mockito.Mockito.doAnswer;
12import static org.mockito.Mockito.eq;
13import static org.mockito.Mockito.mock;
14import static org.mockito.Mockito.times;
15import static org.mockito.Mockito.verify;
17import android.view.KeyCharacterMap;
19import androidx.annotation.NonNull;
20import androidx.annotation.Nullable;
21import androidx.test.ext.junit.runners.AndroidJUnit4;
22import io.flutter.embedding.android.KeyData.DeviceType;
23import io.flutter.plugin.common.BinaryMessenger;
24import io.flutter.plugin.common.JSONMessageCodec;
25import io.flutter.util.FakeKeyEvent;
26import java.nio.ByteBuffer;
27import java.util.ArrayList;
30import java.util.function.BiConsumer;
31import java.util.function.Consumer;
32import java.util.stream.Collectors;
33import org.json.JSONException;
34import org.json.JSONObject;
35import org.junit.Before;
37import org.junit.runner.RunWith;
38import org.mockito.Mock;
39import org.mockito.MockitoAnnotations;
40import org.mockito.invocation.InvocationOnMock;
41import org.robolectric.annotation.Config;
44@RunWith(AndroidJUnit4.class)
46 public static final int SCAN_KEY_A = 0x1e;
47 public static final int SCAN_DIGIT1 = 0x2;
48 public static final int SCAN_SHIFT_LEFT = 0x2a;
49 public static final int SCAN_SHIFT_RIGHT = 0x36;
50 public static final int SCAN_CONTROL_LEFT = 0x1d;
51 public static final int SCAN_CONTROL_RIGHT = 0x61;
52 public static final int SCAN_ALT_LEFT = 0x38;
53 public static final int SCAN_ALT_RIGHT = 0x64;
54 public static final int SCAN_ARROW_LEFT = 0x69;
55 public static final int SCAN_ARROW_RIGHT = 0x6a;
56 public static final int SCAN_CAPS_LOCK = 0x3a;
58 public static final boolean DOWN_EVENT =
true;
59 public static final boolean UP_EVENT =
false;
60 public static final boolean SHIFT_LEFT_EVENT =
true;
61 public static final boolean SHIFT_RIGHT_EVENT =
false;
63 private static final int DEAD_KEY =
'`' | KeyCharacterMap.COMBINING_ACCENT;
112 @NonNull JSONObject channelObject, @Nullable Consumer<Boolean> reply) {
115 record.channelObject = channelObject;
116 record.reply = reply;
124 record.keyData = keyData;
125 record.reply = reply;
136 JSONObject body =
new JSONObject();
138 body.put(
"handled", handled);
139 }
catch (JSONException
e) {
143 binaryReply.rewind();
153 byte[] body =
new byte[1];
154 body[0] = (byte) (handled ? 1 : 0);
155 final ByteBuffer binaryReply = ByteBuffer.wrap(body);
156 binaryReply.rewind();
182 respondToChannelCallsWith(
false);
183 respondToEmbedderCallsWith(
false);
184 respondToTextInputWith(
false);
187 doAnswer(invocation -> onMessengerMessage(invocation))
189 .send(
any(String.class),
any(ByteBuffer.class),
eq(
null));
190 doAnswer(invocation -> onMessengerMessage(invocation))
195 doAnswer(invocation -> mockMessenger).when(mockView).getBinaryMessenger();
196 doAnswer(invocation -> textInputResult)
198 .onTextInputKeyEvent(
any(KeyEvent.class));
201 KeyEvent
event = invocation.getArgument(0);
202 boolean handled = keyboardManager.handleEvent(
event);
203 assertEquals(handled,
false);
207 .redispatch(
any(KeyEvent.class));
212 public @Mock KeyboardManager.ViewDelegate
mockView;
218 (JSONObject
data, Consumer<Boolean> reply) -> {
220 reply.accept(handled);
232 (JSONObject
data, Consumer<Boolean> reply) -> {
240 (
KeyData keyData, Consumer<Boolean> reply) -> {
242 reply.accept(handled);
254 (
KeyData keyData, Consumer<Boolean> reply) ->
260 textInputResult = response;
265 private Boolean textInputResult;
267 private Object onMessengerMessage(@NonNull InvocationOnMock invocation) {
268 final String channel = invocation.getArgument(0);
269 final ByteBuffer
buffer = invocation.getArgument(1);
272 final BinaryMessenger.BinaryReply reply = invocation.getArgument(2);
273 if (channel ==
"flutter/keyevent") {
276 final Consumer<Boolean> jsonReply =
277 reply ==
null ? null : handled -> reply.reply(buildJsonResponse(handled));
278 channelHandler.accept(jsonObject, jsonReply);
279 }
else if (channel ==
"flutter/keydata") {
282 final Consumer<Boolean> booleanReply =
283 reply ==
null ? null : handled -> reply.reply(buildBinaryResponse(handled));
284 embedderHandler.accept(keyData, booleanReply);
302 @NonNull JSONObject
message, @NonNull String
type, @NonNull Integer keyCode) {
305 assertEquals(
"android",
message.get(
"keymap"));
306 assertEquals(keyCode,
message.get(
"keyCode"));
307 }
catch (JSONException
e) {
322 assertEquals(physicalKey,
data.physicalKey);
323 assertEquals(logicalKey,
data.logicalKey);
325 assertEquals(synthesized,
data.synthesized);
326 assertEquals(deviceType,
data.deviceType);
330 assertEquals(receivedCalls.size(), expectedData.length);
331 for (
int idx = 0; idx < receivedCalls.size(); idx += 1) {
333 assertEmbedderEventEquals(
334 receivedCalls.get(idx).keyData,
348 @Nullable String characters,
352 result.physicalKey = physicalKey;
353 result.logicalKey = logicalKey;
354 result.timestamp = 0x0;
356 result.character = characters;
357 result.synthesized = synthesized;
358 result.deviceType = deviceType;
373 boolean preEventLeftPressed,
374 boolean preEventRightPressed,
375 boolean rightEventIsDown,
376 boolean truePressed) {
377 final ArrayList<CallRecord> calls =
new ArrayList<>();
380 final int SHIFT_LEFT_ON = META_SHIFT_LEFT_ON | META_SHIFT_ON;
383 tester.respondToTextInputWith(
true);
384 if (preEventLeftPressed) {
385 tester.keyboardManager.handleEvent(
387 ACTION_DOWN, SCAN_SHIFT_LEFT, KEYCODE_SHIFT_LEFT, 0,
'\0', SHIFT_LEFT_ON));
389 if (preEventRightPressed) {
390 tester.keyboardManager.handleEvent(
392 ACTION_DOWN, SCAN_SHIFT_RIGHT, KEYCODE_SHIFT_RIGHT, 0,
'\0', SHIFT_LEFT_ON));
394 tester.recordEmbedderCallsTo(calls);
395 tester.keyboardManager.handleEvent(
397 rightEventIsDown ? ACTION_DOWN : ACTION_UP,
402 truePressed ? SHIFT_LEFT_ON : 0));
403 return calls.stream()
404 .filter(
data ->
data.keyData.physicalKey != 0)
405 .collect(Collectors.toList());
410 data.type = isDown ? Type.kDown :
Type.kUp;
411 data.physicalKey = isLeft ? PHYSICAL_SHIFT_LEFT : PHYSICAL_SHIFT_RIGHT;
412 data.logicalKey = isLeft ? LOGICAL_SHIFT_LEFT : LOGICAL_SHIFT_RIGHT;
413 data.synthesized = isSynthesized;
425 final String[] results =
new String[
buffer.capacity()];
426 for (
int byteIdx = 0; byteIdx <
buffer.capacity(); byteIdx += 1) {
427 results[byteIdx] = String.format(
"%02x",
buffer.get(byteIdx));
429 return String.join(
"", results);
434 MockitoAnnotations.openMocks(
this);
443 data1.physicalKey = 0x0a;
444 data1.logicalKey = 0x0b;
445 data1.timestamp = 0x0c;
446 data1.type =
Type.kRepeat;
447 data1.character =
"A";
448 data1.synthesized =
true;
451 final ByteBuffer data1Buffer = data1.
toBytes();
463 printBufferBytes(data1Buffer));
465 assertEquals(57, data1Buffer.position());
467 data1Buffer.rewind();
473 data2.physicalKey = 0xaaaabbbbccccl;
474 data2.logicalKey = 0x666677778888l;
475 data2.timestamp = 0x333344445555l;
476 data2.type =
Type.kUp;
477 data2.character =
null;
478 data2.synthesized =
false;
481 final ByteBuffer data2Buffer = data2.
toBytes();
491 +
"0100000000000000",
492 printBufferBytes(data2Buffer));
494 data2Buffer.rewind();
502 assertEquals(0, (
int) combiner.applyCombiningCharacterToBaseCharacter(0));
503 assertEquals(
'B', (
int) combiner.applyCombiningCharacterToBaseCharacter(
'B'));
504 assertEquals(
'B', (
int) combiner.applyCombiningCharacterToBaseCharacter(
'B'));
505 assertEquals(
'A', (
int) combiner.applyCombiningCharacterToBaseCharacter(
'A'));
506 assertEquals(0, (
int) combiner.applyCombiningCharacterToBaseCharacter(0));
507 assertEquals(0, (
int) combiner.applyCombiningCharacterToBaseCharacter(0));
509 assertEquals(
'`', (
int) combiner.applyCombiningCharacterToBaseCharacter(DEAD_KEY));
510 assertEquals(
'`', (
int) combiner.applyCombiningCharacterToBaseCharacter(DEAD_KEY));
511 assertEquals(
'À', (
int) combiner.applyCombiningCharacterToBaseCharacter(
'A'));
513 assertEquals(
'`', (
int) combiner.applyCombiningCharacterToBaseCharacter(DEAD_KEY));
514 assertEquals(0, (
int) combiner.applyCombiningCharacterToBaseCharacter(0));
516 assertEquals(
'A', (
int) combiner.applyCombiningCharacterToBaseCharacter(
'A'));
518 assertEquals(0, (
int) combiner.applyCombiningCharacterToBaseCharacter(0));
519 assertEquals(
'`', (
int) combiner.applyCombiningCharacterToBaseCharacter(DEAD_KEY));
520 assertEquals(
'À', (
int) combiner.applyCombiningCharacterToBaseCharacter(
'A'));
526 final KeyEvent keyEvent =
new FakeKeyEvent(ACTION_DOWN, 65);
527 final ArrayList<CallRecord> calls =
new ArrayList<>();
529 tester.recordChannelCallsTo(calls);
531 final boolean result =
tester.keyboardManager.handleEvent(keyEvent);
533 assertEquals(
true,
result);
534 assertEquals(calls.size(), 1);
535 assertChannelEventEquals(calls.get(0).channelObject,
"keydown", 65);
539 verify(
tester.mockView,
times(0)).onTextInputKeyEvent(
any(KeyEvent.class));
540 verify(
tester.mockView,
times(0)).redispatch(
any(KeyEvent.class));
546 final KeyEvent keyEvent =
new FakeKeyEvent(ACTION_DOWN, 65);
547 final ArrayList<CallRecord> calls =
new ArrayList<>();
549 tester.recordChannelCallsTo(calls);
551 final boolean result =
tester.keyboardManager.handleEvent(keyEvent);
553 assertEquals(
true,
result);
554 assertEquals(calls.size(), 1);
555 assertChannelEventEquals(calls.get(0).channelObject,
"keydown", 65);
559 verify(
tester.mockView,
times(0)).onTextInputKeyEvent(
any(KeyEvent.class));
560 verify(
tester.mockView,
times(0)).redispatch(
any(KeyEvent.class));
563 assertNotNull(calls.get(0).reply);
564 calls.get(0).reply.accept(
true);
565 verify(
tester.mockView,
times(0)).onTextInputKeyEvent(
any(KeyEvent.class));
566 verify(
tester.mockView,
times(0)).redispatch(
any(KeyEvent.class));
572 final KeyEvent keyEvent =
new FakeKeyEvent(ACTION_DOWN, SCAN_KEY_A, KEYCODE_A, 0,
'a', 0);
573 final ArrayList<CallRecord> calls =
new ArrayList<>();
575 tester.recordEmbedderCallsTo(calls);
577 final boolean result =
tester.keyboardManager.handleEvent(keyEvent);
579 assertEquals(
true,
result);
580 assertEquals(calls.size(), 1);
581 assertEmbedderEventEquals(
582 calls.get(0).keyData,
592 verify(
tester.mockView,
times(0)).onTextInputKeyEvent(
any(KeyEvent.class));
593 verify(
tester.mockView,
times(0)).redispatch(
any(KeyEvent.class));
596 assertNotNull(calls.get(0).reply);
597 calls.get(0).reply.accept(
true);
598 verify(
tester.mockView,
times(0)).onTextInputKeyEvent(
any(KeyEvent.class));
599 verify(
tester.mockView,
times(0)).redispatch(
any(KeyEvent.class));
608 final BinaryMessenger.BinaryReply reply = invocation.getArgument(2);
619 doAnswer(invocation -> mockMessenger).when(mockView).getBinaryMessenger();
622 final KeyEvent keyEvent =
new FakeKeyEvent(ACTION_DOWN, SCAN_KEY_A, KEYCODE_A, 0,
'a', 0);
624 boolean exceptionThrown =
false;
627 }
catch (Exception exception) {
628 exceptionThrown =
true;
631 assertEquals(
false, exceptionThrown);
637 final ArrayList<CallRecord> calls =
new ArrayList<>();
639 tester.recordChannelCallsTo(calls);
640 tester.recordEmbedderCallsTo(calls);
641 tester.respondToTextInputWith(
true);
644 tester.keyboardManager.handleEvent(
645 new FakeKeyEvent(ACTION_DOWN, SCAN_KEY_A, KEYCODE_A, 0,
'a', 0));
647 assertEquals(
true,
result);
648 assertEquals(calls.size(), 2);
649 assertEmbedderEventEquals(
650 calls.get(0).keyData,
657 assertChannelEventEquals(calls.get(1).channelObject,
"keydown", KEYCODE_A);
659 verify(
tester.mockView,
times(0)).onTextInputKeyEvent(
any(KeyEvent.class));
660 verify(
tester.mockView,
times(0)).redispatch(
any(KeyEvent.class));
662 calls.get(0).reply.accept(
true);
663 verify(
tester.mockView,
times(0)).onTextInputKeyEvent(
any(KeyEvent.class));
664 verify(
tester.mockView,
times(0)).redispatch(
any(KeyEvent.class));
666 calls.get(1).reply.accept(
true);
667 verify(
tester.mockView,
times(0)).onTextInputKeyEvent(
any(KeyEvent.class));
668 verify(
tester.mockView,
times(0)).redispatch(
any(KeyEvent.class));
674 final KeyEvent keyEvent =
new FakeKeyEvent(ACTION_DOWN, 65);
675 final ArrayList<CallRecord> calls =
new ArrayList<>();
677 tester.recordChannelCallsTo(calls);
679 final boolean result =
tester.keyboardManager.handleEvent(keyEvent);
681 assertEquals(
true,
result);
682 assertEquals(calls.size(), 1);
683 assertChannelEventEquals(calls.get(0).channelObject,
"keydown", 65);
687 verify(
tester.mockView,
times(0)).onTextInputKeyEvent(
any(KeyEvent.class));
688 verify(
tester.mockView,
times(0)).redispatch(
any(KeyEvent.class));
692 assertNotNull(calls.get(0).reply);
694 tester.respondToTextInputWith(
true);
695 calls.get(0).reply.accept(
false);
697 verify(
tester.mockView,
times(1)).onTextInputKeyEvent(keyEvent);
698 verify(
tester.mockView,
times(0)).redispatch(
any(KeyEvent.class));
704 final KeyEvent keyEvent =
new FakeKeyEvent(ACTION_DOWN, 65);
705 final ArrayList<CallRecord> calls =
new ArrayList<>();
707 tester.recordChannelCallsTo(calls);
709 final boolean result =
tester.keyboardManager.handleEvent(keyEvent);
711 assertEquals(
true,
result);
712 assertEquals(calls.size(), 1);
713 assertChannelEventEquals(calls.get(0).channelObject,
"keydown", 65);
717 verify(
tester.mockView,
times(0)).onTextInputKeyEvent(
any(KeyEvent.class));
718 verify(
tester.mockView,
times(0)).redispatch(
any(KeyEvent.class));
721 tester.respondToTextInputWith(
false);
722 calls.get(0).reply.accept(
false);
724 verify(
tester.mockView,
times(1)).onTextInputKeyEvent(keyEvent);
725 verify(
tester.mockView,
times(1)).redispatch(keyEvent);
731 final ArrayList<CallRecord> calls =
new ArrayList<>();
733 tester.recordChannelCallsTo(calls);
735 final KeyEvent keyEvent =
new FakeKeyEvent(ACTION_DOWN, 65);
736 final boolean result =
tester.keyboardManager.handleEvent(keyEvent);
738 assertEquals(
true,
result);
739 assertEquals(calls.size(), 1);
740 assertChannelEventEquals(calls.get(0).channelObject,
"keydown", 65);
744 verify(
tester.mockView,
times(0)).onTextInputKeyEvent(
any(KeyEvent.class));
745 verify(
tester.mockView,
times(0)).redispatch(
any(KeyEvent.class));
748 tester.respondToTextInputWith(
false);
749 calls.get(0).reply.accept(
false);
751 verify(
tester.mockView,
times(1)).onTextInputKeyEvent(keyEvent);
752 verify(
tester.mockView,
times(1)).redispatch(keyEvent);
755 assertEquals(calls.size(), 1);
761 final ArrayList<CallRecord> calls =
new ArrayList<>();
763 tester.recordEmbedderCallsTo(calls);
764 tester.respondToTextInputWith(
true);
768 tester.keyboardManager.handleEvent(
769 new FakeKeyEvent(ACTION_DOWN, SCAN_KEY_A, KEYCODE_A, 0,
'a', 0)));
771 verifyEmbedderEvents(
780 tester.keyboardManager.handleEvent(
781 new FakeKeyEvent(ACTION_DOWN, SCAN_KEY_A, KEYCODE_A, 1,
'a', 0)));
782 verifyEmbedderEvents(
792 tester.keyboardManager.handleEvent(
793 new FakeKeyEvent(ACTION_UP, SCAN_KEY_A, KEYCODE_A, 0,
'a', 0)));
794 verifyEmbedderEvents(
805 final ArrayList<CallRecord> calls =
new ArrayList<>();
807 tester.recordEmbedderCallsTo(calls);
808 tester.respondToTextInputWith(
true);
813 tester.keyboardManager.handleEvent(
814 new FakeKeyEvent(ACTION_DOWN, SCAN_SHIFT_LEFT, KEYCODE_SHIFT_LEFT, 0,
'\0', 0x41)));
815 verifyEmbedderEvents(
830 tester.keyboardManager.handleEvent(
831 new FakeKeyEvent(ACTION_DOWN, SCAN_KEY_A, KEYCODE_A, 0,
'A', 0x41)));
832 verifyEmbedderEvents(
841 tester.keyboardManager.handleEvent(
842 new FakeKeyEvent(ACTION_UP, SCAN_KEY_A, KEYCODE_A, 0,
'A', 0x41)));
843 verifyEmbedderEvents(
853 tester.keyboardManager.handleEvent(
854 new FakeKeyEvent(ACTION_UP, SCAN_SHIFT_LEFT, KEYCODE_SHIFT_LEFT, 0,
'\0', 0)));
855 verifyEmbedderEvents(
867 final ArrayList<CallRecord> calls =
new ArrayList<>();
869 tester.recordEmbedderCallsTo(calls);
870 tester.respondToTextInputWith(
true);
875 tester.keyboardManager.handleEvent(
876 new FakeKeyEvent(ACTION_DOWN, 0, KEYCODE_ENTER, 0,
'\n', 0)));
877 verifyEmbedderEvents(
886 true,
tester.keyboardManager.handleEvent(
new FakeKeyEvent(ACTION_DOWN, 0, 0, 0,
'\0', 0)));
887 verifyEmbedderEvents(
897 tester.keyboardManager.handleEvent(
898 new FakeKeyEvent(ACTION_DOWN, 0xDEADBEEF, 0, 0,
'\0', 0)));
899 verifyEmbedderEvents(
909 tester.keyboardManager.handleEvent(
910 new FakeKeyEvent(ACTION_DOWN, SCAN_ARROW_LEFT, 0, 0,
'\0', 0)));
911 verifyEmbedderEvents(
922 tester.keyboardManager.handleEvent(
923 new FakeKeyEvent(ACTION_DOWN, SCAN_ARROW_RIGHT, 0xDEADBEEF, 0,
'\0', 0)));
924 verifyEmbedderEvents(
936 final ArrayList<CallRecord> calls =
new ArrayList<>();
938 tester.recordEmbedderCallsTo(calls);
939 tester.respondToTextInputWith(
true);
943 tester.keyboardManager.handleEvent(
944 new FakeKeyEvent(ACTION_DOWN, SCAN_KEY_A, KEYCODE_A, 0,
'a', 0)));
945 verifyEmbedderEvents(
954 tester.keyboardManager.handleEvent(
955 new FakeKeyEvent(ACTION_DOWN, SCAN_KEY_A, KEYCODE_A, 0,
'a', 0)));
956 assertEquals(calls.size(), 2);
957 assertEmbedderEventEquals(
958 calls.get(0).keyData,
965 assertEmbedderEventEquals(
966 calls.get(1).keyData,
979 final ArrayList<CallRecord> calls =
new ArrayList<>();
981 tester.recordEmbedderCallsTo(calls);
982 tester.respondToTextInputWith(
true);
986 tester.keyboardManager.handleEvent(
987 new FakeKeyEvent(ACTION_UP, SCAN_KEY_A, KEYCODE_A, 0,
'a', 0)));
988 verifyEmbedderEvents(
999 final ArrayList<CallRecord> calls =
new ArrayList<>();
1001 tester.recordEmbedderCallsTo(calls);
1002 tester.respondToTextInputWith(
true);
1005 tester.keyboardManager.handleEvent(
1006 new FakeKeyEvent(ACTION_DOWN, SCAN_SHIFT_LEFT, KEYCODE_SHIFT_LEFT, 0,
'\0', 0x41));
1007 verifyEmbedderEvents(
1012 PHYSICAL_SHIFT_LEFT,
1020 tester.keyboardManager.handleEvent(
1021 new FakeKeyEvent(ACTION_UP, SCAN_SHIFT_LEFT, KEYCODE_SHIFT_LEFT, 0,
'\0', 0));
1022 verifyEmbedderEvents(
1031 tester.keyboardManager.handleEvent(
1032 new FakeKeyEvent(ACTION_DOWN, SCAN_SHIFT_RIGHT, KEYCODE_SHIFT_RIGHT, 0,
'\0', 0x41));
1033 verifyEmbedderEvents(
1038 PHYSICAL_SHIFT_RIGHT,
1039 LOGICAL_SHIFT_RIGHT,
1046 tester.keyboardManager.handleEvent(
1047 new FakeKeyEvent(ACTION_UP, SCAN_SHIFT_RIGHT, KEYCODE_SHIFT_RIGHT, 0,
'\0', 0));
1048 verifyEmbedderEvents(
1053 PHYSICAL_SHIFT_RIGHT,
1054 LOGICAL_SHIFT_RIGHT,
1062 tester.keyboardManager.handleEvent(
1063 new FakeKeyEvent(ACTION_DOWN, SCAN_CONTROL_LEFT, KEYCODE_CTRL_LEFT, 0,
'\0', 0x3000));
1064 verifyEmbedderEvents(
1069 PHYSICAL_CONTROL_LEFT,
1070 LOGICAL_CONTROL_LEFT,
1077 tester.keyboardManager.handleEvent(
1078 new FakeKeyEvent(ACTION_UP, SCAN_CONTROL_LEFT, KEYCODE_CTRL_LEFT, 0,
'\0', 0));
1079 verifyEmbedderEvents(
1084 PHYSICAL_CONTROL_LEFT,
1085 LOGICAL_CONTROL_LEFT,
1093 tester.keyboardManager.handleEvent(
1094 new FakeKeyEvent(ACTION_DOWN, SCAN_CONTROL_RIGHT, KEYCODE_CTRL_RIGHT, 0,
'\0', 0x3000));
1095 verifyEmbedderEvents(
1100 PHYSICAL_CONTROL_RIGHT,
1101 LOGICAL_CONTROL_RIGHT,
1108 tester.keyboardManager.handleEvent(
1109 new FakeKeyEvent(ACTION_UP, SCAN_CONTROL_RIGHT, KEYCODE_CTRL_RIGHT, 0,
'\0', 0));
1110 verifyEmbedderEvents(
1115 PHYSICAL_CONTROL_RIGHT,
1116 LOGICAL_CONTROL_RIGHT,
1124 tester.keyboardManager.handleEvent(
1125 new FakeKeyEvent(ACTION_DOWN, SCAN_ALT_LEFT, KEYCODE_ALT_LEFT, 0,
'\0', 0x12));
1126 verifyEmbedderEvents(
1134 tester.keyboardManager.handleEvent(
1135 new FakeKeyEvent(ACTION_UP, SCAN_ALT_LEFT, KEYCODE_ALT_LEFT, 0,
'\0', 0));
1136 verifyEmbedderEvents(
1145 tester.keyboardManager.handleEvent(
1146 new FakeKeyEvent(ACTION_DOWN, SCAN_ALT_RIGHT, KEYCODE_ALT_RIGHT, 0,
'\0', 0x12));
1147 verifyEmbedderEvents(
1155 tester.keyboardManager.handleEvent(
1156 new FakeKeyEvent(ACTION_UP, SCAN_ALT_RIGHT, KEYCODE_ALT_RIGHT, 0,
'\0', 0));
1157 verifyEmbedderEvents(
1169 final ArrayList<CallRecord> calls =
new ArrayList<>();
1171 tester.recordEmbedderCallsTo(calls);
1172 tester.respondToTextInputWith(
true);
1175 tester.keyboardManager.handleEvent(
1176 new FakeKeyEvent(ACTION_DOWN, SCAN_DIGIT1, KEYCODE_1, 0,
'1', 0));
1177 verifyEmbedderEvents(
1185 tester.keyboardManager.handleEvent(
1186 new FakeKeyEvent(ACTION_UP, SCAN_DIGIT1, KEYCODE_1, 0,
'1', 0));
1187 verifyEmbedderEvents(
1196 tester.keyboardManager.handleEvent(
1197 new FakeKeyEvent(ACTION_DOWN, SCAN_SHIFT_LEFT, KEYCODE_SHIFT_LEFT, 0,
'\0', 0x41));
1200 tester.keyboardManager.handleEvent(
1201 new FakeKeyEvent(ACTION_DOWN, SCAN_DIGIT1, KEYCODE_1, 0,
'&', 0x41));
1202 verifyEmbedderEvents(
1210 tester.keyboardManager.handleEvent(
1211 new FakeKeyEvent(ACTION_UP, SCAN_DIGIT1, KEYCODE_1, 0,
'&', 0x41));
1212 verifyEmbedderEvents(
1220 tester.keyboardManager.handleEvent(
1221 new FakeKeyEvent(ACTION_UP, SCAN_SHIFT_LEFT, KEYCODE_SHIFT_LEFT, 0,
'\0', 0));
1225 tester.keyboardManager.handleEvent(
1226 new FakeKeyEvent(ACTION_DOWN, SCAN_KEY_A, KEYCODE_A, 0,
'\u0444', 0));
1227 verifyEmbedderEvents(
1234 tester.keyboardManager.handleEvent(
1235 new FakeKeyEvent(ACTION_UP, SCAN_KEY_A, KEYCODE_A, 0,
'\u0444', 0));
1236 verifyEmbedderEvents(
1248 final ArrayList<CallRecord> calls =
new ArrayList<>();
1250 tester.recordEmbedderCallsTo(calls);
1251 tester.respondToTextInputWith(
true);
1253 final int SHIFT_LEFT_ON = META_SHIFT_LEFT_ON | META_SHIFT_ON;
1257 tester.keyboardManager.handleEvent(
1259 ACTION_DOWN, SCAN_ARROW_LEFT, KEYCODE_DPAD_LEFT, 0,
'\0', SHIFT_LEFT_ON)));
1260 assertEquals(calls.size(), 2);
1261 assertEmbedderEventEquals(
1262 calls.get(0).keyData,
1264 PHYSICAL_SHIFT_LEFT,
1273 tester.keyboardManager.handleEvent(
1274 new FakeKeyEvent(ACTION_UP, SCAN_ARROW_LEFT, KEYCODE_DPAD_LEFT, 0,
'\0', 0)));
1275 assertEquals(calls.size(), 2);
1276 assertEmbedderEventEquals(
1277 calls.get(0).keyData,
1279 PHYSICAL_SHIFT_LEFT,
1291 final ArrayList<CallRecord> calls =
new ArrayList<>();
1293 tester.recordEmbedderCallsTo(calls);
1294 tester.respondToTextInputWith(
true);
1296 final int SHIFT_LEFT_ON = META_SHIFT_LEFT_ON | META_SHIFT_ON;
1303 tester.keyboardManager.handleEvent(
1305 ACTION_DOWN, SCAN_SHIFT_LEFT, KEYCODE_SHIFT_LEFT, 1,
'\0', SHIFT_LEFT_ON)));
1306 assertEquals(calls.size(), 1);
1307 assertEmbedderEventEquals(
1308 calls.get(0).keyData,
1310 PHYSICAL_SHIFT_LEFT,
1320 tester.keyboardManager.handleEvent(
1322 ACTION_DOWN, SCAN_SHIFT_LEFT, KEYCODE_SHIFT_LEFT, 0,
'\0', SHIFT_LEFT_ON)));
1323 assertEquals(calls.size(), 2);
1324 assertEmbedderEventEquals(
1325 calls.get(0).keyData,
1327 PHYSICAL_SHIFT_LEFT,
1332 assertEmbedderEventEquals(
1333 calls.get(1).keyData,
1335 PHYSICAL_SHIFT_LEFT,
1345 tester.keyboardManager.handleEvent(
1346 new FakeKeyEvent(ACTION_UP, SCAN_SHIFT_LEFT, KEYCODE_SHIFT_LEFT, 0,
'\0', 0)));
1347 assertEquals(calls.size(), 1);
1348 assertEmbedderEventEquals(
1349 calls.get(0).keyData,
1351 PHYSICAL_SHIFT_LEFT,
1361 tester.keyboardManager.handleEvent(
1362 new FakeKeyEvent(ACTION_UP, SCAN_SHIFT_LEFT, KEYCODE_SHIFT_LEFT, 0,
'\0', 0)));
1363 assertEquals(calls.size(), 1);
1364 assertEmbedderEventEquals(
1371 tester.keyboardManager.handleEvent(
1373 ACTION_DOWN, SCAN_SHIFT_LEFT, KEYCODE_SHIFT_LEFT, 0,
'\0', SHIFT_LEFT_ON)));
1374 assertEquals(calls.size(), 1);
1375 assertEmbedderEventEquals(
1376 calls.get(0).keyData,
1378 PHYSICAL_SHIFT_LEFT,
1388 tester.keyboardManager.handleEvent(
1390 ACTION_DOWN, SCAN_SHIFT_LEFT, KEYCODE_SHIFT_LEFT, 1,
'\0', SHIFT_LEFT_ON)));
1391 assertEquals(calls.size(), 1);
1392 assertEmbedderEventEquals(
1393 calls.get(0).keyData,
1395 PHYSICAL_SHIFT_LEFT,
1411 verifyEmbedderEvents(testShiftRightEvent(
false,
false, UP_EVENT,
false),
new KeyData[] {});
1412 verifyEmbedderEvents(
1413 testShiftRightEvent(
false,
true, UP_EVENT,
false),
1415 buildShiftKeyData(SHIFT_RIGHT_EVENT, UP_EVENT,
false),
1417 verifyEmbedderEvents(
1418 testShiftRightEvent(
true,
false, UP_EVENT,
false),
1420 buildShiftKeyData(SHIFT_LEFT_EVENT, UP_EVENT,
true),
1422 verifyEmbedderEvents(
1423 testShiftRightEvent(
true,
true, UP_EVENT,
false),
1425 buildShiftKeyData(SHIFT_LEFT_EVENT, UP_EVENT,
true),
1426 buildShiftKeyData(SHIFT_RIGHT_EVENT, UP_EVENT,
false),
1431 verifyEmbedderEvents(
1432 testShiftRightEvent(
false,
false, UP_EVENT,
true),
1434 buildShiftKeyData(SHIFT_LEFT_EVENT, DOWN_EVENT,
true),
1436 verifyEmbedderEvents(
1437 testShiftRightEvent(
false,
true, UP_EVENT,
true),
1439 buildShiftKeyData(SHIFT_LEFT_EVENT, DOWN_EVENT,
true),
1440 buildShiftKeyData(SHIFT_RIGHT_EVENT, UP_EVENT,
false),
1442 verifyEmbedderEvents(testShiftRightEvent(
true,
false, UP_EVENT,
true),
new KeyData[] {});
1443 verifyEmbedderEvents(
1444 testShiftRightEvent(
true,
true, UP_EVENT,
true),
1446 buildShiftKeyData(SHIFT_RIGHT_EVENT, UP_EVENT,
false),
1453 verifyEmbedderEvents(
1454 testShiftRightEvent(
false,
false, DOWN_EVENT,
true),
1456 buildShiftKeyData(SHIFT_RIGHT_EVENT, DOWN_EVENT,
false),
1458 verifyEmbedderEvents(
1459 testShiftRightEvent(
false,
true, DOWN_EVENT,
true),
1461 buildShiftKeyData(SHIFT_RIGHT_EVENT, UP_EVENT,
true),
1462 buildShiftKeyData(SHIFT_RIGHT_EVENT, DOWN_EVENT,
false),
1464 verifyEmbedderEvents(
1465 testShiftRightEvent(
true,
false, DOWN_EVENT,
true),
1467 buildShiftKeyData(SHIFT_RIGHT_EVENT, DOWN_EVENT,
false),
1469 verifyEmbedderEvents(
1470 testShiftRightEvent(
true,
true, DOWN_EVENT,
true),
1472 buildShiftKeyData(SHIFT_RIGHT_EVENT, UP_EVENT,
true),
1473 buildShiftKeyData(SHIFT_RIGHT_EVENT, DOWN_EVENT,
false),
1482 final ArrayList<CallRecord> calls =
new ArrayList<>();
1484 tester.recordEmbedderCallsTo(calls);
1485 tester.respondToTextInputWith(
true);
1489 tester.keyboardManager.handleEvent(
1491 ACTION_DOWN, SCAN_ARROW_LEFT, KEYCODE_DPAD_LEFT, 0,
'\0', META_CTRL_ON)));
1492 assertEquals(calls.size(), 2);
1493 assertEmbedderEventEquals(
1494 calls.get(0).keyData,
1496 PHYSICAL_CONTROL_LEFT,
1497 LOGICAL_CONTROL_LEFT,
1505 tester.keyboardManager.handleEvent(
1506 new FakeKeyEvent(ACTION_UP, SCAN_ARROW_LEFT, KEYCODE_DPAD_LEFT, 0,
'\0', 0)));
1507 assertEquals(calls.size(), 2);
1508 assertEmbedderEventEquals(
1509 calls.get(0).keyData,
1511 PHYSICAL_CONTROL_LEFT,
1512 LOGICAL_CONTROL_LEFT,
1520 tester.keyboardManager.handleEvent(
1522 ACTION_DOWN, SCAN_ARROW_LEFT, KEYCODE_DPAD_LEFT, 0,
'\0', META_ALT_ON)));
1523 assertEquals(calls.size(), 2);
1524 assertEmbedderEventEquals(
1525 calls.get(0).keyData,
1536 tester.keyboardManager.handleEvent(
1537 new FakeKeyEvent(ACTION_UP, SCAN_ARROW_LEFT, KEYCODE_DPAD_LEFT, 0,
'\0', 0)));
1538 assertEquals(calls.size(), 2);
1539 assertEmbedderEventEquals(
1540 calls.get(0).keyData,
1556 final ArrayList<CallRecord> calls =
new ArrayList<>();
1559 final int SHIFT_LEFT_ON = META_SHIFT_LEFT_ON | META_SHIFT_ON;
1561 tester.recordEmbedderCallsTo(calls);
1562 tester.respondToTextInputWith(
true);
1567 tester.keyboardManager.handleEvent(
1568 new FakeKeyEvent(ACTION_DOWN, SCAN_SHIFT_LEFT, KEYCODE_SHIFT_LEFT, 0,
'\0', 0)));
1569 assertEquals(calls.size(), 2);
1570 assertEmbedderEventEquals(
1571 calls.get(0).keyData,
1573 PHYSICAL_SHIFT_LEFT,
1578 assertEmbedderEventEquals(
1579 calls.get(1).keyData,
1581 PHYSICAL_SHIFT_LEFT,
1591 tester.keyboardManager.handleEvent(
1593 ACTION_DOWN, SCAN_SHIFT_LEFT, KEYCODE_SHIFT_LEFT, 0,
'\0', SHIFT_LEFT_ON)));
1594 assertEquals(calls.size(), 1);
1595 assertEmbedderEventEquals(
1596 calls.get(0).keyData,
1598 PHYSICAL_SHIFT_LEFT,
1608 tester.keyboardManager.handleEvent(
1609 new FakeKeyEvent(ACTION_DOWN, SCAN_SHIFT_LEFT, KEYCODE_SHIFT_LEFT, 1,
'\0', 0)));
1610 assertEquals(calls.size(), 2);
1611 assertEmbedderEventEquals(
1612 calls.get(0).keyData,
1614 PHYSICAL_SHIFT_LEFT,
1619 assertEmbedderEventEquals(
1620 calls.get(1).keyData,
1622 PHYSICAL_SHIFT_LEFT,
1636 final ArrayList<CallRecord> calls =
new ArrayList<>();
1638 tester.recordEmbedderCallsTo(calls);
1639 tester.respondToTextInputWith(
true);
1642 final KeyEvent keyEvent =
new FakeKeyEvent(ACTION_DOWN, 0, KEYCODE_SHIFT_LEFT, 0,
'\0', 0);
1646 assertEquals(
tester.keyboardManager.handleEvent(keyEvent),
true);
1647 assertEquals(calls.size(), 2);
1648 assertEmbedderEventEquals(
1649 calls.get(0).keyData,
1656 assertEmbedderEventEquals(
1657 calls.get(1).keyData,
1670 final ArrayList<CallRecord> calls =
new ArrayList<>();
1672 tester.recordEmbedderCallsTo(calls);
1673 tester.respondToTextInputWith(
true);
1680 tester.keyboardManager.handleEvent(
1682 ACTION_DOWN, SCAN_CAPS_LOCK, KEYCODE_CAPS_LOCK, 0,
'\0', META_CAPS_LOCK_ON)));
1683 assertEquals(calls.size(), 1);
1684 assertEmbedderEventEquals(
1685 calls.get(0).keyData,
1696 tester.keyboardManager.handleEvent(
1697 new FakeKeyEvent(ACTION_UP, SCAN_CAPS_LOCK, KEYCODE_CAPS_LOCK, 0,
'\0', 0)));
1698 assertEquals(calls.size(), 1);
1699 assertEmbedderEventEquals(
1700 calls.get(0).keyData,
1711 tester.keyboardManager.handleEvent(
1713 ACTION_DOWN, SCAN_ARROW_LEFT, KEYCODE_DPAD_LEFT, 0,
'\0', META_CAPS_LOCK_ON)));
1714 assertEquals(calls.size(), 1);
1715 assertEmbedderEventEquals(
1716 calls.get(0).keyData,
1718 PHYSICAL_ARROW_LEFT,
1727 tester.keyboardManager.handleEvent(
1729 ACTION_UP, SCAN_ARROW_LEFT, KEYCODE_DPAD_LEFT, 0,
'\0', META_CAPS_LOCK_ON)));
1730 assertEquals(calls.size(), 1);
1731 assertEmbedderEventEquals(
1732 calls.get(0).keyData,
1734 PHYSICAL_ARROW_LEFT,
1743 tester.keyboardManager.handleEvent(
1745 ACTION_DOWN, SCAN_CAPS_LOCK, KEYCODE_CAPS_LOCK, 0,
'\0', META_CAPS_LOCK_ON)));
1746 assertEquals(calls.size(), 1);
1747 assertEmbedderEventEquals(
1748 calls.get(0).keyData,
1759 tester.keyboardManager.handleEvent(
1760 new FakeKeyEvent(ACTION_UP, SCAN_CAPS_LOCK, KEYCODE_CAPS_LOCK, 0,
'\0', 0)));
1761 assertEquals(calls.size(), 1);
1762 assertEmbedderEventEquals(
1763 calls.get(0).keyData,
1774 tester.keyboardManager.handleEvent(
1775 new FakeKeyEvent(ACTION_DOWN, SCAN_ARROW_LEFT, KEYCODE_DPAD_LEFT, 0,
'\0', 0)));
1776 assertEquals(calls.size(), 1);
1777 assertEmbedderEventEquals(
1778 calls.get(0).keyData,
1780 PHYSICAL_ARROW_LEFT,
1789 tester.keyboardManager.handleEvent(
1790 new FakeKeyEvent(ACTION_UP, SCAN_ARROW_LEFT, KEYCODE_DPAD_LEFT, 0,
'\0', 0)));
1791 assertEquals(calls.size(), 1);
1792 assertEmbedderEventEquals(
1793 calls.get(0).keyData,
1795 PHYSICAL_ARROW_LEFT,
1806 final ArrayList<CallRecord> calls =
new ArrayList<>();
1808 tester.recordEmbedderCallsTo(calls);
1809 tester.respondToTextInputWith(
true);
1813 tester.keyboardManager.handleEvent(
1815 ACTION_DOWN, SCAN_ARROW_LEFT, KEYCODE_DPAD_LEFT, 0,
'\0', META_CAPS_LOCK_ON)));
1816 assertEquals(calls.size(), 3);
1817 assertEmbedderEventEquals(
1818 calls.get(0).keyData,
1825 assertEmbedderEventEquals(
1826 calls.get(1).keyData,
1833 assertEmbedderEventEquals(
1834 calls.get(2).keyData,
1836 PHYSICAL_ARROW_LEFT,
1845 tester.keyboardManager.handleEvent(
1847 ACTION_DOWN, SCAN_CAPS_LOCK, KEYCODE_CAPS_LOCK, 0,
'\0', META_CAPS_LOCK_ON)));
1848 assertEquals(calls.size(), 1);
1849 assertEmbedderEventEquals(
1850 calls.get(0).keyData,
1861 tester.keyboardManager.handleEvent(
1863 ACTION_UP, SCAN_ARROW_LEFT, KEYCODE_DPAD_LEFT, 0,
'\0', META_CAPS_LOCK_ON)));
1864 assertEquals(calls.size(), 3);
1865 assertEmbedderEventEquals(
1866 calls.get(0).keyData,
1873 assertEmbedderEventEquals(
1874 calls.get(1).keyData,
1881 assertEmbedderEventEquals(
1882 calls.get(2).keyData,
1884 PHYSICAL_ARROW_LEFT,
1893 tester.keyboardManager.handleEvent(
1894 new FakeKeyEvent(ACTION_UP, SCAN_CAPS_LOCK, KEYCODE_CAPS_LOCK, 0,
'\0', 0)));
1895 assertEquals(calls.size(), 1);
1896 assertEmbedderEventEquals(
1897 calls.get(0).keyData,
1911 tester.respondToTextInputWith(
true);
1914 assertEquals(
tester.keyboardManager.getKeyboardState(), Map.of());
1916 tester.keyboardManager.handleEvent(
1917 new FakeKeyEvent(ACTION_DOWN, SCAN_KEY_A, KEYCODE_A, 1,
'a', 0));
1918 assertEquals(
tester.keyboardManager.getKeyboardState(), Map.of(PHYSICAL_KEY_A, LOGICAL_KEY_A));
1920 tester.keyboardManager.handleEvent(
1921 new FakeKeyEvent(ACTION_UP, SCAN_KEY_A, KEYCODE_A, 0,
'a', 0));
1922 assertEquals(
tester.keyboardManager.getKeyboardState(), Map.of());
static SkISize times(const SkISize &size, float factor)
static bool eq(const SkM44 &a, const SkM44 &b, float tol)
Consumer< Boolean > reply
static CallRecord embedderCall(@NonNull KeyData keyData, @Nullable Consumer< Boolean > reply)
static CallRecord channelCall( @NonNull JSONObject channelObject, @Nullable Consumer< Boolean > reply)
void respondToEmbedderCallsWith(boolean handled)
void recordEmbedderCallsTo(@NonNull ArrayList< CallRecord > storage)
void recordChannelCallsTo(@NonNull ArrayList< CallRecord > storage)
KeyboardManager keyboardManager
void respondToChannelCallsWith(boolean handled)
KeyboardManager.ViewDelegate mockView
void respondToTextInputWith(boolean response)
static void assertChannelEventEquals( @NonNull JSONObject message, @NonNull String type, @NonNull Integer keyCode)
static void assertEmbedderEventEquals( @NonNull KeyData data, Type type, long physicalKey, long logicalKey, String character, boolean synthesized, DeviceType deviceType)
void synchronizeOtherModifiers()
void synchronizeCapsLock()
void synchronizeShiftLeftDuringSiblingKeyEvents()
static ByteBuffer buildJsonResponse(boolean handled)
void redispatchedEventsAreCorrectlySkipped()
void synchronizeShiftLeftDuringSelfKeyEvents()
static KeyData buildShiftKeyData(boolean isLeft, boolean isDown, boolean isSynthesized)
static String printBufferBytes(@NonNull ByteBuffer buffer)
void synchronizeModifiersForZeroedScanCode()
void bothRespondersHandlesEvents()
void abruptUpEventsAreIgnored()
void synchronizeModifiersForConflictingMetaState()
void eventsWithMintedCodes()
void basicCombingCharactersTest()
static KeyData buildKeyData(Type type, long physicalKey, long logicalKey, @Nullable String characters, boolean synthesized, DeviceType deviceType)
void embedderResponderHandlesEvents()
void redispatchEventsIfTextInputDoesntHandle()
void synchronizeShiftLeftDuringForeignKeyEvents()
void normalCapsLockEvents()
void channelResponderHandlesEvents()
void embedderResponderHandlesNullReply()
static ByteBuffer buildBinaryResponse(boolean handled)
void respondsTrueWhenHandlingNewEvents()
void serializeAndDeserializeKeyData()
static void verifyEmbedderEvents(List< CallRecord > receivedCalls, KeyData[] expectedData)
void duplicateDownEventsArePrecededBySynthesizedUpEvents()
void textInputHandlesEventsIfNoRespondersDo()
static List< CallRecord > testShiftRightEvent(boolean preEventLeftPressed, boolean preEventRightPressed, boolean rightEventIsDown, boolean truePressed)
boolean handleEvent(@NonNull KeyEvent keyEvent)
static final long kAndroidPlane
Object decodeMessage(@Nullable ByteBuffer message)
static final JSONMessageCodec INSTANCE
ByteBuffer encodeMessage(@Nullable Object message)
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
SIT bool any(const Vec< 1, T > &x)
std::shared_ptr< const fml::Mapping > data