When deleting you need to take into account the following situations:
- There is a composing selection.
- The editor/user has a cursor selection on the text.
- There is no selection of any kind.
If there is a selection then it should be deleted. If there is no selection then the character in front of the cursor should be deleted.
Solution 1
At first I used this method. I like it because it only uses the input connection.
CharSequence selectedText = inputConnection.getSelectedText(0);
if (TextUtils.isEmpty(selectedText)) {
// no selection, so delete previous character
inputConnection.deleteSurroundingText(1, 0);
} else {
// delete the selection
inputConnection.commitText("", 1);
}
As long as the input connection is using the default BaseInputConnection.deleteSurroundingText
method, this should be fine. However, it should be noted that the documentation warns
IME authors: please be careful not to delete only half of a surrogate
pair. Also take care not to delete more characters than are in the
editor, as that may have ill effects on the application.
If some custom view is using an input connection that doesn't correctly check for for text length or surrogate pairs, then this could cause a crash. Even though this is an unlikely senario, if you use this solution, then you should add that extra checking code here.
This may be why the sample Android keyboard first checks if there is a composing span, and if there isn't then it using the following solution.
Solution 2
You can also use the input connection to send a KeyEvent
with KEYCODE_DEL
. In my opinion this is not as good because it is a soft keyboard masquerading as a hard keyboard. But many keyboards do this. When I was making a custom view that accepted keyboard input, I had to handle deletes as a KeyEvent
, that is, independently of the input connection (because the input connection was not deleting the text).
So just send the delete message as a KeyEvent
(as if you were pressing a hard keyboard key down and then letting it up).
getCurrentInputConnection().sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DEL));
getCurrentInputConnection().sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_DEL));
This works as expected. It will delete the selection if there is one, or delete one character behind the cursor if there isn't a selection. (However, you should handle any composing span separately.)
Thanks to this answer for the idea.