From e2999ada34618a08571a0853d8f5ec7b7029398b Mon Sep 17 00:00:00 2001 From: Aleksandras Kostarevas Date: Sun, 7 Jan 2024 16:20:20 +0200 Subject: [PATCH] Add undo, redo, paste actions --- java/res/drawable/clipboard.xml | 20 +++++++++++++++ java/res/drawable/redo.xml | 20 +++++++++++++++ java/res/drawable/undo.xml | 20 +++++++++++++++ java/res/values/strings-uix.xml | 3 +++ .../org/futo/inputmethod/latin/LatinIME.kt | 15 ++++++++++- .../latin/inputlogic/InputLogic.java | 14 +++++------ .../org/futo/inputmethod/latin/uix/Action.kt | 3 +++ .../futo/inputmethod/latin/uix/ActionBar.kt | 25 ++++++++++++------- .../latin/uix/actions/ClipboardAction.kt | 14 +++++++++++ .../latin/uix/actions/EmojiAction.kt | 5 ++-- .../latin/uix/actions/UndoRedoActions.kt | 22 ++++++++++++++++ 11 files changed, 142 insertions(+), 19 deletions(-) create mode 100644 java/res/drawable/clipboard.xml create mode 100644 java/res/drawable/redo.xml create mode 100644 java/res/drawable/undo.xml create mode 100644 java/src/org/futo/inputmethod/latin/uix/actions/ClipboardAction.kt create mode 100644 java/src/org/futo/inputmethod/latin/uix/actions/UndoRedoActions.kt diff --git a/java/res/drawable/clipboard.xml b/java/res/drawable/clipboard.xml new file mode 100644 index 000000000..e4cf2e78d --- /dev/null +++ b/java/res/drawable/clipboard.xml @@ -0,0 +1,20 @@ + + + + diff --git a/java/res/drawable/redo.xml b/java/res/drawable/redo.xml new file mode 100644 index 000000000..290274cdb --- /dev/null +++ b/java/res/drawable/redo.xml @@ -0,0 +1,20 @@ + + + + diff --git a/java/res/drawable/undo.xml b/java/res/drawable/undo.xml new file mode 100644 index 000000000..8ad21710b --- /dev/null +++ b/java/res/drawable/undo.xml @@ -0,0 +1,20 @@ + + + + diff --git a/java/res/values/strings-uix.xml b/java/res/values/strings-uix.xml index 579c94cef..ebd092013 100644 --- a/java/res/values/strings-uix.xml +++ b/java/res/values/strings-uix.xml @@ -2,6 +2,9 @@ Voice Input Theme Switcher + Paste from Clipboard + Undo + Redo AMOLED Dark Purple AOSP Material Dark diff --git a/java/src/org/futo/inputmethod/latin/LatinIME.kt b/java/src/org/futo/inputmethod/latin/LatinIME.kt index 10243c55c..c0e8827e0 100644 --- a/java/src/org/futo/inputmethod/latin/LatinIME.kt +++ b/java/src/org/futo/inputmethod/latin/LatinIME.kt @@ -5,6 +5,8 @@ import android.content.res.Configuration import android.inputmethodservice.InputMethodService import android.os.Build import android.os.Bundle +import android.os.SystemClock +import android.view.KeyCharacterMap import android.view.KeyEvent import android.view.View import android.view.inputmethod.CompletionInfo @@ -277,7 +279,9 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save @Composable private fun LegacyKeyboardView(hidden: Boolean) { val modifier = if(hidden) { - Modifier.clipToBounds().size(0.dp) + Modifier + .clipToBounds() + .size(0.dp) } else { Modifier.onSizeChanged { inputViewHeight = it.height @@ -703,6 +707,15 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save } } + override fun sendCodePointEvent(codePoint: Int) { + latinIMELegacy.onCodeInput(codePoint, NOT_A_COORDINATE, NOT_A_COORDINATE, false) + } + + override fun sendKeyEvent(keyCode: Int, metaState: Int) { + latinIMELegacy.mInputLogic.sendDownUpKeyEvent(keyCode, metaState) + } + + @RequiresApi(Build.VERSION_CODES.R) override fun onCreateInlineSuggestionsRequest(uiExtras: Bundle): InlineSuggestionsRequest { return createInlineSuggestionsRequest(this, this.activeColorScheme) diff --git a/java/src/org/futo/inputmethod/latin/inputlogic/InputLogic.java b/java/src/org/futo/inputmethod/latin/inputlogic/InputLogic.java index 41ff7f60b..96a3fcf11 100644 --- a/java/src/org/futo/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/org/futo/inputmethod/latin/inputlogic/InputLogic.java @@ -1132,7 +1132,7 @@ public final class InputLogic { // As for the case where we don't know the cursor position, it can happen // because of bugs in the framework. But the framework should know, so the next // best thing is to leave it to whatever it thinks is best. - sendDownUpKeyEvent(KeyEvent.KEYCODE_DEL); + sendDownUpKeyEvent(KeyEvent.KEYCODE_DEL, 0); int totalDeletedLength = 1; if (mDeleteCount > Constants.DELETE_ACCELERATE_AT) { // If this is an accelerated (i.e., double) deletion, then we need to @@ -1140,7 +1140,7 @@ public final class InputLogic { // the previous word, and will lose it after next deletion. hasUnlearnedWordBeingDeleted |= unlearnWordBeingDeleted( inputTransaction.mSettingsValues, currentKeyboardScriptId); - sendDownUpKeyEvent(KeyEvent.KEYCODE_DEL); + sendDownUpKeyEvent(KeyEvent.KEYCODE_DEL, 0); totalDeletedLength++; } StatsUtils.onBackspacePressed(totalDeletedLength); @@ -2021,13 +2021,13 @@ public final class InputLogic { * * @param keyCode the key code to send inside the key event. */ - private void sendDownUpKeyEvent(final int keyCode) { + public void sendDownUpKeyEvent(final int keyCode, final int metaState) { final long eventTime = SystemClock.uptimeMillis(); mConnection.sendKeyEvent(new KeyEvent(eventTime, eventTime, - KeyEvent.ACTION_DOWN, keyCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, + KeyEvent.ACTION_DOWN, keyCode, 0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE)); mConnection.sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime, - KeyEvent.ACTION_UP, keyCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, + KeyEvent.ACTION_UP, keyCode, 0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE)); } @@ -2045,7 +2045,7 @@ public final class InputLogic { // TODO: Remove this special handling of digit letters. // For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}. if (codePoint >= '0' && codePoint <= '9') { - sendDownUpKeyEvent(codePoint - '0' + KeyEvent.KEYCODE_0); + sendDownUpKeyEvent(codePoint - '0' + KeyEvent.KEYCODE_0, 0); return; } @@ -2055,7 +2055,7 @@ public final class InputLogic { // a hardware keyboard event on pressing enter or delete. This is bad for many // reasons (there are race conditions with commits) but some applications are // relying on this behavior so we continue to support it for older apps. - sendDownUpKeyEvent(KeyEvent.KEYCODE_ENTER); + sendDownUpKeyEvent(KeyEvent.KEYCODE_ENTER, 0); } else { mConnection.commitText(StringUtils.newSingleCodePointString(codePoint), 1); } diff --git a/java/src/org/futo/inputmethod/latin/uix/Action.kt b/java/src/org/futo/inputmethod/latin/uix/Action.kt index aa21b1bfd..20b606963 100644 --- a/java/src/org/futo/inputmethod/latin/uix/Action.kt +++ b/java/src/org/futo/inputmethod/latin/uix/Action.kt @@ -29,6 +29,9 @@ interface KeyboardManagerForAction { fun triggerSystemVoiceInput() fun updateTheme(newTheme: ThemeOption) + + fun sendCodePointEvent(codePoint: Int) + fun sendKeyEvent(keyCode: Int, metaState: Int) } interface ActionWindow { diff --git a/java/src/org/futo/inputmethod/latin/uix/ActionBar.kt b/java/src/org/futo/inputmethod/latin/uix/ActionBar.kt index df22b8249..8ffbe8a81 100644 --- a/java/src/org/futo/inputmethod/latin/uix/ActionBar.kt +++ b/java/src/org/futo/inputmethod/latin/uix/ActionBar.kt @@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyRow import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ColorScheme import androidx.compose.material3.Icon @@ -60,8 +61,11 @@ import org.futo.inputmethod.latin.SuggestedWords import org.futo.inputmethod.latin.SuggestedWords.SuggestedWordInfo import org.futo.inputmethod.latin.SuggestedWords.SuggestedWordInfo.KIND_TYPED import org.futo.inputmethod.latin.suggestions.SuggestionStripView +import org.futo.inputmethod.latin.uix.actions.ClipboardAction import org.futo.inputmethod.latin.uix.actions.EmojiAction +import org.futo.inputmethod.latin.uix.actions.RedoAction import org.futo.inputmethod.latin.uix.actions.ThemeAction +import org.futo.inputmethod.latin.uix.actions.UndoAction import org.futo.inputmethod.latin.uix.actions.VoiceInputAction import org.futo.inputmethod.latin.uix.theme.DarkColorScheme import org.futo.inputmethod.latin.uix.theme.UixThemeWrapper @@ -287,7 +291,7 @@ fun ActionItem(action: Action, onSelect: (Action) -> Unit) { cornerRadius = CornerRadius(radius, radius) ) } - .width(64.dp) + .width(50.dp) .fillMaxHeight(), colors = IconButtonDefaults.iconButtonColors(contentColor = contentCol) ) { @@ -317,12 +321,9 @@ fun RowScope.ActionItems(onSelect: (Action) -> Unit) { ActionItem(EmojiAction, onSelect) ActionItem(VoiceInputAction, onSelect) ActionItem(ThemeAction, onSelect) - - Box(modifier = Modifier - .fillMaxHeight() - .weight(1.0f)) { - - } + ActionItem(UndoAction, onSelect) + ActionItem(RedoAction, onSelect) + ActionItem(ClipboardAction, onSelect) } @@ -386,7 +387,11 @@ fun ActionBar( ExpandActionsButton(isActionsOpen.value) { isActionsOpen.value = !isActionsOpen.value } if(isActionsOpen.value) { - ActionItems(onActionActivated) + LazyRow { + item { + ActionItems(onActionActivated) + } + } } else if(inlineSuggestions.isNotEmpty() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { InlineSuggestions(inlineSuggestions) } else if(words != null) { @@ -399,7 +404,9 @@ fun ActionBar( Spacer(modifier = Modifier.weight(1.0f)) } - ActionItemSmall(VoiceInputAction, onActionActivated) + if(!isActionsOpen.value) { + ActionItemSmall(VoiceInputAction, onActionActivated) + } } } } diff --git a/java/src/org/futo/inputmethod/latin/uix/actions/ClipboardAction.kt b/java/src/org/futo/inputmethod/latin/uix/actions/ClipboardAction.kt new file mode 100644 index 000000000..07ee7f3f1 --- /dev/null +++ b/java/src/org/futo/inputmethod/latin/uix/actions/ClipboardAction.kt @@ -0,0 +1,14 @@ +package org.futo.inputmethod.latin.uix.actions + +import android.view.KeyEvent +import org.futo.inputmethod.latin.R +import org.futo.inputmethod.latin.uix.Action + +val ClipboardAction = Action( + icon = R.drawable.clipboard, + name = R.string.clipboard_action_title, + simplePressImpl = { manager, _ -> + manager.sendKeyEvent(KeyEvent.KEYCODE_V, KeyEvent.META_CTRL_ON) + }, + windowImpl = null, +) \ No newline at end of file diff --git a/java/src/org/futo/inputmethod/latin/uix/actions/EmojiAction.kt b/java/src/org/futo/inputmethod/latin/uix/actions/EmojiAction.kt index d23637fda..8cf36d093 100644 --- a/java/src/org/futo/inputmethod/latin/uix/actions/EmojiAction.kt +++ b/java/src/org/futo/inputmethod/latin/uix/actions/EmojiAction.kt @@ -55,6 +55,7 @@ import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive import org.futo.inputmethod.latin.R +import org.futo.inputmethod.latin.common.Constants import org.futo.inputmethod.latin.uix.Action import org.futo.inputmethod.latin.uix.ActionWindow import org.futo.inputmethod.latin.uix.PersistentActionState @@ -293,9 +294,9 @@ val EmojiAction = Action( }, onExit = { manager.closeActionWindow() }, onSpace = { - manager.typeText(" ") + manager.sendCodePointEvent(Constants.CODE_SPACE) }, onBackspace = { - manager.backspace(1) + manager.sendCodePointEvent(Constants.CODE_DELETE) }, bitmaps = state.bitmaps, emojis = emojis) } } diff --git a/java/src/org/futo/inputmethod/latin/uix/actions/UndoRedoActions.kt b/java/src/org/futo/inputmethod/latin/uix/actions/UndoRedoActions.kt new file mode 100644 index 000000000..09742728a --- /dev/null +++ b/java/src/org/futo/inputmethod/latin/uix/actions/UndoRedoActions.kt @@ -0,0 +1,22 @@ +package org.futo.inputmethod.latin.uix.actions + +import android.view.KeyEvent +import org.futo.inputmethod.latin.R +import org.futo.inputmethod.latin.uix.Action + +val UndoAction = Action( + icon = R.drawable.undo, + name = R.string.undo_action_title, + simplePressImpl = { manager, _ -> + manager.sendKeyEvent(KeyEvent.KEYCODE_Z, KeyEvent.META_CTRL_ON) + }, + windowImpl = null, +) +val RedoAction = Action( + icon = R.drawable.redo, + name = R.string.redo_action_title, + simplePressImpl = { manager, _ -> + manager.sendKeyEvent(KeyEvent.KEYCODE_Y, KeyEvent.META_CTRL_ON) + }, + windowImpl = null, +) \ No newline at end of file