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:
parent
90162b2eb5
commit
2899bd9234
@ -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() }
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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" }
|
||||
|
@ -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
|
||||
|
@ -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]).
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user