Add support for vertical cursor movement using the spacebar (#486)

---------

Co-authored-by: Helium314 <helium314@disroot.org>
This commit is contained in:
arcarum 2024-03-12 01:42:25 +04:00 committed by GitHub
parent 1ffa4766af
commit 4b78546e97
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 155 additions and 58 deletions

View file

@ -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

View file

@ -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<InputMethodSubtype> 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;
// 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();

View file

@ -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<InputMethodSubtype> 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

View file

@ -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) {

View file

@ -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);

View file

@ -106,4 +106,25 @@
<item>@string/show_popup_keys_more</item>
<item>@string/show_popup_keys_all</item>
</string-array>
<string-array name="horizontal_space_swipe_values">
<item>move_cursor</item>
<item>switch_language</item>
<item>none</item>
</string-array>
<string-array name="horizontal_space_swipe_entries">
<item>@string/space_swipe_move_cursor_entry</item>
<item>@string/language_switch_key_switch_subtype</item>
<item>@string/action_none</item>
</string-array>
<string-array name="vertical_space_swipe_values">
<item>move_cursor</item>
<item>switch_language</item>
<item>none</item>
</string-array>
<string-array name="vertical_space_swipe_entries">
<item>@string/space_swipe_move_cursor_entry</item>
<item>@string/language_switch_key_switch_subtype</item>
<item>@string/action_none</item>
</string-array>
</resources>

View file

@ -776,4 +776,12 @@ New dictionary:
<string name="label_pause_key" tools:keep="@string/label_pause_key">Pause</string>
<!-- Label for "Wait" key of phone number keyboard. Must be short to fit on key. 5 chars or less is preferable. [CHAR LIMIT=7]-->
<string name="label_wait_key" tools:keep="@string/label_wait_key">Wait</string>
<!-- Title of the settings for horizontal spacebar swipe gesture -->
<string name="show_horizontal_space_swipe">Horizontal spacebar swipe gesture</string>
<!-- Title of the settings for vertical spacebar swipe gesture -->
<string name="show_vertical_space_swipe">Vertical spacebar swipe gesture</string>
<!-- Option for no action when (currently only used for swiping the spacebar) -->
<string name="action_none">None</string>
<!-- Option to move the cursor when swiping the spacebar -->
<string name="space_swipe_move_cursor_entry">Move Cursor</string>
</resources>

View file

@ -23,11 +23,23 @@
latin:maxValue="@integer/config_max_longpress_timeout"
latin:stepValue="@integer/config_longpress_timeout_step" />
<SwitchPreference
android:key="space_trackpad"
android:title="@string/space_trackpad"
android:summary="@string/space_trackpad_summary"
android:defaultValue="true" />
<ListPreference
android:defaultValue="none"
android:entries="@array/horizontal_space_swipe_entries"
android:entryValues="@array/horizontal_space_swipe_values"
android:key="horizontal_space_swipe"
android:persistent="true"
android:summary="%s"
android:title="@string/show_horizontal_space_swipe" />
<ListPreference
android:defaultValue="none"
android:entries="@array/vertical_space_swipe_entries"
android:entryValues="@array/vertical_space_swipe_values"
android:key="vertical_space_swipe"
android:persistent="true"
android:summary="%s"
android:title="@string/show_vertical_space_swipe" />
<SwitchPreference
android:key="delete_swipe"
@ -79,12 +91,6 @@
<PreferenceCategory
android:title="@string/settings_category_experimental">
<SwitchPreference
android:key="space_language_slide"
android:title="@string/space_language_slide"
android:summary="@string/space_language_slide_summary"
android:defaultValue="false" />
<SwitchPreference
android:key="url_detection"
android:title="@string/url_detection_title"