1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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. 15 */ 16 17package com.android.commands.input; 18 19import android.hardware.input.InputManager; 20import android.os.SystemClock; 21import android.util.Log; 22import android.view.InputDevice; 23import android.view.KeyCharacterMap; 24import android.view.KeyEvent; 25import android.view.MotionEvent; 26 27/** 28 * Command that sends key events to the device, either by their keycode, or by 29 * desired character output. 30 */ 31 32public class Input { 33 private static final String TAG = "Input"; 34 35 /** 36 * Command-line entry point. 37 * 38 * @param args The command-line arguments 39 */ 40 public static void main(String[] args) { 41 (new Input()).run(args); 42 } 43 44 private void run(String[] args) { 45 if (args.length < 1) { 46 showUsage(); 47 return; 48 } 49 50 String command = args[0]; 51 52 try { 53 if (command.equals("text")) { 54 if (args.length == 2) { 55 sendText(args[1]); 56 return; 57 } 58 } else if (command.equals("keyevent")) { 59 if (args.length == 2) { 60 int keyCode = KeyEvent.keyCodeFromString(args[1]); 61 if (keyCode == KeyEvent.KEYCODE_UNKNOWN) { 62 keyCode = KeyEvent.keyCodeFromString("KEYCODE_" + args[1]); 63 } 64 sendKeyEvent(keyCode); 65 return; 66 } 67 } else if (command.equals("tap")) { 68 if (args.length == 3) { 69 sendTap(InputDevice.SOURCE_TOUCHSCREEN, Float.parseFloat(args[1]), Float.parseFloat(args[2])); 70 return; 71 } 72 } else if (command.equals("swipe")) { 73 if (args.length == 5) { 74 sendSwipe(InputDevice.SOURCE_TOUCHSCREEN, Float.parseFloat(args[1]), Float.parseFloat(args[2]), 75 Float.parseFloat(args[3]), Float.parseFloat(args[4])); 76 return; 77 } 78 } else if (command.equals("touchscreen") || command.equals("touchpad")) { 79 // determine input source 80 int inputSource = InputDevice.SOURCE_TOUCHSCREEN; 81 if (command.equals("touchpad")) { 82 inputSource = InputDevice.SOURCE_TOUCHPAD; 83 } 84 // determine subcommand 85 if (args.length > 1) { 86 String subcommand = args[1]; 87 if (subcommand.equals("tap")) { 88 if (args.length == 4) { 89 sendTap(inputSource, Float.parseFloat(args[2]), 90 Float.parseFloat(args[3])); 91 return; 92 } 93 } else if (subcommand.equals("swipe")) { 94 if (args.length == 6) { 95 sendSwipe(inputSource, Float.parseFloat(args[2]), 96 Float.parseFloat(args[3]), Float.parseFloat(args[4]), 97 Float.parseFloat(args[5])); 98 return; 99 } 100 } 101 } 102 } else if (command.equals("trackball")) { 103 // determine subcommand 104 if (args.length > 1) { 105 String subcommand = args[1]; 106 if (subcommand.equals("press")) { 107 sendTap(InputDevice.SOURCE_TRACKBALL, 0.0f, 0.0f); 108 return; 109 } else if (subcommand.equals("roll")) { 110 if (args.length == 4) { 111 sendMove(InputDevice.SOURCE_TRACKBALL, Float.parseFloat(args[2]), 112 Float.parseFloat(args[3])); 113 return; 114 } 115 } 116 } 117 } else { 118 System.err.println("Error: Unknown command: " + command); 119 showUsage(); 120 return; 121 } 122 } catch (NumberFormatException ex) { 123 } 124 System.err.println("Error: Invalid arguments for command: " + command); 125 showUsage(); 126 } 127 128 /** 129 * Convert the characters of string text into key event's and send to 130 * device. 131 * 132 * @param text is a string of characters you want to input to the device. 133 */ 134 private void sendText(String text) { 135 136 StringBuffer buff = new StringBuffer(text); 137 138 boolean escapeFlag = false; 139 for (int i=0; i<buff.length(); i++) { 140 if (escapeFlag) { 141 escapeFlag = false; 142 if (buff.charAt(i) == 's') { 143 buff.setCharAt(i, ' '); 144 buff.deleteCharAt(--i); 145 } 146 } 147 if (buff.charAt(i) == '%') { 148 escapeFlag = true; 149 } 150 } 151 152 char[] chars = buff.toString().toCharArray(); 153 154 KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); 155 KeyEvent[] events = kcm.getEvents(chars); 156 for(int i = 0; i < events.length; i++) { 157 injectKeyEvent(events[i]); 158 } 159 } 160 161 private void sendKeyEvent(int keyCode) { 162 long now = SystemClock.uptimeMillis(); 163 injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0, 164 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD)); 165 injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0, 166 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD)); 167 } 168 169 private void sendTap(int inputSource, float x, float y) { 170 long now = SystemClock.uptimeMillis(); 171 injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x, y, 1.0f); 172 injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x, y, 0.0f); 173 } 174 175 private void sendSwipe(int inputSource, float x1, float y1, float x2, float y2) { 176 final int NUM_STEPS = 11; 177 long now = SystemClock.uptimeMillis(); 178 injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f); 179 for (int i = 1; i < NUM_STEPS; i++) { 180 float alpha = (float) i / NUM_STEPS; 181 injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha), 182 lerp(y1, y2, alpha), 1.0f); 183 } 184 injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x1, y1, 0.0f); 185 } 186 187 /** 188 * Sends a simple zero-pressure move event. 189 * 190 * @param inputSource the InputDevice.SOURCE_* sending the input event 191 * @param dx change in x coordinate due to move 192 * @param dy change in y coordinate due to move 193 */ 194 private void sendMove(int inputSource, float dx, float dy) { 195 long now = SystemClock.uptimeMillis(); 196 injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, dx, dy, 0.0f); 197 } 198 199 private void injectKeyEvent(KeyEvent event) { 200 Log.i(TAG, "injectKeyEvent: " + event); 201 InputManager.getInstance().injectInputEvent(event, 202 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH); 203 } 204 205 /** 206 * Builds a MotionEvent and injects it into the event stream. 207 * 208 * @param inputSource the InputDevice.SOURCE_* sending the input event 209 * @param action the MotionEvent.ACTION_* for the event 210 * @param when the value of SystemClock.uptimeMillis() at which the event happened 211 * @param x x coordinate of event 212 * @param y y coordinate of event 213 * @param pressure pressure of event 214 */ 215 private void injectMotionEvent(int inputSource, int action, long when, float x, float y, float pressure) { 216 final float DEFAULT_SIZE = 1.0f; 217 final int DEFAULT_META_STATE = 0; 218 final float DEFAULT_PRECISION_X = 1.0f; 219 final float DEFAULT_PRECISION_Y = 1.0f; 220 final int DEFAULT_DEVICE_ID = 0; 221 final int DEFAULT_EDGE_FLAGS = 0; 222 MotionEvent event = MotionEvent.obtain(when, when, action, x, y, pressure, DEFAULT_SIZE, 223 DEFAULT_META_STATE, DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y, DEFAULT_DEVICE_ID, 224 DEFAULT_EDGE_FLAGS); 225 event.setSource(inputSource); 226 Log.i("Input", "injectMotionEvent: " + event); 227 InputManager.getInstance().injectInputEvent(event, 228 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH); 229 } 230 231 private static final float lerp(float a, float b, float alpha) { 232 return (b - a) * alpha + a; 233 } 234 235 private void showUsage() { 236 System.err.println("usage: input ..."); 237 System.err.println(" input text <string>"); 238 System.err.println(" input keyevent <key code number or name>"); 239 System.err.println(" input [touchscreen|touchpad] tap <x> <y>"); 240 System.err.println(" input [touchscreen|touchpad] swipe <x1> <y1> <x2> <y2>"); 241 System.err.println(" input trackball press"); 242 System.err.println(" input trackball roll <dx> <dy>"); 243 } 244} 245