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

@ -0,0 +1,10 @@
[morekeys]
punctuation !fixedColumnOrder!7 ٕ|ٕ ٔ|ٔ ْ|ْ ٍ|ٍ ٌ|ٌ ً|ً ّ|ّ ٖ|ٖ ٰ|ٰ ٓ|ٓ ِ|ِ ُ|ُ َ|َ ـــ|ـ
[labels]
alphabet: أ‌ب‌ج
symbol: ٣٢١؟
comma: ،
[number_row]
١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩ ٠

View file

@ -0,0 +1,8 @@
[morekeys]
е ё
ь ъ
'
" ” „ “
[labels]
alphabet: АБВ

View file

@ -0,0 +1,5 @@
[morekeys]
" ” „ “
[labels]
alphabet: АБВ

View file

@ -0,0 +1,10 @@
[morekeys]
punctuation !autoColumnOrder!8 \, ॥ ? ! !icon/zwnj_key|\u200C !icon/zwj_key|\u200D # @ ( ) / ; : - + \%
[labels]
alphabet: কখগ
symbol: ?১২৩
period: ।
[number_row]
১ ২ ৩ ৫ ৬ ৮ ৯

View file

@ -0,0 +1,2 @@
[labels]
alphabet: কখগ

View file

@ -0,0 +1,2 @@
[labels]
alphabet: ΑΒΓ

View file

@ -0,0 +1,10 @@
[morekeys]
punctuation !fixedColumnOrder!7 ٕ|ٕ ْ|ْ ّ|ّ ٌ|ٌ ٍ|ٍ ً|ً ٔ|ٔ ٖ|ٖ ٰ|ٰ ٓ|ٓ ُ|ُ ِ|ِ َ|َ ـــ|ـ
[labels]
alphabet: ا‌ب‌پ
symbol: ۳۲۱؟
comma: ،
[number_row]
۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹ ۰

View file

@ -0,0 +1,10 @@
[morekeys]
punctuation !autoColumnOrder!9 \, . ? ! # ) ( / ; ' @ : - " + \% &
[labels]
alphabet: कखग
symbol: ?१२३
period: ।
[number_row]
१ २ ३ ४ ५ ६ ७ ८ ९

View file

@ -0,0 +1,8 @@
[morekeys]
punctuation !autoColumnOrder!8 \, ՞ ՜ … ' = / ՝ ՛ ֊ » « ― ) (
? ՞ ¿
! ՜ ¡
[labels]
alphabet: ԱԲԳ
period: ։

View file

@ -0,0 +1,7 @@
[morekeys]
'
" “ ” „
+ ﬩
[labels]
alphabet: אבג

View file

@ -0,0 +1,6 @@
[morekeys]
'
" ” „ “
[labels]
alphabet: აბგ

View file

@ -0,0 +1,12 @@
[morekeys]
у ү ұ
к қ
е ё
н ң
г ғ
а ә
о ө
ь ъ
[labels]
alphabet: АБВ

View file

@ -0,0 +1,2 @@
[labels]
alphabet: កខគ

View file

@ -0,0 +1,2 @@
[labels]
alphabet: ಅಆಇ

View file

@ -0,0 +1,2 @@
[labels]
alphabet: ㄱㄴㄷ

View file

@ -0,0 +1,9 @@
[morekeys]
у ү
е ё
н ң
о ө
ь ъ
[labels]
alphabet: АБВ

View file

@ -0,0 +1,2 @@
[labels]
alphabet: ກຂຄ

View file

@ -0,0 +1,8 @@
[morekeys]
е ѐ
и ѝ
'
" ” „ “
[labels]
alphabet: АБВ

View file

@ -0,0 +1,2 @@
[labels]
alphabet: അ

View file

@ -0,0 +1,2 @@
[labels]
alphabet: АБВ

View file

@ -0,0 +1,6 @@
[labels]
alphabet: कखग
symbol: ?१२३
[number_row]
१ २ ३ ४ ५ ६ ७ ८ ९

View file

@ -0,0 +1,6 @@
[morekeys]
punctuation !autoColumnOrder!9 ၊ . ? ! # ) ( / ; ... ' @ : - " + \% &
[labels]
alphabet: ကခဂ
period: ။

View file

@ -0,0 +1,10 @@
[morekeys]
punctuation !autoColumnOrder!9 . \, ? ! # ) ( / ; ' @ : - " + \% &
[labels]
alphabet: कखग
symbol: ?१२३
period: ।
[number_row]
१ २ ३ ४ ५ ६ ७ ८ ९

View file

@ -0,0 +1,8 @@
[morekeys]
е ё
ь ъ
'
" ” „ “
[labels]
alphabet: АБВ

View file

@ -0,0 +1,2 @@
[labels]
alphabet: අ ආ

View file

@ -0,0 +1,8 @@
[morekeys]
е ѐ
и ѝ
'
" ” „ “ » «
[labels]
alphabet: АБВ

View file

@ -0,0 +1,2 @@
[labels]
alphabet: தமிழ்

View file

@ -0,0 +1,2 @@
[labels]
alphabet: தமிழ்

View file

@ -0,0 +1,2 @@
[labels]
alphabet: தமிழ்

View file

@ -0,0 +1,2 @@
[labels]
alphabet: అఆఇ

View file

@ -0,0 +1,2 @@
[labels]
alphabet: กขค

View file

@ -0,0 +1,8 @@
[morekeys]
г ґ
ь ъ
'
" ” „ “
[labels]
alphabet: АБВ

View file

@ -0,0 +1,11 @@
[morekeys]
punctuation ؟ ، ! . -
[labels]
alphabet: اب‌پ
comma: ،
symbol: ۳۲۱؟
period: ۔
[number_row]
۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹ ۰

View file

@ -0,0 +1,28 @@
~
`
|
• ♪ ♥ ♠ ♦ ♣
π Π
÷
×
¶ §
@
#
$$$
% ‰
&
- _ — ·
+ ±
( < { [
) > } ]
* † ‡ ★
"
'
:
;
!
?

View file

@ -0,0 +1,28 @@
~
`
|
• ♪ ♥ ♠ ♦ ♣
π Π
÷
×
¶ §
٬ @
٫ #
$$$
٪ % ‰
&
- _ — ·
+ ±
( < { [
) ﴿ > } ]
* ٭ ★ † ‡
« „ “ ”
»
:
؛ ;
!
؟ ? ¿

View file

@ -0,0 +1,28 @@
~
`
|
• ♪ ♥ ♠ ♦ ♣
π Π
÷
×
¶ §
$$$1
$$$2
$$$3
$$$4
^ ↑ ↓ ← →
°
= ≠ ≈ ∞
{
}
\
©
®
[
]

View file

@ -52,12 +52,10 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
mParams.mId = id mParams.mId = id
addLocaleKeyTextsToParams(mContext, mParams, Settings.getInstance().current.mShowMoreKeys) addLocaleKeyTextsToParams(mContext, mParams, Settings.getInstance().current.mShowMoreKeys)
try { try {
val parser = KeyboardParser.createParserForLayout(mParams, mContext) ?: return null keysInRows = KeyboardParser.parseFromAssets(mParams, mContext) ?: return null
Log.d(TAG, "parsing $id using ${parser::class.simpleName}")
keysInRows = parser.parseLayoutFromAssets(id.mSubtype.keyboardLayoutSetName)
} catch (e: Throwable) { } catch (e: Throwable) {
if (DebugFlags.DEBUG_ENABLED || BuildConfig.DEBUG) 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) Log.e(TAG, "loading $id from assets failed", e)
return null return null
} }
@ -65,8 +63,14 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
return this return this
// todo: further plan // todo: further plan
// migrate symbol layouts to this style // add option for number row (latin first vs locale numbers first
// simplified if possible, but json should be fine too // 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 // migrate keypad layouts to this style
// will need more configurable layout definition -> another parser, or do it with compatible jsons // 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?) // 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 // write another parser, it should already consider split
// migrate moreKeys and moreSuggestions to this style? // migrate moreKeys and moreSuggestions to this style?
// at least they should not make use of the KeyTextsSet/Table (and of the XmlKeyboardParser?) // at least they should not make use of the KeyTextsSet/Table (and of the XmlKeyboardParser?)
// migrate other languages to this style // remove the old parser
// may be difficult in some cases, like additional row, or no shift key, or pc qwerty layout // then finally the spanish/german/swiss/nordic layouts can be removed and replaced by some hasExtraKeys parameter
// also the (integrated) number row might cause issues // also the eo check could then be removed
// at least some of these layouts will need more complicated definition, not just a simple text file // and maybe the language -> layout thing could be moved to assets? and maybe even here the extra keys could be defined...
// some languages also change symbol view, e.g. fa changes symbols row 3 // should be either both in method.xml, or both in assets (actually method might be more suitable)
// add more layouts before doing this? or just keep the layout conversion script
// labelFlags should be set correctly // labelFlags should be set correctly
// alignHintLabelToBottom: on lxx and rounded themes, but did not find what it actually does... // 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> { fun loadFromXml(xmlId: Int, id: KeyboardId): KeyboardBuilder<KP> {
if (Settings.getInstance().current.mUseNewKeyboardParsing 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 && this::class == KeyboardBuilder::class // otherwise this will apply to moreKeys and moreSuggestions, and then some parameters are off
) { ) {
if (loadFromAssets(id) != null) 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.Context
import android.content.res.Resources import android.content.res.Resources
import android.util.Log
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.Toast
import org.dslul.openboard.inputmethod.keyboard.Key import org.dslul.openboard.inputmethod.keyboard.Key
import org.dslul.openboard.inputmethod.keyboard.Key.KeyParams import org.dslul.openboard.inputmethod.keyboard.Key.KeyParams
import org.dslul.openboard.inputmethod.keyboard.KeyboardId 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.KeyData
import org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.floris.toTextKey import org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.floris.toTextKey
import org.dslul.openboard.inputmethod.latin.R 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.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.InputTypeUtils
import org.dslul.openboard.inputmethod.latin.utils.RunInLocale import org.dslul.openboard.inputmethod.latin.utils.RunInLocale
import org.dslul.openboard.inputmethod.latin.utils.ScriptUtils
import org.dslul.openboard.inputmethod.latin.utils.sumOf 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. * Currently the number, phone and numpad layouts are not compatible with this parser.
*/ */
abstract class KeyboardParser(private val params: KeyboardParams, private val context: Context) { 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 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 keysInRows = ArrayList<ArrayList<KeyParams>>()
val baseKeys: MutableList<List<KeyData>> = parseCoreLayout(layoutContent) val baseKeys: MutableList<List<KeyData>> = parseCoreLayout(layoutContent)
if (!params.mId.mNumberRowEnabled) { if (!params.mId.mNumberRowEnabled && params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS) {
// todo (non-latin): not all layouts have numbers on first row, so maybe have some layout flag to switch it off (or an option) // replace first symbols row with number row
((1..9) + 0).forEachIndexed { i, n -> baseKeys.first().getOrNull(i)?.popup?.number = n } 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() val functionalKeysReversed = parseFunctionalKeys().reversed()
@ -98,7 +110,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
for (key in row) { for (key in row) {
// todo: maybe autoScale / autoXScale if label has more than 2 characters (exception for emojis?) // todo: maybe autoScale / autoXScale if label has more than 2 characters (exception for emojis?)
// but that could also be determined in toKeyParams // 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) paramsRow.add(keyParams)
} }
if (spacerWidth != 0f) { if (spacerWidth != 0f) {
@ -185,25 +197,25 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
adjustedKeys?.get(1)?.label ?: "/", adjustedKeys?.get(1)?.label ?: "/",
params, params,
params.mDefaultRelativeKeyWidth, params.mDefaultRelativeKeyWidth,
0, defaultLabelFlags,
Key.BACKGROUND_TYPE_FUNCTIONAL, Key.BACKGROUND_TYPE_FUNCTIONAL,
adjustedKeys?.get(1)?.popup?.toMoreKeys(params) adjustedKeys?.get(1)?.popup?.toMoreKeys(params)
)) ))
} else if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) { } else if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) {
bottomRow.add(KeyParams( bottomRow.add(KeyParams(
adjustedKeys?.get(1)?.label ?: "<", (adjustedKeys?.get(1)?.label ?: "<").rtlLabel(params),
params, params,
params.mDefaultRelativeKeyWidth, params.mDefaultRelativeKeyWidth,
0, defaultLabelFlags,
Key.BACKGROUND_TYPE_FUNCTIONAL, Key.BACKGROUND_TYPE_FUNCTIONAL,
adjustedKeys?.get(1)?.popup?.toMoreKeys(params) adjustedKeys?.get(1)?.popup?.toMoreKeys(params)
)) ))
bottomRow.add(keyParams) bottomRow.add(keyParams)
bottomRow.add(KeyParams( bottomRow.add(KeyParams(
adjustedKeys?.get(2)?.label ?: ">", (adjustedKeys?.get(2)?.label ?: ">").rtlLabel(params),
params, params,
params.mDefaultRelativeKeyWidth, params.mDefaultRelativeKeyWidth,
0, defaultLabelFlags,
Key.BACKGROUND_TYPE_FUNCTIONAL, Key.BACKGROUND_TYPE_FUNCTIONAL,
adjustedKeys?.get(2)?.popup?.toMoreKeys(params) 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(getFunctionalKeyParams(FunctionalKey.EMOJI))
bottomRow.add(keyParams) bottomRow.add(keyParams)
if (params.mId.locale.language in languagesThatNeedZwnjKey) if (params.mId.locale.language in languagesThatNeedZwnjKey)
bottomRow.add(getFunctionalKeyParams(FunctionalKey.ZWNJ)) // todo (non-latin): test it bottomRow.add(getFunctionalKeyParams(FunctionalKey.ZWNJ))
} }
} else { } else {
bottomRow.add(keyParams) bottomRow.add(keyParams)
@ -226,19 +238,9 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
return bottomRow return bottomRow
} }
private fun getNumberRow(): ArrayList<KeyParams> { private fun getNumberRow(): ArrayList<KeyParams> =
val row = ArrayList<KeyParams>() params.mLocaleKeyTexts.getNumberRow().mapTo(ArrayList()) {
((1..9) + 0).forEachIndexed { i, n -> it.toKeyParams(params, labelFlags = Key.LABEL_FLAGS_DISABLE_HINT_LABEL or defaultLabelFlags)
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
))
}
return row
} }
private fun getFunctionalKeyParams(def: String, label: String? = null, moreKeys: Array<String>? = null): KeyParams { private fun getFunctionalKeyParams(def: String, label: String? = null, moreKeys: Array<String>? = null): KeyParams {
@ -254,7 +256,17 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
val width = relativeWidth ?: params.mDefaultRelativeKeyWidth val width = relativeWidth ?: params.mDefaultRelativeKeyWidth
return when (key) { return when (key) {
FunctionalKey.SYMBOL -> KeyParams( 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, params,
width, width,
Key.LABEL_FLAGS_PRESERVE_CASE or Key.LABEL_FLAGS_FOLLOW_FUNCTIONAL_TEXT_COLOR, 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 null
) )
FunctionalKey.COMMA -> KeyParams( FunctionalKey.COMMA -> KeyParams(
label ?: getDefaultCommaLabel(), label ?: getCommaLabel(),
params, params,
width, width,
Key.LABEL_FLAGS_HAS_POPUP_HINT, // previously only if normal comma, but always is more correct Key.LABEL_FLAGS_HAS_POPUP_HINT, // previously only if normal comma, but always is more correct
if (label?.first() if (label?.first()?.isLetter() == true) Key.BACKGROUND_TYPE_NORMAL // mimic behavior of old dvorak and halmak layouts
?.isLetter() == true else Key.BACKGROUND_TYPE_FUNCTIONAL,
) Key.BACKGROUND_TYPE_NORMAL else Key.BACKGROUND_TYPE_FUNCTIONAL,
moreKeys?.let { getCommaMoreKeys() + it } ?: getCommaMoreKeys() 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( FunctionalKey.SPACE -> KeyParams(
"!icon/space_key|!code/key_space", // !icon/space_key_for_number_layout in number layout, but not on tablet "!icon/space_key|!code/key_space", // !icon/space_key_for_number_layout in number layout, but not on tablet
params, params,
@ -279,16 +299,6 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
Key.BACKGROUND_TYPE_SPACEBAR, Key.BACKGROUND_TYPE_SPACEBAR,
null 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( FunctionalKey.ACTION -> KeyParams(
"${getActionKeyLabel()}|${getActionKeyCode()}", "${getActionKeyLabel()}|${getActionKeyCode()}",
params, params,
@ -348,14 +358,6 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
Key.BACKGROUND_TYPE_FUNCTIONAL, Key.BACKGROUND_TYPE_FUNCTIONAL,
null 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( FunctionalKey.NUMPAD -> KeyParams(
"!icon/numpad_key|!code/key_numpad", "!icon/numpad_key|!code/key_numpad",
params, params,
@ -460,34 +462,51 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
private fun String.replaceIconWithLabelIfNoDrawable(): String { private fun String.replaceIconWithLabelIfNoDrawable(): String {
if (params.mIconsSet.getIconDrawable(KeyboardIconsSet.getIconId(this)) != null) return this if (params.mIconsSet.getIconDrawable(KeyboardIconsSet.getIconId(this)) != null) return this
val id = context.resources.getIdentifier("label_$this", "string", context.packageName) 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? val ril = object : RunInLocale<String>() { // todo (later): simpler way of doing this in a single line?
override fun job(res: Resources) = res.getString(id) override fun job(res: Resources) = res.getString(id)
} }
return ril.runInLocale(context.resources, params.mId.locale) 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 { private fun getShiftLabel(): String {
val elementId = params.mId.mElementId val elementId = params.mId.mElementId
if (elementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) if (elementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED)
return params.mLocaleKeyTexts.labelShiftSymbols return params.mLocaleKeyTexts.labelSymbol
if (elementId == KeyboardId.ELEMENT_SYMBOLS) if (elementId == KeyboardId.ELEMENT_SYMBOLS)
return getSymbolLabel() return params.mLocaleKeyTexts.labelShiftSymbol
if (elementId == KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED || elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED 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) || elementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED || elementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED)
return "!icon/shift_key_shifted" return "!icon/shift_key_shifted"
return "!icon/shift_key" return "!icon/shift_key"
} }
private fun getDefaultCommaLabel(): String { private fun getCommaLabel(): String {
if (params.mId.mMode == KeyboardId.MODE_URL) if (params.mId.mMode == KeyboardId.MODE_URL)
return "/" return "/"
if (params.mId.mMode == KeyboardId.MODE_EMAIL) if (params.mId.mMode == KeyboardId.MODE_EMAIL)
return "\\@" return "\\@"
return "," return params.mLocaleKeyTexts.labelComma
} }
private fun getCommaMoreKeys(): Array<String> { private fun getCommaMoreKeys(): Array<String> {
@ -509,7 +528,6 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS || params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS || params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED)
return arrayOf("") return arrayOf("")
val moreKeys = params.mLocaleKeyTexts.getMoreKeys("punctuation") ?: 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("?")) { 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 // we have a tablet, remove ! and ? keys and reduce number in autoColumnOrder
@ -524,19 +542,26 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
} }
companion object { 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 layoutName = params.mId.mSubtype.keyboardLayoutSetName
val layoutFileNames = context.assets.list("layouts") ?: return null val layoutFileNames = context.assets.list("layouts") ?: return null
if (layoutFileNames.contains("$layoutName.json")) return when {
return JsonKeyboardParser(params, context) id.mElementId == KeyboardId.ELEMENT_SYMBOLS && ScriptUtils.getScriptFromSpellCheckerLocale(params.mId.locale) == ScriptUtils.SCRIPT_ARABIC
val simpleLayoutName = getSimpleLayoutName(layoutName) -> SimpleKeyboardParser(params, context).parseLayoutFromAssets("symbols_arabic")
if (layoutFileNames.contains("$simpleLayoutName.txt")) id.mElementId == KeyboardId.ELEMENT_SYMBOLS -> SimpleKeyboardParser(params, context).parseLayoutFromAssets("symbols")
return SimpleKeyboardParser(params, context) id.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED
return null -> 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 @JvmStatic // unsupported without JvmStatic
protected fun getSimpleLayoutName(layoutName: String)= when (layoutName) { protected fun getSimpleLayoutName(layoutName: String) = when (layoutName) {
"swiss", "german", "serbian_qwertz" -> "qwertz" "swiss", "german", "serbian_qwertz" -> "qwertz"
"nordic", "spanish" -> "qwerty" "nordic", "spanish" -> "qwerty"
else -> layoutName 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 fun String.rtlLabel(params: KeyboardParams): String {
private val numbersMoreKeys = arrayOf( if (!params.mId.mSubtype.isRtlSubtype) return this
arrayOf("¹", "½", "","¼", ""), return when (this) {
arrayOf("²", ""), "{" -> "{|}"
arrayOf("³", "¾", ""), "}" -> "}|{"
arrayOf(""), "(" -> "(|)"
arrayOf(""), ")" -> ")|("
null, "[" -> "{|]"
arrayOf(""), "]" -> "]|["
null, "<" -> "<|>"
null, ">" -> ">|<"
arrayOf("", ""), "" -> "≤|≥"
) "" -> "≥|≤"
"«" -> "«|»"
"»" -> "»|«"
"" -> "|"
"" -> "|"
"" -> "|﴿"
"﴿" -> "﴿|"
else -> this
}
}
// could make arrays right away, but they need to be copied anyway as moreKeys arrays are modified when creating KeyParams // 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" 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 java.util.Locale
import kotlin.math.round import kotlin.math.round
class LocaleKeyTexts(dataStream: InputStream?) { class LocaleKeyTexts(dataStream: InputStream?, locale: Locale) {
private val moreKeys = hashMapOf<String, Array<String>>() private val moreKeys = hashMapOf<String, Array<String>>()
private val extraKeys = Array<MutableList<KeyData>?>(5) { null } private val extraKeys = Array<MutableList<KeyData>?>(5) { null }
var labelSymbols = "\\?123" var labelSymbol = "\\?123"
private set
var labelAlphabet = "ABC" 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 { init {
readStream(dataStream, false) readStream(dataStream, false)
// set default quote moreKeys if necessary // set default quote moreKeys if necessary
@ -42,11 +64,13 @@ class LocaleKeyTexts(dataStream: InputStream?) {
"[morekeys]" -> { mode = READER_MODE_MORE_KEYS; return@forEachLine } "[morekeys]" -> { mode = READER_MODE_MORE_KEYS; return@forEachLine }
"[extra_keys]" -> { mode = READER_MODE_EXTRA_KEYS; return@forEachLine } "[extra_keys]" -> { mode = READER_MODE_EXTRA_KEYS; return@forEachLine }
"[labels]" -> { mode = READER_MODE_LABELS; return@forEachLine } "[labels]" -> { mode = READER_MODE_LABELS; return@forEachLine }
"[number_row]" -> { mode = READER_MODE_NUMBER_ROW; return@forEachLine }
} }
when (mode) { when (mode) {
READER_MODE_MORE_KEYS -> addMoreKeys(line.splitOnWhitespace()) READER_MODE_MORE_KEYS -> addMoreKeys(line.splitOnWhitespace())
READER_MODE_EXTRA_KEYS -> if (!onlyMoreKeys) addExtraKey(line.split(colonSpaceRegex, 2)) READER_MODE_EXTRA_KEYS -> if (!onlyMoreKeys) addExtraKey(line.split(colonSpaceRegex, 2))
READER_MODE_LABELS -> if (!onlyMoreKeys) addLabel(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 // need tp provide a copy because some functions like MoreKeySpec.insertAdditionalMoreKeys may modify the array
fun getMoreKeys(label: String): Array<String>? = moreKeys[label]?.copyOf() 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>? = fun getExtraKeys(row: Int): List<KeyData>? =
if (row > extraKeys.size) null if (row > extraKeys.size) null
else extraKeys[row] else extraKeys[row]
@ -84,11 +109,33 @@ class LocaleKeyTexts(dataStream: InputStream?) {
private fun addLabel(split: List<String>) { private fun addLabel(split: List<String>) {
if (split.size < 2) return if (split.size < 2) return
when (split.first()) { when (split.first()) {
"symbols" -> labelSymbols = split.last() "symbol" -> labelSymbol = split.last()
"alphabet" -> labelAlphabet = 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> { 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 { 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) if (moreKeysSetting == MORE_KEYS_MORE)
lkt.addFile(context.assets.open("$LANGUAGE_TEXTS_FOLDER/all_more_keys.txt")) lkt.addFile(context.assets.open("$LANGUAGE_TEXTS_FOLDER/all_more_keys.txt"))
else if (moreKeysSetting == MORE_KEYS_ALL) 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_MORE_KEYS = 1
private const val READER_MODE_EXTRA_KEYS = 2 private const val READER_MODE_EXTRA_KEYS = 2
private const val READER_MODE_LABELS = 3 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 // 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)) if (locale.country.matches(euroCountries))
return euro return euro
if (locale.toString().matches(euroLocales)) if (locale.toString().matches(euroLocales))
return euro return euro
if (locale.language.matches("ca|eu|lb|mt".toRegex())) if (locale.language.matches("ca|eu|lb|mt".toRegex()))
return euro 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)) return genericCurrencyKey(getCurrency(locale))
if (locale.language == "hy") if (locale.language == "hy")
return dram return dram
@ -193,6 +241,8 @@ fun getCurrencyKey(locale: Locale): Pair<String, Array<String>> {
return ruble return ruble
if (locale.country == "LK" || locale.country == "BD") if (locale.country == "LK" || locale.country == "BD")
return genericCurrencyKey(getCurrency(locale)) 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())) if (locale.country == "IN" || locale.language.matches("hi|kn|ml|mr|ta|te".toRegex()))
return rupee return rupee
if (locale.country == "GB") if (locale.country == "GB")
@ -217,6 +267,7 @@ private fun getCurrency(locale: Locale): String {
"th" -> "฿" "th" -> "฿"
"uk" -> "" "uk" -> ""
"vi" -> "" "vi" -> ""
"km" -> ""
else -> "$" 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) { class SimpleKeyboardParser(private val params: KeyboardParams, private val context: Context) : KeyboardParser(params, context) {
private val addExtraKeys = 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") && params.mId.mSubtype.keyboardLayoutSetName in listOf("nordic", "spanish", "german", "swiss", "serbian_qwertz")
override fun getLayoutFromAssets(layoutName: String) = 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.Key.KeyParams
import org.dslul.openboard.inputmethod.keyboard.KeyboardId import org.dslul.openboard.inputmethod.keyboard.KeyboardId
import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams 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 import org.dslul.openboard.inputmethod.latin.common.StringUtils
// taken from FlorisBoard, small modifications // 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) // 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 // but also longer labels should work without issues, also for MultiTextKeyData
KeyParams( KeyParams(
label, // todo (when supported): convert special labels to keySpec label.rtlLabel(params), // todo (when supported): convert special labels to keySpec
params, params,
width, width,
labelFlags, // todo (non-latin): label flags... maybe relevant for some languages labelFlags, // todo (non-latin): label flags... maybe relevant for some languages
@ -123,7 +124,7 @@ interface KeyData : AbstractKeyData {
} else { } else {
KeyParams( KeyParams(
label.ifEmpty { StringUtils.newSingleCodePointString(code) }, 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, params,
width, width,
labelFlags, labelFlags,

View file

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

View file

@ -8,13 +8,12 @@ package org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.floris
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient 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 import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams
// taken from FlorisBoard, small modifications (see also KeyData) // taken from FlorisBoard, small modifications (see also KeyData)
// internal keys removed (currently no plan to support them) // internal keys removed (currently no plan to support them)
// added String.toTextKey // added String.toTextKey
// currency key handling (see todo below...)
/** /**
* Data class which describes a single key and its attributes. * 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) // 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 return this
} }

View file

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

View file

@ -29,6 +29,8 @@ def read_keys(file):
root = ET.parse(file).getroot() root = ET.parse(file).getroot()
morekeys = dict() morekeys = dict()
extra_keys = dict() extra_keys = dict()
labels = dict()
number_row = dict()
for key in root.iter("resources"): for key in root.iter("resources"):
for string in key.iter("string"): for string in key.iter("string"):
for tag, value in string.items(): for tag, value in string.items():
@ -41,23 +43,51 @@ def read_keys(file):
text = resolve_text(string.text, file) text = resolve_text(string.text, file)
if "!text/" in text: if "!text/" in text:
raise ValueError(f"can't have !text/ in {text} (from {string.text})") raise ValueError(f"can't have !text/ in {text} (from {string.text})")
if " " in text: if " " in text and "fixedColumnOrder" not in text: # issues with arabic punctuation (more) keys
raise ValueError(f"can't have consecutive spaces in {text} (from {string.text})") raise ValueError(f"can't have consecutive spaces in {text} (from {string.text})")
if value.startswith("keyspec_") and "_row" in value: if value.startswith("keyspec_") and "_row" in value and "slavic" not in value:
# put additional key labels (for nordic, spanish, swiss) # put additional key labels (for nordic, spanish, swiss, german, but not for slavic, because here the keys are not extra)
key = value.split("_row")[1] key = value.split("_row")[1]
d = extra_keys.get(key, dict()) d = extra_keys.get(key, dict())
d["label"] = text d["label"] = text
extra_keys[key] = d extra_keys[key] = d
elif value.startswith("morekeys_") and "_row" in value: elif value.startswith("morekeys_") and "_row" in value and "slavic" not in value:
# put additional key morekeys (for nordic, spanish, swiss) # put additional key morekeys (for nordic, spanish, swiss, german, but not for slavic, because here the keys are not extra)
key = value.split("_row")[1] key = value.split("_row")[1]
d = extra_keys.get(key, dict()) d = extra_keys.get(key, dict())
d["morekeys"] = text d["morekeys"] = text
extra_keys[key] = d extra_keys[key] = d
elif value.startswith("morekeys_"): elif value.startswith("morekeys_"):
key_label = value.split("morekeys_")[1] key_label = value.split("morekeys_")[1]
if key_label == "period":
key_label = "punctuation" # used in the same place
if len(key_label) > 1 and key_label != "punctuation": if len(key_label) > 1 and key_label != "punctuation":
if key_label.startswith("cyrillic_"):
label = key_label.split("cyrillic_")[1]
if label == "u":
key_label = "у"
elif label == "ka":
key_label = "к"
elif label == "ie":
key_label = "е"
elif label == "en":
key_label = "н"
elif label == "ghe":
key_label = "г"
elif label == "o":
key_label = "о"
elif label == "soft_sign":
key_label = "ь"
elif label == "a":
key_label = "а"
elif label == "i":
key_label = "и"
else:
print(f"ignoring cyrillic long more key: {key_label}: {text}")
continue
else:
if key_label not in ["bullet", "star", "left_parenthesis", "right_parenthesis", "less_than", "greater_than", "symbols_semicolon", "symbols_percent"]:
# only print for keys that are not already handled
print(f"ignoring long more key: {key_label}: {text}") print(f"ignoring long more key: {key_label}: {text}")
continue continue
morekeys[key_label] = text morekeys[key_label] = text
@ -69,19 +99,35 @@ def read_keys(file):
prepend_to_morekeys(morekeys, text, '\"') prepend_to_morekeys(morekeys, text, '\"')
elif value == "double_angle_quotes": elif value == "double_angle_quotes":
append_to_morekeys(morekeys, text, '\"') append_to_morekeys(morekeys, text, '\"')
# todo: labels should be in [labels] and use sth like symbols: ?123 elif value == "keylabel_to_alpha":
labels["alphabet"] = text
elif value == "keylabel_to_symbol":
labels["symbol"] = text
elif value == "keyspec_comma":
labels["comma"] = text
elif value == "keyspec_period":
labels["period"] = text
elif value.startswith("keyspec_symbols_") and len(value.split("keyspec_symbols_")[1]) == 1: # checking whether it's an int would be better, but bah
number_row[value.split("keyspec_symbols_")[1]] = text
elif "values-ur" in file and value.startswith("additional_morekeys_symbols_"):
number_row[value.split("additional_morekeys_symbols_")[1]] = text
# for some reason ur has the arabic numbers in moreKeys
elif value in ["keyspec_currency", "symbols_semicolon", "symbols_percent"] or value.startswith("additional_morekeys_symbols_") or "_left_" in value or "_right_" in value or "_greater" in value or "_less_" in value:
pass # ignore keys handled somewhere else (currency key not yet fully replaced)
else: else:
print(f"ignored tag: {tag}={value}, {text}") print(f"ignored tag: {tag}={value}, {text}")
keys = dict() keys = dict()
keys["morekeys"] = morekeys keys["morekeys"] = morekeys
keys["extra_keys"] = extra_keys keys["extra_keys"] = extra_keys
keys["labels"] = labels
keys["number_row"] = number_row
return keys return keys
def resolve_text(text, file): def resolve_text(text, file):
if text.startswith("\"") and text.endswith("\"") and len(text) > 1: if text.startswith("\"") and text.endswith("\"") and len(text) > 1:
text = text[1:-1] text = text[1:-1]
sp = re.split("(?<!\\\\),", text) sp = re.split("(?<!\\\\),", text) # split on comma, but not on escaped comma "\,"
if len(sp) > 1: # resolve each entry separately if len(sp) > 1: # resolve each entry separately
result = [] result = []
@ -121,13 +167,16 @@ def read_locale_from_folder(folder):
def write_keys(outfile, keys, locc=""): def write_keys(outfile, keys, locc=""):
with open(outfile, "w") as f: with open(outfile, "w") as f:
# write section [more_keys], then [extra_keys], skip if empty # write section [more_keys], then [extra_keys], skip if empty
has_extra_keys = len(keys["extra_keys"]) > 0
has_labels = len(keys["labels"]) > 0
has_number_row = len(keys["number_row"]) > 0
if len(keys["morekeys"]) > 0: if len(keys["morekeys"]) > 0:
f.write("[morekeys]\n") f.write("[morekeys]\n")
for k, v in keys["morekeys"].items(): for k, v in keys["morekeys"].items():
f.write(f"{k} {v}\n") f.write(f"{k} {v}\n")
if len(keys["extra_keys"]) > 0: if has_labels or has_number_row or has_extra_keys:
f.write("\n") f.write("\n")
if len(keys["extra_keys"]) > 0 and locc != "eo": # eo has the extra key moved into the layout if has_extra_keys and locc != "eo": # eo has the extra key moved into the layout
f.write("[extra_keys]\n") f.write("[extra_keys]\n")
# clarify somewhere that extra keys only apply to default layout (where to get?) # clarify somewhere that extra keys only apply to default layout (where to get?)
for k, v in sorted(keys["extra_keys"].items()): for k, v in sorted(keys["extra_keys"].items()):
@ -138,6 +187,24 @@ def write_keys(outfile, keys, locc=""):
f.write(f"{row}: {label}\n") f.write(f"{row}: {label}\n")
else: else:
f.write(f"{row}: {label} {morekeys}\n") f.write(f"{row}: {label} {morekeys}\n")
if has_labels or has_number_row:
f.write("\n")
if has_labels:
f.write("[labels]\n")
for k, v in keys["labels"].items():
f.write(f"{k}: {v}\n")
if has_number_row:
f.write("\n")
if has_number_row:
if len(keys["number_row"]) != 10:
raise ValueError("number row must have 10 keys")
f.write("[number_row]\n")
zero = keys["number_row"]["0"]
for k, v in sorted(keys["number_row"].items()):
if k == "0":
continue
f.write(f"{v} ")
f.write(f"{zero}\n")
def get_morekeys_texts(write=False): def get_morekeys_texts(write=False):
@ -156,7 +223,7 @@ def get_morekeys_texts(write=False):
script = "Latn" script = "Latn"
if script is None: if script is None:
raise ValueError("undefined script") raise ValueError("undefined script")
if script != "Latn": if script == "Latn":
continue # skip non-latin scripts for now continue # skip non-latin scripts for now
print(file) print(file)
keys = read_keys(f"{file}/donottranslate-more-keys.xml") keys = read_keys(f"{file}/donottranslate-more-keys.xml")
@ -164,12 +231,14 @@ def get_morekeys_texts(write=False):
if not write: if not write:
continue continue
outfile_name = locc.replace("-r", "_").lower() + ".txt" outfile_name = locc.replace("-r", "_").lower() + ".txt"
outfile = pathlib.Path(out_folder + outfile_name) # outfile = pathlib.Path(out_folder + outfile_name)
outfile = out_folder / outfile_name
outfile.parent.mkdir(exist_ok=True, parents=True) outfile.parent.mkdir(exist_ok=True, parents=True)
write_keys(outfile, keys, locc) write_keys(outfile, keys, locc)
return val return val
# write lists of all moreKeys from different languages
def write_combined_lists(keys): def write_combined_lists(keys):
infos_by_letters = dict() infos_by_letters = dict()
for key in keys: for key in keys:
@ -198,10 +267,8 @@ def write_combined_lists(keys):
def main(): def main():
# k = read_keys(default_file) # k = read_keys(default_file)
# write_keys(pathlib.Path(__file__).parent / f"defaultkeys.txt", k) # write_keys(pathlib.Path(__file__).parent / f"defaultkeys.txt", k)
keys = get_morekeys_texts() keys = get_morekeys_texts(True)
write_combined_lists(keys) # write_combined_lists(keys)
# need to check strings: # need to check strings: