【问题标题】:Android simulate key pressAndroid模拟按键
【发布时间】:2012-01-31 13:28:22
【问题描述】:

如何以编程方式模拟 Droid 上的按键?我想模仿手动按键(出现在机器人上有人正在按键但它是以编程方式完成的)。

有一些涉及 IWindowManager 的解决方案,但在新的 SDK 中不再是一个选项。

【问题讨论】:

  • 测试工具、修改应用程序以响应实际触摸以外的其他内容以及“root”设备以在 linux 级别注入事件是您的 3 个选择。

标签: java android key keypress simulate


【解决方案1】:

您可以使用检测,即从您的活动的 onCreate 调用的以下代码将导致菜单多次打开和关闭:

    new Thread(new Runnable() {         
        @Override
        public void run() {
            try {
            Instrumentation inst = new Instrumentation();
            for ( int i = 0; i < 10; ++i ) {
                inst.sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
                Thread.sleep(2000);
                inst.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
                Thread.sleep(2000);
            }
            }
            catch(InterruptedException e){
            }
        }   
    }).start();

...但我不确定这是不是你想要的

【讨论】:

  • 这正是我正在寻找的,但是......不是严格用于测试的仪器吗?我正在寻找可以在实时应用程序中使用的解决方案,而不是测试。提前致谢。
  • @calcrisk33 我无法找到有关这是否是实时应用程序的可行解决方案的任何信息。你最终以这种方式使用它吗?
  • @Kirk 我做了,它在模拟击键/按下时效果很好。
  • 完美地满足了我的需求(JNI 的自定义键盘),虽然我不需要 try / catch 块,但发现它必须在线程中。
  • 需要 INJECT_EVENTS 权限,该权限仅适用于系统应用程序。
【解决方案2】:

如果您有一个想要使用该事件的视图,您可以使用BaseInputConnection 类及其sendKeyEvent 方法。

要使用它,您需要指定一个接收 KeyEvent 的目标视图(例如 EditText)。例如:

EditText editText;
BaseInputConnection inputConnection = new BaseInputConnection(editText, true);
inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_POUND));

这样的结果就像用户实际上按下了 # 键(同时关注编辑文本)。

【讨论】:

  • 这让我想知道您是否还需要发送KeyEvent.ACTION_UP。我想这样做是合乎逻辑的。
  • 这种方法也适用于其他视图吗?例如:如果我想在 RecyclerView 上模拟 DPAD_UP ?
【解决方案3】:

在我看来,使用检测不能按预期工作,当 editText 获得焦点时,有时会导致软键盘弹出。

在我的项目中,我有一个数字键盘片段,它应该像普通键盘一样工作,这是我实现所需解决方案的方式:

我在 3 台 android 7+ 的设备上测试了这个解决方案:

键盘片段 onClick():

@Override
public void onClick(View v) {

    switch(v.getId()) {

        case R.id.button0:
            simulateKeyPress(KeyEvent.KEYCODE_0);
            break;
        case R.id.button1:
            simulateKeyPress(KeyEvent.KEYCODE_1);
            break;
        case R.id.button2:
            simulateKeyPress(KeyEvent.KEYCODE_2);
            break;
        case R.id.button3:
            simulateKeyPress(KeyEvent.KEYCODE_3);
            break;
        case R.id.button4:
            simulateKeyPress(KeyEvent.KEYCODE_4);
            break;
        case R.id.button5:
            simulateKeyPress(KeyEvent.KEYCODE_5);
            break;
        case R.id.button6:
            simulateKeyPress(KeyEvent.KEYCODE_6);
            break;
        case R.id.button7:
            simulateKeyPress(KeyEvent.KEYCODE_7);
            break;
        case R.id.button8:
            simulateKeyPress(KeyEvent.KEYCODE_8);
            break;
        case R.id.button9:
            simulateKeyPress(KeyEvent.KEYCODE_9);
            break;
    }

}

public void simulateKeyPress(int key){
    Activity a = (Activity) getContext();
    a.getWindow().getDecorView().getRootView();
    BaseInputConnection inputConnection = new BaseInputConnection(a.getWindow().getDecorView().getRootView(),
            true);
    KeyEvent downEvent = new KeyEvent(KeyEvent.ACTION_DOWN, key);
    KeyEvent upEvent = new KeyEvent(KeyEvent.ACTION_UP, key);
    inputConnection.sendKeyEvent(downEvent);
    inputConnection.sendKeyEvent(upEvent);
}

这样我将事件发送到活动的根视图,然后它会转到所需的焦点编辑文本。

这是一个有点粗略的解决方案,但工作正常。

【讨论】:

    【解决方案4】:

    如果您正在运行 UI Automator 测试,您可以使用两种技术,具体取决于设备的 Android 版本:

    API 21+

    如果您只针对 API 18 或更高版本,则可以只使用 shell:

    UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
    device.executeShellCommand("input text 1234"); // Type '1234'
    device.executeShellCommand("input keyevent 66"); // Press the Enter key
    

    API 18+

    如果您还支持 API 18-19,那么您将无法使用 shell,因为它不可用,并且如果您正在与不是您自己的应用(例如系统 UI)进行交互,则您无法使用检测密钥注入。请改用UiAutomation.injectInputEvent()

    获取UiAutomation 的实例并存储在某处:

    UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
    

    然后定义一些辅助方法:

    private void sendKey(int keyCode) {
        sendKeyEvent(keyCode, KeyEvent.ACTION_DOWN);
        sendKeyEvent(keyCode, KeyEvent.ACTION_UP);
    }
    
    private void sendKeyEvent(int keyCode, int action) {
        long downTime = SystemClock.uptimeMillis();
        KeyEvent event = new KeyEvent(
                downTime,
                downTime,
                action,
                keyCode,
                0,
                0,
                KeyCharacterMap.VIRTUAL_KEYBOARD,
                0,
                KeyEvent.FLAG_FROM_SYSTEM,
                InputDevice.SOURCE_KEYBOARD
        );
    
        uiAutomation.injectInputEvent(event, true);
    }
    

    然后像这样使用它:

    sendKey(KeyEvent.KEYCODE_1);
    sendKey(KeyEvent.KEYCODE_2);
    sendKey(KeyEvent.KEYCODE_3);
    sendKey(KeyEvent.KEYCODE_4);
    sendKey(KeyEvent.KEYCODE_ENTER);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-07
      • 1970-01-01
      • 1970-01-01
      • 2013-07-24
      相关资源
      最近更新 更多