From cd44d2dc9fc724f3b85eca9350a31cb4216d31e1 Mon Sep 17 00:00:00 2001 From: Helium314 Date: Wed, 27 Mar 2024 06:09:59 +0100 Subject: [PATCH] move keyboardActionListener implementation into separate class (it will be extended later) --- .../keyboard/KeyboardActionListenerImpl.kt | 142 +++++++++++++++ .../keyboard/keyboard/KeyboardSwitcher.java | 8 +- .../helium314/keyboard/latin/LatinIME.java | 161 ++---------------- 3 files changed, 156 insertions(+), 155 deletions(-) create mode 100644 app/src/main/java/helium314/keyboard/keyboard/KeyboardActionListenerImpl.kt diff --git a/app/src/main/java/helium314/keyboard/keyboard/KeyboardActionListenerImpl.kt b/app/src/main/java/helium314/keyboard/keyboard/KeyboardActionListenerImpl.kt new file mode 100644 index 000000000..5f005e690 --- /dev/null +++ b/app/src/main/java/helium314/keyboard/keyboard/KeyboardActionListenerImpl.kt @@ -0,0 +1,142 @@ +package helium314.keyboard.keyboard + +import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode +import helium314.keyboard.latin.LatinIME +import helium314.keyboard.latin.RichInputMethodManager +import helium314.keyboard.latin.common.Constants +import helium314.keyboard.latin.common.InputPointers +import helium314.keyboard.latin.inputlogic.InputLogic +import helium314.keyboard.latin.settings.Settings +import kotlin.math.abs + +class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inputLogic: InputLogic) : KeyboardActionListener { + + private val keyboardSwitcher = KeyboardSwitcher.getInstance() + private val settings = Settings.getInstance() + + override fun onPressKey(primaryCode: Int, repeatCount: Int, isSinglePointer: Boolean) { + keyboardSwitcher.onPressKey(primaryCode, isSinglePointer, latinIME.currentAutoCapsState, latinIME.currentRecapitalizeState) + } + + override fun onReleaseKey(primaryCode: Int, withSliding: Boolean) { + keyboardSwitcher.onReleaseKey(primaryCode, withSliding, latinIME.currentAutoCapsState, latinIME.currentRecapitalizeState) + } + + override fun onCodeInput(primaryCode: Int, x: Int, y: Int, isKeyRepeat: Boolean) = + latinIME.onCodeInput(primaryCode, x, y, isKeyRepeat) + + override fun onTextInput(text: String?) = latinIME.onTextInput(text) + + override fun onStartBatchInput() = latinIME.onStartBatchInput() + + override fun onUpdateBatchInput(batchPointers: InputPointers?) = latinIME.onUpdateBatchInput(batchPointers) + + override fun onEndBatchInput(batchPointers: InputPointers?) = latinIME.onEndBatchInput(batchPointers) + + override fun onCancelBatchInput() = latinIME.onCancelBatchInput() + + // User released a finger outside any key + override fun onCancelInput() { } + + override fun onFinishSlidingInput() = + keyboardSwitcher.onFinishSlidingInput(latinIME.currentAutoCapsState, latinIME.currentRecapitalizeState) + + override fun onCustomRequest(requestCode: Int): Boolean { + if (requestCode == Constants.CUSTOM_CODE_SHOW_INPUT_METHOD_PICKER) + return latinIME.showInputPickerDialog() + return false + } + + override fun onHorizontalSpaceSwipe(steps: Int): Boolean = when (Settings.getInstance().current.mSpaceSwipeHorizontal) { + KeyboardActionListener.SWIPE_MOVE_CURSOR -> onMoveCursorHorizontally(steps) + KeyboardActionListener.SWIPE_SWITCH_LANGUAGE -> onLanguageSlide(steps) + else -> false + } + + override fun onVerticalSpaceSwipe(steps: Int): Boolean = when (Settings.getInstance().current.mSpaceSwipeVertical) { + KeyboardActionListener.SWIPE_MOVE_CURSOR -> onMoveCursorVertically(steps) + KeyboardActionListener.SWIPE_SWITCH_LANGUAGE -> onLanguageSlide(steps) + else -> false + } + + override fun onMoveDeletePointer(steps: Int) { + inputLogic.finishInput() + val end = inputLogic.mConnection.expectedSelectionEnd + val start = inputLogic.mConnection.expectedSelectionStart + steps + if (start > end) return + inputLogic.mConnection.setSelection(start, end) + } + + override fun onUpWithDeletePointerActive() { + if (!inputLogic.mConnection.hasSelection()) return + inputLogic.finishInput() + onCodeInput(KeyCode.DELETE, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, false) + } + + private fun onLanguageSlide(steps: Int): Boolean { + if (abs(steps) < 4) return false + val 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 + val current = RichInputMethodManager.getInstance().currentSubtype.rawSubtype + var wantedIndex = subtypes.indexOf(current) + if (steps > 0) 1 else -1 + wantedIndex %= subtypes.size + if (wantedIndex < 0) + wantedIndex += subtypes.size + KeyboardSwitcher.getInstance().switchToSubtype(subtypes[wantedIndex]) + return true + } + + private fun onMoveCursorVertically(steps: Int): Boolean { + if (steps == 0) return false + val code = if (steps < 0) KeyCode.ARROW_UP else KeyCode.ARROW_DOWN + onCodeInput(code, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, false) + return true + } + + private fun onMoveCursorHorizontally(_steps: Int): Boolean { + if (_steps == 0) return false + var steps = _steps + // for RTL languages we want to invert pointer movement + if (RichInputMethodManager.getInstance().currentSubtype.isRtlSubtype) steps = -steps + val moveSteps: Int + if (steps < 0) { + val availableCharacters: Int = inputLogic.mConnection.getTextBeforeCursor(64, 0).length + moveSteps = if (availableCharacters < -steps) -availableCharacters else steps + if (moveSteps == 0) { + // some apps don't return any text via input connection, and the cursor can't be moved + // we fall back to virtually pressing the left/right key one or more times instead + while (steps != 0) { + onCodeInput(KeyCode.ARROW_LEFT, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, false) + ++steps + } + return true + } + } else { + val availableCharacters: Int = inputLogic.mConnection.getTextAfterCursor(64, 0).length + moveSteps = availableCharacters.coerceAtMost(steps) + if (moveSteps == 0) { + while (steps != 0) { + onCodeInput(KeyCode.ARROW_RIGHT, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, false) + --steps + } + return true + } + } + if (inputLogic.moveCursorByAndReturnIfInsideComposingWord(moveSteps)) { + // no need to finish input and restart suggestions if we're still in the word + // this is a noticeable performance improvement + val newPosition: Int = inputLogic.mConnection.mExpectedSelStart + moveSteps + inputLogic.mConnection.setSelection(newPosition, newPosition) + return true + } + inputLogic.finishInput() + val newPosition: Int = inputLogic.mConnection.mExpectedSelStart + moveSteps + inputLogic.mConnection.setSelection(newPosition, newPosition) + inputLogic.restartSuggestionsOnWordTouchedByCursor(settings.current, keyboardSwitcher.currentKeyboardScript) + return true + } + +} diff --git a/app/src/main/java/helium314/keyboard/keyboard/KeyboardSwitcher.java b/app/src/main/java/helium314/keyboard/keyboard/KeyboardSwitcher.java index 5f8b9cd43..aeed202d9 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/KeyboardSwitcher.java +++ b/app/src/main/java/helium314/keyboard/keyboard/KeyboardSwitcher.java @@ -561,14 +561,14 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { mClipboardHistoryView = mCurrentInputView.findViewById(R.id.clipboard_history_view); mKeyboardViewWrapper = mCurrentInputView.findViewById(R.id.keyboard_view_wrapper); - mKeyboardViewWrapper.setKeyboardActionListener(mLatinIME); + mKeyboardViewWrapper.setKeyboardActionListener(mLatinIME.mKeyboardActionListener); mKeyboardView = mCurrentInputView.findViewById(R.id.keyboard_view); mKeyboardView.setHardwareAcceleratedDrawingEnabled(isHardwareAcceleratedDrawingEnabled); - mKeyboardView.setKeyboardActionListener(mLatinIME); + mKeyboardView.setKeyboardActionListener(mLatinIME.mKeyboardActionListener); mEmojiPalettesView.setHardwareAcceleratedDrawingEnabled(isHardwareAcceleratedDrawingEnabled); - mEmojiPalettesView.setKeyboardActionListener(mLatinIME); + mEmojiPalettesView.setKeyboardActionListener(mLatinIME.mKeyboardActionListener); mClipboardHistoryView.setHardwareAcceleratedDrawingEnabled(isHardwareAcceleratedDrawingEnabled); - mClipboardHistoryView.setKeyboardActionListener(mLatinIME); + mClipboardHistoryView.setKeyboardActionListener(mLatinIME.mKeyboardActionListener); mEmojiTabStripView = mCurrentInputView.findViewById(R.id.emoji_tab_strip); mClipboardStripView = mCurrentInputView.findViewById(R.id.clipboard_strip); mSuggestionStripView = mCurrentInputView.findViewById(R.id.suggestion_strip_view); diff --git a/app/src/main/java/helium314/keyboard/latin/LatinIME.java b/app/src/main/java/helium314/keyboard/latin/LatinIME.java index 850007f87..66738a2e3 100644 --- a/app/src/main/java/helium314/keyboard/latin/LatinIME.java +++ b/app/src/main/java/helium314/keyboard/latin/LatinIME.java @@ -42,6 +42,8 @@ import android.view.inputmethod.InputMethodSubtype; import helium314.keyboard.accessibility.AccessibilityUtils; import helium314.keyboard.compat.ConfigurationCompatKt; import helium314.keyboard.compat.EditorInfoCompatUtils; +import helium314.keyboard.keyboard.KeyboardActionListener; +import helium314.keyboard.keyboard.KeyboardActionListenerImpl; import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode; import helium314.keyboard.latin.common.InsetsOutlineProvider; import helium314.keyboard.dictionarypack.DictionaryPackConstants; @@ -51,7 +53,6 @@ import helium314.keyboard.event.HardwareEventDecoder; import helium314.keyboard.event.HardwareKeyboardEventDecoder; import helium314.keyboard.event.InputTransaction; import helium314.keyboard.keyboard.Keyboard; -import helium314.keyboard.keyboard.KeyboardActionListener; import helium314.keyboard.keyboard.KeyboardId; import helium314.keyboard.keyboard.KeyboardLayoutSet; import helium314.keyboard.keyboard.KeyboardSwitcher; @@ -102,7 +103,7 @@ import androidx.core.content.ContextCompat; /** * Input method implementation for Qwerty'ish keyboard. */ -public class LatinIME extends InputMethodService implements KeyboardActionListener, +public class LatinIME extends InputMethodService implements SuggestionStripView.Listener, SuggestionStripViewAccessor, DictionaryFacilitator.DictionaryInitializationListener, PermissionsManager.PermissionsResultCallback { @@ -122,6 +123,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private static final String SCHEME_PACKAGE = "package"; final Settings mSettings; + public final KeyboardActionListener mKeyboardActionListener; private int mOriginalNavBarColor = 0; private int mOriginalNavBarFlags = 0; private final DictionaryFacilitator mDictionaryFacilitator = @@ -562,6 +564,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mSettings = Settings.getInstance(); mKeyboardSwitcher = KeyboardSwitcher.getInstance(); mStatsUtilsManager = StatsUtilsManager.getInstance(); + mKeyboardActionListener = new KeyboardActionListenerImpl(this, mInputLogic); mIsHardwareAcceleratedDrawingEnabled = this.enableHardwareAcceleration(); Log.i(TAG, "Hardware accelerated drawing: " + mIsHardwareAcceleratedDrawingEnabled); } @@ -1374,121 +1377,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen launchSettings(); } - @Override - public boolean onCustomRequest(final int requestCode) { + public boolean showInputPickerDialog() { if (isShowingOptionDialog()) return false; - if (requestCode == Constants.CUSTOM_CODE_SHOW_INPUT_METHOD_PICKER) { - if (mRichImm.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) { - mOptionsDialog = InputMethodPickerKt.createInputMethodPickerDialog(this, mRichImm, mKeyboardSwitcher.getMainKeyboardView().getWindowToken()); - mOptionsDialog.show(); - return true; - } - return false; - } - return false; - } - - @Override - 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; - - final int moveSteps; - if (steps < 0) { - int availableCharacters = mInputLogic.mConnection.getTextBeforeCursor(64, 0).length(); - moveSteps = availableCharacters < -steps ? -availableCharacters : steps; - if (moveSteps == 0) { - // some apps don't return any text via input connection, and the cursor can't be moved - // we fall back to virtually pressing the left/right key one or more times instead - while (steps != 0) { - onCodeInput(KeyCode.ARROW_LEFT, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, false); - ++steps; - } - return true; - } - } else { - int availableCharacters = mInputLogic.mConnection.getTextAfterCursor(64, 0).length(); - moveSteps = Math.min(availableCharacters, steps); - if (moveSteps == 0) { - while (steps != 0) { - onCodeInput(KeyCode.ARROW_RIGHT, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, false); - --steps; - } - return true; - } - } - - if (mInputLogic.moveCursorByAndReturnIfInsideComposingWord(moveSteps)) { - // no need to finish input and restart suggestions if we're still in the word - // this is a noticeable performance improvement - int newPosition = mInputLogic.mConnection.mExpectedSelStart + moveSteps; - mInputLogic.mConnection.setSelection(newPosition, newPosition); + if (mRichImm.hasMultipleEnabledIMEsOrSubtypes(true)) { + mOptionsDialog = InputMethodPickerKt.createInputMethodPickerDialog(this, mRichImm, mKeyboardSwitcher.getMainKeyboardView().getWindowToken()); + mOptionsDialog.show(); 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 - public void onMoveDeletePointer(int steps) { - mInputLogic.finishInput(); - int end = mInputLogic.mConnection.getExpectedSelectionEnd(); - int start = mInputLogic.mConnection.getExpectedSelectionStart() + steps; - if (start > end) - return; - mInputLogic.mConnection.setSelection(start, end); - } - - @Override - public void onUpWithDeletePointerActive() { - if (mInputLogic.mConnection.hasSelection()) { - mInputLogic.finishInput(); - onCodeInput(KeyCode.DELETE, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, false); - } + return false; } private boolean isShowingOptionDialog() { @@ -1628,24 +1524,20 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mKeyboardSwitcher.onEvent(event, getCurrentAutoCapsState(), getCurrentRecapitalizeState()); } - @Override public void onStartBatchInput() { mInputLogic.onStartBatchInput(mSettings.getCurrent(), mKeyboardSwitcher, mHandler); mGestureConsumer.onGestureStarted(mRichImm.getCurrentSubtypeLocale(), mKeyboardSwitcher.getKeyboard()); } - @Override public void onUpdateBatchInput(final InputPointers batchPointers) { mInputLogic.onUpdateBatchInput(batchPointers); } - @Override public void onEndBatchInput(final InputPointers batchPointers) { mInputLogic.onEndBatchInput(batchPointers); mGestureConsumer.onGestureCompleted(batchPointers); } - @Override public void onCancelBatchInput() { mInputLogic.onCancelBatchInput(mHandler); mGestureConsumer.onGestureCanceled(); @@ -1673,21 +1565,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen dismissGestureFloatingPreviewText /* dismissDelayed */); } - // Called from PointerTracker through the KeyboardActionListener interface - @Override - public void onFinishSlidingInput() { - // User finished sliding input. - mKeyboardSwitcher.onFinishSlidingInput(getCurrentAutoCapsState(), - getCurrentRecapitalizeState()); - } - - // Called from PointerTracker through the KeyboardActionListener interface - @Override - public void onCancelInput() { - // User released a finger outside any key - // Nothing to do so far. - } - public boolean hasSuggestionStripView() { return null != mSuggestionStripView; } @@ -1846,24 +1723,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen feedbackManager.performAudioFeedback(code); } - // Callback of the {@link KeyboardActionListener}. This is called when a key is depressed; - // release matching call is {@link #onReleaseKey(int,boolean)} below. - @Override - public void onPressKey(final int primaryCode, final int repeatCount, - final boolean isSinglePointer) { - mKeyboardSwitcher.onPressKey(primaryCode, isSinglePointer, getCurrentAutoCapsState(), - getCurrentRecapitalizeState()); - hapticAndAudioFeedback(primaryCode, repeatCount); - } - - // Callback of the {@link KeyboardActionListener}. This is called when a key is released; - // press matching call is {@link #onPressKey(int,int,boolean)} above. - @Override - public void onReleaseKey(final int primaryCode, final boolean withSliding) { - mKeyboardSwitcher.onReleaseKey(primaryCode, withSliding, getCurrentAutoCapsState(), - getCurrentRecapitalizeState()); - } - private HardwareEventDecoder getHardwareKeyEventDecoder(final int deviceId) { final HardwareEventDecoder decoder = mHardwareEventDecoders.get(deviceId); if (null != decoder) return decoder;