Home | History | Annotate | Download | only in input
      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