Input.java revision 797e4465fbc1f6a818e2905d17719e5df8c2a705
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.commands.input;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ServiceManager;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.IWindowManager;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyCharacterMap;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent;
26797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brownimport android.view.MotionEvent;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Command that sends key events to the device, either by their keycode, or by
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * desired character output.
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class Input {
34797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    private static final String TAG = "Input";
35797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown
36797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    private IWindowManager mWindowManager;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Command-line entry point.
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param args The command-line arguments
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void main(String[] args) {
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        (new Input()).run(args);
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
47797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    private IWindowManager getWindowManager() {
48797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        if (mWindowManager == null) {
49797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            mWindowManager = (IWindowManager.Stub.asInterface(ServiceManager.getService("window")));
50797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        }
51797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        return mWindowManager;
52797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    }
53797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void run(String[] args) {
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (args.length < 1) {
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            showUsage();
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String command = args[0];
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
62797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        try {
63797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            if (command.equals("text")) {
64797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                if (args.length == 2) {
65797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                    sendText(args[1]);
66797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                    return;
67797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                }
68797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            } else if (command.equals("keyevent")) {
69797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                if (args.length == 2) {
70797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                    sendKeyEvent(Integer.parseInt(args[1]));
71797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                    return;
72797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                }
73797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            } else if (command.equals("tap")) {
74797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                if (args.length == 3) {
75797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                    sendTap(Float.parseFloat(args[1]), Float.parseFloat(args[2]));
76797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                    return;
77797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                }
78797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            } else if (command.equals("swipe")) {
79797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                if (args.length == 5) {
80797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                    sendSwipe(Float.parseFloat(args[1]), Float.parseFloat(args[2]),
81797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                            Float.parseFloat(args[3]), Float.parseFloat(args[4]));
82797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                    return;
83797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                }
84797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            } else {
85797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                System.err.println("Error: Unknown command: " + command);
86797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                showUsage();
87797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                return;
88797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            }
89797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        } catch (NumberFormatException ex) {
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
91797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        System.err.println("Error: Invalid arguments for command: " + command);
92797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        showUsage();
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Convert the characters of string text into key event's and send to
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * device.
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param text is a string of characters you want to input to the device.
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void sendText(String text) {
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuffer buff = new StringBuffer(text);
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean escapeFlag = false;
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i=0; i<buff.length(); i++) {
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (escapeFlag) {
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                escapeFlag = false;
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (buff.charAt(i) == 's') {
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    buff.setCharAt(i, ' ');
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    buff.deleteCharAt(--i);
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (buff.charAt(i) == '%') {
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                escapeFlag = true;
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        char[] chars = buff.toString().toCharArray();
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
121797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
122797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        KeyEvent[] events = kcm.getEvents(chars);
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for(int i = 0; i < events.length; i++) {
124797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            injectKeyEvent(events[i]);
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
128797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    private void sendKeyEvent(int keyCode) {
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long now = SystemClock.uptimeMillis();
130797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0));
131797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0));
132797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    }
133797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown
134797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    private void sendTap(float x, float y) {
135797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        long now = SystemClock.uptimeMillis();
136797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, x, y, 0));
137797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, x, y, 0));
138797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    }
139797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown
140797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    private void sendSwipe(float x1, float y1, float x2, float y2) {
141797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        final int NUM_STEPS = 11;
142797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        long now = SystemClock.uptimeMillis();
143797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, x1, y1, 0));
144797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        for (int i = 1; i < NUM_STEPS; i++) {
145797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            float alpha = (float)i / NUM_STEPS;
146797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_MOVE,
147797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                    lerp(x1, x2, alpha), lerp(y1, y2, alpha), 0));
148797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        }
149797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, x2, y2, 0));
150797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    }
151797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown
152797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    private void injectKeyEvent(KeyEvent event) {
153797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        try {
154797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            Log.i(TAG, "InjectKeyEvent: " + event);
155797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            getWindowManager().injectKeyEvent(event, true);
156797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        } catch (RemoteException ex) {
157797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            Log.i(TAG, "RemoteException", ex);
158797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        }
159797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    }
160797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown
161797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    private void injectPointerEvent(MotionEvent event) {
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
163797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            Log.i("Input", "InjectPointerEvent: " + event);
164797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            getWindowManager().injectPointerEvent(event, true);
165797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        } catch (RemoteException ex) {
166797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            Log.i(TAG, "RemoteException", ex);
167797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        } finally {
168797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            event.recycle();
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
172797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    private static final float lerp(float a, float b, float alpha) {
173797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        return (b - a) * alpha + a;
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void showUsage() {
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        System.err.println("usage: input [text|keyevent]");
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        System.err.println("       input text <string>");
179797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        System.err.println("       input keyevent <key code>");
180797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        System.err.println("       input tap <x> <y>");
181797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        System.err.println("       input swipe <x1> <y1> <x2> <y2>");
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
184