如何在用户更改选择时将撰写文本提交给 InputConnection

How to commit composing text to an InputConnection when the user changes the selection

我正在做一个custom keyboard and have to set composing text before committing it. This is described in

我知道一般如何提交文本

inputConnection.commitText("text", 1);

但是如果用户通过触摸 EditText 的另一部分来更改光标位置,我不知道如何提交它。通过观察其他键盘,我知道这是可能的,因为他们这样做了。但是在我的键盘上,如果我有

inputConnection.setComposingText("text", 1);

再改变光标位置,排版就剩下了。以后的任何更改都将替换组合跨度,不会在新的光标位置输入。

post Android EditText listener for cursor position change 提供了一些关于您可以对 EditText 执行的操作的想法,但在自定义键盘中我无法使用 EditText除了 InputConnection 给我的东西。

我如何知道 cursor/selection 何时移动?

在开始写问题后找到了问题的答案。我会post下面的答案。

编辑器(EditText等)调用updateSelection on the InputMethodManager, which in turn notifies the onUpdateSelection监听器。因此,键盘可以覆盖 onUpdateSelection 并处理那里未完成的组合跨度。

要处理未完成的合成跨度,您可以在 InputConnection 上使用 finishComposingText。这将删除组合跨度并提交跨度中的任何文本。

下面是它在 sample Android soft keyboard 中的实现方式:

/**
 * Deal with the editor reporting movement of its cursor.
 */
@Override public void onUpdateSelection(int oldSelStart, int oldSelEnd,
        int newSelStart, int newSelEnd,
        int candidatesStart, int candidatesEnd) {
    super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
            candidatesStart, candidatesEnd);

    // If the current selection in the text view changes, we should
    // clear whatever candidate text we have.
    if (mComposing.length() > 0 && (newSelStart != candidatesEnd
            || newSelEnd != candidatesEnd)) {
        mComposing.setLength(0);
        updateCandidates();
        InputConnection ic = getCurrentInputConnection();
        if (ic != null) {
            ic.finishComposingText();
        }
    }
}

https://chromium.googlesource.com/android_tools/+/refs/heads/master/sdk/sources/android-25/android/widget/Editor.java#1604

int candStart = -1;
int candEnd = -1;
if (mTextView.getText() instanceof Spannable) {
  final Spannable sp = (Spannable) mTextView.getText();
  candStart = EditableInputConnection.getComposingSpanStart(sp);
  candEnd = EditableInputConnection.getComposingSpanEnd(sp);
}