Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit c98ffdf

Browse files
committed
use android QwertyKeyListener for deleting backward
1 parent 06e2ef8 commit c98ffdf

File tree

2 files changed

+36
-46
lines changed

2 files changed

+36
-46
lines changed

shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java

Lines changed: 7 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
import android.text.Layout;
1717
import android.text.Selection;
1818
import android.text.TextPaint;
19+
import android.text.method.QwertyKeyListener;
20+
import android.text.method.TextKeyListener.Capitalize;
1921
import android.view.KeyEvent;
2022
import android.view.View;
2123
import android.view.inputmethod.BaseInputConnection;
@@ -237,53 +239,12 @@ public boolean sendKeyEvent(KeyEvent event) {
237239
updateEditingState();
238240
return true;
239241
} else if (selStart > 0) {
240-
// Delete to the left/right of the cursor depending on direction of text.
241-
// TODO(garyq): Explore how to obtain per-character direction. The
242-
// isRTLCharAt() call below is returning blanket direction assumption
243-
// based on the first character in the line.
244-
245-
Boolean selectedCharIsEmoji = false;
246-
if (selStart > 1) {
247-
final String emo_regex =
248-
"([\\u20a0-\\u32ff\\ud83c\\udc00-\\ud83d\\udeff\\udbb9\\udce5-\\udbb9\\udcee])";
249-
String lastChars = mLayout.getText().subSequence(selStart - 2, selStart).toString();
250-
selectedCharIsEmoji = lastChars.matches(emo_regex);
251-
}
252-
253-
// The Selection.extendLeft and extendRight calls have some problems
254-
// when mixing RTL and LTR text so if selected character is not emoji
255-
// simply select that character
256-
if (selectedCharIsEmoji) {
257-
boolean isRtl =
258-
mLayout.isRtlCharAt(mLayout.getLineStart(mLayout.getLineForOffset(selStart)));
259-
Log.i("isRtl", Boolean.toString(isRtl));
260-
try {
261-
if (isRtl) {
262-
Selection.extendRight(mEditable, mLayout);
263-
} else {
264-
Selection.extendLeft(mEditable, mLayout);
265-
}
266-
} catch (IndexOutOfBoundsException e) {
267-
// On some Chinese devices (primarily Huawei, some Xiaomi),
268-
// on initial app startup before focus is lost, the
269-
// Selection.extendLeft and extendRight calls always extend
270-
// from the index of the initial contents of mEditable. This
271-
// try-catch will prevent crashing on Huawei devices by falling
272-
// back to a simple way of deletion, although this a hack and
273-
// will not handle emojis.
274-
Selection.setSelection(mEditable, selStart, selStart - 1);
275-
}
276-
} else {
277-
Selection.setSelection(mEditable, selStart, selStart - 1);
242+
QwertyKeyListener qwertyKeyListener = new QwertyKeyListener(Capitalize.NONE, false);
243+
if (qwertyKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event)) {
244+
updateEditingState();
245+
return true;
278246
}
279-
int newStart = clampIndexToEditable(Selection.getSelectionStart(mEditable), mEditable);
280-
int newEnd = clampIndexToEditable(Selection.getSelectionEnd(mEditable), mEditable);
281-
Selection.setSelection(mEditable, Math.min(newStart, newEnd));
282-
// Min/Max the values since RTL selections will start at a higher
283-
// index than they end at.
284-
mEditable.delete(Math.min(newStart, newEnd), Math.max(newStart, newEnd));
285-
updateEditingState();
286-
return true;
247+
return false;
287248
}
288249
} else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) {
289250
int selStart = Selection.getSelectionStart(mEditable);

shell/platform/android/test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,15 +256,44 @@ public void testSendKeyEvent_downKeyMovesCaretDown() {
256256
assertTrue(Selection.getSelectionStart(editable) > selStart);
257257
}
258258

259+
@Test
260+
public void testSendKeyEvent_delKeyDeletesBackward() {
261+
int selStart = 29;
262+
Editable editable = sampleRtlEditable(selStart, selStart);
263+
InputConnectionAdaptor adaptor = sampleInputConnectionAdaptor(editable);
264+
265+
KeyEvent downKeyDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL);
266+
267+
for (int i = 0; i < 9; i++) {
268+
boolean didConsume = adaptor.sendKeyEvent(downKeyDown);
269+
assertTrue(didConsume);
270+
}
271+
assertEquals(Selection.getSelectionStart(editable), 19);
272+
273+
for (int i = 0; i < 9; i++) {
274+
boolean didConsume = adaptor.sendKeyEvent(downKeyDown);
275+
assertTrue(didConsume);
276+
}
277+
assertEquals(Selection.getSelectionStart(editable), 10);
278+
}
279+
259280
private static final String SAMPLE_TEXT =
260281
"Lorem ipsum dolor sit amet," + "\nconsectetur adipiscing elit.";
261282

283+
private static final String SAMPLE_RTL_TEXT = "متن ساختگی" + "\nبرای تستfor test😊";
284+
262285
private static Editable sampleEditable(int selStart, int selEnd) {
263286
SpannableStringBuilder sample = new SpannableStringBuilder(SAMPLE_TEXT);
264287
Selection.setSelection(sample, selStart, selEnd);
265288
return sample;
266289
}
267290

291+
private static Editable sampleRtlEditable(int selStart, int selEnd) {
292+
SpannableStringBuilder sample = new SpannableStringBuilder(SAMPLE_RTL_TEXT);
293+
Selection.setSelection(sample, selStart, selEnd);
294+
return sample;
295+
}
296+
268297
private static InputConnectionAdaptor sampleInputConnectionAdaptor(Editable editable) {
269298
View testView = new View(RuntimeEnvironment.application);
270299
int client = 0;

0 commit comments

Comments
 (0)