From 312812147a0e7a4271a7aca4539950617386989b Mon Sep 17 00:00:00 2001 From: WhiredPlanck Date: Thu, 16 Jan 2025 22:44:30 +0800 Subject: [PATCH] refactor: make clear how to get and expand active text for command express --- .../main/java/com/osfans/trime/core/Rime.kt | 17 ++++-- .../java/com/osfans/trime/core/RimeApi.kt | 6 ++ .../trime/ime/core/TrimeInputMethodService.kt | 58 +++++++++++++------ .../keyboard/CommonKeyboardActionListener.kt | 39 +++++-------- 4 files changed, 74 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/com/osfans/trime/core/Rime.kt b/app/src/main/java/com/osfans/trime/core/Rime.kt index 0933e5eded..ea6100eb2c 100644 --- a/app/src/main/java/com/osfans/trime/core/Rime.kt +++ b/app/src/main/java/com/osfans/trime/core/Rime.kt @@ -15,7 +15,6 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.withContext import timber.log.Timber -import kotlin.system.measureTimeMillis /** * Rime JNI and instance methods @@ -41,6 +40,15 @@ class Rime : override var inputStatusCached = InputStatus() private set + override var compositionCached = RimeProto.Context.Composition() + private set + + override var menuCached = RimeProto.Context.Menu() + private set + + override var rawInputCached = "" + private set + private val dispatcher = RimeDispatcher( object : RimeDispatcher.RimeLooper { @@ -206,6 +214,9 @@ class Rime : } } inputContext = data.context // for compatibility + compositionCached = data.context.composition + menuCached = data.context.menu + rawInputCached = data.context.input } else -> {} } @@ -272,10 +283,6 @@ class Rime : @JvmStatic fun showAsciiPunch(): Boolean = inputStatus?.isAsciiPunch == true || inputStatus?.isAsciiMode == true - @JvmStatic - val composingText: String - get() = inputContext?.composition?.commitTextPreview ?: "" - @JvmStatic fun simulateKeySequence(sequence: CharSequence): Boolean { if (!sequence.first().isAsciiPrintable()) return false diff --git a/app/src/main/java/com/osfans/trime/core/RimeApi.kt b/app/src/main/java/com/osfans/trime/core/RimeApi.kt index efab204249..16b4e86053 100644 --- a/app/src/main/java/com/osfans/trime/core/RimeApi.kt +++ b/app/src/main/java/com/osfans/trime/core/RimeApi.kt @@ -17,6 +17,12 @@ interface RimeApi { val inputStatusCached: InputStatus + val compositionCached: RimeProto.Context.Composition + + val menuCached: RimeProto.Context.Menu + + val rawInputCached: String + suspend fun isEmpty(): Boolean suspend fun processKey( diff --git a/app/src/main/java/com/osfans/trime/ime/core/TrimeInputMethodService.kt b/app/src/main/java/com/osfans/trime/ime/core/TrimeInputMethodService.kt index edc38b2492..1c65f3ef45 100644 --- a/app/src/main/java/com/osfans/trime/ime/core/TrimeInputMethodService.kt +++ b/app/src/main/java/com/osfans/trime/ime/core/TrimeInputMethodService.kt @@ -31,6 +31,7 @@ import android.view.inputmethod.InlineSuggestionsResponse import android.widget.FrameLayout import androidx.annotation.Keep import androidx.core.content.ContextCompat +import androidx.core.view.inputmethod.EditorInfoCompat import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams import androidx.lifecycle.lifecycleScope @@ -38,7 +39,6 @@ import com.osfans.trime.BuildConfig import com.osfans.trime.R import com.osfans.trime.core.KeyModifiers import com.osfans.trime.core.KeyValue -import com.osfans.trime.core.Rime import com.osfans.trime.core.RimeApi import com.osfans.trime.core.RimeKeyMapping import com.osfans.trime.core.RimeMessage @@ -736,22 +736,6 @@ open class TrimeInputMethodService : LifecycleInputMethodService() { return true } - fun getActiveText(type: Int): String { - if (type == 2) return Rime.getRimeRawInput() ?: "" // 當前編碼 - var s = Rime.composingText // 當前候選 - if (s.isEmpty()) { - val ic = currentInputConnection - var cs = ic?.getSelectedText(0) // 選中字 - if (type == 1 && cs.isNullOrEmpty()) cs = lastCommittedText // 剛上屏字 - if (cs.isNullOrEmpty() && ic != null) { - cs = ic.getTextBeforeCursor(if (type == 4) 1024 else 1, 0) // 光標前字 - } - if (cs.isNullOrEmpty() && ic != null) cs = ic.getTextAfterCursor(1024, 0) // 光標後面所有字 - if (cs != null) s = cs.toString() - } - return s - } - private fun forwardKeyEvent(event: KeyEvent): Boolean { val modifiers = KeyModifiers.fromKeyEvent(event) val charCode = event.unicodeChar @@ -976,6 +960,46 @@ open class TrimeInputMethodService : LifecycleInputMethodService() { } } + fun getActiveText(type: Int): String { + if (type == 2) return rime.run { rawInputCached } // 當前編碼 + var text: CharSequence? = rime.run { compositionCached }.commitTextPreview // 當前候選 + if (text.isNullOrEmpty()) { + val info = currentInputEditorInfo + text = EditorInfoCompat.getInitialSelectedText(info, 0) // 選中字 + } + if (text.isNullOrEmpty()) { + if (type == 1) text = lastCommittedText // 剛上屏字 + } + if (text.isNullOrEmpty()) { + val step = if (type == 4) 1024 else 1 + text = getTextAroundCursor(step, before = true) + } + if (text.isNullOrEmpty()) { + text = getTextAroundCursor(before = false) + } + return text.toString() + } + + private fun getTextAroundCursor( + initialStep: Int = 1024, + before: Boolean, + ): String? { + val info = currentInputEditorInfo ?: return null + var step = initialStep + while (true) { + val text = + if (before) { + EditorInfoCompat.getInitialTextBeforeCursor(info, step, 0) + } else { + EditorInfoCompat.getInitialTextAfterCursor(info, step, 0) + } ?: return null + if (text.length < step) { + return text.toString() + } + step *= 2 + } + } + override fun onEvaluateFullscreenMode(): Boolean = false private var showingDialog: Dialog? = null diff --git a/app/src/main/java/com/osfans/trime/ime/keyboard/CommonKeyboardActionListener.kt b/app/src/main/java/com/osfans/trime/ime/keyboard/CommonKeyboardActionListener.kt index 7b82f63000..7b9debb7f9 100644 --- a/app/src/main/java/com/osfans/trime/ime/keyboard/CommonKeyboardActionListener.kt +++ b/app/src/main/java/com/osfans/trime/ime/keyboard/CommonKeyboardActionListener.kt @@ -60,6 +60,8 @@ class CommonKeyboardActionListener( /** Pattern for braced key event to capture `{Escape}` as group 2 */ private val BRACED_KEY_EVENT_WITH_ESCAPE = """^((\{Escape\})?[^{}]+).*$""".toRegex() + + private val PLACEHOLDER_PATTERN = Regex(".*(%([1-4]\\$)?s).*") } private val prefs = AppPrefs.defaultInstance() @@ -115,6 +117,18 @@ class CommonKeyboardActionListener( } } + private fun expandActiveText(input: String): String = + if (input.matches(PLACEHOLDER_PATTERN)) { + input.format( + service.getActiveText(1), + service.getActiveText(2), + service.getActiveText(3), + service.getActiveText(4), + ) + } else { + input + } + val listener by lazy { object : KeyboardActionListener { override fun onPress(keyEventCode: Int) { @@ -160,30 +174,7 @@ class CommonKeyboardActionListener( } } KeyEvent.KEYCODE_FUNCTION -> { // Command Express - // Comments from trime.yaml: - // %s或者%1$s爲當前字符 - // %2$s爲當前輸入的編碼 - // %3$s爲光標前字符 - // %4$s爲光標前所有字符 - var arg = action.option - val activeTextRegex = Regex(".*%(\\d*)\\$" + "s.*") - if (arg.matches(activeTextRegex)) { - var activeTextMode = - arg.replaceFirst(activeTextRegex, "$1").toDouble().toInt() - if (activeTextMode < 1) { - activeTextMode = 1 - } - val activeText = service.getActiveText(activeTextMode) - arg = - String.format( - arg, - service.lastCommittedText, - Rime.getRimeRawInput() ?: "", - activeText, - activeText, - ) - } - + val arg = expandActiveText(action.option) when (action.command) { "liquid_keyboard" -> { val target =