如何使用 InputConnection 模拟具有逐个字符延迟的键入?

How to simulate typing with char-by-char delay using InputConnection?

提问人:hldev 提问时间:1/21/2023 最后编辑:hldev 更新时间:1/23/2023 访问量:113

问:

我需要在 WebView 上使用软输入键盘模拟具有逐个字符延迟的文本输入。我不能使用 WebView#dispatchKeyEvent,因为它不适合键入 Unicode 文本,并且不能模拟软输入键盘。

我正在重写 WebView#onCreateInputConnection 以获取对 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 is a custom ResultReceiver which resolves a deferred on the callback
        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")
        val ic = onCreateInputConnection(EditorInfo()) ?:
            throw Exception("could not create InputConnection")
        for (char in text) {
            ic.commitText(char.toString(), 1)
            delay(Random.nextLong(keyDelayStart, keyDelayEnd))
        }
        imm.hideSoftInputFromWindow(windowToken, 0)
    }
}

我通过在输入字段上键入来测试,但是在键入下一个字符时,它会清除以前的字符:Hello, world!

enter image description here

向后键入时,请完全键入:ic.commitText(char.toString(), 0)

enter image description here

该测试在 Android 12 上运行。

android kotlin 输入 android-webview android-input-method

评论


答:

1赞 hldev 1/23/2023 #1

InputConnection#commitText()替换实际合成区域的内容。要添加新字符,您需要将合成区域(“光标”)向前移动。尝试:InputConnection#setComposingRegion()

for (i in text.indices) {
    ic.setComposingRegion(i, i + 1)
    ic.commitText(text[i].toString(), 1)
    delay(Random.nextLong(keyDelayStart, keyDelayEnd))
}