mirror of
https://gitlab.futo.org/keyboard/latinime.git
synced 2024-09-28 14:54:30 +01:00
Add sliding cursor/deletion
This commit is contained in:
parent
e2999ada34
commit
7f17d66072
@ -101,6 +101,11 @@ public interface KeyboardActionListener {
|
||||
*/
|
||||
public boolean onCustomRequest(int requestCode);
|
||||
|
||||
public void onMovePointer(int steps);
|
||||
public void onMoveDeletePointer(int steps);
|
||||
public void onUpWithDeletePointerActive();
|
||||
public void onUpWithPointerActive();
|
||||
|
||||
public static final KeyboardActionListener EMPTY_LISTENER = new Adapter();
|
||||
|
||||
public static class Adapter implements KeyboardActionListener {
|
||||
@ -125,8 +130,14 @@ public interface KeyboardActionListener {
|
||||
@Override
|
||||
public void onFinishSlidingInput() {}
|
||||
@Override
|
||||
public boolean onCustomRequest(int requestCode) {
|
||||
return false;
|
||||
}
|
||||
public boolean onCustomRequest(int requestCode) { return false; }
|
||||
@Override
|
||||
public void onMovePointer(int steps) {}
|
||||
@Override
|
||||
public void onMoveDeletePointer(int steps) {}
|
||||
@Override
|
||||
public void onUpWithDeletePointerActive() {}
|
||||
@Override
|
||||
public void onUpWithPointerActive() {}
|
||||
}
|
||||
}
|
||||
|
@ -85,6 +85,8 @@ 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 GestureStrokeRecognitionParams sGestureStrokeRecognitionParams;
|
||||
private static GestureStrokeDrawingParams sGestureStrokeDrawingParams;
|
||||
private static boolean sNeedsPhantomSuddenMoveEventHack;
|
||||
@ -128,6 +130,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
|
||||
private int mLastX;
|
||||
private int mLastY;
|
||||
|
||||
private int mStartX;
|
||||
private int mStartY;
|
||||
private long mStartTime;
|
||||
private boolean mCursorMoved = false;
|
||||
|
||||
// true if keyboard layout has been changed.
|
||||
private boolean mKeyboardLayoutHasBeenChanged;
|
||||
|
||||
@ -691,6 +698,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
|
||||
startRepeatKey(key);
|
||||
startLongPressTimer(key);
|
||||
setPressedKeyGraphics(key, eventTime);
|
||||
|
||||
mStartX = x;
|
||||
mStartY = y;
|
||||
mStartTime = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
@ -892,6 +903,29 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
|
||||
final int lastX = mLastX;
|
||||
final int lastY = mLastY;
|
||||
final Key oldKey = mCurrentKey;
|
||||
|
||||
if (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;
|
||||
if (steps != 0 && mStartTime + swipeIgnoreTime < System.currentTimeMillis()) {
|
||||
mCursorMoved = true;
|
||||
mStartX += steps * sPointerStep;
|
||||
sListener.onMovePointer(steps);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldKey != null && oldKey.getCode() == Constants.CODE_DELETE) {
|
||||
int steps = (x - mStartX) / sPointerStep;
|
||||
if (steps != 0) {
|
||||
sTimerProxy.cancelKeyTimersOf(this);
|
||||
mCursorMoved = true;
|
||||
mStartX += steps * sPointerStep;
|
||||
sListener.onMoveDeletePointer(steps);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final Key newKey = onMoveKey(x, y);
|
||||
|
||||
if (sGestureEnabler.shouldHandleGesture()) {
|
||||
@ -966,6 +1000,14 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
|
||||
// Release the last pressed key.
|
||||
setReleasedKeyGraphics(currentKey, true /* withAnimation */);
|
||||
|
||||
if(mCursorMoved && currentKey.getCode() == Constants.CODE_DELETE) {
|
||||
sListener.onUpWithDeletePointerActive();
|
||||
}
|
||||
|
||||
if(mCursorMoved) {
|
||||
sListener.onUpWithPointerActive();
|
||||
}
|
||||
|
||||
if (isShowingMoreKeysPanel()) {
|
||||
if (!mIsTrackingForActionDisabled) {
|
||||
final int translatedX = mMoreKeysPanel.translateX(x);
|
||||
@ -988,6 +1030,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCursorMoved) {
|
||||
mCursorMoved = false;
|
||||
return;
|
||||
}
|
||||
if (mIsTrackingForActionDisabled) {
|
||||
return;
|
||||
}
|
||||
@ -1018,6 +1064,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
|
||||
if (isShowingMoreKeysPanel()) {
|
||||
return;
|
||||
}
|
||||
if (mCursorMoved) {
|
||||
return;
|
||||
}
|
||||
final Key key = getKey();
|
||||
if (key == null) {
|
||||
return;
|
||||
|
@ -41,6 +41,7 @@ import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.InputType;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.PrintWriterPrinter;
|
||||
import android.util.Printer;
|
||||
@ -158,6 +159,7 @@ public class LatinIMELegacy implements KeyboardActionListener,
|
||||
private static final String SCHEME_PACKAGE = "package";
|
||||
|
||||
final Settings mSettings;
|
||||
private Locale mLocale;
|
||||
final DictionaryFacilitator mDictionaryFacilitator =
|
||||
DictionaryFacilitatorProvider.getDictionaryFacilitator(
|
||||
false /* isNeededForSpellChecking */);
|
||||
@ -671,18 +673,18 @@ public class LatinIMELegacy implements KeyboardActionListener,
|
||||
// Has to be package-visible for unit tests
|
||||
@UsedForTesting
|
||||
void loadSettings() {
|
||||
final Locale locale = mRichImm.getCurrentSubtypeLocale();
|
||||
mLocale = mRichImm.getCurrentSubtypeLocale();
|
||||
final EditorInfo editorInfo = mInputMethodService.getCurrentInputEditorInfo();
|
||||
final InputAttributes inputAttributes = new InputAttributes(
|
||||
editorInfo, mInputMethodService.isFullscreenMode(), mInputMethodService.getPackageName());
|
||||
mSettings.loadSettings(mInputMethodService, locale, inputAttributes);
|
||||
mSettings.loadSettings(mInputMethodService, mLocale, inputAttributes);
|
||||
final SettingsValues currentSettingsValues = mSettings.getCurrent();
|
||||
AudioAndHapticFeedbackManager.getInstance().onSettingsChanged(currentSettingsValues);
|
||||
// This method is called on startup and language switch, before the new layout has
|
||||
// been displayed. Opening dictionaries never affects responsivity as dictionaries are
|
||||
// asynchronously loaded.
|
||||
if (!mHandler.hasPendingReopenDictionaries()) {
|
||||
resetDictionaryFacilitator(locale);
|
||||
resetDictionaryFacilitator(mLocale);
|
||||
}
|
||||
refreshPersonalizationDictionarySession(currentSettingsValues);
|
||||
resetDictionaryFacilitatorIfNecessary();
|
||||
@ -1365,6 +1367,54 @@ public class LatinIMELegacy implements KeyboardActionListener,
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMovePointer(int steps) {
|
||||
if (mInputLogic.mConnection.hasCursorPosition()) {
|
||||
if (TextUtils.getLayoutDirectionFromLocale(mLocale) == View.LAYOUT_DIRECTION_RTL)
|
||||
steps = -steps;
|
||||
|
||||
steps = mInputLogic.mConnection.getUnicodeSteps(steps, true);
|
||||
final int end = mInputLogic.mConnection.getExpectedSelectionEnd() + steps;
|
||||
final int start = mInputLogic.mConnection.hasSelection() ? mInputLogic.mConnection.getExpectedSelectionStart() : end;
|
||||
|
||||
mInputLogic.finishInput();
|
||||
mInputLogic.mConnection.setSelection(start, end);
|
||||
} else {
|
||||
for (; steps < 0; steps++)
|
||||
mInputLogic.sendDownUpKeyEvent(KeyEvent.KEYCODE_DPAD_LEFT, 0);
|
||||
for (; steps > 0; steps--)
|
||||
mInputLogic.sendDownUpKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
} else {
|
||||
for (; steps < 0; steps++)
|
||||
mInputLogic.sendDownUpKeyEvent(KeyEvent.KEYCODE_DEL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpWithDeletePointerActive() {
|
||||
if (mInputLogic.mConnection.hasSelection())
|
||||
mInputLogic.sendDownUpKeyEvent(KeyEvent.KEYCODE_DEL, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpWithPointerActive() {
|
||||
mInputLogic.restartSuggestionsOnWordTouchedByCursor(mSettings.getCurrent(), false, mKeyboardSwitcher.getCurrentKeyboardScriptId());
|
||||
}
|
||||
|
||||
private boolean isShowingOptionDialog() {
|
||||
return mOptionsDialog != null && mOptionsDialog.isShowing();
|
||||
}
|
||||
|
@ -1044,4 +1044,41 @@ public final class RichInputConnection implements PrivateCommandPerformer {
|
||||
return InputConnectionCompatUtils.requestCursorUpdates(
|
||||
mIC, enableMonitor, requestImmediateCallback);
|
||||
}
|
||||
|
||||
public boolean hasCursorPosition() {
|
||||
return mExpectedSelStart != INVALID_CURSOR_POSITION && mExpectedSelEnd != INVALID_CURSOR_POSITION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some chars, such as emoji consist of 2 chars (surrogate pairs). We should treat them as one character.
|
||||
*/
|
||||
public int getUnicodeSteps(int chars, boolean rightSidePointer) {
|
||||
int steps = 0;
|
||||
if (chars < 0) {
|
||||
CharSequence charsBeforeCursor = rightSidePointer && hasSelection() ?
|
||||
getSelectedText(0) :
|
||||
getTextBeforeCursor(-chars * 2, 0);
|
||||
if (charsBeforeCursor != null) {
|
||||
for (int i = charsBeforeCursor.length() - 1; i >= 0 && chars < 0; i--, chars++, steps--) {
|
||||
if (Character.isSurrogate(charsBeforeCursor.charAt(i))) {
|
||||
steps--;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (chars > 0) {
|
||||
CharSequence charsAfterCursor = !rightSidePointer && hasSelection() ?
|
||||
getSelectedText(0) :
|
||||
getTextAfterCursor(chars * 2, 0);
|
||||
if (charsAfterCursor != null) {
|
||||
for (int i = 0; i < charsAfterCursor.length() && chars > 0; i++, chars--, steps++) {
|
||||
if (Character.isSurrogate(charsAfterCursor.charAt(i))) {
|
||||
steps++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return steps;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user