Android 如何通过代码发送KeyEvent事件

我通常会使用 adb shell input keyevent 4 来模拟发送 keyevent 事件, 那么如何以代码的方式发送keyevent呢?这就翻一翻 input 的源码了,Input.java 源码处理如下:

Input() {
        COMMANDS.put("text", new InputText());
        COMMANDS.put("keyevent", new InputKeyEvent()); //1. 处理keyevent类型
        COMMANDS.put("tap", new InputTap());
        COMMANDS.put("swipe", new InputSwipe());
        COMMANDS.put("draganddrop", new InputDragAndDrop());
        COMMANDS.put("press", new InputPress());
        COMMANDS.put("roll", new InputRoll());
        COMMANDS.put("motionevent", new InputMotionEvent());
    }

处理keyevent事件类型的是InputKeyEvent类型:

class InputKeyEvent implements InputCmd {
        @Override
        public void run(int inputSource, int displayId) {
            String arg = nextArgRequired();
            final boolean longpress = "--longpress".equals(arg);
            if (longpress) {
                arg = nextArgRequired();
            }

            do {
                final int keycode = KeyEvent.keyCodeFromString(arg);
                sendKeyEvent(inputSource, keycode, longpress, displayId);
            } while ((arg = nextArg()) != null);
        }

        private void sendKeyEvent(int inputSource, int keyCode, boolean longpress, int displayId) {
            final long now = SystemClock.uptimeMillis();
            int repeatCount = 0;
			//1. 创建KeyEvent
            KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, repeatCount,
                    0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/,
                    inputSource);
            //2. 设置要发送的屏幕id
            event.setDisplayId(displayId);
			//3. 发送该keyevent的ACTION_DOWN事件
            injectKeyEvent(event);
            if (longpress) {
                repeatCount++;
                injectKeyEvent(KeyEvent.changeTimeRepeat(event, now, repeatCount,
                        KeyEvent.FLAG_LONG_PRESS));
            }
            //4. 发送该keyevent的ACTION_UP事件
            injectKeyEvent(KeyEvent.changeAction(event, KeyEvent.ACTION_UP));
        }
    }

再看看 injectKeyEvent 方法是如何发送的:

    private static void injectKeyEvent(KeyEvent event) {
        InputManager.getInstance().injectInputEvent(event,
                InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
    }

原来是调用InputManager的injectInputEvent方法即可:

@UnsupportedAppUsage
    public boolean injectInputEvent(InputEvent event, int mode) {
        if (event == null) {
            throw new IllegalArgumentException("event must not be null");
        }
        if (mode != INJECT_INPUT_EVENT_MODE_ASYNC
                && mode != INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
                && mode != INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
            throw new IllegalArgumentException("mode is invalid");
        }

        try {
            return mIm.injectInputEvent(event, mode);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }

但是这个方法添加@UnsupportedAppUsage注解,App 要使用一些骚操作(不是本文重点)。照葫芦画瓢的使用:

private void sendDownAndUpKeyEvents(int keyCode) {
        final long downTime = SystemClock.uptimeMillis();
        sendKeyEventIdentityCleared(keyCode, KeyEvent.ACTION_DOWN, downTime, downTime);
        sendKeyEventIdentityCleared(
                keyCode, KeyEvent.ACTION_UP, downTime, SystemClock.uptimeMillis());
    }

    private void sendKeyEventIdentityCleared(int keyCode, int action, long downTime, long time) {
        KeyEvent event = KeyEvent.obtain(downTime, time, action, keyCode, 0, 0,
                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
                InputDevice.SOURCE_KEYBOARD, null);
        InputManager.getInstance()
                .injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
        event.recycle();
    }

以返回事件为例:

sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK);

搞定。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值