mirror of
https://gitlab.futo.org/keyboard/latinime.git
synced 2024-09-28 14:54:30 +01:00
Add option to swipe spacebar to change language
This commit is contained in:
parent
6613e3e57f
commit
d52b5ddfdd
@ -251,6 +251,9 @@ public final class Constants {
|
||||
public static final int CODE_ACTION_0 = -1050;
|
||||
public static final int CODE_ACTION_MAX = CODE_ACTION_0 + 100;
|
||||
|
||||
public static final int CODE_ALT_ACTION_0 = -2050;
|
||||
public static final int CODE_ALT_ACTION_MAX = CODE_ALT_ACTION_0 + 100;
|
||||
|
||||
public static boolean isLetterCode(final int code) {
|
||||
return code >= CODE_SPACE;
|
||||
}
|
||||
|
@ -105,6 +105,8 @@ public interface KeyboardActionListener {
|
||||
public void onMoveDeletePointer(int steps);
|
||||
public void onUpWithDeletePointerActive();
|
||||
public void onUpWithPointerActive();
|
||||
public void onSwipeLanguage(int direction);
|
||||
public void onMovingCursorLockEvent(boolean canMoveCursor);
|
||||
|
||||
public static final KeyboardActionListener EMPTY_LISTENER = new Adapter();
|
||||
|
||||
@ -139,5 +141,9 @@ public interface KeyboardActionListener {
|
||||
public void onUpWithDeletePointerActive() {}
|
||||
@Override
|
||||
public void onUpWithPointerActive() {}
|
||||
@Override
|
||||
public void onSwipeLanguage(int direction) {}
|
||||
@Override
|
||||
public void onMovingCursorLockEvent(boolean canMoveCursor) {}
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ import org.futo.inputmethod.latin.common.CoordinateUtils;
|
||||
import org.futo.inputmethod.latin.common.InputPointers;
|
||||
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.utils.ResourceUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -86,6 +87,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
|
||||
// Parameters for pointer handling.
|
||||
private static PointerTrackerParams sParams;
|
||||
private static final int sPointerStep = (int)(16.0 * Resources.getSystem().getDisplayMetrics().density);
|
||||
private static final int sPointerBigStep = (int)(32.0 * Resources.getSystem().getDisplayMetrics().density);
|
||||
private static final int sPointerHugeStep = Integer.min(
|
||||
(int)(128.0 * Resources.getSystem().getDisplayMetrics().density),
|
||||
Resources.getSystem().getDisplayMetrics().widthPixels * 3 / 2
|
||||
);
|
||||
|
||||
private static GestureStrokeRecognitionParams sGestureStrokeRecognitionParams;
|
||||
private static GestureStrokeDrawingParams sGestureStrokeDrawingParams;
|
||||
@ -135,6 +141,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
|
||||
private int mStartY;
|
||||
private long mStartTime;
|
||||
private boolean mCursorMoved = false;
|
||||
private boolean mSpacebarLongPressed = false;
|
||||
|
||||
// true if keyboard layout has been changed.
|
||||
private boolean mKeyboardLayoutHasBeenChanged;
|
||||
@ -705,6 +712,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
|
||||
mStartX = x;
|
||||
mStartY = y;
|
||||
mStartTime = System.currentTimeMillis();
|
||||
mSpacebarLongPressed = false;
|
||||
|
||||
mIsSlidingCursor = key.getCode() == Constants.CODE_DELETE || key.getCode() == Constants.CODE_SPACE;
|
||||
mCurrentKey = key;
|
||||
@ -910,25 +918,48 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
|
||||
final int lastY = mLastY;
|
||||
final Key oldKey = mCurrentKey;
|
||||
|
||||
final SettingsValues settingsValues = Settings.getInstance().getCurrent();
|
||||
|
||||
if (mIsSlidingCursor && oldKey != null && oldKey.getCode() == Constants.CODE_SPACE) {
|
||||
int steps = (x - mStartX) / sPointerStep;
|
||||
final int swipeIgnoreTime = Settings.getInstance().getCurrent().mKeyLongpressTimeout / MULTIPLIER_FOR_LONG_PRESS_TIMEOUT_IN_SLIDING_INPUT;
|
||||
int pointerStep = sPointerStep;
|
||||
if(settingsValues.mSpacebarMode == Settings.SPACEBAR_MODE_SWIPE_LANGUAGE && !mSpacebarLongPressed) {
|
||||
pointerStep = sPointerHugeStep;
|
||||
}
|
||||
|
||||
int steps = (x - mStartX) / pointerStep;
|
||||
final int swipeIgnoreTime = settingsValues.mKeyLongpressTimeout / MULTIPLIER_FOR_LONG_PRESS_TIMEOUT_IN_SLIDING_INPUT;
|
||||
if (steps != 0 && mStartTime + swipeIgnoreTime < System.currentTimeMillis()) {
|
||||
mCursorMoved = true;
|
||||
mStartX += steps * sPointerStep;
|
||||
sListener.onMovePointer(steps);
|
||||
mStartX += steps * pointerStep;
|
||||
|
||||
if(settingsValues.mSpacebarMode == Settings.SPACEBAR_MODE_SWIPE_LANGUAGE && !mSpacebarLongPressed) {
|
||||
sListener.onSwipeLanguage(steps);
|
||||
} else {
|
||||
sListener.onMovePointer(steps);
|
||||
}
|
||||
}
|
||||
|
||||
mLastX = x;
|
||||
mLastY = y;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIsSlidingCursor && oldKey != null && oldKey.getCode() == Constants.CODE_DELETE) {
|
||||
int steps = (x - mStartX) / sPointerStep;
|
||||
int pointerStep = sPointerStep;
|
||||
if(settingsValues.mBackspaceMode == Settings.BACKSPACE_MODE_WORDS) {
|
||||
pointerStep = sPointerBigStep;
|
||||
}
|
||||
|
||||
int steps = (x - mStartX) / pointerStep;
|
||||
if (steps != 0) {
|
||||
sTimerProxy.cancelKeyTimersOf(this);
|
||||
mCursorMoved = true;
|
||||
mStartX += steps * sPointerStep;
|
||||
mStartX += steps * pointerStep;
|
||||
sListener.onMoveDeletePointer(steps);
|
||||
}
|
||||
|
||||
mLastX = x;
|
||||
mLastY = y;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1086,6 +1117,17 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
|
||||
}
|
||||
final int code = key.getCode();
|
||||
if (code == Constants.CODE_SPACE || code == Constants.CODE_LANGUAGE_SWITCH) {
|
||||
int spacebarMode = Settings.getInstance().getCurrent().mSpacebarMode;
|
||||
if(spacebarMode == Settings.SPACEBAR_MODE_SWIPE_LANGUAGE) {
|
||||
mSpacebarLongPressed = true;
|
||||
mStartX = mLastX;
|
||||
mStartY = mLastY;
|
||||
sListener.onMovingCursorLockEvent(true);
|
||||
return;
|
||||
}else if(spacebarMode == Settings.SPACEBAR_MODE_SWIPE_CURSOR_ONLY) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Long pressing the space key invokes IME switcher dialog.
|
||||
if (sListener.onCustomRequest(Constants.CUSTOM_CODE_SHOW_INPUT_METHOD_PICKER)) {
|
||||
cancelKeyTracking();
|
||||
@ -1094,6 +1136,16 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
|
||||
}
|
||||
}
|
||||
|
||||
if (code > Constants.CODE_ACTION_0 && code < Constants.CODE_ACTION_MAX) {
|
||||
cancelKeyTracking();
|
||||
sListener.onCodeInput(
|
||||
code - Constants.CODE_ACTION_0 + Constants.CODE_ALT_ACTION_0,
|
||||
Constants.NOT_A_COORDINATE,
|
||||
Constants.NOT_A_COORDINATE,
|
||||
false /* isKeyRepeat */);
|
||||
return;
|
||||
}
|
||||
|
||||
setReleasedKeyGraphics(key, false /* withAnimation */);
|
||||
final MoreKeysPanel moreKeysPanel = sDrawingProxy.showMoreKeysKeyboard(key, this);
|
||||
if (moreKeysPanel == null) {
|
||||
@ -1196,6 +1248,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
|
||||
// We use longer timeout for sliding finger input started from the modifier key.
|
||||
return longpressTimeout * MULTIPLIER_FOR_LONG_PRESS_TIMEOUT_IN_SLIDING_INPUT;
|
||||
}
|
||||
|
||||
if (code == Constants.CODE_SPACE) {
|
||||
return longpressTimeout * 2;
|
||||
}
|
||||
return longpressTimeout;
|
||||
}
|
||||
|
||||
|
@ -186,7 +186,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
|
||||
mParams.mKeyStyles.addDynamicKeyStyle("bottomEmojiKeyStyle",
|
||||
actionKeySpec,
|
||||
2,
|
||||
2);
|
||||
0x02 | 0x08);
|
||||
|
||||
final XmlResourceParser parser = mResources.getXml(xmlId);
|
||||
try {
|
||||
|
@ -535,7 +535,14 @@ public class LatinIMELegacy implements KeyboardActionListener,
|
||||
public void triggerAction(int actionId) {
|
||||
final LatinIMELegacy latinImeLegacy = getOwnerInstance();
|
||||
if (latinImeLegacy != null) {
|
||||
((LatinIME) (latinImeLegacy.getInputMethodService())).getUixManager().triggerAction(actionId);
|
||||
((LatinIME) (latinImeLegacy.getInputMethodService())).getUixManager().triggerAction(actionId, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void triggerActionAlt(int actionId) {
|
||||
final LatinIMELegacy latinImeLegacy = getOwnerInstance();
|
||||
if (latinImeLegacy != null) {
|
||||
((LatinIME) (latinImeLegacy.getInputMethodService())).getUixManager().triggerAction(actionId, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1355,12 +1362,24 @@ public class LatinIMELegacy implements KeyboardActionListener,
|
||||
mInputLogic.restartSuggestionsOnWordTouchedByCursor(mSettings.getCurrent(), false, mKeyboardSwitcher.getCurrentKeyboardScriptId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwipeLanguage(int direction) {
|
||||
Subtypes.INSTANCE.switchToNextLanguage(mInputMethodService, direction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMovingCursorLockEvent(boolean canMoveCursor) {
|
||||
if(canMoveCursor) {
|
||||
hapticAndAudioFeedback(Constants.CODE_UNSPECIFIED, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isShowingOptionDialog() {
|
||||
return mOptionsDialog != null && mOptionsDialog.isShowing();
|
||||
}
|
||||
|
||||
public void switchToNextSubtype() {
|
||||
SwitchLanguageActionKt.switchToNextLanguage(mInputMethodService);
|
||||
Subtypes.INSTANCE.switchToNextLanguage(mInputMethodService, 1);
|
||||
}
|
||||
|
||||
// TODO: Instead of checking for alphabetic keyboard here, separate keycodes for
|
||||
|
@ -47,6 +47,7 @@ import org.futo.inputmethod.latin.uix.settings.useDataStoreValueBlocking
|
||||
import org.futo.inputmethod.latin.uix.theme.Typography
|
||||
import org.futo.inputmethod.latin.utils.SubtypeLocaleUtils
|
||||
import java.util.Locale
|
||||
import kotlin.math.sign
|
||||
|
||||
fun Locale.stripExtensionsIfNeeded(): Locale {
|
||||
val newLocale = if(Build.VERSION.SDK_INT >= 26) {
|
||||
@ -251,6 +252,23 @@ object Subtypes {
|
||||
return layouts
|
||||
}
|
||||
|
||||
fun switchToNextLanguage(context: Context, direction: Int) {
|
||||
if(direction == 0) return
|
||||
|
||||
val enabledSubtypes = context.getSettingBlocking(SubtypesSetting).toList()
|
||||
val currentSubtype = context.getSettingBlocking(ActiveSubtype)
|
||||
|
||||
val index = enabledSubtypes.indexOf(currentSubtype)
|
||||
val nextIndex = if(index == -1) {
|
||||
0
|
||||
} else {
|
||||
(index + direction.sign).mod(enabledSubtypes.size)
|
||||
}
|
||||
|
||||
if(enabledSubtypes.isEmpty()) return
|
||||
|
||||
context.setSettingBlocking(ActiveSubtype.key, enabledSubtypes[nextIndex])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -683,6 +683,13 @@ public final class InputLogic {
|
||||
return;
|
||||
}
|
||||
|
||||
if(event.mKeyCode <= Constants.CODE_ALT_ACTION_MAX && event.mKeyCode >= Constants.CODE_ALT_ACTION_0) {
|
||||
final int actionId = event.mKeyCode - Constants.CODE_ALT_ACTION_0;
|
||||
handler.triggerActionAlt(actionId);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.mKeyCode) {
|
||||
case Constants.CODE_DELETE:
|
||||
handleBackspaceEvent(event, inputTransaction, currentKeyboardScriptId);
|
||||
|
@ -61,6 +61,7 @@ interface KeyboardManagerForAction {
|
||||
fun unsetInputConnection()
|
||||
|
||||
fun requestDialog(text: String, options: List<DialogRequestItem>, onCancel: () -> Unit)
|
||||
fun openInputMethodPicker()
|
||||
}
|
||||
|
||||
interface ActionWindow {
|
||||
@ -105,5 +106,6 @@ data class Action(
|
||||
val windowImpl: ((KeyboardManagerForAction, PersistentActionState?) -> ActionWindow)?,
|
||||
val simplePressImpl: ((KeyboardManagerForAction, PersistentActionState?) -> Unit)?,
|
||||
val persistentState: ((KeyboardManagerForAction) -> PersistentActionState)? = null,
|
||||
val persistentStateInitialization: PersistentStateInitialization = PersistentStateInitialization.OnActionTrigger
|
||||
val persistentStateInitialization: PersistentStateInitialization = PersistentStateInitialization.OnActionTrigger,
|
||||
val altPressImpl: ((KeyboardManagerForAction, PersistentActionState?) -> Unit)? = null,
|
||||
)
|
||||
|
@ -243,6 +243,10 @@ class UixActionKeyboardManager(val uixManager: UixManager, val latinIME: LatinIM
|
||||
uixManager.activeDialogRequestDismissed.value = false
|
||||
}
|
||||
|
||||
override fun openInputMethodPicker() {
|
||||
uixManager.showLanguageSwitcher()
|
||||
}
|
||||
|
||||
override fun announce(s: String) {
|
||||
AccessibilityUtils.init(getContext())
|
||||
if(AccessibilityUtils.getInstance().isAccessibilityEnabled) {
|
||||
@ -666,14 +670,20 @@ class UixManager(private val latinIME: LatinIME) {
|
||||
}
|
||||
}
|
||||
|
||||
fun triggerAction(id: Int) {
|
||||
fun triggerAction(id: Int, alt: Boolean) {
|
||||
val action = AllActions.getOrNull(id) ?: throw IllegalArgumentException("No such action with ID $id")
|
||||
|
||||
if(currWindowAction != null && action.windowImpl != null) {
|
||||
closeActionWindow()
|
||||
}
|
||||
if(alt) {
|
||||
if(action.altPressImpl != null) {
|
||||
action.altPressImpl.invoke(keyboardManagerForAction, persistentStates[action])
|
||||
}
|
||||
} else {
|
||||
if (currWindowAction != null && action.windowImpl != null) {
|
||||
closeActionWindow()
|
||||
}
|
||||
|
||||
onActionActivated(action)
|
||||
onActionActivated(action)
|
||||
}
|
||||
}
|
||||
|
||||
fun requestForgetWord(suggestedWordInfo: SuggestedWords.SuggestedWordInfo) {
|
||||
|
@ -1,32 +1,18 @@
|
||||
package org.futo.inputmethod.latin.uix.actions
|
||||
|
||||
import android.content.Context
|
||||
import org.futo.inputmethod.latin.ActiveSubtype
|
||||
import org.futo.inputmethod.latin.R
|
||||
import org.futo.inputmethod.latin.SubtypesSetting
|
||||
import org.futo.inputmethod.latin.Subtypes
|
||||
import org.futo.inputmethod.latin.uix.Action
|
||||
import org.futo.inputmethod.latin.uix.getSettingBlocking
|
||||
import org.futo.inputmethod.latin.uix.setSettingBlocking
|
||||
|
||||
fun switchToNextLanguage(context: Context) {
|
||||
val enabledSubtypes = context.getSettingBlocking(SubtypesSetting).toList()
|
||||
val currentSubtype = context.getSettingBlocking(ActiveSubtype)
|
||||
|
||||
val index = enabledSubtypes.indexOf(currentSubtype)
|
||||
val nextIndex = if(index == -1) {
|
||||
0
|
||||
} else {
|
||||
(index + 1) % enabledSubtypes.size
|
||||
}
|
||||
|
||||
context.setSettingBlocking(ActiveSubtype.key, enabledSubtypes[nextIndex])
|
||||
}
|
||||
|
||||
val SwitchLanguageAction = Action(
|
||||
icon = R.drawable.globe,
|
||||
name = R.string.show_language_switch_key,
|
||||
simplePressImpl = { manager, _ ->
|
||||
switchToNextLanguage(manager.getContext())
|
||||
Subtypes.switchToNextLanguage(manager.getContext(), 1)
|
||||
},
|
||||
altPressImpl = { manager, _ ->
|
||||
manager.openInputMethodPicker()
|
||||
},
|
||||
windowImpl = null,
|
||||
)
|
Loading…
Reference in New Issue
Block a user