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
19ac14351e16e1258f1cb54e2bf772b8be004eb2b8Jeff Brownimport android.hardware.input.InputManager;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
22ac14351e16e1258f1cb54e2bf772b8be004eb2b8Jeff Brownimport android.view.InputDevice;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyCharacterMap;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent;
25797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brownimport android.view.MotionEvent;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
279d83b4783c33f1fafc43f367503e129e5a5047faMichael Wrightimport java.util.HashMap;
289d83b4783c33f1fafc43f367503e129e5a5047faMichael Wrightimport java.util.Map;
299d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Command that sends key events to the device, either by their keycode, or by
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * desired character output.
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class Input {
36797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    private static final String TAG = "Input";
379d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright    private static final String INVALID_ARGUMENTS = "Error: Invalid arguments for command: ";
389d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright
399d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright    private static final Map<String, Integer> SOURCES = new HashMap<String, Integer>() {{
409d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        put("keyboard", InputDevice.SOURCE_KEYBOARD);
419d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        put("dpad", InputDevice.SOURCE_DPAD);
429d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        put("gamepad", InputDevice.SOURCE_GAMEPAD);
439d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        put("touchscreen", InputDevice.SOURCE_TOUCHSCREEN);
449d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        put("mouse", InputDevice.SOURCE_MOUSE);
459d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        put("stylus", InputDevice.SOURCE_STYLUS);
469d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        put("trackball", InputDevice.SOURCE_TRACKBALL);
479d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        put("touchpad", InputDevice.SOURCE_TOUCHPAD);
489d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        put("touchnavigation", InputDevice.SOURCE_TOUCH_NAVIGATION);
499d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        put("joystick", InputDevice.SOURCE_JOYSTICK);
509d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright    }};
519d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright
52797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Command-line entry point.
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param args The command-line arguments
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void main(String[] args) {
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        (new Input()).run(args);
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void run(String[] args) {
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (args.length < 1) {
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            showUsage();
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
689d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        int index = 0;
699d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        String command = args[index];
709d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        int inputSource = InputDevice.SOURCE_UNKNOWN;
719d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        if (SOURCES.containsKey(command)) {
729d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright            inputSource = SOURCES.get(command);
739d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright            index++;
749d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright            command = args[index];
759d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        }
769d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        final int length = args.length - index;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
78797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        try {
79797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            if (command.equals("text")) {
809d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                if (length == 2) {
819d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                    inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);
829d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                    sendText(inputSource, args[index+1]);
83797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                    return;
84797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                }
85797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            } else if (command.equals("keyevent")) {
869d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                if (length >= 2) {
879d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                    final boolean longpress = "--longpress".equals(args[index + 1]);
889d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                    final int start = longpress ? index + 2 : index + 1;
899d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                    inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);
909d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                    if (length > start) {
919d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                        for (int i = start; i < length; i++) {
9211744d15364b16a976413599933ed1b1d59e4a6fJeff Sharkey                            int keyCode = KeyEvent.keyCodeFromString(args[i]);
9311744d15364b16a976413599933ed1b1d59e4a6fJeff Sharkey                            if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
9411744d15364b16a976413599933ed1b1d59e4a6fJeff Sharkey                                keyCode = KeyEvent.keyCodeFromString("KEYCODE_" + args[i]);
9511744d15364b16a976413599933ed1b1d59e4a6fJeff Sharkey                            }
969d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                            sendKeyEvent(inputSource, keyCode, longpress);
972ac9d8d0f0ea65aae6ba43490b5be6617ad97125Diego Torres Milano                        }
9811744d15364b16a976413599933ed1b1d59e4a6fJeff Sharkey                        return;
99ca13fed08bf38c2f2811b3ec3f995d0ca57ac6acJeff Brown                    }
100797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                }
101797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            } else if (command.equals("tap")) {
1029d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                if (length == 3) {
1039d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                    inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
1049d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                    sendTap(inputSource, Float.parseFloat(args[index+1]),
1059d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                            Float.parseFloat(args[index+2]));
106797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                    return;
107797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                }
108797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            } else if (command.equals("swipe")) {
1099d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                int duration = -1;
1109d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
1119d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                switch (length) {
1129d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                    case 6:
1139d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                        duration = Integer.parseInt(args[index+5]);
1149d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                    case 5:
1159d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                        sendSwipe(inputSource,
1169d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                                Float.parseFloat(args[index+1]), Float.parseFloat(args[index+2]),
1179d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                                Float.parseFloat(args[index+3]), Float.parseFloat(args[index+4]),
1189d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                                duration);
1199d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                        return;
120b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease                }
1219d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright            } else if (command.equals("press")) {
1229d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
1239d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                if (length == 1) {
1249d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                    sendTap(inputSource, 0.0f, 0.0f);
1259d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                    return;
126b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease                }
1279d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright            } else if (command.equals("roll")) {
1289d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
1299d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                if (length == 3) {
1309d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                    sendMove(inputSource, Float.parseFloat(args[index+1]),
1319d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                            Float.parseFloat(args[index+2]));
1329d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                    return;
133b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease                }
134797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            } else {
135797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                System.err.println("Error: Unknown command: " + command);
136797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                showUsage();
137797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown                return;
138797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown            }
139797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        } catch (NumberFormatException ex) {
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1419d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        System.err.println(INVALID_ARGUMENTS + command);
142797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        showUsage();
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Convert the characters of string text into key event's and send to
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * device.
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param text is a string of characters you want to input to the device.
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1519d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright    private void sendText(int source, String text) {
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuffer buff = new StringBuffer(text);
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean escapeFlag = false;
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i=0; i<buff.length(); i++) {
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (escapeFlag) {
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                escapeFlag = false;
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (buff.charAt(i) == 's') {
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    buff.setCharAt(i, ' ');
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    buff.deleteCharAt(--i);
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1639d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright            }
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (buff.charAt(i) == '%') {
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                escapeFlag = true;
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        char[] chars = buff.toString().toCharArray();
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
171797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
172797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        KeyEvent[] events = kcm.getEvents(chars);
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for(int i = 0; i < events.length; i++) {
1749d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright            KeyEvent e = events[i];
1759d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright            if (source != e.getSource()) {
1769d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                e.setSource(source);
1779d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright            }
1789d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright            injectKeyEvent(e);
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1829d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright    private void sendKeyEvent(int inputSource, int keyCode, boolean longpress) {
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long now = SystemClock.uptimeMillis();
184ac14351e16e1258f1cb54e2bf772b8be004eb2b8Jeff Brown        injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
1859d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));
18611744d15364b16a976413599933ed1b1d59e4a6fJeff Sharkey        if (longpress) {
18711744d15364b16a976413599933ed1b1d59e4a6fJeff Sharkey            injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 1, 0,
18811744d15364b16a976413599933ed1b1d59e4a6fJeff Sharkey                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_LONG_PRESS,
1899d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                    inputSource));
19011744d15364b16a976413599933ed1b1d59e4a6fJeff Sharkey        }
191ac14351e16e1258f1cb54e2bf772b8be004eb2b8Jeff Brown        injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0,
1929d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));
193797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    }
194797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown
195b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease    private void sendTap(int inputSource, float x, float y) {
196797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        long now = SystemClock.uptimeMillis();
197b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease        injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x, y, 1.0f);
198b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease        injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x, y, 0.0f);
199797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    }
200797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown
2014ec7ea72d2a9de6b79b11f7e0d12def5b58ef878Chet Haase    private void sendSwipe(int inputSource, float x1, float y1, float x2, float y2, int duration) {
2024ec7ea72d2a9de6b79b11f7e0d12def5b58ef878Chet Haase        if (duration < 0) {
2034ec7ea72d2a9de6b79b11f7e0d12def5b58ef878Chet Haase            duration = 300;
2044ec7ea72d2a9de6b79b11f7e0d12def5b58ef878Chet Haase        }
205797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        long now = SystemClock.uptimeMillis();
206b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease        injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f);
2074ec7ea72d2a9de6b79b11f7e0d12def5b58ef878Chet Haase        long startTime = now;
2084ec7ea72d2a9de6b79b11f7e0d12def5b58ef878Chet Haase        long endTime = startTime + duration;
2094ec7ea72d2a9de6b79b11f7e0d12def5b58ef878Chet Haase        while (now < endTime) {
2104ec7ea72d2a9de6b79b11f7e0d12def5b58ef878Chet Haase            long elapsedTime = now - startTime;
2114ec7ea72d2a9de6b79b11f7e0d12def5b58ef878Chet Haase            float alpha = (float) elapsedTime / duration;
212b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease            injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha),
213b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease                    lerp(y1, y2, alpha), 1.0f);
2144ec7ea72d2a9de6b79b11f7e0d12def5b58ef878Chet Haase            now = SystemClock.uptimeMillis();
215797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        }
21677a2dabf01039da8dfe0bf43d41b223d79a8c9d2Michael Wright        injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x2, y2, 0.0f);
217b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease    }
218b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease
219b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease    /**
220b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease     * Sends a simple zero-pressure move event.
221b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease     *
222b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease     * @param inputSource the InputDevice.SOURCE_* sending the input event
223b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease     * @param dx change in x coordinate due to move
224b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease     * @param dy change in y coordinate due to move
225b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease     */
226b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease    private void sendMove(int inputSource, float dx, float dy) {
227b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease        long now = SystemClock.uptimeMillis();
228b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease        injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, dx, dy, 0.0f);
229797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    }
230797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown
231797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    private void injectKeyEvent(KeyEvent event) {
232b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease        Log.i(TAG, "injectKeyEvent: " + event);
2339f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        InputManager.getInstance().injectInputEvent(event,
2349f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown                InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
235797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    }
236797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown
237b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease    /**
238b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease     * Builds a MotionEvent and injects it into the event stream.
239b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease     *
240b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease     * @param inputSource the InputDevice.SOURCE_* sending the input event
241b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease     * @param action the MotionEvent.ACTION_* for the event
242b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease     * @param when the value of SystemClock.uptimeMillis() at which the event happened
243b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease     * @param x x coordinate of event
244b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease     * @param y y coordinate of event
245b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease     * @param pressure pressure of event
246b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease     */
247b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease    private void injectMotionEvent(int inputSource, int action, long when, float x, float y, float pressure) {
248b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease        final float DEFAULT_SIZE = 1.0f;
249b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease        final int DEFAULT_META_STATE = 0;
250b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease        final float DEFAULT_PRECISION_X = 1.0f;
251b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease        final float DEFAULT_PRECISION_Y = 1.0f;
252b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease        final int DEFAULT_DEVICE_ID = 0;
253b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease        final int DEFAULT_EDGE_FLAGS = 0;
254b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease        MotionEvent event = MotionEvent.obtain(when, when, action, x, y, pressure, DEFAULT_SIZE,
255b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease                DEFAULT_META_STATE, DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y, DEFAULT_DEVICE_ID,
256b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease                DEFAULT_EDGE_FLAGS);
257b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease        event.setSource(inputSource);
2582ac9d8d0f0ea65aae6ba43490b5be6617ad97125Diego Torres Milano        Log.i(TAG, "injectMotionEvent: " + event);
2599f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        InputManager.getInstance().injectInputEvent(event,
2609f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown                InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
263797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown    private static final float lerp(float a, float b, float alpha) {
264797e4465fbc1f6a818e2905d17719e5df8c2a705Jeff Brown        return (b - a) * alpha + a;
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2679d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright    private static final int getSource(int inputSource, int defaultSource) {
2682132198d052ca68a6aa2433274f12203a71451dfMichael Wright        return inputSource == InputDevice.SOURCE_UNKNOWN ? defaultSource : inputSource;
2699d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright    }
2709d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void showUsage() {
2729d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        System.err.println("Usage: input [<source>] <command> [<arg>...]");
2739d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        System.err.println();
2749d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        System.err.println("The sources are: ");
2759d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        for (String src : SOURCES.keySet()) {
2769d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright            System.err.println("      " + src);
2779d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        }
2789d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        System.err.println();
2799d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        System.err.println("The commands and default sources are:");
2809d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        System.err.println("      text <string> (Default: touchscreen)");
2819d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        System.err.println("      keyevent [--longpress] <key code number or name> ..."
2829d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                + " (Default: keyboard)");
2839d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        System.err.println("      tap <x> <y> (Default: touchscreen)");
2849d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        System.err.println("      swipe <x1> <y1> <x2> <y2> [duration(ms)]"
2859d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright                + " (Default: touchscreen)");
2869d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        System.err.println("      press (Default: trackball)");
2879d83b4783c33f1fafc43f367503e129e5a5047faMichael Wright        System.err.println("      roll <dx> <dy> (Default: trackball)");
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
290