From 017cf35b7fa9d3a164cb6e2f067ca7effae9b370 Mon Sep 17 00:00:00 2001 From: tyiu Date: Sat, 13 May 2023 01:54:46 +0000 Subject: [PATCH] Add shell input meshing delay Added 45 ms delay for input meshing to allow gesture launcher service to detect consecutive key presses. Async inject key event for input shell to prevent buttons from timing out. Bug: 279940768 Bug: 261737207 Test: adb shell input keyevent --async --delay 45 26 26 26 26 26 Test: adb shell input keyevent --async --delay 45 264 264 264 Change-Id: I3ec225baa017c65b5c7ef69efd7e98add5a02e6a --- .../server/input/InputShellCommand.java | 87 ++++++++++--------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/services/core/java/com/android/server/input/InputShellCommand.java b/services/core/java/com/android/server/input/InputShellCommand.java index 513259145da03..16b23ca28e36a 100644 --- a/services/core/java/com/android/server/input/InputShellCommand.java +++ b/services/core/java/com/android/server/input/InputShellCommand.java @@ -74,6 +74,8 @@ public class InputShellCommand extends ShellCommand { private static final int DEFAULT_EDGE_FLAGS = 0; private static final int DEFAULT_BUTTON_STATE = 0; private static final int DEFAULT_FLAGS = 0; + private static final boolean INJECT_ASYNC = true; + private static final boolean INJECT_SYNC = false; /** Modifier key to meta state */ private static final Map MODIFIER; @@ -109,9 +111,11 @@ public class InputShellCommand extends ShellCommand { SOURCES = unmodifiableMap(map); } - private void injectKeyEvent(KeyEvent event) { - InputManagerGlobal.getInstance().injectInputEvent(event, - InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH); + private void injectKeyEvent(KeyEvent event, boolean async) { + int injectMode = async + ? InputManager.INJECT_INPUT_EVENT_MODE_ASYNC + : InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH; + InputManagerGlobal.getInstance().injectInputEvent(event, injectMode); } private int getInputDeviceId(int inputSource) { @@ -271,7 +275,9 @@ public class InputShellCommand extends ShellCommand { out.println(); out.println("The commands and default sources are:"); out.println(" text (Default: touchscreen)"); - out.println(" keyevent [--longpress|--doubletap] ..." + out.println(" keyevent [--longpress|--doubletap|--async" + + "|--delay ]" + + " ..." + " (Default: keyboard)"); out.println(" tap (Default: touchscreen)"); out.println(" swipe [duration(ms)]" @@ -322,32 +328,45 @@ public class InputShellCommand extends ShellCommand { e.setSource(source); } e.setDisplayId(displayId); - injectKeyEvent(e); + injectKeyEvent(e, INJECT_SYNC); } } private void runKeyEvent(int inputSource, int displayId) { - String arg = getNextArgRequired(); - final boolean longpress = "--longpress".equals(arg); - if (longpress) { - arg = getNextArgRequired(); - } else { - final boolean doubleTap = "--doubletap".equals(arg); - if (doubleTap) { - arg = getNextArgRequired(); - final int keycode = KeyEvent.keyCodeFromString(arg); - sendKeyDoubleTap(inputSource, keycode, displayId); - return; - } - } + boolean longPress = false; + boolean async = false; + boolean doubleTap = false; + long delayMs = 0; + String arg = getNextArgRequired(); do { - final int keycode = KeyEvent.keyCodeFromString(arg); - sendKeyEvent(inputSource, keycode, longpress, displayId); + if (!arg.startsWith("--")) break; + longPress = (longPress || arg.equals("--longpress")); + async = (async || arg.equals("--async")); + doubleTap = (doubleTap || arg.equals("--doubletap")); + if (arg.equals("--delay")) { + delayMs = Long.parseLong(getNextArgRequired()); + } + } while ((arg = getNextArg()) != null); + + boolean firstInput = true; + do { + if (!firstInput && delayMs > 0) { + sleep(delayMs); + } + firstInput = false; + + final int keyCode = KeyEvent.keyCodeFromString(arg); + sendKeyEvent(inputSource, keyCode, longPress, displayId, async); + if (doubleTap) { + sleep(ViewConfiguration.getDoubleTapMinTime()); + sendKeyEvent(inputSource, keyCode, longPress, displayId, async); + } } while ((arg = getNextArg()) != null); } - private void sendKeyEvent(int inputSource, int keyCode, boolean longpress, int displayId) { + private void sendKeyEvent( + int inputSource, int keyCode, boolean longPress, int displayId, boolean async) { final long now = SystemClock.uptimeMillis(); KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0 /* repeatCount */, @@ -355,21 +374,16 @@ public class InputShellCommand extends ShellCommand { inputSource); event.setDisplayId(displayId); - injectKeyEvent(event); - if (longpress) { + injectKeyEvent(event, async); + if (longPress) { sleep(ViewConfiguration.getLongPressTimeout()); // Some long press behavior would check the event time, we set a new event time here. final long nextEventTime = now + ViewConfiguration.getLongPressTimeout(); - injectKeyEvent(KeyEvent.changeTimeRepeat(event, nextEventTime, 1 /* repeatCount */, - KeyEvent.FLAG_LONG_PRESS)); + KeyEvent longPressEvent = KeyEvent.changeTimeRepeat( + event, nextEventTime, 1 /* repeatCount */, KeyEvent.FLAG_LONG_PRESS); + injectKeyEvent(longPressEvent, async); } - injectKeyEvent(KeyEvent.changeAction(event, KeyEvent.ACTION_UP)); - } - - private void sendKeyDoubleTap(int inputSource, int keyCode, int displayId) { - sendKeyEvent(inputSource, keyCode, false, displayId); - sleep(ViewConfiguration.getDoubleTapMinTime()); - sendKeyEvent(inputSource, keyCode, false, displayId); + injectKeyEvent(KeyEvent.changeAction(event, KeyEvent.ACTION_UP), async); } private void runTap(int inputSource, int displayId) { @@ -530,11 +544,6 @@ public class InputShellCommand extends ShellCommand { sendKeyCombination(inputSource, keyCodes, displayId, duration); } - private void injectKeyEventAsync(KeyEvent event) { - InputManagerGlobal.getInstance().injectInputEvent(event, - InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); - } - private void sendKeyCombination(int inputSource, IntArray keyCodes, int displayId, long duration) { final long now = SystemClock.uptimeMillis(); @@ -555,7 +564,7 @@ public class InputShellCommand extends ShellCommand { for (KeyEvent event: events) { // Use async inject so interceptKeyBeforeQueueing or interceptKeyBeforeDispatching could // handle keys. - injectKeyEventAsync(event); + injectKeyEvent(event, INJECT_ASYNC); } sleep(duration); @@ -565,7 +574,7 @@ public class InputShellCommand extends ShellCommand { final KeyEvent upEvent = new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/, inputSource); - injectKeyEventAsync(upEvent); + injectKeyEvent(upEvent, INJECT_ASYNC); metaState &= ~MODIFIER.getOrDefault(keyCode, 0); } }