From 4b78546e97bef18456c4f19110d8d40cd6a3228d Mon Sep 17 00:00:00 2001 From: arcarum <134963929+arcarum@users.noreply.github.com> Date: Tue, 12 Mar 2024 01:42:25 +0400 Subject: [PATCH] Add support for vertical cursor movement using the spacebar (#486) --------- Co-authored-by: Helium314 --- .../keyboard/KeyboardActionListener.java | 21 ++++++- .../keyboard/keyboard/PointerTracker.java | 56 ++++++++----------- .../helium314/keyboard/latin/LatinIME.java | 50 +++++++++++++++-- .../keyboard/latin/settings/Settings.java | 21 +++++-- .../latin/settings/SettingsValues.java | 8 +-- app/src/main/res/values/donottranslate.xml | 21 +++++++ app/src/main/res/values/strings.xml | 8 +++ .../main/res/xml/prefs_screen_advanced.xml | 28 ++++++---- 8 files changed, 155 insertions(+), 58 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/KeyboardActionListener.java b/app/src/main/java/helium314/keyboard/keyboard/KeyboardActionListener.java index 48f46abf3..cd1763e11 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/KeyboardActionListener.java +++ b/app/src/main/java/helium314/keyboard/keyboard/KeyboardActionListener.java @@ -90,12 +90,23 @@ public interface KeyboardActionListener { * @return true if the request has been consumed, false otherwise. */ boolean onCustomRequest(int requestCode); - void onMovePointer(int steps); + + /** + * Called when the user performs a horizontal or vertical swipe gesture + * on the space bar. + */ + boolean onHorizontalSpaceSwipe(int steps); + boolean onVerticalSpaceSwipe(int steps); + void onMoveDeletePointer(int steps); void onUpWithDeletePointerActive(); KeyboardActionListener EMPTY_LISTENER = new Adapter(); + static int SWIPE_NO_ACTION = 0; + static int SWIPE_MOVE_CURSOR = 1; + static int SWIPE_SWITCH_LANGUAGE = 2; + class Adapter implements KeyboardActionListener { @Override public void onPressKey(int primaryCode, int repeatCount, boolean isSinglePointer) {} @@ -122,7 +133,13 @@ public interface KeyboardActionListener { return false; } @Override - public void onMovePointer(int steps) {} + public boolean onHorizontalSpaceSwipe(int steps) { + return false; + } + @Override + public boolean onVerticalSpaceSwipe(int steps) { + return false; + } @Override public void onMoveDeletePointer(int steps) {} @Override diff --git a/app/src/main/java/helium314/keyboard/keyboard/PointerTracker.java b/app/src/main/java/helium314/keyboard/keyboard/PointerTracker.java index 98279a6b4..0b9581a36 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/PointerTracker.java +++ b/app/src/main/java/helium314/keyboard/keyboard/PointerTracker.java @@ -130,10 +130,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element, private int mLastY; private int mStartX; private int mStartY; - private int mPreviousY; private long mStartTime; - private boolean mCursorMoved = false; - private boolean mLanguageSlideStarted = false; + private boolean mInHorizontalSwipe = false; + private boolean mInVerticalSwipe = false; // true if keyboard layout has been changed. private boolean mKeyboardLayoutHasBeenChanged; @@ -704,7 +703,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element, setPressedKeyGraphics(key, eventTime); mStartX = x; mStartY = y; - mPreviousY = y; mStartTime = System.currentTimeMillis(); } } @@ -909,31 +907,25 @@ public final class PointerTracker implements PointerTrackerQueue.Element, if (oldKey != null && oldKey.getCode() == Constants.CODE_SPACE) { int dX = x - mStartX; int dY = y - mStartY; - // language switch: upwards movement - if (!mCursorMoved && sv.mSpaceLanguageSlide && -dY > abs(dX) && dY / sPointerStep != 0) { - List subtypes = RichInputMethodManager.getInstance().getMyEnabledInputMethodSubtypeList(false); - if (subtypes.size() > 1) { // only allow if we have more than one subtype - mLanguageSlideStarted = true; - if (abs(y - mPreviousY) / sPointerStep < 4) - // we want large enough steps between switches - return; - // decide next or previous dependent on up or down - InputMethodSubtype current = RichInputMethodManager.getInstance().getCurrentSubtype().getRawSubtype(); - int wantedIndex = (subtypes.indexOf(current) + ((y - mPreviousY > 0) ? 1 : -1)) % subtypes.size(); - if (wantedIndex < 0) wantedIndex += subtypes.size(); - KeyboardSwitcher.getInstance().switchToSubtype(subtypes.get(wantedIndex)); - mPreviousY = y; - return; + // vertical movement + int stepsY = dY / sPointerStep; + if (abs(dX) < abs(dY) && !mInHorizontalSwipe) { + mInVerticalSwipe = true; + if (sListener.onVerticalSpaceSwipe(stepsY)) { + mStartY += stepsY * sPointerStep; } + return; } - // Pointer slider: sideways movement - int steps = dX / sPointerStep; + + // Horizontal movement + int stepsX = dX / sPointerStep; final int longpressTimeout = 2 * sv.mKeyLongpressTimeout / MULTIPLIER_FOR_LONG_PRESS_TIMEOUT_IN_SLIDING_INPUT; - if (sv.mSpaceTrackpadEnabled && !mLanguageSlideStarted && steps != 0 && mStartTime + longpressTimeout < System.currentTimeMillis()) { - mCursorMoved = true; - mStartX += steps * sPointerStep; - sListener.onMovePointer(steps); + if (!mInVerticalSwipe && mStartTime + longpressTimeout < System.currentTimeMillis()) { + mInHorizontalSwipe = true; + if (sListener.onHorizontalSpaceSwipe(stepsX)) { + mStartX += stepsX * sPointerStep; + } } return; } @@ -941,9 +933,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element, if (oldKey != null && oldKey.getCode() == KeyCode.DELETE && sv.mDeleteSwipeEnabled) { // Delete slider int steps = (x - mStartX) / sPointerStep; - if (abs(steps) > 2 || (mCursorMoved && steps != 0)) { + if (abs(steps) > 2 || (mInHorizontalSwipe && steps != 0)) { sTimerProxy.cancelKeyTimersOf(this); - mCursorMoved = true; + mInHorizontalSwipe = true; mStartX += steps * sPointerStep; sListener.onMoveDeletePointer(steps); } @@ -1026,7 +1018,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element, // Release the last pressed key. setReleasedKeyGraphics(currentKey, true); - if(mCursorMoved && currentKey.getCode() == KeyCode.DELETE) { + if(mInHorizontalSwipe && currentKey.getCode() == KeyCode.DELETE) { sListener.onUpWithDeletePointerActive(); } @@ -1042,9 +1034,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element, return; } - if (mCursorMoved || mLanguageSlideStarted) { - mCursorMoved = false; - mLanguageSlideStarted = false; + if (mInHorizontalSwipe || mInVerticalSwipe) { + mInHorizontalSwipe = false; + mInVerticalSwipe = false; return; } @@ -1090,7 +1082,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element, if (isShowingPopupKeysPanel()) { return; } - if(mCursorMoved) { + if(mInHorizontalSwipe || mInVerticalSwipe) { return; } final Key key = getKey(); diff --git a/app/src/main/java/helium314/keyboard/latin/LatinIME.java b/app/src/main/java/helium314/keyboard/latin/LatinIME.java index 64d2382c7..850007f87 100644 --- a/app/src/main/java/helium314/keyboard/latin/LatinIME.java +++ b/app/src/main/java/helium314/keyboard/latin/LatinIME.java @@ -1389,8 +1389,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } @Override - public void onMovePointer(int steps) { - if (steps == 0) return; + public boolean onHorizontalSpaceSwipe(final int steps) { + return switch (mSettings.getCurrent().mSpaceSwipeHorizontal) { + case KeyboardActionListener.SWIPE_MOVE_CURSOR -> onMoveCursorHorizontally(steps); + case KeyboardActionListener.SWIPE_SWITCH_LANGUAGE -> onLanguageSlide(steps); + default -> false; + }; + } + + private boolean onMoveCursorHorizontally(int steps) { + if (steps == 0) return false; // for RTL languages we want to invert pointer movement if (mRichImm.getCurrentSubtype().isRtlSubtype()) steps = -steps; @@ -1406,7 +1414,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen onCodeInput(KeyCode.ARROW_LEFT, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, false); ++steps; } - return; + return true; } } else { int availableCharacters = mInputLogic.mConnection.getTextAfterCursor(64, 0).length(); @@ -1416,7 +1424,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen onCodeInput(KeyCode.ARROW_RIGHT, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, false); --steps; } - return; + return true; } } @@ -1425,12 +1433,44 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // this is a noticeable performance improvement int newPosition = mInputLogic.mConnection.mExpectedSelStart + moveSteps; mInputLogic.mConnection.setSelection(newPosition, newPosition); - return; + return true; } mInputLogic.finishInput(); int newPosition = mInputLogic.mConnection.mExpectedSelStart + moveSteps; mInputLogic.mConnection.setSelection(newPosition, newPosition); mInputLogic.restartSuggestionsOnWordTouchedByCursor(mSettings.getCurrent(), mKeyboardSwitcher.getCurrentKeyboardScript()); + return true; + } + + @Override + public boolean onVerticalSpaceSwipe(final int steps) { + return switch (mSettings.getCurrent().mSpaceSwipeVertical) { + case KeyboardActionListener.SWIPE_MOVE_CURSOR -> onMoveCursorVertically(steps); + case KeyboardActionListener.SWIPE_SWITCH_LANGUAGE -> onLanguageSlide(steps); + default -> false; + }; + } + + private boolean onLanguageSlide(final int steps) { + if (Math.abs(steps) < 4) + return false; + List subtypes = RichInputMethodManager.getInstance().getMyEnabledInputMethodSubtypeList(false); + if (subtypes.size() <= 1) { // only allow if we have more than one subtype + return false; + } + // decide next or previous dependent on up or down + InputMethodSubtype current = RichInputMethodManager.getInstance().getCurrentSubtype().getRawSubtype(); + int wantedIndex = (subtypes.indexOf(current) + ((steps > 0) ? 1 : -1)) % subtypes.size(); + if (wantedIndex < 0) wantedIndex += subtypes.size(); + KeyboardSwitcher.getInstance().switchToSubtype(subtypes.get(wantedIndex)); + return true; + } + + private boolean onMoveCursorVertically(int steps) { + if (steps == 0) return false; + int code = (steps < 0) ? KeyCode.ARROW_UP : KeyCode.ARROW_DOWN; + onCodeInput(code, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, false); + return true; } @Override diff --git a/app/src/main/java/helium314/keyboard/latin/settings/Settings.java b/app/src/main/java/helium314/keyboard/latin/settings/Settings.java index 583d83cc0..f9ab36310 100644 --- a/app/src/main/java/helium314/keyboard/latin/settings/Settings.java +++ b/app/src/main/java/helium314/keyboard/latin/settings/Settings.java @@ -26,6 +26,7 @@ import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.preference.PreferenceManager; +import helium314.keyboard.keyboard.KeyboardActionListener; import helium314.keyboard.keyboard.KeyboardTheme; import helium314.keyboard.keyboard.internal.keyboard_parser.LocaleKeyboardInfosKt; import helium314.keyboard.latin.AudioAndHapticFeedbackManager; @@ -98,7 +99,8 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_SPLIT_SPACER_SCALE = "split_spacer_scale"; public static final String PREF_KEYBOARD_HEIGHT_SCALE = "keyboard_height_scale"; public static final String PREF_BOTTOM_PADDING_SCALE = "bottom_padding_scale"; - public static final String PREF_SPACE_TRACKPAD = "space_trackpad"; + public static final String PREF_SPACE_HORIZONTAL_SWIPE = "horizontal_space_swipe"; + public static final String PREF_SPACE_VERTICAL_SWIPE = "vertical_space_swipe"; public static final String PREF_DELETE_SWIPE = "delete_swipe"; public static final String PREF_AUTOSPACE_AFTER_PUNCTUATION = "autospace_after_punctuation"; public static final String PREF_ALWAYS_INCOGNITO_MODE = "always_incognito_mode"; @@ -129,7 +131,6 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_MORE_POPUP_KEYS = "more_popup_keys"; public static final String PREF_SPACE_TO_CHANGE_LANG = "prefs_long_press_keyboard_to_change_lang"; - public static final String PREF_SPACE_LANGUAGE_SLIDE = "space_language_slide"; public static final String PREF_ENABLE_CLIPBOARD_HISTORY = "enable_clipboard_history"; public static final String PREF_CLIPBOARD_HISTORY_RETENTION_TIME = "clipboard_history_retention_time"; @@ -384,8 +385,20 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang return res.getInteger(R.integer.config_clipboard_history_retention_time); } - public static boolean readSpaceTrackpadEnabled(final SharedPreferences prefs) { - return prefs.getBoolean(PREF_SPACE_TRACKPAD, true); + public static int readHorizontalSpaceSwipe(final SharedPreferences prefs) { + return switch (prefs.getString(PREF_SPACE_HORIZONTAL_SWIPE, "none")) { + case "move_cursor" -> KeyboardActionListener.SWIPE_MOVE_CURSOR; + case "switch_language" -> KeyboardActionListener.SWIPE_SWITCH_LANGUAGE; + default -> KeyboardActionListener.SWIPE_NO_ACTION; + }; + } + + public static int readVerticalSpaceSwipe(final SharedPreferences prefs) { + return switch (prefs.getString(PREF_SPACE_VERTICAL_SWIPE, "none")) { + case "move_cursor" -> KeyboardActionListener.SWIPE_MOVE_CURSOR; + case "switch_language" -> KeyboardActionListener.SWIPE_SWITCH_LANGUAGE; + default -> KeyboardActionListener.SWIPE_NO_ACTION; + }; } public static boolean readDeleteSwipeEnabled(final SharedPreferences prefs) { diff --git a/app/src/main/java/helium314/keyboard/latin/settings/SettingsValues.java b/app/src/main/java/helium314/keyboard/latin/settings/SettingsValues.java index e328204de..52170b9bc 100644 --- a/app/src/main/java/helium314/keyboard/latin/settings/SettingsValues.java +++ b/app/src/main/java/helium314/keyboard/latin/settings/SettingsValues.java @@ -67,12 +67,12 @@ public class SettingsValues { public final boolean mShowsHints; public final boolean mShowsPopupHints; public final boolean mSpaceForLangChange; - public final boolean mSpaceLanguageSlide; public final boolean mShowsEmojiKey; public final boolean mUsePersonalizedDicts; public final boolean mUseDoubleSpacePeriod; public final boolean mBlockPotentiallyOffensive; - public final boolean mSpaceTrackpadEnabled; + public final int mSpaceSwipeHorizontal; + public final int mSpaceSwipeVertical; public final boolean mDeleteSwipeEnabled; public final boolean mAutospaceAfterPunctuationEnabled; public final boolean mClipboardHistoryEnabled; @@ -149,7 +149,6 @@ public class SettingsValues { mShowsHints = prefs.getBoolean(Settings.PREF_SHOW_HINTS, true); mShowsPopupHints = prefs.getBoolean(Settings.PREF_SHOW_POPUP_HINTS, false); mSpaceForLangChange = prefs.getBoolean(Settings.PREF_SPACE_TO_CHANGE_LANG, true); - mSpaceLanguageSlide = prefs.getBoolean(Settings.PREF_SPACE_LANGUAGE_SLIDE, false); mShowsEmojiKey = prefs.getBoolean(Settings.PREF_SHOW_EMOJI_KEY, false); mUsePersonalizedDicts = prefs.getBoolean(Settings.PREF_KEY_USE_PERSONALIZED_DICTS, true); mUseDoubleSpacePeriod = prefs.getBoolean(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true) @@ -193,7 +192,8 @@ public class SettingsValues { || mInputAttributes.mIsPasswordField; mKeyboardHeightScale = prefs.getFloat(Settings.PREF_KEYBOARD_HEIGHT_SCALE, DEFAULT_SIZE_SCALE); mDisplayOrientation = res.getConfiguration().orientation; - mSpaceTrackpadEnabled = Settings.readSpaceTrackpadEnabled(prefs); + mSpaceSwipeHorizontal = Settings.readHorizontalSpaceSwipe(prefs); + mSpaceSwipeVertical = Settings.readVerticalSpaceSwipe(prefs); mDeleteSwipeEnabled = Settings.readDeleteSwipeEnabled(prefs); mAutospaceAfterPunctuationEnabled = Settings.readAutospaceAfterPunctuationEnabled(prefs); mClipboardHistoryEnabled = Settings.readClipboardHistoryEnabled(prefs); diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index 958226be8..ecb3bbd1f 100644 --- a/app/src/main/res/values/donottranslate.xml +++ b/app/src/main/res/values/donottranslate.xml @@ -106,4 +106,25 @@ @string/show_popup_keys_more @string/show_popup_keys_all + + + move_cursor + switch_language + none + + + @string/space_swipe_move_cursor_entry + @string/language_switch_key_switch_subtype + @string/action_none + + + move_cursor + switch_language + none + + + @string/space_swipe_move_cursor_entry + @string/language_switch_key_switch_subtype + @string/action_none + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d7f111157..8640eb166 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -776,4 +776,12 @@ New dictionary: Pause Wait + + Horizontal spacebar swipe gesture + + Vertical spacebar swipe gesture + + None + + Move Cursor diff --git a/app/src/main/res/xml/prefs_screen_advanced.xml b/app/src/main/res/xml/prefs_screen_advanced.xml index 48d43d811..ae5c0f6a1 100644 --- a/app/src/main/res/xml/prefs_screen_advanced.xml +++ b/app/src/main/res/xml/prefs_screen_advanced.xml @@ -23,11 +23,23 @@ latin:maxValue="@integer/config_max_longpress_timeout" latin:stepValue="@integer/config_longpress_timeout_step" /> - + + + - -