Loading services/core/java/com/android/server/input/InputShellCommand.java +79 −23 Original line number Original line Diff line number Diff line Loading @@ -18,10 +18,34 @@ package com.android.server.input; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.KeyEvent.KEYCODE_ALT_LEFT; import static android.view.KeyEvent.KEYCODE_ALT_RIGHT; import static android.view.KeyEvent.KEYCODE_CTRL_LEFT; import static android.view.KeyEvent.KEYCODE_CTRL_RIGHT; import static android.view.KeyEvent.KEYCODE_META_LEFT; import static android.view.KeyEvent.KEYCODE_META_RIGHT; import static android.view.KeyEvent.KEYCODE_SHIFT_LEFT; import static android.view.KeyEvent.KEYCODE_SHIFT_RIGHT; import static android.view.KeyEvent.META_ALT_LEFT_ON; import static android.view.KeyEvent.META_ALT_ON; import static android.view.KeyEvent.META_ALT_RIGHT_ON; import static android.view.KeyEvent.META_CTRL_LEFT_ON; import static android.view.KeyEvent.META_CTRL_ON; import static android.view.KeyEvent.META_CTRL_RIGHT_ON; import static android.view.KeyEvent.META_META_LEFT_ON; import static android.view.KeyEvent.META_META_ON; import static android.view.KeyEvent.META_META_RIGHT_ON; import static android.view.KeyEvent.META_SHIFT_LEFT_ON; import static android.view.KeyEvent.META_SHIFT_ON; import static android.view.KeyEvent.META_SHIFT_RIGHT_ON; import static java.util.Collections.unmodifiableMap; import android.hardware.input.InputManager; import android.hardware.input.InputManager; import android.os.ShellCommand; import android.os.ShellCommand; import android.os.SystemClock; import android.os.SystemClock; import android.util.ArrayMap; import android.util.IntArray; import android.view.InputDevice; import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.KeyEvent; Loading @@ -29,8 +53,6 @@ import android.view.MotionEvent; import android.view.ViewConfiguration; import android.view.ViewConfiguration; import java.io.PrintWriter; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Map; /** /** Loading @@ -52,18 +74,39 @@ public class InputShellCommand extends ShellCommand { private static final int DEFAULT_BUTTON_STATE = 0; private static final int DEFAULT_BUTTON_STATE = 0; private static final int DEFAULT_FLAGS = 0; private static final int DEFAULT_FLAGS = 0; private static final Map<String, Integer> SOURCES = new HashMap<String, Integer>() {{ /** Modifier key to meta state */ put("keyboard", InputDevice.SOURCE_KEYBOARD); private static final Map<Integer, Integer> MODIFIER; put("dpad", InputDevice.SOURCE_DPAD); static { put("gamepad", InputDevice.SOURCE_GAMEPAD); final Map<Integer, Integer> map = new ArrayMap<>(); put("touchscreen", InputDevice.SOURCE_TOUCHSCREEN); map.put(KEYCODE_CTRL_LEFT, META_CTRL_LEFT_ON | META_CTRL_ON); put("mouse", InputDevice.SOURCE_MOUSE); map.put(KEYCODE_CTRL_RIGHT, META_CTRL_RIGHT_ON | META_CTRL_ON); put("stylus", InputDevice.SOURCE_STYLUS); map.put(KEYCODE_ALT_LEFT, META_ALT_LEFT_ON | META_ALT_ON); put("trackball", InputDevice.SOURCE_TRACKBALL); map.put(KEYCODE_ALT_RIGHT, META_ALT_RIGHT_ON | META_ALT_ON); put("touchpad", InputDevice.SOURCE_TOUCHPAD); map.put(KEYCODE_SHIFT_LEFT, META_SHIFT_LEFT_ON | META_SHIFT_ON); put("touchnavigation", InputDevice.SOURCE_TOUCH_NAVIGATION); map.put(KEYCODE_SHIFT_RIGHT, META_SHIFT_RIGHT_ON | META_SHIFT_ON); put("joystick", InputDevice.SOURCE_JOYSTICK); map.put(KEYCODE_META_LEFT, META_META_LEFT_ON | META_META_ON); }}; map.put(KEYCODE_META_RIGHT, META_META_RIGHT_ON | META_META_ON); MODIFIER = unmodifiableMap(map); } /** String to device source */ private static final Map<String, Integer> SOURCES; static { final Map<String, Integer> map = new ArrayMap<>(); map.put("keyboard", InputDevice.SOURCE_KEYBOARD); map.put("dpad", InputDevice.SOURCE_DPAD); map.put("gamepad", InputDevice.SOURCE_GAMEPAD); map.put("touchscreen", InputDevice.SOURCE_TOUCHSCREEN); map.put("mouse", InputDevice.SOURCE_MOUSE); map.put("stylus", InputDevice.SOURCE_STYLUS); map.put("trackball", InputDevice.SOURCE_TRACKBALL); map.put("touchpad", InputDevice.SOURCE_TOUCHPAD); map.put("touchnavigation", InputDevice.SOURCE_TOUCH_NAVIGATION); map.put("joystick", InputDevice.SOURCE_JOYSTICK); SOURCES = unmodifiableMap(map); } private void injectKeyEvent(KeyEvent event) { private void injectKeyEvent(KeyEvent event) { InputManager.getInstance().injectInputEvent(event, InputManager.getInstance().injectInputEvent(event, Loading Loading @@ -237,8 +280,8 @@ public class InputShellCommand extends ShellCommand { out.println(" press (Default: trackball)"); out.println(" press (Default: trackball)"); out.println(" roll <dx> <dy> (Default: trackball)"); out.println(" roll <dx> <dy> (Default: trackball)"); out.println(" motionevent <DOWN|UP|MOVE|CANCEL> <x> <y> (Default: touchscreen)"); out.println(" motionevent <DOWN|UP|MOVE|CANCEL> <x> <y> (Default: touchscreen)"); out.println(" keycombination <key code 1> <key code 2> ..." out.println(" keycombination [-t duration(ms)] <key code 1> <key code 2> ..." + " (Default: keyboard)"); + " (Default: keyboard, the key order is important here.)"); } } } } Loading Loading @@ -459,8 +502,16 @@ public class InputShellCommand extends ShellCommand { private void runKeyCombination(int inputSource, int displayId) { private void runKeyCombination(int inputSource, int displayId) { String arg = getNextArgRequired(); String arg = getNextArgRequired(); ArrayList<Integer> keyCodes = new ArrayList<>(); // Get duration (optional). long duration = 0; if ("-t".equals(arg)) { arg = getNextArgRequired(); duration = Integer.parseInt(arg); arg = getNextArgRequired(); } IntArray keyCodes = new IntArray(); while (arg != null) { while (arg != null) { final int keyCode = KeyEvent.keyCodeFromString(arg); final int keyCode = KeyEvent.keyCodeFromString(arg); if (keyCode == KeyEvent.KEYCODE_UNKNOWN) { if (keyCode == KeyEvent.KEYCODE_UNKNOWN) { Loading @@ -475,7 +526,7 @@ public class InputShellCommand extends ShellCommand { throw new IllegalArgumentException("keycombination requires at least 2 keycodes"); throw new IllegalArgumentException("keycombination requires at least 2 keycodes"); } } sendKeyCombination(inputSource, keyCodes, displayId); sendKeyCombination(inputSource, keyCodes, displayId, duration); } } private void injectKeyEventAsync(KeyEvent event) { private void injectKeyEventAsync(KeyEvent event) { Loading @@ -483,16 +534,21 @@ public class InputShellCommand extends ShellCommand { InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); } } private void sendKeyCombination(int inputSource, ArrayList<Integer> keyCodes, int displayId) { private void sendKeyCombination(int inputSource, IntArray keyCodes, int displayId, long duration) { final long now = SystemClock.uptimeMillis(); final long now = SystemClock.uptimeMillis(); final int count = keyCodes.size(); final int count = keyCodes.size(); final KeyEvent[] events = new KeyEvent[count]; final KeyEvent[] events = new KeyEvent[count]; int metaState = 0; for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) { final KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCodes.get(i), 0, final int keyCode = keyCodes.get(i); 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/, final KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/, inputSource); inputSource); event.setDisplayId(displayId); event.setDisplayId(displayId); events[i] = event; events[i] = event; // The order is important here, metaState could be updated and applied to the next key. metaState |= MODIFIER.getOrDefault(keyCode, 0); } } for (KeyEvent event: events) { for (KeyEvent event: events) { Loading @@ -501,7 +557,7 @@ public class InputShellCommand extends ShellCommand { injectKeyEventAsync(event); injectKeyEventAsync(event); } } sleep(ViewConfiguration.getTapTimeout()); sleep(duration); for (KeyEvent event: events) { for (KeyEvent event: events) { injectKeyEventAsync(KeyEvent.changeAction(event, KeyEvent.ACTION_UP)); injectKeyEventAsync(KeyEvent.changeAction(event, KeyEvent.ACTION_UP)); Loading @@ -513,7 +569,7 @@ public class InputShellCommand extends ShellCommand { * * * @param milliseconds The time to sleep in milliseconds. * @param milliseconds The time to sleep in milliseconds. */ */ private void sleep(int milliseconds) { private void sleep(long milliseconds) { try { try { Thread.sleep(milliseconds); Thread.sleep(milliseconds); } catch (InterruptedException e) { } catch (InterruptedException e) { Loading Loading
services/core/java/com/android/server/input/InputShellCommand.java +79 −23 Original line number Original line Diff line number Diff line Loading @@ -18,10 +18,34 @@ package com.android.server.input; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.KeyEvent.KEYCODE_ALT_LEFT; import static android.view.KeyEvent.KEYCODE_ALT_RIGHT; import static android.view.KeyEvent.KEYCODE_CTRL_LEFT; import static android.view.KeyEvent.KEYCODE_CTRL_RIGHT; import static android.view.KeyEvent.KEYCODE_META_LEFT; import static android.view.KeyEvent.KEYCODE_META_RIGHT; import static android.view.KeyEvent.KEYCODE_SHIFT_LEFT; import static android.view.KeyEvent.KEYCODE_SHIFT_RIGHT; import static android.view.KeyEvent.META_ALT_LEFT_ON; import static android.view.KeyEvent.META_ALT_ON; import static android.view.KeyEvent.META_ALT_RIGHT_ON; import static android.view.KeyEvent.META_CTRL_LEFT_ON; import static android.view.KeyEvent.META_CTRL_ON; import static android.view.KeyEvent.META_CTRL_RIGHT_ON; import static android.view.KeyEvent.META_META_LEFT_ON; import static android.view.KeyEvent.META_META_ON; import static android.view.KeyEvent.META_META_RIGHT_ON; import static android.view.KeyEvent.META_SHIFT_LEFT_ON; import static android.view.KeyEvent.META_SHIFT_ON; import static android.view.KeyEvent.META_SHIFT_RIGHT_ON; import static java.util.Collections.unmodifiableMap; import android.hardware.input.InputManager; import android.hardware.input.InputManager; import android.os.ShellCommand; import android.os.ShellCommand; import android.os.SystemClock; import android.os.SystemClock; import android.util.ArrayMap; import android.util.IntArray; import android.view.InputDevice; import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.KeyEvent; Loading @@ -29,8 +53,6 @@ import android.view.MotionEvent; import android.view.ViewConfiguration; import android.view.ViewConfiguration; import java.io.PrintWriter; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Map; /** /** Loading @@ -52,18 +74,39 @@ public class InputShellCommand extends ShellCommand { private static final int DEFAULT_BUTTON_STATE = 0; private static final int DEFAULT_BUTTON_STATE = 0; private static final int DEFAULT_FLAGS = 0; private static final int DEFAULT_FLAGS = 0; private static final Map<String, Integer> SOURCES = new HashMap<String, Integer>() {{ /** Modifier key to meta state */ put("keyboard", InputDevice.SOURCE_KEYBOARD); private static final Map<Integer, Integer> MODIFIER; put("dpad", InputDevice.SOURCE_DPAD); static { put("gamepad", InputDevice.SOURCE_GAMEPAD); final Map<Integer, Integer> map = new ArrayMap<>(); put("touchscreen", InputDevice.SOURCE_TOUCHSCREEN); map.put(KEYCODE_CTRL_LEFT, META_CTRL_LEFT_ON | META_CTRL_ON); put("mouse", InputDevice.SOURCE_MOUSE); map.put(KEYCODE_CTRL_RIGHT, META_CTRL_RIGHT_ON | META_CTRL_ON); put("stylus", InputDevice.SOURCE_STYLUS); map.put(KEYCODE_ALT_LEFT, META_ALT_LEFT_ON | META_ALT_ON); put("trackball", InputDevice.SOURCE_TRACKBALL); map.put(KEYCODE_ALT_RIGHT, META_ALT_RIGHT_ON | META_ALT_ON); put("touchpad", InputDevice.SOURCE_TOUCHPAD); map.put(KEYCODE_SHIFT_LEFT, META_SHIFT_LEFT_ON | META_SHIFT_ON); put("touchnavigation", InputDevice.SOURCE_TOUCH_NAVIGATION); map.put(KEYCODE_SHIFT_RIGHT, META_SHIFT_RIGHT_ON | META_SHIFT_ON); put("joystick", InputDevice.SOURCE_JOYSTICK); map.put(KEYCODE_META_LEFT, META_META_LEFT_ON | META_META_ON); }}; map.put(KEYCODE_META_RIGHT, META_META_RIGHT_ON | META_META_ON); MODIFIER = unmodifiableMap(map); } /** String to device source */ private static final Map<String, Integer> SOURCES; static { final Map<String, Integer> map = new ArrayMap<>(); map.put("keyboard", InputDevice.SOURCE_KEYBOARD); map.put("dpad", InputDevice.SOURCE_DPAD); map.put("gamepad", InputDevice.SOURCE_GAMEPAD); map.put("touchscreen", InputDevice.SOURCE_TOUCHSCREEN); map.put("mouse", InputDevice.SOURCE_MOUSE); map.put("stylus", InputDevice.SOURCE_STYLUS); map.put("trackball", InputDevice.SOURCE_TRACKBALL); map.put("touchpad", InputDevice.SOURCE_TOUCHPAD); map.put("touchnavigation", InputDevice.SOURCE_TOUCH_NAVIGATION); map.put("joystick", InputDevice.SOURCE_JOYSTICK); SOURCES = unmodifiableMap(map); } private void injectKeyEvent(KeyEvent event) { private void injectKeyEvent(KeyEvent event) { InputManager.getInstance().injectInputEvent(event, InputManager.getInstance().injectInputEvent(event, Loading Loading @@ -237,8 +280,8 @@ public class InputShellCommand extends ShellCommand { out.println(" press (Default: trackball)"); out.println(" press (Default: trackball)"); out.println(" roll <dx> <dy> (Default: trackball)"); out.println(" roll <dx> <dy> (Default: trackball)"); out.println(" motionevent <DOWN|UP|MOVE|CANCEL> <x> <y> (Default: touchscreen)"); out.println(" motionevent <DOWN|UP|MOVE|CANCEL> <x> <y> (Default: touchscreen)"); out.println(" keycombination <key code 1> <key code 2> ..." out.println(" keycombination [-t duration(ms)] <key code 1> <key code 2> ..." + " (Default: keyboard)"); + " (Default: keyboard, the key order is important here.)"); } } } } Loading Loading @@ -459,8 +502,16 @@ public class InputShellCommand extends ShellCommand { private void runKeyCombination(int inputSource, int displayId) { private void runKeyCombination(int inputSource, int displayId) { String arg = getNextArgRequired(); String arg = getNextArgRequired(); ArrayList<Integer> keyCodes = new ArrayList<>(); // Get duration (optional). long duration = 0; if ("-t".equals(arg)) { arg = getNextArgRequired(); duration = Integer.parseInt(arg); arg = getNextArgRequired(); } IntArray keyCodes = new IntArray(); while (arg != null) { while (arg != null) { final int keyCode = KeyEvent.keyCodeFromString(arg); final int keyCode = KeyEvent.keyCodeFromString(arg); if (keyCode == KeyEvent.KEYCODE_UNKNOWN) { if (keyCode == KeyEvent.KEYCODE_UNKNOWN) { Loading @@ -475,7 +526,7 @@ public class InputShellCommand extends ShellCommand { throw new IllegalArgumentException("keycombination requires at least 2 keycodes"); throw new IllegalArgumentException("keycombination requires at least 2 keycodes"); } } sendKeyCombination(inputSource, keyCodes, displayId); sendKeyCombination(inputSource, keyCodes, displayId, duration); } } private void injectKeyEventAsync(KeyEvent event) { private void injectKeyEventAsync(KeyEvent event) { Loading @@ -483,16 +534,21 @@ public class InputShellCommand extends ShellCommand { InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); } } private void sendKeyCombination(int inputSource, ArrayList<Integer> keyCodes, int displayId) { private void sendKeyCombination(int inputSource, IntArray keyCodes, int displayId, long duration) { final long now = SystemClock.uptimeMillis(); final long now = SystemClock.uptimeMillis(); final int count = keyCodes.size(); final int count = keyCodes.size(); final KeyEvent[] events = new KeyEvent[count]; final KeyEvent[] events = new KeyEvent[count]; int metaState = 0; for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) { final KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCodes.get(i), 0, final int keyCode = keyCodes.get(i); 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/, final KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/, inputSource); inputSource); event.setDisplayId(displayId); event.setDisplayId(displayId); events[i] = event; events[i] = event; // The order is important here, metaState could be updated and applied to the next key. metaState |= MODIFIER.getOrDefault(keyCode, 0); } } for (KeyEvent event: events) { for (KeyEvent event: events) { Loading @@ -501,7 +557,7 @@ public class InputShellCommand extends ShellCommand { injectKeyEventAsync(event); injectKeyEventAsync(event); } } sleep(ViewConfiguration.getTapTimeout()); sleep(duration); for (KeyEvent event: events) { for (KeyEvent event: events) { injectKeyEventAsync(KeyEvent.changeAction(event, KeyEvent.ACTION_UP)); injectKeyEventAsync(KeyEvent.changeAction(event, KeyEvent.ACTION_UP)); Loading @@ -513,7 +569,7 @@ public class InputShellCommand extends ShellCommand { * * * @param milliseconds The time to sleep in milliseconds. * @param milliseconds The time to sleep in milliseconds. */ */ private void sleep(int milliseconds) { private void sleep(long milliseconds) { try { try { Thread.sleep(milliseconds); Thread.sleep(milliseconds); } catch (InterruptedException e) { } catch (InterruptedException e) { Loading