use new parser for symbols layouts

This commit is contained in:
Helium314 2023-11-27 13:50:46 +01:00
parent 4d0b7915c8
commit 57bf742da0
45 changed files with 574 additions and 136 deletions

View file

@ -52,12 +52,10 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
mParams.mId = id
addLocaleKeyTextsToParams(mContext, mParams, Settings.getInstance().current.mShowMoreKeys)
try {
val parser = KeyboardParser.createParserForLayout(mParams, mContext) ?: return null
Log.d(TAG, "parsing $id using ${parser::class.simpleName}")
keysInRows = parser.parseLayoutFromAssets(id.mSubtype.keyboardLayoutSetName)
keysInRows = KeyboardParser.parseFromAssets(mParams, mContext) ?: return null
} catch (e: Throwable) {
if (DebugFlags.DEBUG_ENABLED || BuildConfig.DEBUG)
Toast.makeText(mContext, "error loading keyboard: ${e.message}", Toast.LENGTH_LONG).show()
Toast.makeText(mContext, "error parsing keyboard: ${e.message}", Toast.LENGTH_LONG).show()
Log.e(TAG, "loading $id from assets failed", e)
return null
}
@ -65,8 +63,14 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
return this
// todo: further plan
// migrate symbol layouts to this style
// simplified if possible, but json should be fine too
// add option for number row (latin first vs locale numbers first
// show only if number row enabled
// release next version before continuing
// migrate other languages to this style
// may be tricky in some cases, like additional row, or no shift key, or pc qwerty layout
// also the integrated number row might cause issues, and should be removed / ignored
// at least some of these layouts will need more complicated definition
// test the zwnj key
// migrate keypad layouts to this style
// will need more configurable layout definition -> another parser, or do it with compatible jsons
// allow users to define their own layouts (maybe migrate other layouts first?)
@ -105,12 +109,11 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
// write another parser, it should already consider split
// migrate moreKeys and moreSuggestions to this style?
// at least they should not make use of the KeyTextsSet/Table (and of the XmlKeyboardParser?)
// migrate other languages to this style
// may be difficult in some cases, like additional row, or no shift key, or pc qwerty layout
// also the (integrated) number row might cause issues
// at least some of these layouts will need more complicated definition, not just a simple text file
// some languages also change symbol view, e.g. fa changes symbols row 3
// add more layouts before doing this? or just keep the layout conversion script
// remove the old parser
// then finally the spanish/german/swiss/nordic layouts can be removed and replaced by some hasExtraKeys parameter
// also the eo check could then be removed
// and maybe the language -> layout thing could be moved to assets? and maybe even here the extra keys could be defined...
// should be either both in method.xml, or both in assets (actually method might be more suitable)
// labelFlags should be set correctly
// alignHintLabelToBottom: on lxx and rounded themes, but did not find what it actually does...
@ -145,7 +148,6 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
fun loadFromXml(xmlId: Int, id: KeyboardId): KeyboardBuilder<KP> {
if (Settings.getInstance().current.mUseNewKeyboardParsing
&& id.isAlphabetKeyboard
&& this::class == KeyboardBuilder::class // otherwise this will apply to moreKeys and moreSuggestions, and then some parameters are off
) {
if (loadFromAssets(id) != null)

View file

@ -2,7 +2,9 @@ package org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser
import android.content.Context
import android.content.res.Resources
import android.util.Log
import android.view.inputmethod.EditorInfo
import android.widget.Toast
import org.dslul.openboard.inputmethod.keyboard.Key
import org.dslul.openboard.inputmethod.keyboard.Key.KeyParams
import org.dslul.openboard.inputmethod.keyboard.KeyboardId
@ -12,9 +14,12 @@ import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams
import org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.floris.KeyData
import org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.floris.toTextKey
import org.dslul.openboard.inputmethod.latin.R
import org.dslul.openboard.inputmethod.latin.common.Constants
import org.dslul.openboard.inputmethod.latin.common.splitOnWhitespace
import org.dslul.openboard.inputmethod.latin.define.DebugFlags
import org.dslul.openboard.inputmethod.latin.utils.InputTypeUtils
import org.dslul.openboard.inputmethod.latin.utils.RunInLocale
import org.dslul.openboard.inputmethod.latin.utils.ScriptUtils
import org.dslul.openboard.inputmethod.latin.utils.sumOf
/**
@ -29,6 +34,9 @@ import org.dslul.openboard.inputmethod.latin.utils.sumOf
* Currently the number, phone and numpad layouts are not compatible with this parser.
*/
abstract class KeyboardParser(private val params: KeyboardParams, private val context: Context) {
private val defaultLabelFlags = if (!params.mId.isAlphabetKeyboard)
Key.LABEL_FLAGS_DISABLE_HINT_LABEL // reproduce the no-hints in symbol layouts, todo: add setting
else 0
protected abstract fun getLayoutFromAssets(layoutName: String): String
@ -42,9 +50,13 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
val keysInRows = ArrayList<ArrayList<KeyParams>>()
val baseKeys: MutableList<List<KeyData>> = parseCoreLayout(layoutContent)
if (!params.mId.mNumberRowEnabled) {
// todo (non-latin): not all layouts have numbers on first row, so maybe have some layout flag to switch it off (or an option)
((1..9) + 0).forEachIndexed { i, n -> baseKeys.first().getOrNull(i)?.popup?.number = n }
if (!params.mId.mNumberRowEnabled && params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS) {
// replace first symbols row with number row
baseKeys[0] = params.mLocaleKeyTexts.getNumberRow()
} else if (!params.mId.mNumberRowEnabled && params.mId.isAlphabetKeyboard) {
// add number to the first 10 keys in first row
// setting the correct moreKeys is handled in PopupSet
baseKeys.first().take(10).forEachIndexed { index, keyData -> keyData.popup.numberIndex = index }
}
val functionalKeysReversed = parseFunctionalKeys().reversed()
@ -62,7 +74,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
}
// parse functional keys for this row (if any)
val functionalKeysDefs = if (i < functionalKeysReversed.size) functionalKeysReversed[i]
else emptyList<String>() to emptyList()
else emptyList<String>() to emptyList()
val functionalKeysLeft = functionalKeysDefs.first.map { getFunctionalKeyParams(it) }
val functionalKeysRight = functionalKeysDefs.second.map { getFunctionalKeyParams(it) }
val paramsRow = ArrayList<KeyParams>(functionalKeysLeft)
@ -98,7 +110,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
for (key in row) {
// todo: maybe autoScale / autoXScale if label has more than 2 characters (exception for emojis?)
// but that could also be determined in toKeyParams
val keyParams = key.compute(params)?.toKeyParams(params, keyWidth) ?: continue
val keyParams = key.compute(params)?.toKeyParams(params, keyWidth, defaultLabelFlags) ?: continue
paramsRow.add(keyParams)
}
if (spacerWidth != 0f) {
@ -165,7 +177,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
else -> 2 // must be alphabet, parser doesn't work for other elementIds
}
val adjustedKeys = if (baseKeys.last().size == adjustableKeyCount) baseKeys.last()
else null
else null
if (adjustedKeys != null)
baseKeys.removeLast()
val bottomRow = ArrayList<KeyParams>()
@ -185,25 +197,25 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
adjustedKeys?.get(1)?.label ?: "/",
params,
params.mDefaultRelativeKeyWidth,
0,
defaultLabelFlags,
Key.BACKGROUND_TYPE_FUNCTIONAL,
adjustedKeys?.get(1)?.popup?.toMoreKeys(params)
))
} else if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) {
bottomRow.add(KeyParams(
adjustedKeys?.get(1)?.label ?: "<",
(adjustedKeys?.get(1)?.label ?: "<").rtlLabel(params),
params,
params.mDefaultRelativeKeyWidth,
0,
defaultLabelFlags,
Key.BACKGROUND_TYPE_FUNCTIONAL,
adjustedKeys?.get(1)?.popup?.toMoreKeys(params)
))
bottomRow.add(keyParams)
bottomRow.add(KeyParams(
adjustedKeys?.get(2)?.label ?: ">",
(adjustedKeys?.get(2)?.label ?: ">").rtlLabel(params),
params,
params.mDefaultRelativeKeyWidth,
0,
defaultLabelFlags,
Key.BACKGROUND_TYPE_FUNCTIONAL,
adjustedKeys?.get(2)?.popup?.toMoreKeys(params)
))
@ -214,7 +226,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
bottomRow.add(getFunctionalKeyParams(FunctionalKey.EMOJI))
bottomRow.add(keyParams)
if (params.mId.locale.language in languagesThatNeedZwnjKey)
bottomRow.add(getFunctionalKeyParams(FunctionalKey.ZWNJ)) // todo (non-latin): test it
bottomRow.add(getFunctionalKeyParams(FunctionalKey.ZWNJ))
}
} else {
bottomRow.add(keyParams)
@ -226,20 +238,10 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
return bottomRow
}
private fun getNumberRow(): ArrayList<KeyParams> {
val row = ArrayList<KeyParams>()
((1..9) + 0).forEachIndexed { i, n ->
row.add(KeyParams(
n.toString(), // todo (non-latin): use language more keys to adjust, possibly in combination with some setting
params,
params.mDefaultRelativeKeyWidth,
Key.LABEL_FLAGS_DISABLE_HINT_LABEL, // todo (later): maybe optional or enable (but then all numbers should have moreKeys)
Key.BACKGROUND_TYPE_NORMAL,
numbersMoreKeys[i] // todo (non-latin): alternative numbers should be in language more keys, which to put where needs to be decided
))
private fun getNumberRow(): ArrayList<KeyParams> =
params.mLocaleKeyTexts.getNumberRow().mapTo(ArrayList()) {
it.toKeyParams(params, labelFlags = Key.LABEL_FLAGS_DISABLE_HINT_LABEL or defaultLabelFlags)
}
return row
}
private fun getFunctionalKeyParams(def: String, label: String? = null, moreKeys: Array<String>? = null): KeyParams {
val split = def.trim().splitOnWhitespace()
@ -254,7 +256,17 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
val width = relativeWidth ?: params.mDefaultRelativeKeyWidth
return when (key) {
FunctionalKey.SYMBOL -> KeyParams(
"${getSymbolLabel()}|!code/key_switch_alpha_symbol", // todo (later): in numpad the code is key_symbolNumpad
getToSymbolLabel(),
getToSymbolCode(),
params,
width,
Key.LABEL_FLAGS_PRESERVE_CASE or Key.LABEL_FLAGS_FOLLOW_FUNCTIONAL_TEXT_COLOR,
Key.BACKGROUND_TYPE_FUNCTIONAL,
null
)
FunctionalKey.ALPHA -> KeyParams(
params.mLocaleKeyTexts.labelAlphabet,
getToAlphaCode(),
params,
width,
Key.LABEL_FLAGS_PRESERVE_CASE or Key.LABEL_FLAGS_FOLLOW_FUNCTIONAL_TEXT_COLOR,
@ -262,15 +274,23 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
null
)
FunctionalKey.COMMA -> KeyParams(
label ?: getDefaultCommaLabel(),
label ?: getCommaLabel(),
params,
width,
Key.LABEL_FLAGS_HAS_POPUP_HINT, // previously only if normal comma, but always is more correct
if (label?.first()
?.isLetter() == true
) Key.BACKGROUND_TYPE_NORMAL else Key.BACKGROUND_TYPE_FUNCTIONAL,
if (label?.first()?.isLetter() == true) Key.BACKGROUND_TYPE_NORMAL // mimic behavior of old dvorak and halmak layouts
else Key.BACKGROUND_TYPE_FUNCTIONAL,
moreKeys?.let { getCommaMoreKeys() + it } ?: getCommaMoreKeys()
)
FunctionalKey.PERIOD -> KeyParams(
label ?: params.mLocaleKeyTexts.labelPeriod,
params,
width,
Key.LABEL_FLAGS_HAS_POPUP_HINT or Key.LABEL_FLAGS_HAS_SHIFTED_LETTER_HINT or defaultLabelFlags, // todo (later): check what LABEL_FLAGS_HAS_SHIFTED_LETTER_HINT does, maybe remove the flag here
if (label?.first()?.isLetter() == true) Key.BACKGROUND_TYPE_NORMAL
else Key.BACKGROUND_TYPE_FUNCTIONAL,
moreKeys?.let { getPunctuationMoreKeys() + it } ?: getPunctuationMoreKeys()
)
FunctionalKey.SPACE -> KeyParams(
"!icon/space_key|!code/key_space", // !icon/space_key_for_number_layout in number layout, but not on tablet
params,
@ -279,16 +299,6 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
Key.BACKGROUND_TYPE_SPACEBAR,
null
)
FunctionalKey.PERIOD -> KeyParams(
label ?: ".",
params,
width,
Key.LABEL_FLAGS_HAS_POPUP_HINT or Key.LABEL_FLAGS_HAS_SHIFTED_LETTER_HINT, // todo (later): check what LABEL_FLAGS_HAS_SHIFTED_LETTER_HINT does, maybe remove the flag here
if (label?.first()
?.isLetter() == true
) Key.BACKGROUND_TYPE_NORMAL else Key.BACKGROUND_TYPE_FUNCTIONAL,
moreKeys?.let { getPunctuationMoreKeys() + it } ?: getPunctuationMoreKeys()
)
FunctionalKey.ACTION -> KeyParams(
"${getActionKeyLabel()}|${getActionKeyCode()}",
params,
@ -348,14 +358,6 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
Key.BACKGROUND_TYPE_FUNCTIONAL,
null
)
FunctionalKey.ALPHA -> KeyParams(
"${getAlphabetLabel()}|!code/key_switch_alpha_symbol", // todo (later): in numpad the code is key_alphaNumpad
params,
width,
Key.LABEL_FLAGS_PRESERVE_CASE or Key.LABEL_FLAGS_FOLLOW_FUNCTIONAL_TEXT_COLOR,
Key.BACKGROUND_TYPE_FUNCTIONAL,
null
)
FunctionalKey.NUMPAD -> KeyParams(
"!icon/numpad_key|!code/key_numpad",
params,
@ -460,34 +462,51 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
private fun String.replaceIconWithLabelIfNoDrawable(): String {
if (params.mIconsSet.getIconDrawable(KeyboardIconsSet.getIconId(this)) != null) return this
val id = context.resources.getIdentifier("label_$this", "string", context.packageName)
if (id == 0) {
Log.w(this::class.simpleName, "no resource for label $this")
if (DebugFlags.DEBUG_ENABLED)
Toast.makeText(context, "no resource for label $this", Toast.LENGTH_LONG).show()
return this
}
val ril = object : RunInLocale<String>() { // todo (later): simpler way of doing this in a single line?
override fun job(res: Resources) = res.getString(id)
}
return ril.runInLocale(context.resources, params.mId.locale)
}
private fun getAlphabetLabel() = params.mLocaleKeyTexts.labelAlphabet
private fun getToSymbolLabel() =
if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS || params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED)
params.mLocaleKeyTexts.labelAlphabet
else params.mLocaleKeyTexts.labelSymbol
private fun getSymbolLabel() = params.mLocaleKeyTexts.labelSymbols
private fun getToSymbolCode() =
if (params.mId.mElementId == KeyboardId.ELEMENT_NUMPAD)
Constants.CODE_SYMBOL_FROM_NUMPAD
else Constants.CODE_SWITCH_ALPHA_SYMBOL
private fun getToAlphaCode() =
if (params.mId.mElementId == KeyboardId.ELEMENT_NUMPAD)
Constants.CODE_ALPHA_FROM_NUMPAD
else Constants.CODE_SWITCH_ALPHA_SYMBOL
private fun getShiftLabel(): String {
val elementId = params.mId.mElementId
if (elementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED)
return params.mLocaleKeyTexts.labelShiftSymbols
return params.mLocaleKeyTexts.labelSymbol
if (elementId == KeyboardId.ELEMENT_SYMBOLS)
return getSymbolLabel()
return params.mLocaleKeyTexts.labelShiftSymbol
if (elementId == KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED || elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED
|| elementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED || elementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED)
return "!icon/shift_key_shifted"
return "!icon/shift_key"
}
private fun getDefaultCommaLabel(): String {
private fun getCommaLabel(): String {
if (params.mId.mMode == KeyboardId.MODE_URL)
return "/"
if (params.mId.mMode == KeyboardId.MODE_EMAIL)
return "\\@"
return ","
return params.mLocaleKeyTexts.labelComma
}
private fun getCommaMoreKeys(): Array<String> {
@ -509,8 +528,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS || params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED)
return arrayOf("")
val moreKeys = params.mLocaleKeyTexts.getMoreKeys("punctuation") ?:
// todo: some (non-latin) languages have different parenthesis keys (maybe rtl has inverted?)
arrayOf("${Key.MORE_KEYS_AUTO_COLUMN_ORDER}8", "\\,", "?", "!", "#", ")", "(", "/", ";", "'", "@", ":", "-", "\"", "+", "\\%", "&")
arrayOf("${Key.MORE_KEYS_AUTO_COLUMN_ORDER}8", "\\,", "?", "!", "#", ")", "(", "/", ";", "'", "@", ":", "-", "\"", "+", "\\%", "&")
if (context.resources.getInteger(R.integer.config_screen_metrics) >= 3 && moreKeys.contains("!") && moreKeys.contains("?")) {
// we have a tablet, remove ! and ? keys and reduce number in autoColumnOrder
// this makes use of removal of empty moreKeys in MoreKeySpec.insertAdditionalMoreKeys
@ -524,19 +542,26 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
}
companion object {
fun createParserForLayout(params: KeyboardParams, context: Context): KeyboardParser? {
fun parseFromAssets(params: KeyboardParams, context: Context): ArrayList<ArrayList<KeyParams>>? {
val id = params.mId
val layoutName = params.mId.mSubtype.keyboardLayoutSetName
val layoutFileNames = context.assets.list("layouts") ?: return null
if (layoutFileNames.contains("$layoutName.json"))
return JsonKeyboardParser(params, context)
val simpleLayoutName = getSimpleLayoutName(layoutName)
if (layoutFileNames.contains("$simpleLayoutName.txt"))
return SimpleKeyboardParser(params, context)
return null
return when {
id.mElementId == KeyboardId.ELEMENT_SYMBOLS && ScriptUtils.getScriptFromSpellCheckerLocale(params.mId.locale) == ScriptUtils.SCRIPT_ARABIC
-> SimpleKeyboardParser(params, context).parseLayoutFromAssets("symbols_arabic")
id.mElementId == KeyboardId.ELEMENT_SYMBOLS -> SimpleKeyboardParser(params, context).parseLayoutFromAssets("symbols")
id.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED
-> SimpleKeyboardParser(params, context).parseLayoutFromAssets("symbols_shifted")
!id.isAlphabetKeyboard -> null
layoutFileNames.contains("$layoutName.json") -> JsonKeyboardParser(params, context).parseLayoutFromAssets(layoutName)
layoutFileNames.contains("${getSimpleLayoutName(layoutName)}.txt")
-> SimpleKeyboardParser(params, context).parseLayoutFromAssets(layoutName)
else -> null
}
}
@JvmStatic // unsupported without JvmStatic
protected fun getSimpleLayoutName(layoutName: String)= when (layoutName) {
protected fun getSimpleLayoutName(layoutName: String) = when (layoutName) {
"swiss", "german", "serbian_qwertz" -> "qwertz"
"nordic", "spanish" -> "qwerty"
else -> layoutName
@ -548,20 +573,29 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
}
}
// moreKeys for numbers, order is 1-9 and then 0
// todo (later): like numbers, for non-latin layouts this depends on language and therefore should not be in the parser
private val numbersMoreKeys = arrayOf(
arrayOf("¹", "½", "","¼", ""),
arrayOf("²", ""),
arrayOf("³", "¾", ""),
arrayOf(""),
arrayOf(""),
null,
arrayOf(""),
null,
null,
arrayOf("", ""),
)
fun String.rtlLabel(params: KeyboardParams): String {
if (!params.mId.mSubtype.isRtlSubtype) return this
return when (this) {
"{" -> "{|}"
"}" -> "}|{"
"(" -> "(|)"
")" -> ")|("
"[" -> "{|]"
"]" -> "]|["
"<" -> "<|>"
">" -> ">|<"
"" -> "≤|≥"
"" -> "≥|≤"
"«" -> "«|»"
"»" -> "»|«"
"" -> "|"
"" -> "|"
"" -> "|﴿"
"﴿" -> "﴿|"
else -> this
}
}
// could make arrays right away, but they need to be copied anyway as moreKeys arrays are modified when creating KeyParams
private const val MORE_KEYS_NAVIGATE_PREVIOUS = "!icon/previous_key|!code/key_action_previous,!icon/clipboard_action_key|!code/key_clipboard"

View file

@ -11,12 +11,34 @@ import java.io.InputStream
import java.util.Locale
import kotlin.math.round
class LocaleKeyTexts(dataStream: InputStream?) {
class LocaleKeyTexts(dataStream: InputStream?, locale: Locale) {
private val moreKeys = hashMapOf<String, Array<String>>()
private val extraKeys = Array<MutableList<KeyData>?>(5) { null }
var labelSymbols = "\\?123"
var labelSymbol = "\\?123"
private set
var labelAlphabet = "ABC"
var labelShiftSymbols = "=\\<"
private set
var labelShiftSymbol = "= \\\\ <"
private set
var labelComma = ","
private set
var labelPeriod = "."
private set
val currencyKey = getCurrencyKey(locale)
private var numberKeys = ((1..9) + 0).map { it.toString() }
private val numbersMoreKeys = arrayOf(
mutableListOf("¹", "½", "","¼", ""),
mutableListOf("²", ""),
mutableListOf("³", "¾", ""),
mutableListOf(""),
mutableListOf(""),
mutableListOf(),
mutableListOf(""),
mutableListOf(),
mutableListOf(),
mutableListOf("", ""),
)
init {
readStream(dataStream, false)
// set default quote moreKeys if necessary
@ -42,11 +64,13 @@ class LocaleKeyTexts(dataStream: InputStream?) {
"[morekeys]" -> { mode = READER_MODE_MORE_KEYS; return@forEachLine }
"[extra_keys]" -> { mode = READER_MODE_EXTRA_KEYS; return@forEachLine }
"[labels]" -> { mode = READER_MODE_LABELS; return@forEachLine }
"[number_row]" -> { mode = READER_MODE_NUMBER_ROW; return@forEachLine }
}
when (mode) {
READER_MODE_MORE_KEYS -> addMoreKeys(line.splitOnWhitespace())
READER_MODE_EXTRA_KEYS -> if (!onlyMoreKeys) addExtraKey(line.split(colonSpaceRegex, 2))
READER_MODE_LABELS -> if (!onlyMoreKeys) addLabel(line.split(colonSpaceRegex, 2))
READER_MODE_NUMBER_ROW -> if (!onlyMoreKeys) setNumberRow(line.splitOnWhitespace())
}
}
}
@ -55,6 +79,7 @@ class LocaleKeyTexts(dataStream: InputStream?) {
// need tp provide a copy because some functions like MoreKeySpec.insertAdditionalMoreKeys may modify the array
fun getMoreKeys(label: String): Array<String>? = moreKeys[label]?.copyOf()
// used by simple parser only, but could be possible for json as well (if necessary)
fun getExtraKeys(row: Int): List<KeyData>? =
if (row > extraKeys.size) null
else extraKeys[row]
@ -84,11 +109,33 @@ class LocaleKeyTexts(dataStream: InputStream?) {
private fun addLabel(split: List<String>) {
if (split.size < 2) return
when (split.first()) {
"symbols" -> labelSymbols = split.last()
"symbol" -> labelSymbol = split.last()
"alphabet" -> labelAlphabet = split.last()
"shift_symbols" -> labelShiftSymbols = split.last()
"shift_symbol" -> labelShiftSymbol = split.last() // never used, but could be...
"comma" -> labelComma = split.last()
"period" -> labelPeriod = split.last()
}
}
// set number row only, does not affect moreKeys
// setting more than 10 number keys will cause crashes, but could actually be implemented at some point
private fun setNumberRow(split: List<String>) {
if (numberKeys == split) return
numberKeys.forEachIndexed { i, n -> numbersMoreKeys[i].add(0, n) }
numberKeys = split
}
// get number row including moreKeys
fun getNumberRow(): List<KeyData> =
numberKeys.mapIndexed { i, label ->
label.toTextKey(numbersMoreKeys[i])
}
// get moreKeys with the number itself (as used on alphabet keyboards)
fun getNumberMoreKeys(numberIndex: Int?): List<String> {
if (numberIndex == null) return emptyList()
return listOf(numberKeys[numberIndex]) + numbersMoreKeys[numberIndex]
}
}
private fun mergeMoreKeys(original: Array<String>, added: List<String>): Array<String> {
@ -141,7 +188,7 @@ fun addLocaleKeyTextsToParams(context: Context, params: KeyboardParams, moreKeys
}
private fun createLocaleKeyTexts(context: Context, params: KeyboardParams, moreKeysSetting: Int): LocaleKeyTexts {
val lkt = LocaleKeyTexts(getStreamForLocale(params.mId.locale, context))
val lkt = LocaleKeyTexts(getStreamForLocale(params.mId.locale, context), params.mId.locale)
if (moreKeysSetting == MORE_KEYS_MORE)
lkt.addFile(context.assets.open("$LANGUAGE_TEXTS_FOLDER/all_more_keys.txt"))
else if (moreKeysSetting == MORE_KEYS_ALL)
@ -174,16 +221,17 @@ private const val READER_MODE_NONE = 0
private const val READER_MODE_MORE_KEYS = 1
private const val READER_MODE_EXTRA_KEYS = 2
private const val READER_MODE_LABELS = 3
private const val READER_MODE_NUMBER_ROW = 4
// probably could be improved and extended, currently this is what's done in key_styles_currency.xml
fun getCurrencyKey(locale: Locale): Pair<String, Array<String>> {
private fun getCurrencyKey(locale: Locale): Pair<String, Array<String>> {
if (locale.country.matches(euroCountries))
return euro
if (locale.toString().matches(euroLocales))
return euro
if (locale.language.matches("ca|eu|lb|mt".toRegex()))
return euro
if (locale.language.matches("fa|iw|ko|lo|mn|ne|th|uk|vi".toRegex()))
if (locale.language.matches("fa|iw|ko|lo|mn|ne|si|th|uk|vi|km".toRegex()))
return genericCurrencyKey(getCurrency(locale))
if (locale.language == "hy")
return dram
@ -193,6 +241,8 @@ fun getCurrencyKey(locale: Locale): Pair<String, Array<String>> {
return ruble
if (locale.country == "LK" || locale.country == "BD")
return genericCurrencyKey(getCurrency(locale))
if (locale.country == "IN" && locale.language == "ta")
return genericCurrencyKey("")
if (locale.country == "IN" || locale.language.matches("hi|kn|ml|mr|ta|te".toRegex()))
return rupee
if (locale.country == "GB")
@ -217,6 +267,7 @@ private fun getCurrency(locale: Locale): String {
"th" -> "฿"
"uk" -> ""
"vi" -> ""
"km" -> ""
else -> "$"
}
}

View file

@ -16,7 +16,7 @@ import org.dslul.openboard.inputmethod.latin.common.splitOnWhitespace
*/
class SimpleKeyboardParser(private val params: KeyboardParams, private val context: Context) : KeyboardParser(params, context) {
private val addExtraKeys =
params.mId.locale.language != "eo"
params.mId.isAlphabetKeyboard && params.mId.locale.language != "eo"
&& params.mId.mSubtype.keyboardLayoutSetName in listOf("nordic", "spanish", "german", "swiss", "serbian_qwertz")
override fun getLayoutFromAssets(layoutName: String) =

View file

@ -11,6 +11,7 @@ import org.dslul.openboard.inputmethod.keyboard.Key
import org.dslul.openboard.inputmethod.keyboard.Key.KeyParams
import org.dslul.openboard.inputmethod.keyboard.KeyboardId
import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams
import org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.rtlLabel
import org.dslul.openboard.inputmethod.latin.common.StringUtils
// taken from FlorisBoard, small modifications
@ -113,7 +114,7 @@ interface KeyData : AbstractKeyData {
// code will be determined from label if possible (i.e. label is single code point)
// but also longer labels should work without issues, also for MultiTextKeyData
KeyParams(
label, // todo (when supported): convert special labels to keySpec
label.rtlLabel(params), // todo (when supported): convert special labels to keySpec
params,
width,
labelFlags, // todo (non-latin): label flags... maybe relevant for some languages
@ -123,7 +124,7 @@ interface KeyData : AbstractKeyData {
} else {
KeyParams(
label.ifEmpty { StringUtils.newSingleCodePointString(code) },
code, // todo (when supported): convert codes < 0
code, // todo (when supported): convert codes < 0, because florisboard layouts should still be usable
params,
width,
labelFlags,

View file

@ -6,12 +6,12 @@ package org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.floris
import kotlinx.serialization.Serializable
import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams
import org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.getCurrencyKey
import org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.rtlLabel
// taken from FlorisBoard, small modifications
// mutable set removed (currently the moreKeys assembly is happening in KeyParams)
// toMoreKeys and size added
// popupKeys not used, but might switch to this later
// .toMoreKeys added
// PopupKeys not used, but might switch to this later
// currently hint would be taken from other, and languageMoreKeys are prioritized
/**
* A popup set for a single key. This set describes, if the key has a [main] character and other [relevant] popups.
@ -29,23 +29,27 @@ open class PopupSet<T : AbstractKeyData>(
// could make use of PopupKeys, and also provide a hint depending on user choice
// then language key joining should be done in here too
// also what about getting the moreKeys and key hint from chosen symbol layout?
fun toMoreKeys(params: KeyboardParams) = if (isEmpty) null // need null instead of empty array for KeyParams
else (listOfNotNull(number?.toString(), main?.getLabel(params)) + relevant
// todo: this is not nice and creates unnecessary intermediate lists
// best treat the currency key properly, like florisboard does
.map { it.getLabel(params) }).map {
if (it == "$$$") {
fun toMoreKeys(params: KeyboardParams): Array<String>? {
val moreKeys = mutableListOf<String>()
// number + main + relevant in this order (label is later taken from first element in resulting array)
moreKeys.addAll(params.mLocaleKeyTexts.getNumberMoreKeys(numberIndex))
main?.getLabel(params)?.let { moreKeys.add(it) }
moreKeys.addAll(relevant.map {
val label = it.getLabel(params)
if (label == "$$$") { // currency key
if (params.mId.passwordInput()) "$"
else getCurrencyKey(params.mId.locale).first
}
else it
}.toTypedArray()
else params.mLocaleKeyTexts.currencyKey.first
} else if (params.mId.mSubtype.isRtlSubtype) {
label.rtlLabel(params)
} else label
})
return moreKeys.takeIf { it.isNotEmpty() }?.toTypedArray()
}
private val popupKeys: PopupKeys<T> by lazy {
PopupKeys(null, listOfNotNull(main), relevant)
}
var number: Int? = null
val isEmpty get() = main == null && relevant.isEmpty() && number == null
var numberIndex: Int? = null
}
/**

View file

@ -8,13 +8,12 @@ package org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.floris
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import org.dslul.openboard.inputmethod.keyboard.Key
import org.dslul.openboard.inputmethod.keyboard.Key.KeyParams
import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams
// taken from FlorisBoard, small modifications (see also KeyData)
// internal keys removed (currently no plan to support them)
// added String.toTextKey
// currency key handling (see todo below...)
/**
* Data class which describes a single key and its attributes.
*
@ -41,6 +40,12 @@ class TextKeyData(
// TextKeyData(type, data.code, data.label, groupId, popup).compute(params)
// }
// }
if (label.startsWith("$$$")) { // currency key
if (label == "$$$") return params.mLocaleKeyTexts.currencyKey.let { it.first.toTextKey(it.second.toList()) }
val n = label.substringAfter("$$$").toIntOrNull()
if (n != null && n <= 4)
return params.mLocaleKeyTexts.currencyKey.second[n - 1].toTextKey()
}
return this
}

View file

@ -50,6 +50,8 @@ public class ScriptUtils {
mLanguageCodeToScriptCode = new TreeMap<>();
mLanguageCodeToScriptCode.put("", SCRIPT_LATIN); // default
mLanguageCodeToScriptCode.put("ar", SCRIPT_ARABIC);
mLanguageCodeToScriptCode.put("ur", SCRIPT_ARABIC);
mLanguageCodeToScriptCode.put("fa", SCRIPT_ARABIC);
mLanguageCodeToScriptCode.put("hy", SCRIPT_ARMENIAN);
mLanguageCodeToScriptCode.put("bg", SCRIPT_BULGARIAN);
mLanguageCodeToScriptCode.put("bn", SCRIPT_BENGALI);