Some of the other answers seem overly complicated or incomplete. This is a general answer for future visitors.
In an activity
If you have a reference to EditText then it is easy.
Set the cursor position
editText.setSelection(index);
Set a selected range
editText.setSelection(startIndex, endIndex);
In an IME (keyboard)
It's a little more difficult from within an IME because you don't have direct access to the EditText. However, you can use the InputConnection to set the cursor position and selection.
The following answers get the input connection like this from within your InputMethodService
subclass:
InputConnection inputConnection = getCurrentInputConnection();
Set the cursor position
inputConnection.setSelection(index, index);
Set a selected range
inputConnection.setSelection(startIndex, endIndex);
Move the cursor to the start
inputConnection.setSelection(0, 0);
Move the cursor to the end
ExtractedText extractedText = inputConnection.getExtractedText(new ExtractedTextRequest(), 0);
if (extractedText == null || extractedText.text == null) return;
int index = extractedText.text.length();
inputConnection.setSelection(index, index);
This method isn't guaranteed to work because the extracted text will not be be the entire text from the EditText if the text is very long. However, for most situations it is fine. Another option would be to use a combination of the following
inputConnection.getTextBeforeCursor(numberOfChars, 0)
inputConnection.getSelectedText(0)
inputConnection.getTextAfterCursor(numberOfChars, 0)
where numberOfChars
is a large number.
Get current cursor index (or selection)
ExtractedText extractedText = inputConnection.getExtractedText(new ExtractedTextRequest(), 0);
int startIndex = extractedText.startOffset + extractedText.selectionStart;
int endIndex = extractedText.startOffset + extractedText.selectionEnd;
In the case that the extractedText
does not return the full text of the EditText
, the startOffset
tells you from what point it was pulled from. Then you can get the actual cursor index by adding the startOffset
to the extracted text's selection start or end.
Move the cursor relative to its current position
Once you know the current position of the cursor, it is easy to move it around. Here is an example that moves the cursor to the beginning of the previous word.
BreakIterator boundary = BreakIterator.getWordInstance();
boundary.setText(extractedText.text.toString());
int preceding = boundary.preceding(extractedText.selectionStart);
int newIndex = (preceding == BreakIterator.DONE) ? selectionStart : preceding;
inputConnection.setSelection(newIndex, newIndex);
See other BreakIterator
options here.
You can also move left, right, up and down by sending d-pad down up events.
Move left
inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT));
inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_LEFT));
Move right
inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT));
inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_RIGHT));
Move up
inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP));
inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_UP));
Move down
inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN));
inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_DOWN));