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 17 package com.android.commands.input; 18 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 27 /** 28 * Command that sends key events to the device, either by their keycode, or by 29 * desired character output. 30 */ 31 32 public 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]), -1); 76 return; 77 } 78 } else if (command.equals("touchscreen") || command.equals("touchpad") 79 || command.equals("touchnavigation")) { 80 // determine input source 81 int inputSource = InputDevice.SOURCE_TOUCHSCREEN; 82 if (command.equals("touchpad")) { 83 inputSource = InputDevice.SOURCE_TOUCHPAD; 84 } else if (command.equals("touchnavigation")) { 85 inputSource = InputDevice.SOURCE_TOUCH_NAVIGATION; 86 } 87 // determine subcommand 88 if (args.length > 1) { 89 String subcommand = args[1]; 90 if (subcommand.equals("tap")) { 91 if (args.length == 4) { 92 sendTap(inputSource, Float.parseFloat(args[2]), 93 Float.parseFloat(args[3])); 94 return; 95 } 96 } else if (subcommand.equals("swipe")) { 97 if (args.length == 6) { 98 sendSwipe(inputSource, Float.parseFloat(args[2]), 99 Float.parseFloat(args[3]), Float.parseFloat(args[4]), 100 Float.parseFloat(args[5]), -1); 101 return; 102 } else if (args.length == 7) { 103 sendSwipe(inputSource, Float.parseFloat(args[2]), 104 Float.parseFloat(args[3]), Float.parseFloat(args[4]), 105 Float.parseFloat(args[5]), Integer.parseInt(args[6])); 106 return; 107 } 108 } 109 } 110 } else if (command.equals("trackball")) { 111 // determine subcommand 112 if (args.length > 1) { 113 String subcommand = args[1]; 114 if (subcommand.equals("press")) { 115 sendTap(InputDevice.SOURCE_TRACKBALL, 0.0f, 0.0f); 116 return; 117 } else if (subcommand.equals("roll")) { 118 if (args.length == 4) { 119 sendMove(InputDevice.SOURCE_TRACKBALL, Float.parseFloat(args[2]), 120 Float.parseFloat(args[3])); 121 return; 122 } 123 } 124 } 125 } else { 126 System.err.println("Error: Unknown command: " + command); 127 showUsage(); 128 return; 129 } 130 } catch (NumberFormatException ex) { 131 } 132 System.err.println("Error: Invalid arguments for command: " + command); 133 showUsage(); 134 } 135 136 /** 137 * Convert the characters of string text into key event's and send to 138 * device. 139 * 140 * @param text is a string of characters you want to input to the device. 141 */ 142 private void sendText(String text) { 143 144 StringBuffer buff = new StringBuffer(text); 145 146 boolean escapeFlag = false; 147 for (int i=0; i<buff.length(); i++) { 148 if (escapeFlag) { 149 escapeFlag = false; 150 if (buff.charAt(i) == 's') { 151 buff.setCharAt(i, ' '); 152 buff.deleteCharAt(--i); 153 } 154 } 155 if (buff.charAt(i) == '%') { 156 escapeFlag = true; 157 } 158 } 159 160 char[] chars = buff.toString().toCharArray(); 161 162 KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); 163 KeyEvent[] events = kcm.getEvents(chars); 164 for(int i = 0; i < events.length; i++) { 165 injectKeyEvent(events[i]); 166 } 167 } 168 169 private void sendKeyEvent(int keyCode) { 170 long now = SystemClock.uptimeMillis(); 171 injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0, 172 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD)); 173 injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0, 174 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD)); 175 } 176 177 private void sendTap(int inputSource, float x, float y) { 178 long now = SystemClock.uptimeMillis(); 179 injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x, y, 1.0f); 180 injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x, y, 0.0f); 181 } 182 183 private void sendSwipe(int inputSource, float x1, float y1, float x2, float y2, int duration) { 184 if (duration < 0) { 185 duration = 300; 186 } 187 long now = SystemClock.uptimeMillis(); 188 injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f); 189 long startTime = now; 190 long endTime = startTime + duration; 191 while (now < endTime) { 192 long elapsedTime = now - startTime; 193 float alpha = (float) elapsedTime / duration; 194 injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha), 195 lerp(y1, y2, alpha), 1.0f); 196 now = SystemClock.uptimeMillis(); 197 } 198 injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x1, y1, 0.0f); 199 } 200 201 /** 202 * Sends a simple zero-pressure move event. 203 * 204 * @param inputSource the InputDevice.SOURCE_* sending the input event 205 * @param dx change in x coordinate due to move 206 * @param dy change in y coordinate due to move 207 */ 208 private void sendMove(int inputSource, float dx, float dy) { 209 long now = SystemClock.uptimeMillis(); 210 injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, dx, dy, 0.0f); 211 } 212 213 private void injectKeyEvent(KeyEvent event) { 214 Log.i(TAG, "injectKeyEvent: " + event); 215 InputManager.getInstance().injectInputEvent(event, 216 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH); 217 } 218 219 /** 220 * Builds a MotionEvent and injects it into the event stream. 221 * 222 * @param inputSource the InputDevice.SOURCE_* sending the input event 223 * @param action the MotionEvent.ACTION_* for the event 224 * @param when the value of SystemClock.uptimeMillis() at which the event happened 225 * @param x x coordinate of event 226 * @param y y coordinate of event 227 * @param pressure pressure of event 228 */ 229 private void injectMotionEvent(int inputSource, int action, long when, float x, float y, float pressure) { 230 final float DEFAULT_SIZE = 1.0f; 231 final int DEFAULT_META_STATE = 0; 232 final float DEFAULT_PRECISION_X = 1.0f; 233 final float DEFAULT_PRECISION_Y = 1.0f; 234 final int DEFAULT_DEVICE_ID = 0; 235 final int DEFAULT_EDGE_FLAGS = 0; 236 MotionEvent event = MotionEvent.obtain(when, when, action, x, y, pressure, DEFAULT_SIZE, 237 DEFAULT_META_STATE, DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y, DEFAULT_DEVICE_ID, 238 DEFAULT_EDGE_FLAGS); 239 event.setSource(inputSource); 240 Log.i("Input", "injectMotionEvent: " + event); 241 InputManager.getInstance().injectInputEvent(event, 242 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH); 243 } 244 245 private static final float lerp(float a, float b, float alpha) { 246 return (b - a) * alpha + a; 247 } 248 249 private void showUsage() { 250 System.err.println("usage: input ..."); 251 System.err.println(" input text <string>"); 252 System.err.println(" input keyevent <key code number or name>"); 253 System.err.println(" input [touchscreen|touchpad|touchnavigation] tap <x> <y>"); 254 System.err.println(" input [touchscreen|touchpad|touchnavigation] swipe " 255 + "<x1> <y1> <x2> <y2> [duration(ms)]"); 256 System.err.println(" input trackball press"); 257 System.err.println(" input trackball roll <dx> <dy>"); 258 } 259 } 260