Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 017cf35b authored by tyiu's avatar tyiu
Browse files

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
parent ed2a0e33
Loading
Loading
Loading
Loading
+46 −37
Original line number Diff line number Diff line
@@ -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<Integer, Integer> 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 <string> (Default: touchscreen)");
            out.println("      keyevent [--longpress|--doubletap] <key code number or name> ..."
            out.println("      keyevent [--longpress|--doubletap|--async"
                    + "|--delay <duration between keycodes in ms>]"
                    + " <key code number or name> ..."
                    + " (Default: keyboard)");
            out.println("      tap <x> <y> (Default: touchscreen)");
            out.println("      swipe <x1> <y1> <x2> <y2> [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) {
        boolean longPress = false;
        boolean async = false;
        boolean doubleTap = false;
        long delayMs = 0;

        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;
            }
        do {
            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 {
            final int keycode = KeyEvent.keyCodeFromString(arg);
            sendKeyEvent(inputSource, keycode, longpress, displayId);
            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);
        }
    }