2 * Copyright (C) 2007 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.commands.input;
19 import android.hardware.input.InputManager;
20 import android.os.SystemClock;
21 import android.util.Log;
22 import android.view.InputDevice;
23 import android.view.KeyCharacterMap;
24 import android.view.KeyEvent;
25 import android.view.MotionEvent;
26 import android.view.ViewConfiguration;
28 import java.util.HashMap;
32 * Command that sends key events to the device, either by their keycode, or by
33 * desired character output.
37 private static final String TAG = "Input";
38 private static final String INVALID_ARGUMENTS = "Error: Invalid arguments for command: ";
40 private static final Map<String, Integer> SOURCES = new HashMap<String, Integer>() {{
41 put("keyboard", InputDevice.SOURCE_KEYBOARD);
42 put("dpad", InputDevice.SOURCE_DPAD);
43 put("gamepad", InputDevice.SOURCE_GAMEPAD);
44 put("touchscreen", InputDevice.SOURCE_TOUCHSCREEN);
45 put("mouse", InputDevice.SOURCE_MOUSE);
46 put("stylus", InputDevice.SOURCE_STYLUS);
47 put("trackball", InputDevice.SOURCE_TRACKBALL);
48 put("touchpad", InputDevice.SOURCE_TOUCHPAD);
49 put("touchnavigation", InputDevice.SOURCE_TOUCH_NAVIGATION);
50 put("joystick", InputDevice.SOURCE_JOYSTICK);
55 * Command-line entry point.
57 * @param args The command-line arguments
59 public static void main(String[] args) {
60 (new Input()).run(args);
63 private void run(String[] args) {
64 if (args.length < 1) {
70 String command = args[index];
71 int inputSource = InputDevice.SOURCE_UNKNOWN;
72 if (SOURCES.containsKey(command)) {
73 inputSource = SOURCES.get(command);
75 command = args[index];
77 final int length = args.length - index;
80 if (command.equals("text")) {
82 inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);
83 sendText(inputSource, args[index+1]);
86 } else if (command.equals("keyevent")) {
88 final boolean longpress = "--longpress".equals(args[index + 1]);
89 final int start = longpress ? index + 2 : index + 1;
90 inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);
92 for (int i = start; i < length; i++) {
93 int keyCode = KeyEvent.keyCodeFromString(args[i]);
94 if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
95 keyCode = KeyEvent.keyCodeFromString("KEYCODE_" + args[i]);
97 sendKeyEvent(inputSource, keyCode, longpress);
102 } else if (command.equals("tap")) {
104 inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
105 sendTap(inputSource, Float.parseFloat(args[index+1]),
106 Float.parseFloat(args[index+2]));
109 } else if (command.equals("swipe")) {
111 inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
114 duration = Integer.parseInt(args[index+5]);
116 sendSwipe(inputSource,
117 Float.parseFloat(args[index+1]), Float.parseFloat(args[index+2]),
118 Float.parseFloat(args[index+3]), Float.parseFloat(args[index+4]),
122 } else if (command.equals("draganddrop")) {
124 inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
127 duration = Integer.parseInt(args[index+5]);
129 sendDragAndDrop(inputSource,
130 Float.parseFloat(args[index+1]), Float.parseFloat(args[index+2]),
131 Float.parseFloat(args[index+3]), Float.parseFloat(args[index+4]),
135 } else if (command.equals("press")) {
136 inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
138 sendTap(inputSource, 0.0f, 0.0f);
141 } else if (command.equals("roll")) {
142 inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
144 sendMove(inputSource, Float.parseFloat(args[index+1]),
145 Float.parseFloat(args[index+2]));
149 System.err.println("Error: Unknown command: " + command);
153 } catch (NumberFormatException ex) {
155 System.err.println(INVALID_ARGUMENTS + command);
160 * Convert the characters of string text into key event's and send to
163 * @param text is a string of characters you want to input to the device.
165 private void sendText(int source, String text) {
167 StringBuffer buff = new StringBuffer(text);
169 boolean escapeFlag = false;
170 for (int i=0; i<buff.length(); i++) {
173 if (buff.charAt(i) == 's') {
174 buff.setCharAt(i, ' ');
175 buff.deleteCharAt(--i);
178 if (buff.charAt(i) == '%') {
183 char[] chars = buff.toString().toCharArray();
185 KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
186 KeyEvent[] events = kcm.getEvents(chars);
187 for(int i = 0; i < events.length; i++) {
188 KeyEvent e = events[i];
189 if (source != e.getSource()) {
196 private void sendKeyEvent(int inputSource, int keyCode, boolean longpress) {
197 long now = SystemClock.uptimeMillis();
198 injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
199 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));
203 } catch (InterruptedException e) {
204 throw new RuntimeException(e);
206 now = SystemClock.uptimeMillis();
208 injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0,
209 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));
212 private void sendTap(int inputSource, float x, float y) {
213 long now = SystemClock.uptimeMillis();
214 injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x, y, 1.0f);
215 injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x, y, 0.0f);
218 private void sendSwipe(int inputSource, float x1, float y1, float x2, float y2, int duration) {
222 long now = SystemClock.uptimeMillis();
223 injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f);
224 long startTime = now;
225 long endTime = startTime + duration;
226 while (now < endTime) {
227 long elapsedTime = now - startTime;
228 float alpha = (float) elapsedTime / duration;
229 injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha),
230 lerp(y1, y2, alpha), 1.0f);
231 now = SystemClock.uptimeMillis();
233 injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x2, y2, 0.0f);
236 private void sendDragAndDrop(int inputSource, float x1, float y1, float x2, float y2,
238 if (dragDuration < 0) {
241 long now = SystemClock.uptimeMillis();
242 injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f);
244 Thread.sleep(ViewConfiguration.getLongPressTimeout());
245 } catch (InterruptedException e) {
246 throw new RuntimeException(e);
248 now = SystemClock.uptimeMillis();
249 long startTime = now;
250 long endTime = startTime + dragDuration;
251 while (now < endTime) {
252 long elapsedTime = now - startTime;
253 float alpha = (float) elapsedTime / dragDuration;
254 injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha),
255 lerp(y1, y2, alpha), 1.0f);
256 now = SystemClock.uptimeMillis();
258 injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x2, y2, 0.0f);
262 * Sends a simple zero-pressure move event.
264 * @param inputSource the InputDevice.SOURCE_* sending the input event
265 * @param dx change in x coordinate due to move
266 * @param dy change in y coordinate due to move
268 private void sendMove(int inputSource, float dx, float dy) {
269 long now = SystemClock.uptimeMillis();
270 injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, dx, dy, 0.0f);
273 private void injectKeyEvent(KeyEvent event) {
274 Log.i(TAG, "injectKeyEvent: " + event);
275 InputManager.getInstance().injectInputEvent(event,
276 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
279 private int getInputDeviceId(int inputSource) {
280 final int DEFAULT_DEVICE_ID = 0;
281 int[] devIds = InputDevice.getDeviceIds();
282 for (int devId : devIds) {
283 InputDevice inputDev = InputDevice.getDevice(devId);
284 if (inputDev.supportsSource(inputSource)) {
288 return DEFAULT_DEVICE_ID;
292 * Builds a MotionEvent and injects it into the event stream.
294 * @param inputSource the InputDevice.SOURCE_* sending the input event
295 * @param action the MotionEvent.ACTION_* for the event
296 * @param when the value of SystemClock.uptimeMillis() at which the event happened
297 * @param x x coordinate of event
298 * @param y y coordinate of event
299 * @param pressure pressure of event
301 private void injectMotionEvent(int inputSource, int action, long when, float x, float y, float pressure) {
302 final float DEFAULT_SIZE = 1.0f;
303 final int DEFAULT_META_STATE = 0;
304 final float DEFAULT_PRECISION_X = 1.0f;
305 final float DEFAULT_PRECISION_Y = 1.0f;
306 final int DEFAULT_EDGE_FLAGS = 0;
307 MotionEvent event = MotionEvent.obtain(when, when, action, x, y, pressure, DEFAULT_SIZE,
308 DEFAULT_META_STATE, DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y,
309 getInputDeviceId(inputSource), DEFAULT_EDGE_FLAGS);
310 event.setSource(inputSource);
311 Log.i(TAG, "injectMotionEvent: " + event);
312 InputManager.getInstance().injectInputEvent(event,
313 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
316 private static final float lerp(float a, float b, float alpha) {
317 return (b - a) * alpha + a;
320 private static final int getSource(int inputSource, int defaultSource) {
321 return inputSource == InputDevice.SOURCE_UNKNOWN ? defaultSource : inputSource;
324 private void showUsage() {
325 System.err.println("Usage: input [<source>] <command> [<arg>...]");
326 System.err.println();
327 System.err.println("The sources are: ");
328 for (String src : SOURCES.keySet()) {
329 System.err.println(" " + src);
331 System.err.println();
332 System.err.println("The commands and default sources are:");
333 System.err.println(" text <string> (Default: touchscreen)");
334 System.err.println(" keyevent [--longpress] <key code number or name> ..."
335 + " (Default: keyboard)");
336 System.err.println(" tap <x> <y> (Default: touchscreen)");
337 System.err.println(" swipe <x1> <y1> <x2> <y2> [duration(ms)]"
338 + " (Default: touchscreen)");
339 System.err.println(" draganddrop <x1> <y1> <x2> <y2> [duration(ms)]"
340 + " (Default: touchscreen)");
341 System.err.println(" press (Default: trackball)");
342 System.err.println(" roll <dx> <dy> (Default: trackball)");