Skip to content

Commit 20a85f2

Browse files
committed
LatinIME: Implement slide-to-delete on backspace key
Change-Id: Ia38e8d6f72bec53cd2f12e708875dcdc2eb9370a
1 parent d6cc930 commit 20a85f2

7 files changed

Lines changed: 136 additions & 1 deletion

File tree

java/res/values/cm_strings.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ disposition rather than other common dispositions for Latin languages. [CHAR LIM
4040
<string name="space_trackpad">Space bar trackpad</string>
4141
<string name="space_trackpad_summary">Swipe on the spacebar to move the cursor</string>
4242

43+
<!-- Preference item for the backspace key track pad -->
44+
<string name="backspace_trackpad">Backspace key trackpad</string>
45+
<string name="backspace_trackpad_summary">Swipe on the backspace key to delete words</string>
46+
4347
<!-- Preference item for enabling longpress key hints -->
4448
<string name="show_longpress_hints">Show long-press key hints</string>
4549
<string name="show_longpress_hints_summary">Shows long-press hints for supported keys</string>

java/res/xml/prefs_screen_advanced.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@
5353
android:title="@string/space_trackpad"
5454
android:summary="@string/space_trackpad_summary"
5555
android:defaultValue="true" />
56+
<CheckBoxPreference
57+
android:key="pref_backspace_trackpad"
58+
android:title="@string/backspace_trackpad"
59+
android:summary="@string/backspace_trackpad_summary"
60+
android:defaultValue="true" />
5661
<com.android.inputmethod.latin.settings.SeekBarDialogPreference
5762
android:key="pref_keyboard_height_scale"
5863
android:title="@string/prefs_keyboard_height_scale"

java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,16 @@ public interface KeyboardActionListener {
106106
*/
107107
public void onMovePointer(int steps);
108108

109+
/**
110+
* Called while user is sliding backspace key.
111+
*/
112+
public void onBackspaceSlide(int steps);
113+
114+
/**
115+
* Called when user finished sliding backspace key.
116+
*/
117+
public void onBackspaceSlideFinished();
118+
109119
public static final KeyboardActionListener EMPTY_LISTENER = new Adapter();
110120

111121
public static class Adapter implements KeyboardActionListener {
@@ -135,5 +145,9 @@ public boolean onCustomRequest(int requestCode) {
135145
}
136146
@Override
137147
public void onMovePointer(int steps) {}
148+
@Override
149+
public void onBackspaceSlide(int steps) {}
150+
@Override
151+
public void onBackspaceSlideFinished() {}
138152
}
139153
}

java/src/com/android/inputmethod/keyboard/PointerTracker.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public PointerTrackerParams(final TypedArray mainKeyboardViewAttr) {
8686
// Parameters for pointer handling.
8787
private static PointerTrackerParams sParams;
8888
private static int sPointerStep;
89+
private static int sPointerWordStep;
8990
private static GestureStrokeRecognitionParams sGestureStrokeRecognitionParams;
9091
private static GestureStrokeDrawingParams sGestureStrokeDrawingParams;
9192
private static boolean sNeedsPhantomSuddenMoveEventHack;
@@ -129,11 +130,12 @@ public PointerTrackerParams(final TypedArray mainKeyboardViewAttr) {
129130
private int mLastX;
130131
private int mLastY;
131132

132-
// For spacebar slide tracking.
133+
// For spacebar/backspace slide tracking.
133134
private int mStartX;
134135
private int mStartY;
135136
private long mStartTime;
136137
private boolean mSlidOnSpaceBar = false;
138+
private boolean mSlidOnBackspace = false;
137139

138140
// true if keyboard layout has been changed.
139141
private boolean mKeyboardLayoutHasBeenChanged;
@@ -164,6 +166,7 @@ public static void init(final TypedArray mainKeyboardViewAttr, final TimerProxy
164166
final DrawingProxy drawingProxy) {
165167
sParams = new PointerTrackerParams(mainKeyboardViewAttr);
166168
sPointerStep = (int)(10.0 * Resources.getSystem().getDisplayMetrics().density);
169+
sPointerWordStep = (int)(20.0 * Resources.getSystem().getDisplayMetrics().density);
167170
sGestureStrokeRecognitionParams = new GestureStrokeRecognitionParams(mainKeyboardViewAttr);
168171
sGestureStrokeDrawingParams = new GestureStrokeDrawingParams(mainKeyboardViewAttr);
169172
sTypingTimeRecorder = new TypingTimeRecorder(
@@ -296,6 +299,9 @@ private void callListenerOnCodeInput(final Key key, final int primaryCode, final
296299
if (ignoreModifierKey) {
297300
return;
298301
}
302+
if (mSlidOnBackspace && code == Constants.CODE_DELETE) {
303+
return;
304+
}
299305
// Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state.
300306
if (key.isEnabled() || altersCode) {
301307
sTypingTimeRecorder.onCodeInput(code, eventTime);
@@ -925,6 +931,20 @@ private void onMoveEventInternal(final int x, final int y, final long eventTime)
925931
return;
926932
}
927933

934+
// Backspace slider
935+
if (oldKey != null && oldKey.getCode() == Constants.CODE_DELETE
936+
&& Settings.getInstance().getCurrent().mBackspaceTrackpadEnabled) {
937+
int steps = (x - mStartX) / sPointerWordStep;
938+
if (steps != 0
939+
&& mStartTime + Settings.getInstance().getCurrent().mKeyLongpressTimeout
940+
< System.currentTimeMillis()) {
941+
mSlidOnBackspace = true;
942+
mStartX += steps * sPointerWordStep;
943+
sListener.onBackspaceSlide(steps);
944+
}
945+
return;
946+
}
947+
928948
if (sGestureEnabler.shouldHandleGesture()) {
929949
// Register move event on gesture tracker.
930950
onGestureMoveEvent(x, y, eventTime, true /* isMajorEvent */, newKey);
@@ -1012,6 +1032,12 @@ private void onUpEventInternal(final int x, final int y, final long eventTime) {
10121032
return;
10131033
}
10141034

1035+
if (mSlidOnBackspace) {
1036+
sListener.onBackspaceSlideFinished();
1037+
mSlidOnBackspace = false;
1038+
return;
1039+
}
1040+
10151041
if (sInGesture) {
10161042
if (currentKey != null) {
10171043
callListenerOnRelease(currentKey, currentKey.getCode(), true /* withSliding */);
@@ -1057,6 +1083,9 @@ public void onLongPressed() {
10571083
if (mSlidOnSpaceBar) {
10581084
return;
10591085
}
1086+
if (mSlidOnBackspace) {
1087+
return;
1088+
}
10601089
final Key key = getKey();
10611090
if (key == null) {
10621091
return;

java/src/com/android/inputmethod/latin/LatinIME.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106

107107
import java.io.FileDescriptor;
108108
import java.io.PrintWriter;
109+
import java.text.BreakIterator;
109110
import java.util.ArrayList;
110111
import java.util.List;
111112
import java.util.Locale;
@@ -159,6 +160,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
159160
// If it turns out we need several, it will get grown seamlessly.
160161
final SparseArray<HardwareEventDecoder> mHardwareEventDecoders = new SparseArray<>(1);
161162

163+
BreakIterator mBreakWordIterator = BreakIterator.getWordInstance();
164+
162165
// TODO: Move these {@link View}s to {@link KeyboardSwitcher}.
163166
private View mInputView;
164167
private InsetsUpdater mInsetsUpdater;
@@ -746,6 +749,19 @@ private void resetDictionaryFacilitator(final Locale locale) {
746749
mInputLogic.mSuggest.setPlausibilityThreshold(settingsValues.mPlausibilityThreshold);
747750
}
748751

752+
/**
753+
* Reset the BreakIterator for the given locale.
754+
*
755+
* @param locale the locale
756+
*/
757+
private void resetBreakIterator(final Locale locale) {
758+
if (locale == null) {
759+
mBreakWordIterator = BreakIterator.getWordInstance(Locale.US);
760+
} else {
761+
mBreakWordIterator = BreakIterator.getWordInstance(locale);
762+
}
763+
}
764+
749765
/**
750766
* Reset suggest by loading the main dictionary of the current locale.
751767
*/
@@ -1441,6 +1457,64 @@ public void onMovePointer(int steps) {
14411457
getCurrentInputConnection().setSelection(newPosition, newPosition);
14421458
}
14431459

1460+
@Override
1461+
public void onBackspaceSlide(int steps) {
1462+
int delta = 0;
1463+
if (steps < 0) {
1464+
CharSequence text =
1465+
getCurrentInputConnection().getTextBeforeCursor(MAX_SPACESLIDE_CHARS, 0);
1466+
if (text == null || text.length() == 0) {
1467+
return;
1468+
}
1469+
mBreakWordIterator.setText(text.toString());
1470+
mBreakWordIterator.last();
1471+
delta = text.length();
1472+
while (steps < 0) {
1473+
int start = mBreakWordIterator.previous();
1474+
if (start == BreakIterator.DONE) {
1475+
break;
1476+
}
1477+
delta = start;
1478+
steps++;
1479+
}
1480+
delta -= text.length();
1481+
} else if (steps > 0) {
1482+
CharSequence text = getCurrentInputConnection().getSelectedText(0);
1483+
if (text == null || text.length() == 0) {
1484+
return;
1485+
}
1486+
mBreakWordIterator.setText(text.toString());
1487+
mBreakWordIterator.first();
1488+
while (steps > 0) {
1489+
int end = mBreakWordIterator.next();
1490+
if (end == BreakIterator.DONE) {
1491+
break;
1492+
}
1493+
delta = end;
1494+
steps--;
1495+
}
1496+
} else {
1497+
return;
1498+
}
1499+
1500+
// We only extend the start of the selection, never going past the original selection end.
1501+
int newStart = mInputLogic.mConnection.getExpectedSelectionStart() + delta;
1502+
int newEnd = mInputLogic.mConnection.getExpectedSelectionEnd();
1503+
if (newStart > newEnd) {
1504+
newStart = newEnd;
1505+
}
1506+
getCurrentInputConnection().setSelection(newStart, newEnd);
1507+
}
1508+
1509+
@Override
1510+
public void onBackspaceSlideFinished() {
1511+
final int start = mInputLogic.mConnection.getExpectedSelectionStart();
1512+
final int end = mInputLogic.mConnection.getExpectedSelectionEnd();
1513+
if (start != end) {
1514+
getCurrentInputConnection().commitText("", 1);
1515+
}
1516+
}
1517+
14441518
private boolean isShowingOptionDialog() {
14451519
return mOptionsDialog != null && mOptionsDialog.isShowing();
14461520
}

java/src/com/android/inputmethod/latin/settings/Settings.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
124124
// Space bar trackpad slider
125125
public static final String PREF_SPACE_TRACKPAD = "pref_space_trackpad";
126126

127+
// Backspace key trackpad slider
128+
public static final String PREF_BACKSPACE_TRACKPAD = "pref_backspace_trackpad";
129+
127130
// Emoji
128131
public static final String PREF_EMOJI_RECENT_KEYS = "emoji_recent_keys";
129132
public static final String PREF_EMOJI_CATEGORY_LAST_TYPED_ID = "emoji_category_last_typed_id";
@@ -372,6 +375,10 @@ public static boolean readSpaceTrackpadEnabled(final SharedPreferences prefs) {
372375
return prefs.getBoolean(PREF_SPACE_TRACKPAD, true);
373376
}
374377

378+
public static boolean readBackspaceTrackpadEnabled(final SharedPreferences prefs) {
379+
return prefs.getBoolean(PREF_BACKSPACE_TRACKPAD, true);
380+
}
381+
375382
public static boolean readUseFullscreenMode(final Resources res) {
376383
return res.getBoolean(R.bool.config_use_fullscreen_mode);
377384
}

java/src/com/android/inputmethod/latin/settings/SettingsValues.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public class SettingsValues {
7777
public final boolean mUseDoubleSpacePeriod;
7878
public final boolean mBlockPotentiallyOffensive;
7979
public final boolean mSpaceTrackpadEnabled;
80+
public final boolean mBackspaceTrackpadEnabled;
8081
// Use bigrams to predict the next word when there is no input for it yet
8182
public final boolean mBigramPredictionEnabled;
8283
public final boolean mGestureInputEnabled;
@@ -228,6 +229,7 @@ public SettingsValues(final Context context, final SharedPreferences prefs, fina
228229
.execute(mInputAttributes.mTargetApplicationPackageName);
229230
}
230231
mSpaceTrackpadEnabled = Settings.readSpaceTrackpadEnabled(prefs);
232+
mBackspaceTrackpadEnabled = Settings.readBackspaceTrackpadEnabled(prefs);
231233
}
232234

233235
public boolean isMetricsLoggingEnabled() {

0 commit comments

Comments
 (0)