0
0
mirror of https://github.com/florisboard/florisboard.git synced 2024-09-20 03:52:18 +02:00

Add support for multi-codepoint characters

This commit is contained in:
Patrick Goldinger 2021-04-29 20:21:30 +02:00
parent 90162b2eb5
commit 2899bd9234
5 changed files with 63 additions and 27 deletions

View File

@ -36,6 +36,7 @@ class AssetManager private constructor(val applicationContext: Context) {
polymorphic(KeyData::class) {
subclass(BasicTextKeyData::class, BasicTextKeyData.serializer())
subclass(AutoTextKeyData::class, AutoTextKeyData.serializer())
subclass(MultiTextKeyData::class, MultiTextKeyData.serializer())
subclass(EmojiKeyData::class, EmojiKeyData.serializer())
subclass(CaseSelector::class, CaseSelector.serializer())
subclass(VariationSelector::class, VariationSelector.serializer())
@ -44,6 +45,7 @@ class AssetManager private constructor(val applicationContext: Context) {
polymorphic(TextKeyData::class) {
subclass(BasicTextKeyData::class, BasicTextKeyData.serializer())
subclass(AutoTextKeyData::class, AutoTextKeyData.serializer())
subclass(MultiTextKeyData::class, MultiTextKeyData.serializer())
default { BasicTextKeyData.serializer() }
}
}

View File

@ -181,7 +181,7 @@ class PopupManager<V : View>(
* @param key Reference to the key currently controlling the popup.
*/
fun show(key: Key, keyHintMode: KeyHintMode) {
if (key is TextKey && key.computedData.code <= KeyCode.SPACE) {
if (key is TextKey && key.computedData.code <= KeyCode.SPACE && key.computedData.code != KeyCode.MULTIPLE_CODE_POINTS) {
return
}
@ -230,7 +230,7 @@ class PopupManager<V : View>(
* @param key Reference to the key currently controlling the popup.
*/
fun extend(key: Key, keyHintMode: KeyHintMode) {
if (key is TextKey && key.computedData.code <= KeyCode.SPACE
if (key is TextKey && key.computedData.code <= KeyCode.SPACE && key.computedData.code != KeyCode.MULTIPLE_CODE_POINTS
&& !exceptionsForKeyCodes.contains(key.computedData.code)) {
return
}

View File

@ -854,7 +854,7 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
KeyboardMode.PHONE2 -> when (data.type) {
KeyType.CHARACTER,
KeyType.NUMERIC -> {
val text = data.code.toChar().toString()
val text = data.asString(isForDisplay = false)
if (isGlidePostEffect && (CachedInput.isWordComponent(text) || text.isDigitsOnly())) {
activeEditorInstance.commitText(" ")
}
@ -863,7 +863,7 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
else -> when (data.code) {
KeyCode.PHONE_PAUSE,
KeyCode.PHONE_WAIT -> {
val text = data.code.toChar().toString()
val text = data.asString(isForDisplay = false)
if (isGlidePostEffect && (CachedInput.isWordComponent(text) || text.isDigitsOnly())) {
activeEditorInstance.commitText(" ")
}
@ -872,23 +872,12 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
}
}
else -> when (data.type) {
KeyType.CHARACTER, KeyType.NUMERIC -> when (data.code) {
KeyCode.URI_COMPONENT_TLD -> {
val tld = data.label.toLowerCase(Locale.ENGLISH)
activeEditorInstance.commitText(tld)
}
else -> {
var text = data.code.toChar().toString()
val locale = if (florisboard.activeSubtype.locale.language == "el") { Locale.getDefault() } else { florisboard.activeSubtype.locale }
text = when (caps && activeKeyboardMode == KeyboardMode.CHARACTERS) {
true -> text.toUpperCase(locale)
false -> text
}
if (isGlidePostEffect && (CachedInput.isWordComponent(text) || text.isDigitsOnly())) {
activeEditorInstance.commitText(" ")
}
activeEditorInstance.commitText(text)
KeyType.CHARACTER, KeyType.NUMERIC ->{
val text = data.asString(isForDisplay = false)
if (isGlidePostEffect && (CachedInput.isWordComponent(text) || text.isDigitsOnly())) {
activeEditorInstance.commitText(" ")
}
activeEditorInstance.commitText(text)
}
else -> {
flogError(LogTopic.KEY_EVENTS) { "Received unknown key: $data" }

View File

@ -98,6 +98,7 @@ object KeyCode {
const val CURRENCY_SLOT_6 = -806
const val INTERNAL_BATCH_EDIT = -901
const val MULTIPLE_CODE_POINTS = -902
const val KESHIDA = 1600
const val HALF_SPACE = 8204

View File

@ -35,12 +35,36 @@ interface TextKeyData : KeyData {
override fun asString(isForDisplay: Boolean): String {
return StringBuilder().run {
// Combining Diacritical Marks
// See: https://en.wikipedia.org/wiki/Combining_Diacritical_Marks
if (isForDisplay && code in 0x0300..0x036F) {
append("")
if (!isForDisplay && code == KeyCode.MULTIPLE_CODE_POINTS) {
if (this@TextKeyData is MultiTextKeyData) {
for (codePoint in codePoints) {
if (Character.isBmpCodePoint(codePoint)) {
append(codePoint.toChar())
} else {
try {
append(Character.toChars(codePoint))
} catch (_: Throwable) {
}
}
}
}
} else if (isForDisplay || code == KeyCode.URI_COMPONENT_TLD || code < KeyCode.SPACE) {
// Combining Diacritical Marks
// See: https://en.wikipedia.org/wiki/Combining_Diacritical_Marks
if (code in 0x0300..0x036F) {
append("")
}
append(label)
} else {
if (Character.isBmpCodePoint(code)) {
append(code.toChar())
} else {
try {
append(Character.toChars(code))
} catch (_: Throwable) {
}
}
}
append(label)
toString()
}
}
@ -322,9 +346,9 @@ class AutoTextKeyData(
val popup: PopupSet<TextKeyData>? = null
) : TextKeyData {
@Transient private val lower: BasicTextKeyData =
BasicTextKeyData(type, code, label.toLowerCase(Locale.getDefault()), groupId, popup)
BasicTextKeyData(type, Character.toLowerCase(code), label.toLowerCase(Locale.getDefault()), groupId, popup)
@Transient private val upper: BasicTextKeyData =
BasicTextKeyData(type, code, label.toUpperCase(Locale.getDefault()), groupId, popup)
BasicTextKeyData(type, Character.toUpperCase(code), label.toUpperCase(Locale.getDefault()), groupId, popup)
override fun computeTextKeyData(evaluator: TextComputingEvaluator): TextKeyData? {
return if (evaluator.isSlot(this)) {
@ -344,6 +368,26 @@ class AutoTextKeyData(
}
}
@Serializable
@SerialName("multi_text_key")
class MultiTextKeyData(
override val type: KeyType = KeyType.CHARACTER,
val codePoints: IntArray = intArrayOf(),
override val label: String = "",
override val groupId: Int = TextKeyData.GROUP_DEFAULT,
val popup: PopupSet<TextKeyData>? = null
) : TextKeyData {
@Transient override val code: Int = KeyCode.MULTIPLE_CODE_POINTS
override fun computeTextKeyData(evaluator: TextComputingEvaluator): TextKeyData {
return this
}
override fun toString(): String {
return "${AutoTextKeyData::class.simpleName} { type=$type code=$code label=\"$label\" groupId=$groupId }"
}
}
/**
* Data class for a single emoji (with possible emoji variants in [popup]).
*