Add delete whole words during backspace option

This commit is contained in:
Aleksandras Kostarevas 2024-07-14 15:36:43 +03:00
parent e181717692
commit 6613e3e57f
9 changed files with 104 additions and 41 deletions

View File

@ -1217,7 +1217,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
// Don't start key repeat when we are in the dragging finger mode.
if (mIsInDraggingFinger) return;
final int startRepeatCount = 1;
startKeyRepeatTimer(startRepeatCount);
startKeyRepeatTimer(key.getCode(), startRepeatCount);
}
public void onKeyRepeat(final int code, final int repeatCount) {
@ -1229,15 +1229,20 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
mCurrentRepeatingKeyCode = code;
mIsDetectingGesture = false;
final int nextRepeatCount = repeatCount + 1;
startKeyRepeatTimer(nextRepeatCount);
startKeyRepeatTimer(code, nextRepeatCount);
callListenerOnPressAndCheckKeyboardLayoutChange(key, repeatCount);
callListenerOnCodeInput(key, code, mKeyX, mKeyY, SystemClock.uptimeMillis(),
true /* isKeyRepeat */);
}
private void startKeyRepeatTimer(final int repeatCount) {
final int delay =
(repeatCount == 1) ? sParams.mKeyRepeatStartTimeout : sParams.mKeyRepeatInterval;
private void startKeyRepeatTimer(final int code, final int repeatCount) {
int delay = (repeatCount == 1) ? sParams.mKeyRepeatStartTimeout : sParams.mKeyRepeatInterval;
// Slow down the repeat key if we are deleting whole words
if(code == Constants.CODE_DELETE && Settings.getInstance().getCurrent().mBackspaceMode == Settings.BACKSPACE_MODE_WORDS && repeatCount > 1) {
delay = (int)((float)delay * (7.0f * (1.0f / ((float)(repeatCount - 1))) + 1.0f));
}
sTimerProxy.startKeyRepeatTimerOf(this, repeatCount, delay);
}

View File

@ -60,7 +60,7 @@ public final class AudioAndHapticFeedbackManager {
public void performHapticAndAudioFeedback(final int code,
final View viewToPerformHapticFeedbackOn) {
performHapticFeedback(viewToPerformHapticFeedbackOn);
performHapticFeedback(viewToPerformHapticFeedbackOn, false);
performAudioFeedback(code);
}
@ -108,12 +108,12 @@ public final class AudioAndHapticFeedbackManager {
mAudioManager.playSoundEffect(sound, mSettingsValues.mKeypressSoundVolume);
}
public void performHapticFeedback(final View viewToPerformHapticFeedbackOn) {
public void performHapticFeedback(final View viewToPerformHapticFeedbackOn, final boolean repeatKey) {
if (!mSettingsValues.mVibrateOn) {
return;
}
if (mSettingsValues.mKeypressVibrationDuration >= 0) {
vibrate(mSettingsValues.mKeypressVibrationDuration);
vibrate(mSettingsValues.mKeypressVibrationDuration / (repeatKey ? 2 : 1));
return;
}
// Go ahead with the system default

View File

@ -1304,14 +1304,12 @@ public class LatinIMELegacy implements KeyboardActionListener,
@Override
public void onMoveDeletePointer(int steps) {
if (mInputLogic.mConnection.hasCursorPosition()) {
steps = mInputLogic.mConnection.getUnicodeSteps(steps, false);
final int end = mInputLogic.mConnection.getExpectedSelectionEnd();
final int start = mInputLogic.mConnection.getExpectedSelectionStart() + steps;
if (start > end)
return;
mInputLogic.finishInput();
mInputLogic.mConnection.setSelection(start, end);
boolean stepOverWords = mSettings.getCurrent().mBackspaceMode == Settings.BACKSPACE_MODE_WORDS;
if(steps < 0) {
mInputLogic.cursorLeft(steps, stepOverWords, true);
} else {
mInputLogic.cursorRight(steps, stepOverWords, true);
}
} else {
for (; steps < 0; steps++)
onCodeInput(
@ -1691,10 +1689,7 @@ public class LatinIMELegacy implements KeyboardActionListener,
}
final AudioAndHapticFeedbackManager feedbackManager =
AudioAndHapticFeedbackManager.getInstance();
if (repeatCount == 0) {
// TODO: Reconsider how to perform haptic feedback when repeating key.
feedbackManager.performHapticFeedback(keyboardView);
}
feedbackManager.performHapticFeedback(keyboardView, repeatCount > 0);
feedbackManager.performAudioFeedback(code);
}

View File

@ -1077,7 +1077,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
public int getUnicodeSteps(int chars, boolean rightSidePointer) {
int steps = 0;
if (chars < 0) {
CharSequence charsBeforeCursor = rightSidePointer && hasSelection() ?
CharSequence charsBeforeCursor = !rightSidePointer && hasSelection() ?
getSelectedText(0) :
getTextBeforeCursor(-chars * 2, 0);
if (charsBeforeCursor != null) {
@ -1089,7 +1089,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
}
}
} else if (chars > 0) {
CharSequence charsAfterCursor = !rightSidePointer && hasSelection() ?
CharSequence charsAfterCursor = rightSidePointer && hasSelection() ?
getSelectedText(0) :
getTextAfterCursor(chars * 2, 0);
if (charsAfterCursor != null) {
@ -1105,7 +1105,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
}
private int getCharacterClass(char c) {
if(Character.isLetter(c) || c == '_' || Character.isDigit(c)) return 1;
if(Character.isLetter(c) || c == '_' || Character.isDigit(c) || c == '\'') return 1;
else if(Character.isWhitespace(c)) return 2;
else return 3;
}

View File

@ -49,6 +49,7 @@ import org.futo.inputmethod.latin.common.Constants;
import org.futo.inputmethod.latin.common.InputPointers;
import org.futo.inputmethod.latin.common.StringUtils;
import org.futo.inputmethod.latin.define.DebugFlags;
import org.futo.inputmethod.latin.settings.Settings;
import org.futo.inputmethod.latin.settings.SettingsValues;
import org.futo.inputmethod.latin.settings.SettingsValuesForSuggestion;
import org.futo.inputmethod.latin.settings.SpacingAndPunctuations;
@ -1053,6 +1054,10 @@ public final class InputLogic {
mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */);
// When we exit this if-clause, mWordComposer.isComposingWord() will return false.
}
final boolean deleteWholeWords = event.isKeyRepeat()
&& Settings.getInstance().getCurrent().mBackspaceMode == Settings.BACKSPACE_MODE_WORDS;
if (mWordComposer.isComposingWord()) {
if (mWordComposer.isBatchMode()) {
final String rejectedSuggestion = mWordComposer.getTypedWord();
@ -1063,6 +1068,13 @@ public final class InputLogic {
Constants.EVENT_REJECTION);
}
StatsUtils.onBackspaceWordDelete(rejectedSuggestion.length());
} else if(deleteWholeWords) {
final String removedWord = mWordComposer.getTypedWord();
mWordComposer.reset();
if (!TextUtils.isEmpty(removedWord)) {
unlearnWord(removedWord, inputTransaction.mSettingsValues,
Constants.EVENT_BACKSPACE);
}
} else {
mWordComposer.applyProcessedEvent(event);
StatsUtils.onBackspacePressed(1);
@ -1195,13 +1207,23 @@ public final class InputLogic {
Character.isSupplementaryCodePoint(codePointBeforeCursor) ? 2 : 1;
// Handle emoji sequences (flags, etc)
CharSequence textBeforeCursor = mConnection.getTextBeforeCursor(8, 0);
CharSequence textBeforeCursor = mConnection.getTextBeforeCursor(deleteWholeWords ? 48 : 8, 0);
if (textBeforeCursor != null && textBeforeCursor.length() > 0) {
BreakIterator breakIterator = BreakIterator.getCharacterInstance();
BreakIterator breakIterator;
if(deleteWholeWords) {
breakIterator = BreakIterator.getWordInstance();
} else {
breakIterator = BreakIterator.getCharacterInstance();
}
breakIterator.setText(textBeforeCursor.toString());
int end = breakIterator.last();
int start = breakIterator.previous();
if(deleteWholeWords && textBeforeCursor.subSequence(start, end).toString().equals(" ")) {
start = breakIterator.previous();
}
if (start != BreakIterator.DONE) {
lengthToDelete = end - start;
textDeleted = textBeforeCursor.subSequence(start, end).toString();

View File

@ -114,6 +114,16 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
private static final String PREF_CORPUS_HANDLES_FOR_PERSONALIZATION =
"pref_corpus_handles_for_personalization";
public static final String PREF_SPACEBAR_MODE = "pref_spacebar_mode";
public static final int SPACEBAR_MODE_SWIPE_CURSOR = 0; // Long-Press switches language, swipe moves cursor
public static final int SPACEBAR_MODE_SWIPE_LANGUAGE = 1; // Swipe switches language, long-press+drag moves cursor
public static final int SPACEBAR_MODE_SWIPE_CURSOR_ONLY = 2; // Swipe and long-press+drag moves cursor
public static final String PREF_BACKSPACE_MODE = "pref_backspace_mode";
public static final int BACKSPACE_MODE_CHARACTERS = 0; // Long-press backspace and swipe backspace removes just characters
public static final int BACKSPACE_MODE_WORDS = 1; // Long-press backspace and swipe backspace removes entire words
// Emoji
public static final String PREF_EMOJI_RECENT_KEYS = "emoji_recent_keys";
public static final String PREF_EMOJI_CATEGORY_LAST_TYPED_ID = "emoji_category_last_typed_id";

View File

@ -93,6 +93,9 @@ public class SettingsValues {
public final boolean mIsNumberRowEnabled;
public final int mScreenMetrics;
public final int mSpacebarMode;
public final int mBackspaceMode;
// From the input box
@Nonnull
public final InputAttributes mInputAttributes;
@ -164,6 +167,9 @@ public class SettingsValues {
mIsSplitKeyboardEnabled = prefs.getBoolean(Settings.PREF_ENABLE_SPLIT_KEYBOARD, false);
mScreenMetrics = Settings.readScreenMetrics(res);
mSpacebarMode = prefs.getInt(Settings.PREF_SPACEBAR_MODE, Settings.SPACEBAR_MODE_SWIPE_CURSOR);
mBackspaceMode = prefs.getInt(Settings.PREF_BACKSPACE_MODE, Settings.BACKSPACE_MODE_CHARACTERS);
mShouldShowLxxSuggestionUi = Settings.SHOULD_SHOW_LXX_SUGGESTION_UI
&& prefs.getBoolean(DebugSettings.PREF_SHOULD_SHOW_LXX_SUGGESTION_UI, true);
// Compute other readable settings

View File

@ -282,15 +282,13 @@ fun<T> SettingRadio(
title: String,
options: List<T>,
optionNames: List<String>,
setting: SettingsKey<T>,
setting: DataStoreItem<T>,
) {
val (value, setValue) = useDataStore(key = setting.key, default = setting.default)
ScreenTitle(title, showBack = false)
Column {
options.zip(optionNames).forEach {
SettingItem(title = it.second, onClick = { setValue(it.first) }, icon = {
RadioButton(selected = value == it.first, onClick = null)
SettingItem(title = it.second, onClick = { setting.setValue(it.first) }, icon = {
RadioButton(selected = setting.value == it.first, onClick = null)
}) {
}

View File

@ -83,6 +83,7 @@ import org.futo.inputmethod.latin.uix.settings.ScreenTitle
import org.futo.inputmethod.latin.uix.settings.ScrollableList
import org.futo.inputmethod.latin.uix.settings.SettingItem
import org.futo.inputmethod.latin.uix.settings.SettingListLazy
import org.futo.inputmethod.latin.uix.settings.SettingRadio
import org.futo.inputmethod.latin.uix.settings.SettingSlider
import org.futo.inputmethod.latin.uix.settings.SettingSliderSharedPrefsInt
import org.futo.inputmethod.latin.uix.settings.SettingToggleDataStore
@ -364,17 +365,43 @@ fun LongPressScreen(navController: NavHostController = rememberNavController())
)
}
/*
SettingRadio(
title = "Spacebar behavior",
options = listOf(0, 1, 2),
optionNames = listOf(
"Swiping moves cursor, long-pressing switches language",
"Swiping changes language, long-pressing moves cursor",
"Swiping and long-pressing only moves cursor"
),
setting =
)*/
item {
SettingRadio(
title = "Backspace Behavior when holding/swiping",
options = listOf(
Settings.BACKSPACE_MODE_CHARACTERS,
Settings.BACKSPACE_MODE_WORDS
),
optionNames = listOf(
"Delete characters",
"Delete entire words"
),
setting = useSharedPrefsInt(
key = Settings.PREF_BACKSPACE_MODE,
default = Settings.BACKSPACE_MODE_CHARACTERS
)
)
}
item {
SettingRadio(
title = "Spacebar Behavior",
options = listOf(
Settings.SPACEBAR_MODE_SWIPE_CURSOR,
Settings.SPACEBAR_MODE_SWIPE_LANGUAGE,
Settings.SPACEBAR_MODE_SWIPE_CURSOR_ONLY
),
optionNames = listOf(
"Swiping moves cursor, long-pressing switches language",
"Swiping changes language, long-pressing moves cursor",
"Swiping and long-pressing only moves cursor"
),
setting = useSharedPrefsInt(
key = Settings.PREF_SPACEBAR_MODE,
default = Settings.SPACEBAR_MODE_SWIPE_CURSOR
)
)
}
}
}