Skip to content

Commit 20ea880

Browse files
committed
refactor: improve inline preedit update
refactor: add InlinePreeditMessage to split out inline preedit and compostion
1 parent 23158ee commit 20ea880

File tree

6 files changed

+108
-53
lines changed

6 files changed

+108
-53
lines changed

app/src/main/java/com/osfans/trime/core/Rime.kt

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import com.osfans.trime.BuildConfig
99
import com.osfans.trime.data.base.DataManager
1010
import com.osfans.trime.data.opencc.OpenCCDictManager
1111
import com.osfans.trime.data.prefs.AppPrefs
12+
import com.osfans.trime.ime.core.InlinePreeditMode
1213
import com.osfans.trime.util.appContext
1314
import com.osfans.trime.util.isStorageAvailable
1415
import kotlinx.coroutines.Job
@@ -68,6 +69,7 @@ class Rime :
6869
},
6970
)
7071

72+
private val inlinePreeditMode by AppPrefs.defaultInstance().general.inlinePreeditMode
7173
private val showAsciiSwitchTips by AppPrefs.defaultInstance().general.asciiSwitchTips
7274
private var lastAsciiTipsText = ""
7375
private var asciiSwitchTipsJob: Job? = null
@@ -207,7 +209,7 @@ class Rime :
207209
emitResponse()
208210
if (!handled) {
209211
handleRimeMessage(
210-
9, // RimeMessage.MessageType.Key,
212+
10, // RimeMessage.MessageType.Key,
211213
arrayOf(value, modifiers, isVirtual),
212214
)
213215
}
@@ -233,17 +235,37 @@ class Rime :
233235
) {
234236
handleRimeMessage(4, arrayOf(commit.invoke()))
235237
val context = getRimeContext()
236-
handleRimeMessage(5, arrayOf(context.composition))
238+
handlePreedit(context.composition)
237239
if (context.composition.length <= 0 && lastAsciiTipsText != asciiTipsText) {
238240
showAsciiSwitchTips()
239241
}
240242
if (getRimeOption("paging_mode")) {
241-
handleRimeMessage(6, arrayOf(context.menu))
243+
handleRimeMessage(7, arrayOf(context.menu))
242244
} else {
243245
val bulk = getRimeBulkCandidates()
244-
handleRimeMessage(8, bulk)
246+
handleRimeMessage(9, bulk)
245247
}
246-
handleRimeMessage(7, arrayOf(getRimeStatus()))
248+
handleRimeMessage(8, arrayOf(getRimeStatus()))
249+
}
250+
251+
private fun handlePreedit(composition: RimeProto.Context.Composition) {
252+
val mode = if (getRimeOption("no_inline_preedit")) {
253+
InlinePreeditMode.DISABLE
254+
} else {
255+
inlinePreeditMode
256+
}
257+
val inlinePreedit = when (mode) {
258+
InlinePreeditMode.DISABLE -> ""
259+
InlinePreeditMode.COMPOSING_TEXT -> composition.preedit ?: ""
260+
InlinePreeditMode.COMMIT_TEXT_PREVIEW -> composition.commitTextPreview ?: ""
261+
}
262+
val composition = if (mode == InlinePreeditMode.COMPOSING_TEXT) {
263+
RimeProto.Context.Composition()
264+
} else {
265+
composition
266+
}
267+
handleRimeMessage(5, arrayOf(inlinePreedit))
268+
handleRimeMessage(6, arrayOf(composition))
247269
}
248270

249271
private fun handleRimeMessage(it: RimeMessage<*>) {
@@ -315,7 +337,7 @@ class Rime :
315337
asciiSwitchTipsJob = lifecycleScope.launch {
316338
delay(1000L)
317339
val ctx = getRimeContext()
318-
handleRimeMessage(5, arrayOf(ctx.composition))
340+
handleRimeMessage(6, arrayOf(ctx.composition))
319341
}
320342
}
321343

app/src/main/java/com/osfans/trime/core/RimeMessage.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ sealed class RimeMessage<T>(
7373
override val messageType = MessageType.Commit
7474
}
7575

76+
data class InlinePreeditMessage(
77+
override val data: String,
78+
) : RimeMessage<String>(data) {
79+
override val messageType = MessageType.InlinePreedit
80+
}
81+
7682
data class CompositionMessage(
7783
override val data: RimeProto.Context.Composition,
7884
) : RimeMessage<RimeProto.Context.Composition>(data) {
@@ -142,6 +148,7 @@ sealed class RimeMessage<T>(
142148
Option,
143149
Deploy,
144150
Commit,
151+
InlinePreedit,
145152
Composition,
146153
Menu,
147154
Status,
@@ -176,6 +183,8 @@ sealed class RimeMessage<T>(
176183
)
177184
MessageType.Commit ->
178185
CommitTextMessage(params[0] as RimeProto.Commit)
186+
MessageType.InlinePreedit ->
187+
InlinePreeditMessage(params[0] as String)
179188
MessageType.Composition ->
180189
CompositionMessage(params[0] as RimeProto.Context.Composition)
181190
MessageType.Menu ->

app/src/main/java/com/osfans/trime/ime/composition/CandidatesView.kt

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import com.osfans.trime.data.theme.ColorManager
2727
import com.osfans.trime.data.theme.Theme
2828
import com.osfans.trime.ime.candidates.popup.PagedCandidatesUi
2929
import com.osfans.trime.ime.core.BaseInputView
30-
import com.osfans.trime.ime.core.InlinePreeditMode
3130
import com.osfans.trime.ime.core.TouchEventReceiverWindow
3231
import com.osfans.trime.ime.core.TrimeInputMethodService
3332
import splitties.dimensions.dp
@@ -57,8 +56,6 @@ class CandidatesView(
5756
private val layout by AppPrefs.defaultInstance().candidates.layout
5857
private val position by AppPrefs.defaultInstance().candidates.position
5958

60-
private val inlinePreeditMode by AppPrefs.defaultInstance().general.inlinePreeditMode
61-
6259
private var menu = RimeProto.Context.Menu()
6360
private var composition = RimeProto.Context.Composition()
6461

@@ -113,11 +110,7 @@ class CandidatesView(
113110
override fun handleRimeMessage(it: RimeMessage<*>) {
114111
when (it) {
115112
is RimeMessage.CompositionMessage -> {
116-
composition = if (inlinePreeditMode != InlinePreeditMode.DISABLE) {
117-
RimeProto.Context.Composition()
118-
} else {
119-
it.data
120-
}
113+
composition = it.data
121114
updateUi()
122115
}
123116
is RimeMessage.CandidateMenuMessage -> {

app/src/main/java/com/osfans/trime/ime/core/InputView.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -294,9 +294,7 @@ class InputView(
294294
}
295295
}
296296
is RimeMessage.CompositionMessage -> {
297-
val data = if (inlinePreeditMode != InlinePreeditMode.DISABLE ||
298-
candidatesMode == PopupCandidatesMode.ALWAYS_SHOW
299-
) {
297+
val data = if (candidatesMode == PopupCandidatesMode.ALWAYS_SHOW) {
300298
RimeProto.Context.Composition()
301299
} else {
302300
it.data

app/src/main/java/com/osfans/trime/ime/core/TrimeInputMethodService.kt

Lines changed: 67 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ import com.osfans.trime.core.KeyValue
3939
import com.osfans.trime.core.RimeApi
4040
import com.osfans.trime.core.RimeKeyMapping
4141
import com.osfans.trime.core.RimeMessage
42-
import com.osfans.trime.core.RimeProto
4342
import com.osfans.trime.daemon.RimeDaemon
4443
import com.osfans.trime.daemon.RimeSession
4544
import com.osfans.trime.data.prefs.AppPrefs
@@ -87,8 +86,11 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
8786
}
8887
private val rimeIntentReceiver = RimeIntentReceiver()
8988

90-
var lastCommittedText: CharSequence = ""
91-
private set
89+
private var lastCommittedText: String = ""
90+
91+
private var composingText: String = ""
92+
93+
private var cursorUpdateIndex = 0
9294

9395
private val recreateInputViewPrefs: Array<PreferenceDelegate<*>> =
9496
arrayOf(prefs.keyboard.hideInputBar)
@@ -191,7 +193,7 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
191193
commitText(it.data.text)
192194
}
193195
}
194-
is RimeMessage.CompositionMessage -> {
196+
is RimeMessage.InlinePreeditMessage -> {
195197
updateComposingText(it.data)
196198
}
197199
is RimeMessage.KeyMessage ->
@@ -405,18 +407,45 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
405407
candidatesStart,
406408
candidatesEnd,
407409
)
408-
if (candidatesEnd != -1 && (newSelStart != candidatesEnd || newSelEnd != candidatesEnd)) {
409-
// 移動光標時,更新候選區
410-
if (newSelEnd in candidatesStart..<candidatesEnd) {
411-
val newPosition = newSelEnd - candidatesStart
412-
postRimeJob { moveCursorPos(newPosition) }
410+
cursorUpdateIndex += 1
411+
handleCursorUpdate(newSelStart, newSelEnd, candidatesStart, candidatesEnd, cursorUpdateIndex)
412+
inputView?.updateSelection(newSelStart, newSelEnd)
413+
}
414+
415+
private fun handleCursorUpdate(
416+
newSelStart: Int,
417+
newSelEnd: Int,
418+
candidatesStart: Int,
419+
candidatesEnd: Int,
420+
updateIndex: Int,
421+
) {
422+
if (newSelStart != newSelEnd) return
423+
if (candidatesStart == candidatesEnd) {
424+
postRimeJob {
425+
if (isComposing) {
426+
Timber.d("handleCursorUpdate: commit composition")
427+
commitComposition()
428+
}
413429
}
430+
return
414431
}
415-
if (candidatesStart == -1 && candidatesEnd == -1 && newSelStart == 0 && newSelEnd == 0) {
416-
// 上屏後,清除候選區
417-
postRimeJob { clearComposition() }
432+
if (newSelStart in candidatesStart..candidatesEnd) {
433+
val position = newSelStart - candidatesStart
434+
if (position != composingText.length) {
435+
postRimeJob {
436+
if (updateIndex != cursorUpdateIndex) return@postRimeJob
437+
Timber.d("handleCursorUpdate: move rime cursor to $position")
438+
moveCursorPos(position)
439+
}
440+
}
441+
} else {
442+
Timber.d("handleCursorUpdate: clear composition")
443+
composingText = ""
444+
currentInputConnection?.finishComposingText()
445+
postRimeJob {
446+
clearComposition()
447+
}
418448
}
419-
inputView?.updateSelection(newSelStart, newSelEnd)
420449
}
421450

422451
private val inputViewLocation = intArrayOf(0, 0)
@@ -476,12 +505,15 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
476505
attribute: EditorInfo,
477506
restarting: Boolean,
478507
) {
508+
composingText = ""
479509
Timber.d("onStartInput: restarting=$restarting")
510+
val isNullType = attribute.inputType and InputType.TYPE_MASK_CLASS == InputType.TYPE_NULL
480511
postRimeJob {
481512
if (restarting) {
482513
// when input restarts in the same editor, clear previous composition
483514
clearComposition()
484515
}
516+
setRuntimeOption("no_inline_preedit", isNullType)
485517
}
486518
}
487519

@@ -531,25 +563,25 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
531563
finishComposingText()
532564
monitorCursorAnchor(false)
533565
}
566+
composingText = ""
534567
postRimeJob {
535568
clearComposition()
536569
}
537570
InputFeedbackManager.finishInput()
538571
}
539572

540-
// 直接commit不做任何处理
541-
fun commitText(
542-
text: CharSequence,
543-
clearMeatKeyState: Boolean = false,
544-
) {
573+
fun commitText(text: String) {
545574
val ic = currentInputConnection ?: return
546-
if (ic.commitText(text, 1)) {
547-
lastCommittedText = text
548-
}
549-
InputFeedbackManager.textCommitSpeak(text.toString())
550-
if (clearMeatKeyState) {
551-
ic.clearMetaKeyStates(KeyEvent.getModifierMetaStateMask())
575+
// when composing text equals commit content, finish composing text as-is
576+
if (composingText == text) {
577+
composingText = ""
578+
ic.finishComposingText()
579+
return
552580
}
581+
ic.commitText(text, 1)
582+
lastCommittedText = text
583+
composingText = ""
584+
InputFeedbackManager.textCommitSpeak(text)
553585
}
554586

555587
/**
@@ -877,19 +909,20 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
877909
}
878910
}
879911

880-
private val inlinePreeditMode by prefs.general.inlinePreeditMode
881-
882-
private fun updateComposingText(composition: RimeProto.Context.Composition) {
912+
private fun updateComposingText(text: String) {
883913
val ic = currentInputConnection ?: return
884-
val text =
885-
when (inlinePreeditMode) {
886-
InlinePreeditMode.DISABLE -> ""
887-
InlinePreeditMode.COMPOSING_TEXT -> composition.preedit ?: ""
888-
InlinePreeditMode.COMMIT_TEXT_PREVIEW -> composition.commitTextPreview ?: ""
914+
ic.beginBatchEdit()
915+
if (composingText.isNotEmpty() || text.isNotEmpty()) {
916+
if (!ic.getSelectedText(0).isNullOrEmpty()) {
917+
ic.deleteSurroundingText(1, 0)
889918
}
890-
if (ic.getSelectedText(0).isNullOrEmpty() || text.isNotEmpty()) {
891919
ic.setComposingText(text, 1)
920+
if (text.isEmpty()) {
921+
ic.finishComposingText()
922+
}
892923
}
924+
composingText = text
925+
ic.endBatchEdit()
893926
}
894927

895928
fun getActiveText(type: Int): String {
@@ -899,7 +932,7 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
899932
val preedit = rimeComposition.preedit ?: ""
900933
val beforeCursor = getTextAroundCursor(1024, before = true) ?: ""
901934
val afterCursor = getTextAroundCursor(before = false) ?: ""
902-
val lastCommitted = lastCommittedText.toString()
935+
val lastCommitted = lastCommittedText
903936

904937
return sequenceOf(
905938
when (type) {

app/src/main/java/com/osfans/trime/ime/keyboard/CommonKeyboardActionListener.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ class CommonKeyboardActionListener {
137137
override fun onAction(action: KeyAction) {
138138
val shouldHandle = when {
139139
action.commit.isNotEmpty() -> {
140-
service.commitText(action.commit, true)
140+
service.commitText(action.commit)
141141
false
142142
}
143143
KeyboardSwitcher.currentKeyboard.let { keyboard ->
@@ -248,7 +248,7 @@ class CommonKeyboardActionListener {
248248
clipboardManager.primaryClip
249249
?.getItemAt(0)
250250
?.coerceToText(service)
251-
?.let { service.commitText(it) }
251+
?.let { service.commitText(it.toString()) }
252252
}
253253

254254
private fun handleRunCommand(arg: String) {

0 commit comments

Comments
 (0)