use new parser for number layouts (tablet/landscape still missing some keys)

This commit is contained in:
Helium314 2023-12-09 21:11:46 +01:00
parent 100da1beae
commit 4406f1b224
10 changed files with 347 additions and 46 deletions

View file

@ -958,13 +958,13 @@ public class Key implements Comparable<Key> {
// params that remains constant
public final int mCode;
@Nullable public final String mLabel;
@Nullable public String mLabel;
@Nullable public final String mHintLabel;
public final int mLabelFlags;
public final int mIconId;
@Nullable public final MoreKeySpec[] mMoreKeys;
@Nullable public MoreKeySpec[] mMoreKeys;
public final int mMoreKeysColumnAndFlags;
public final int mBackgroundType;
public int mBackgroundType;
public final int mActionFlags;
@Nullable public final KeyVisualAttributes mKeyVisualAttributes;
@Nullable public OptionalAttributes mOptionalAttributes;
@ -1206,6 +1206,8 @@ public class Key implements Comparable<Key> {
final boolean needsToUpcase = needsToUpcase(mLabelFlags, params.mId.mElementId);
final Locale localeForUpcasing = params.mId.getLocale();
int actionFlags = 0;
if (params.mId.isNumberLayout())
actionFlags = ACTION_FLAGS_NO_KEY_PREVIEW;
final String[] languageMoreKeys = params.mLocaleKeyTexts.getMoreKeys(keySpec);
if (languageMoreKeys != null && layoutMoreKeys != null && languageMoreKeys[0].startsWith("!fixedColumnOrder!"))

View file

@ -178,6 +178,11 @@ public final class KeyboardId {
|| mElementId == ELEMENT_ALPHABET_AUTOMATIC_SHIFTED || mElementId == ELEMENT_ALPHABET_MANUAL_SHIFTED;
}
public boolean isNumberLayout() {
return mElementId == ELEMENT_NUMBER || mElementId == ELEMENT_NUMPAD
|| mElementId == ELEMENT_PHONE || mElementId == ELEMENT_PHONE_SYMBOLS;
}
public int imeAction() {
return InputTypeUtils.getImeOptionsActionIdFromEditorInfo(mEditorInfo);
}

View file

@ -68,8 +68,6 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
return this
// todo: further plan
// migrate keypad layouts to this style
// will need more configurable layout definition -> another parser, or do it with compatible jsons
// make the remove duplicate moreKey thing an option?
// why is it on for serbian (latin), but not for german (german)?
// only nordic and serbian_qwertz layouts have it disabled, default is enabled
@ -81,6 +79,10 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
// write another parser, it should already consider split
// add a setting to display all emojis (and use emojiv2 or emojicompat or whatever is necessary)
// mention in subtitle that they may not be displayed properly, depending on the app you're writing in
// uncomment the toast below
// number layouts missing details
// landscape: numpad layout has some extra keys
// tablet: number and phone layout have some extra keys (unify with numpad, so that extra keys show both in land and sw600? or only land?)
// now all layouts should be using the new parser -> throw an error instead of falling back to old parser
// more settings for localized number row, so it can be different in shift or symbols
// migrate moreKeys and moreSuggestions to this style?
@ -194,19 +196,19 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
Log.w(TAG, "moreKeys not null for ${keyParams.mLabel} / ${keyParams.mCode}, but xml null")
else if (xmlParams.mMoreKeys == null || keyParams.mMoreKeys == null || keyParams.mMoreKeys.contentEquals(xmlParams.mMoreKeys))
Unit
else if (keyParams.mMoreKeys.size < xmlParams.mMoreKeys.size) {
if (keyParams.mMoreKeys.size - xmlParams.mMoreKeys.size == -1 && keyParams.mCode.toChar().lowercase() == "s")
else if (keyParams.mMoreKeys!!.size < xmlParams.mMoreKeys!!.size) {
if (keyParams.mMoreKeys!!.size - xmlParams.mMoreKeys!!.size == -1 && keyParams.mCode.toChar().lowercase() == "s")
Log.i(TAG, "missing moreKeys for ${keyParams.mLabel} / ${keyParams.mCode}")
else
Log.w(TAG, "missing moreKeys for ${keyParams.mLabel} / ${keyParams.mCode}")
} else if (keyParams.mMoreKeys.size > xmlParams.mMoreKeys.size) {
if (keyParams.mMoreKeys.toList().containsAll(xmlParams.mMoreKeys.toList()))
Log.i(TAG, "more moreKeys for ${keyParams.mLabel} / ${keyParams.mCode}, first same: ${keyParams.mMoreKeys.firstOrNull() == xmlParams.mMoreKeys.firstOrNull() }" +
} else if (keyParams.mMoreKeys!!.size > xmlParams.mMoreKeys!!.size) {
if (keyParams.mMoreKeys!!.toList().containsAll(xmlParams.mMoreKeys!!.toList()))
Log.i(TAG, "more moreKeys for ${keyParams.mLabel} / ${keyParams.mCode}, first same: ${keyParams.mMoreKeys?.firstOrNull() == xmlParams.mMoreKeys?.firstOrNull() }" +
", contains all original: true") // not really an issue i would say
else
Log.w(TAG, "more moreKeys for ${keyParams.mLabel} / ${keyParams.mCode}, first same: ${keyParams.mMoreKeys.firstOrNull() == xmlParams.mMoreKeys.firstOrNull() }" +
Log.w(TAG, "more moreKeys for ${keyParams.mLabel} / ${keyParams.mCode}, first same: ${keyParams.mMoreKeys?.firstOrNull() == xmlParams.mMoreKeys?.firstOrNull() }" +
", contains all original: false")
} else if (!keyParams.mMoreKeys.toList().containsAll(xmlParams.mMoreKeys.toList()))
} else if (!keyParams.mMoreKeys!!.toList().containsAll(xmlParams.mMoreKeys!!.toList()))
Log.w(TAG, "same size but missing moreKeys for ${keyParams.mLabel} / ${keyParams.mCode}")
if (keyParams.mCode != xmlParams.mCode)
Log.w(TAG, "code different: ${keyParams.mCode} vs ${xmlParams.mCode}")
@ -237,6 +239,12 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
}
return this
}
if (DebugFlags.DEBUG_ENABLED) {
// looks like only emoji keyboards are still using the old parser, which is expected
Log.w(TAG, "falling back to old parser for $id")
if (mParams.mId.mElementId < KeyboardId.ELEMENT_EMOJI_RECENTS || mParams.mId.mElementId > KeyboardId.ELEMENT_EMOJI_CATEGORY16)
Toast.makeText(mContext, "using old parser for $id", Toast.LENGTH_LONG).show()
}
}
mParams.mId = id
// loading a keyboard should set default params like mParams.readAttributes(mContext, attrs);
@ -298,7 +306,7 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
for (row in keysInRows) {
if (row.isEmpty()) continue
fillGapsWithSpacers(row)
var currentX = 0f
var currentX = mParams.mLeftPadding.toFloat()
row.forEach {
it.setDimensionsFromRelativeSize(currentX, currentY)
if (DebugFlags.DEBUG_ENABLED)

View file

@ -9,6 +9,7 @@ package org.dslul.openboard.inputmethod.keyboard.internal;
import android.content.Context;
import android.content.res.Resources;
import android.text.TextUtils;
import android.util.Log;
import org.dslul.openboard.inputmethod.annotations.UsedForTesting;
import org.dslul.openboard.inputmethod.latin.RichInputMethodManager;
@ -18,7 +19,6 @@ import org.dslul.openboard.inputmethod.latin.utils.RunInLocale;
import org.dslul.openboard.inputmethod.latin.utils.SubtypeLocaleUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Locale;
@ -69,6 +69,7 @@ public final class KeyboardTextsSet {
}
public String getText(final String name) {
Log.w(getClass().getSimpleName(), "still used for resolving "+name);
return getTextInternal(name, 0); // only used for emoji and clipboard keyboards
}

View file

@ -1,6 +1,7 @@
package org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser
import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
import android.util.Log
import android.view.inputmethod.EditorInfo
@ -13,6 +14,7 @@ import org.dslul.openboard.inputmethod.keyboard.KeyboardTheme
import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardIconsSet
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.KeyType
import org.dslul.openboard.inputmethod.latin.R
import org.dslul.openboard.inputmethod.latin.common.Constants
import org.dslul.openboard.inputmethod.latin.common.splitOnWhitespace
@ -32,12 +34,10 @@ import java.util.Locale
* keys in symbol layouts.
* By default, all normal keys have the same width and flags, which may cause issues with the
* requirements of certain non-latin languages. todo: add labelFlags to Json parser, or determine automatically?
*
* 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 infos = layoutInfos(params)
private val defaultLabelFlags = infos.defaultLabelFlags or if (!params.mId.isAlphabetKeyboard)
private val defaultLabelFlags = infos.defaultLabelFlags or if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS || params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED)
Key.LABEL_FLAGS_DISABLE_HINT_LABEL // reproduce the no-hints in symbol layouts, todo: add setting
else 0
@ -48,6 +48,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
fun parseLayoutFromAssets(layoutName: String): ArrayList<ArrayList<KeyParams>> =
parseLayoutString(getLayoutFromAssets(layoutName))
// this thing does too much... make it more understandable after everything is implemented
fun parseLayoutString(layoutContent: String): ArrayList<ArrayList<KeyParams>> {
params.readAttributes(context, null)
if (infos.touchPositionCorrectionData == null) // need to set correctly, as it's not properly done in readAttributes with attr = null
@ -55,17 +56,43 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
else
params.mTouchPositionCorrection.load(context.resources.getStringArray(infos.touchPositionCorrectionData))
val keysInRows = ArrayList<ArrayList<KeyParams>>()
val baseKeys: MutableList<List<KeyData>> = parseCoreLayout(layoutContent)
val keysInRows: ArrayList<ArrayList<KeyParams>>
if (params.mId.mElementId <= KeyboardId.ELEMENT_SYMBOLS_SHIFTED) {
keysInRows = createAlphaSymbolRows(baseKeys)
} else if (params.mId.isNumberLayout) {
keysInRows = createNumericRows(baseKeys)
} else {
throw(UnsupportedOperationException("creating KeyboardId ${params.mId.mElementId} not supported"))
}
// rescale height if we have more than 4 rows (todo: there is some default row count in params that could be used)
val heightRescale = if (keysInRows.size > 4) 4f / keysInRows.size else 1f
if (params.mId.mNumberRowEnabled && params.mId.mElementId <= KeyboardId.ELEMENT_SYMBOLS_SHIFTED)
keysInRows.add(0, getNumberRow()) // todo: maybe this should be in createAlphaSymbolRows, but first need to decide height stuff below
if (heightRescale != 1f) {
// rescale all keys, so number row doesn't look weird (this is done like in current parsing)
// todo: in symbols view, number row is not rescaled
// so the symbols keyboard is higher than the normal one
// not a new issue, but should be solved in this migration
// how? possibly scale all keyboards to height of main alphabet? (consider suggestion strip)
keysInRows.forEach { row -> row.forEach { it.mRelativeHeight *= heightRescale } }
}
return keysInRows
}
private fun createAlphaSymbolRows(baseKeys: MutableList<List<KeyData>>): ArrayList<ArrayList<KeyParams>> {
// number row related modifications of baseKeys
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
&& params.mId.locale.language != "ko"
&& params.mId.locale.language != "th"
&& params.mId.locale.language != "lo"
&& params.mId.mSubtype.keyboardLayoutSetName != "pcqwerty"
) {
&& params.mId.locale.language != "ko"
&& params.mId.locale.language != "th"
&& params.mId.locale.language != "lo"
&& params.mId.mSubtype.keyboardLayoutSetName != "pcqwerty"
) {
// add number to the first 10 keys in first row
// setting the correct moreKeys is handled in PopupSet
// not for korean/lao/thai layouts, todo: should be decided in the layout, not in the parser
@ -76,13 +103,14 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
Toast.makeText(context, message, Toast.LENGTH_LONG).show()
}
}
val keysInRows = ArrayList<ArrayList<KeyParams>>()
val functionalKeysReversed = parseFunctionalKeys(R.string.key_def_functional).reversed()
val functionalKeysTop = parseFunctionalKeys(R.string.key_def_functional_top_row)
// keyboard parsed bottom-up because the number of rows is not fixed, but the functional keys
// are always added to the rows near the bottom
keysInRows.add(getBottomRowAndAdjustBaseKeys(baseKeys))
baseKeys.reversed().forEachIndexed { i, it ->
val row: List<KeyData> = if (i == 0 && isTablet()) {
// add bottom row extra keys
@ -163,19 +191,6 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
keysInRows.add(0, paramsRow) // we're doing it backwards, so add on top
}
resizeLastNormalRowIfNecessaryForAlignment(keysInRows)
// rescale height if we have more than 4 rows
val heightRescale = if (keysInRows.size > 4) 4f / keysInRows.size else 1f
if (params.mId.mNumberRowEnabled)
keysInRows.add(0, getNumberRow())
if (heightRescale != 1f) {
// rescale all keys, so number row doesn't look weird (this is done like in current parsing)
// todo: in symbols view, number row is not rescaled
// so the symbols keyboard is higher than the normal one
// not a new issue, but should be solved in this migration
// how? possibly scale all keyboards to height of main alphabet? (consider suggestion strip)
keysInRows.forEach { row -> row.forEach { it.mRelativeHeight *= heightRescale } }
}
return keysInRows
}
@ -205,6 +220,91 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
lastNormalRow.add(lastNormalRow.indexOfLast { it.mBackgroundType == Key.BACKGROUND_TYPE_NORMAL } + 1, KeyParams.newSpacer(params, spacerWidth))
}
private fun createNumericRows(baseKeys: MutableList<List<KeyData>>): ArrayList<ArrayList<KeyParams>> {
val keysInRows = ArrayList<ArrayList<KeyParams>>()
if (context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
// add padding here instead of using xml (actually this is not good... todo (later))
params.mLeftPadding = (params.mOccupiedWidth * 0.1f).toInt()
params.mRightPadding = (params.mOccupiedWidth * 0.1f).toInt()
params.mBaseWidth = params.mOccupiedWidth - params.mLeftPadding - params.mRightPadding
}
baseKeys.forEachIndexed { i, row ->
val paramsRow = ArrayList<KeyParams>()
row.forEach { key ->
var keyParams: KeyParams? = null
// try parsing a functional key, converting names from florisBoard to what is used here (should be unified)
// note that this is ignoring code on those keys, if any
val functionalKeyName = when (key.label) {
"view_characters" -> "alpha"
"view_symbols" -> "symbol"
"enter" -> "action"
// todo (later): maybe add special moreKeys for phone and number layouts?
"." -> if (params.mId.mElementId == KeyboardId.ELEMENT_NUMPAD) "period" else "."
"," -> if (params.mId.mElementId == KeyboardId.ELEMENT_NUMPAD) "comma" else ","
else -> key.label
}
if (functionalKeyName.length > 1 && key.type != KeyType.NUMERIC) {
try {
keyParams = getFunctionalKeyParams(functionalKeyName)
} catch (_: Throwable) {} // just use normal label
}
if (keyParams == null) {
keyParams = if (key.type == KeyType.NUMERIC) {
val labelFlags = when (params.mId.mElementId) {
KeyboardId.ELEMENT_PHONE -> Key.LABEL_FLAGS_ALIGN_LABEL_OFF_CENTER or Key.LABEL_FLAGS_HAS_HINT_LABEL or Key.LABEL_FLAGS_FOLLOW_KEY_LARGE_LETTER_RATIO
KeyboardId.ELEMENT_PHONE_SYMBOLS -> 0
else -> Key.LABEL_FLAGS_FOLLOW_KEY_LARGE_LETTER_RATIO
}
key.compute(params).toKeyParams(params, 0.17f, labelFlags or defaultLabelFlags)
} else if (key.label.length == 1 && (params.mId.mElementId == KeyboardId.ELEMENT_PHONE || params.mId.mElementId == KeyboardId.ELEMENT_NUMBER))
key.compute(params).toKeyParams(params, additionalLabelFlags = Key.LABEL_FLAGS_FOLLOW_KEY_LARGE_LETTER_RATIO or defaultLabelFlags)
else
key.compute(params).toKeyParams(params, additionalLabelFlags = defaultLabelFlags)
}
if (key.type != KeyType.NUMERIC && keyParams.mBackgroundType != Key.BACKGROUND_TYPE_ACTION)
keyParams.mBackgroundType = Key.BACKGROUND_TYPE_FUNCTIONAL
if (params.mId.mElementId == KeyboardId.ELEMENT_PHONE && key.popup.main?.getLabel(params)?.length?.let { it > 1 } == true) {
keyParams.mMoreKeys = null // the ABC and stuff labels should not create moreKeys
}
if (keyParams.mLabel?.length?.let { it > 1 } == true && keyParams.mLabel?.startsWith("!string/") == true) {
// resolve string label
val id = context.resources.getIdentifier(keyParams.mLabel?.substringAfter("!string/"), "string", context.packageName)
if (id != 0)
keyParams.mLabel = getInLocale(id)
}
paramsRow.add(keyParams)
if (DebugFlags.DEBUG_ENABLED)
Log.d(TAG, "adding key ${keyParams.mLabel}, ${keyParams.mCode}")
}
if (i == baseKeys.lastIndex) { // bottom row needs some adjustments
val n = row.indexOfFirst { it.type == KeyType.NUMERIC }
if (n != -1) {
// make sure the keys next to 0 have normal background
paramsRow.getOrNull(n - 1)?.mBackgroundType = Key.BACKGROUND_TYPE_NORMAL
paramsRow.getOrNull(n + 1)?.mBackgroundType = Key.BACKGROUND_TYPE_NORMAL
// make those keys same width as numeric keys except in numpad layout
// but determine from row size instead of from elementId, in case user wants to adjust numpad layout
if (row.size == baseKeys[0].size) {
paramsRow.getOrNull(n - 1)?.mRelativeWidth = paramsRow[n].mRelativeWidth
paramsRow.getOrNull(n + 1)?.mRelativeWidth = paramsRow[n].mRelativeWidth
} else if (row.size == baseKeys[0].size + 2) {
// numpad last row -> make sure the keys next to 0 fit nicely
paramsRow.getOrNull(n - 1)?.mRelativeWidth = paramsRow[n].mRelativeWidth * 0.55f
paramsRow.getOrNull(n - 2)?.mRelativeWidth = paramsRow[n].mRelativeWidth * 0.45f
paramsRow.getOrNull(n + 1)?.mRelativeWidth = paramsRow[n].mRelativeWidth * 0.55f
paramsRow.getOrNull(n + 2)?.mRelativeWidth = paramsRow[n].mRelativeWidth * 0.45f
}
}
}
val widthSum = paramsRow.sumOf { it.mRelativeWidth }
paramsRow.forEach { it.mRelativeWidth /= widthSum }
keysInRows.add(paramsRow)
}
return keysInRows
}
private fun parseFunctionalKeys(@StringRes id: Int): List<Pair<List<String>, List<String>>> =
context.getString(id).split("\n").mapNotNull { line ->
if (line.isBlank()) return@mapNotNull null
@ -332,7 +432,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
FunctionalKey.PERIOD -> KeyParams(
// special period moreKey only in alphabet layout, except for ar and fa
// todo: here is not the place to decide this, put it somewhere else (labelPeriod and labelPeriodSymbols?)
label ?: if (params.mId.isAlphabetKeyboard || params.mId.locale.language in listOf("ar", "fa")) params.mLocaleKeyTexts.labelPeriod else ".",
label ?: getPeriodLabel(),
params,
width,
Key.LABEL_FLAGS_HAS_POPUP_HINT
@ -344,10 +444,10 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
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
getSpaceLabel(),
params,
width, // will not be used for normal space (only in number layouts)
0, // todo (later): alignIconToBottom for non-tablet number layout -> check what it does / whether it's necessary
if (params.mId.isNumberLayout) Key.LABEL_FLAGS_ALIGN_ICON_TO_BOTTOM else 0,
Key.BACKGROUND_TYPE_SPACEBAR,
null
)
@ -474,7 +574,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
else -> null
}
// could change definition of numbers to query a range, or have a pre-defined list, but not that crucial
params.mId.mMode in listOf(KeyboardId.MODE_URL, KeyboardId.MODE_EMAIL, KeyboardId.ELEMENT_PHONE, KeyboardId.ELEMENT_NUMBER, KeyboardId.MODE_DATE, KeyboardId.MODE_TIME, KeyboardId.MODE_DATETIME) -> when {
params.mId.isNumberLayout || params.mId.mMode in listOf(KeyboardId.MODE_URL, KeyboardId.MODE_EMAIL, KeyboardId.MODE_DATE, KeyboardId.MODE_TIME, KeyboardId.MODE_DATETIME) -> when {
action == EditorInfo.IME_ACTION_NEXT && navigatePrev -> createMoreKeysArray(MORE_KEYS_NAVIGATE_PREVIOUS)
action == EditorInfo.IME_ACTION_NEXT -> null
action == EditorInfo.IME_ACTION_PREVIOUS && navigateNext -> createMoreKeysArray(MORE_KEYS_NAVIGATE_NEXT)
@ -536,6 +636,10 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
Toast.makeText(context, message, Toast.LENGTH_LONG).show()
return this
}
return getInLocale(id)
}
private fun getInLocale(@StringRes id: Int): String {
val ril = object : RunInLocale<String>() { // todo (later): simpler way of doing this in a single line?
override fun job(res: Resources) = res.getString(id)
}
@ -570,11 +674,20 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
return "!icon/shift_key"
}
private fun getPeriodLabel(): String {
if (params.mId.isNumberLayout) return "."
if (params.mId.isAlphabetKeyboard || params.mId.locale.language in listOf("ar", "fa"))
return params.mLocaleKeyTexts.labelPeriod
return "."
}
private fun getCommaLabel(): String {
if (params.mId.mMode == KeyboardId.MODE_URL && params.mId.isAlphabetKeyboard)
return "/"
if (params.mId.mMode == KeyboardId.MODE_EMAIL && params.mId.isAlphabetKeyboard)
return "\\@"
if (params.mId.isNumberLayout)
return ","
return params.mLocaleKeyTexts.labelComma
}
@ -582,7 +695,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
val keys = mutableListOf<String>()
if (!params.mId.mDeviceLocked)
keys.add("!icon/clipboard_normal_key|!code/key_clipboard")
if (!params.mId.mEmojiKeyEnabled)
if (!params.mId.mEmojiKeyEnabled && !params.mId.isNumberLayout)
keys.add("!icon/emoji_normal_key|!code/key_emoji")
if (!params.mId.mLanguageSwitchKeyEnabled)
keys.add("!icon/language_switch_key|!code/key_language_switch")
@ -596,6 +709,8 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
private fun getPunctuationMoreKeys(): Array<String> {
if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS || params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED)
return arrayOf("")
if (params.mId.isNumberLayout)
return arrayOf(":", "", ";", "", "π", "", "°", "^")
val moreKeys = params.mLocaleKeyTexts.getMoreKeys("punctuation")!!
if (params.mId.mSubtype.isRtlSubtype) {
for (i in moreKeys.indices)
@ -613,6 +728,11 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
return moreKeys
}
private fun getSpaceLabel(): String =
if (params.mId.mElementId <= KeyboardId.ELEMENT_SYMBOLS_SHIFTED || isTablet())
"!icon/space_key|!code/key_space"
else "!icon/space_key_for_number_layout|!code/key_space"
private fun isTablet() = context.resources.getInteger(R.integer.config_screen_metrics) >= 3
companion object {
@ -628,6 +748,10 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
id.mElementId == KeyboardId.ELEMENT_SYMBOLS -> SimpleKeyboardParser(params, context).parseLayoutFromAssets("symbols")
id.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED
-> SimpleKeyboardParser(params, context).parseLayoutFromAssets("symbols_shifted")
id.mElementId == KeyboardId.ELEMENT_NUMPAD -> JsonKeyboardParser(params, context).parseLayoutFromAssets("numpad")
id.mElementId == KeyboardId.ELEMENT_NUMBER -> JsonKeyboardParser(params, context).parseLayoutFromAssets("number")
id.mElementId == KeyboardId.ELEMENT_PHONE -> JsonKeyboardParser(params, context).parseLayoutFromAssets("phone")
id.mElementId == KeyboardId.ELEMENT_PHONE_SYMBOLS -> JsonKeyboardParser(params, context).parseLayoutFromAssets("phone_symbols")
!id.isAlphabetKeyboard -> null
layoutFileNames.contains("$layoutName.json") -> JsonKeyboardParser(params, context).parseLayoutFromAssets(layoutName)
layoutFileNames.contains("${getSimpleLayoutName(layoutName, params)}.txt")
@ -701,7 +825,7 @@ data class LayoutInfos(
)
fun String.rtlLabel(params: KeyboardParams): String {
if (!params.mId.mSubtype.isRtlSubtype) return this
if (!params.mId.mSubtype.isRtlSubtype || params.mId.isNumberLayout) return this
return when (this) {
"{" -> "{|}"
"}" -> "}|{"

View file

@ -22,6 +22,7 @@ import org.dslul.openboard.inputmethod.latin.common.StringUtils
// char_width_selector and kana_selector throw an error (not yet supported)
// added labelFlags to keyDate
// added manualOrLocked for shift_state_selector
// added date, time and datetime to VariationSelector
/**
* Basic interface for a key data object. Base for all key data objects across the IME, such as text, emojis and
* selectors. The implementation is as abstract as possible, as different features require different implementations.
@ -111,9 +112,12 @@ interface KeyData : AbstractKeyData {
}
fun toKeyParams(params: KeyboardParams, width: Float = params.mDefaultRelativeKeyWidth, additionalLabelFlags: Int = 0): KeyParams {
require(type == KeyType.CHARACTER) { "currently only KeyType.CHARACTER is supported" }
require(groupId == GROUP_DEFAULT) { "currently only KeyData.GROUP_DEFAULT is supported" }
require(code >= 0) { "functional codes ($code) not (yet) supported" }
// numeric keys are assigned a higher width in number layouts
require(type == KeyType.CHARACTER || type == KeyType.NUMERIC) { "only KeyType CHARACTER or NUMERIC is supported" }
// allow GROUP_ENTER negative codes so original florisboard number layouts can be used, bu actually it's ignored
require(groupId == GROUP_DEFAULT || groupId == GROUP_ENTER) { "currently only GROUP_DEFAULT or GROUP_ENTER is supported" }
// allow some negative codes so original florisboard number layouts can be used, those codes are actually ignored
require(code >= 0 || code == -7 || code == -201 || code == -202) { "functional code $code not (yet) supported" }
require(code != KeyCode.UNSPECIFIED || label.isNotEmpty()) { "key has no code and no label" }
return if (code == KeyCode.UNSPECIFIED || code == KeyCode.MULTIPLE_CODE_POINTS) {
@ -258,6 +262,9 @@ data class VariationSelector(
val uri: AbstractKeyData? = null,
val normal: AbstractKeyData? = null,
val password: AbstractKeyData? = null,
val date: AbstractKeyData? = null,
val time: AbstractKeyData? = null,
val datetime: AbstractKeyData? = null,
) : AbstractKeyData {
override fun compute(params: KeyboardParams): KeyData? {
return when {
@ -267,6 +274,9 @@ data class VariationSelector(
params.mId.passwordInput() -> password ?: default
params.mId.mMode == KeyboardId.MODE_EMAIL -> email ?: default
params.mId.mMode == KeyboardId.MODE_URL -> uri ?: default
params.mId.mMode == KeyboardId.MODE_DATE -> date ?: default
params.mId.mMode == KeyboardId.MODE_TIME -> time ?: default
params.mId.mMode == KeyboardId.MODE_DATETIME -> datetime ?: default
else -> default
}?.compute(params)
}