You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用InputConnection实现WebView带逐字符延迟的模拟输入?

WebView模拟软键盘逐字符输入时内容被覆盖的问题解决

问题根源分析

在Android 12环境下,使用InputConnection的commitText方法逐字符输入文本时,出现后续字符清除之前内容的现象,核心原因有两点:

  1. commitText参数理解偏差:commitText(CharSequence text, int newCursorPosition)的第二个参数newCursorPosition控制光标相对位置:
    • 传入1时,WebView的InputConnection会将其解析为替换当前选中内容(而非追加),导致每次输入都会覆盖之前的文本;
    • 传入0时,文本会追加到当前光标位置,且光标停在新输入文本开头,不会触发替换逻辑。
  2. InputConnection实例错误复用:原代码中手动调用onCreateInputConnection(EditorInfo())创建新的InputConnection,而非复用WebView与输入法关联的实例,导致每次输入都在独立上下文执行,加剧内容覆盖问题。

修正方案

修正后的代码

class CustomWebView(context: Context, attrs: AttributeSet): WebView(context, attrs) {
    private var inputConnection: InputConnection? = null

    override fun onCreateInputConnection(outAttrs: EditorInfo?): InputConnection? {
        val newInputConnection = super.onCreateInputConnection(outAttrs) ?: return inputConnection
        inputConnection = newInputConnection
        return newInputConnection
    }

    suspend fun sendTextInput(text: String, keyDelayStart: Long, keyDelayEnd: Long) {
        val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager ?: 
            throw Exception("could not get system's InputMethodManager")
        requestFocus()
        val defer = CompletableDeferred<Int>()
        // AsyncResultReceiver是自定义ResultReceiver,用于在回调中resolve deferred
        imm.showSoftInput(this, 0, AsyncResultReceiver(WeakReference(defer)))
        val result = defer.await()
        if (result == InputMethodManager.RESULT_HIDDEN || result == InputMethodManager.RESULT_UNCHANGED_HIDDEN)
            throw Exception("could not show IME keyboard")
        
        // 复用WebView关联的InputConnection实例
        val ic = inputConnection ?: throw Exception("could not get valid InputConnection")
        for (char in text) {
            // 传入0确保文本追加,不触发替换
            ic.commitText(char.toString(), 0)
            delay(Random.nextLong(keyDelayStart, keyDelayEnd))
        }
        imm.hideSoftInputFromWindow(windowToken, 0)
    }
}

关键修正点

  • 复用InputConnection实例:直接使用WebView在输入法绑定过程中创建的inputConnection,保证输入上下文一致,避免独立环境导致的内容覆盖。
  • 设置commitText参数为0:适配Android 12 WebView的InputConnection逻辑,确保文本以追加方式输入,而非替换现有内容。

进阶优化(光标停在文本末尾)

如果需要每次输入后光标停在文本末尾,可在提交字符前手动将光标移到现有文本末尾,再使用commitText参数1:

for (char in text) {
    // 获取当前文本长度,将光标移到末尾
    val currentTextLength = ic.getTextBeforeCursor(Int.MAX_VALUE, 0).length
    ic.setSelection(currentTextLength, currentTextLength)
    // 提交字符,光标停在新字符末尾
    ic.commitText(char.toString(), 1)
    delay(Random.nextLong(keyDelayStart, keyDelayEnd))
}

内容的提问来源于stack exchange,提问作者hldev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 22:10:41