mirror of
https://github.com/florisboard/florisboard.git
synced 2024-09-19 19:42:20 +02:00
Re-implement composers into new editor instance logic
This commit is contained in:
parent
01de9a4ae1
commit
753fbc30df
@ -26,6 +26,8 @@ import android.view.KeyEvent
|
||||
import android.view.inputmethod.InputConnection
|
||||
import dev.patrickgold.florisboard.FlorisImeService
|
||||
import dev.patrickgold.florisboard.ime.nlp.BreakIteratorGroup
|
||||
import dev.patrickgold.florisboard.ime.text.composing.Composer
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionComponentName
|
||||
import dev.patrickgold.florisboard.lib.kotlin.guardedByLock
|
||||
import dev.patrickgold.florisboard.subtypeManager
|
||||
import kotlinx.coroutines.MainScope
|
||||
@ -40,7 +42,7 @@ abstract class AbstractEditorInstance(context: Context) {
|
||||
private const val NumCharsBeforeCursor: Int = 256
|
||||
private const val NumCharsAfterCursor: Int = 128
|
||||
private const val NumCharsSafeMarginBeforeCursor: Int = 128
|
||||
private const val NumCharsSafeMarginAfterCursor: Int = 0
|
||||
//private const val NumCharsSafeMarginAfterCursor: Int = 0
|
||||
|
||||
private const val CursorUpdateAll: Int =
|
||||
InputConnection.CURSOR_UPDATE_MONITOR or InputConnection.CURSOR_UPDATE_IMMEDIATE
|
||||
@ -235,6 +237,8 @@ abstract class AbstractEditorInstance(context: Context) {
|
||||
return generateContent(editorInfo, selection, textBeforeSelection, textAfterSelection, selectedText)
|
||||
}
|
||||
|
||||
abstract fun determineComposer(composerName: ExtensionComponentName): Composer
|
||||
|
||||
protected open fun shouldDetermineComposingRegion(editorInfo: FlorisEditorInfo): Boolean {
|
||||
return editorInfo.isRichInputEditor
|
||||
}
|
||||
@ -279,6 +283,42 @@ abstract class AbstractEditorInstance(context: Context) {
|
||||
return true
|
||||
}
|
||||
|
||||
open fun commitChar(char: String): Boolean {
|
||||
val content = activeContent
|
||||
val selection = content.selection
|
||||
// TODO: length enforcement to 1 may be an issue for some Unicode chars which are 2 Java chars
|
||||
if (char.length != 1 || selection.isNotValid || selection.isSelectionMode || activeInfo.isRawInputEditor) {
|
||||
return commitText(char)
|
||||
}
|
||||
val ic = currentInputConnection() ?: return false
|
||||
val composer = determineComposer(subtypeManager.activeSubtype().composer)
|
||||
val previous = content.textBeforeSelection.takeLast(composer.toRead)
|
||||
val (rm, finalText) = composer.getActions(previous, char[0])
|
||||
if (rm <= 0) {
|
||||
commitText(finalText)
|
||||
} else runBlocking {
|
||||
ic.beginBatchEdit()
|
||||
val newSelection = EditorRange.cursor(selection.start - rm + finalText.length)
|
||||
val newContent = content.generateCopy(
|
||||
selection = newSelection,
|
||||
textBeforeSelection = buildString {
|
||||
append(content.textBeforeSelection.dropLast(rm))
|
||||
append(finalText)
|
||||
},
|
||||
selectedText = "",
|
||||
)
|
||||
expectedContentQueue.push(newContent)
|
||||
// Utilize composing region to replace previous chars without using delete. This avoids flickering in the
|
||||
// target editor and improves the UX
|
||||
ic.setComposingRegion(content.selection.start - rm, content.selection.start)
|
||||
ic.setComposingText(finalText, 1)
|
||||
// Now set the proper composing region we expect
|
||||
ic.setComposingRegion(newContent.composing)
|
||||
ic.endBatchEdit()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
open fun commitText(text: String): Boolean {
|
||||
val ic = currentInputConnection() ?: return false
|
||||
val content = activeContent
|
||||
@ -288,7 +328,7 @@ abstract class AbstractEditorInstance(context: Context) {
|
||||
if (activeInfo.isRawInputEditor) {
|
||||
ic.commitText(text, 1)
|
||||
} else runBlocking {
|
||||
val newSelection = EditorRange(selection.start + text.length, selection.start + text.length)
|
||||
val newSelection = EditorRange.cursor(selection.start + text.length)
|
||||
val newContent = content.generateCopy(
|
||||
selection = newSelection,
|
||||
textBeforeSelection = buildString {
|
||||
|
@ -34,11 +34,14 @@ import dev.patrickgold.florisboard.ime.clipboard.provider.ItemType
|
||||
import dev.patrickgold.florisboard.ime.keyboard.KeyboardMode
|
||||
import dev.patrickgold.florisboard.ime.nlp.TextProcessor
|
||||
import dev.patrickgold.florisboard.ime.input.InputShiftState
|
||||
import dev.patrickgold.florisboard.ime.text.composing.Appender
|
||||
import dev.patrickgold.florisboard.ime.text.composing.Composer
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyVariation
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.android.AndroidVersion
|
||||
import dev.patrickgold.florisboard.lib.android.showShortToast
|
||||
import dev.patrickgold.florisboard.lib.devtools.flogDebug
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionComponentName
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
@ -141,6 +144,10 @@ class EditorInstance(context: Context) : AbstractEditorInstance(context) {
|
||||
super.handleFinishInputView()
|
||||
}
|
||||
|
||||
override fun determineComposer(composerName: ExtensionComponentName): Composer {
|
||||
return keyboardManager.resources.composers.value?.get(composerName) ?: Appender.DefaultInstance
|
||||
}
|
||||
|
||||
override fun shouldDetermineComposingRegion(editorInfo: FlorisEditorInfo): Boolean {
|
||||
return super.shouldDetermineComposingRegion(editorInfo) &&
|
||||
(phantomSpace.isInactive || phantomSpace.showComposingRegion)
|
||||
@ -161,6 +168,16 @@ class EditorInstance(context: Context) : AbstractEditorInstance(context) {
|
||||
return super.setSelection(selection)
|
||||
}
|
||||
|
||||
override fun commitChar(char: String): Boolean {
|
||||
val isPhantomSpaceActive = phantomSpace.determine(char)
|
||||
phantomSpace.setInactive()
|
||||
return if (isPhantomSpaceActive) {
|
||||
super.commitChar("$SPACE$char")
|
||||
} else {
|
||||
super.commitChar(char)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits the given [text] to this editor instance and adjusts both the cursor position and
|
||||
* composing region, if any.
|
||||
@ -220,31 +237,6 @@ class EditorInstance(context: Context) : AbstractEditorInstance(context) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal helper, replacing a call to currentInputConnection().commitText with text composition in mind.
|
||||
*/
|
||||
//private fun doCommitText(text: String): Pair<String, Boolean> {
|
||||
// val ic = currentInputConnection() ?: return "" to false
|
||||
// val composer = keyboardManager.resources.composers.value?.get(subtypeManager.activeSubtype().composer) ?: Appender()
|
||||
// return if (text.length != 1) {
|
||||
// ic.commitText(text, 1)
|
||||
// } else {
|
||||
// ic.beginBatchEdit()
|
||||
// ic.finishComposingText()
|
||||
// val previous = getTextBeforeCursor(composer.toRead)
|
||||
// val (rm, finalText) = composer.getActions(previous, text[0])
|
||||
// if (rm == 0) {
|
||||
// ic.commitText(finalText, 1)
|
||||
// } else {
|
||||
// val et = ic.getExtractedText(ExtractedTextRequest(), 0)
|
||||
// ic.setComposingRegion(et.selectionStart-rm, et.selectionStart)
|
||||
// ic.setComposingText(finalText, 1)
|
||||
// }
|
||||
// ic.endBatchEdit()
|
||||
// Pair(true, finalText)
|
||||
// }
|
||||
//}
|
||||
|
||||
/**
|
||||
* Commits the given [ClipboardItem]. If the clip data is text (incl. HTML), it delegates to [commitText].
|
||||
* If the item has a content URI (and the EditText supports it), the item is committed as rich data.
|
||||
|
@ -56,6 +56,8 @@ data class EditorRange(val start: Int, val end: Int) {
|
||||
/** Unspecified range */
|
||||
val Unspecified = EditorRange(-1, -1)
|
||||
|
||||
fun cursor(position: Int) = EditorRange(start = position, end = position)
|
||||
|
||||
fun normalized(start: Int, end: Int) = EditorRange(start = min(start, end), end = max(start, end))
|
||||
}
|
||||
}
|
||||
|
@ -710,7 +710,7 @@ class KeyboardManager(context: Context) : InputKeyEventReceiver {
|
||||
else -> when (data.type) {
|
||||
KeyType.CHARACTER, KeyType.NUMERIC ->{
|
||||
val text = data.asString(isForDisplay = false)
|
||||
editorInstance.commitText(text)
|
||||
editorInstance.commitChar(text)
|
||||
}
|
||||
else -> {
|
||||
flogError(LogTopic.KEY_EVENTS) { "Received unknown key: $data" }
|
||||
|
@ -17,6 +17,10 @@ interface Composer {
|
||||
@Serializable
|
||||
@SerialName("appender")
|
||||
class Appender : Composer {
|
||||
companion object {
|
||||
val DefaultInstance = Appender()
|
||||
}
|
||||
|
||||
override val id: String = "appender"
|
||||
override val label: String = "Appender"
|
||||
override val toRead: Int = 0
|
||||
|
Loading…
Reference in New Issue
Block a user