improvements for tablet layouts with new parser

This commit is contained in:
Helium314 2023-12-04 12:11:53 +01:00
parent 8edf006a32
commit 2232bc3848
11 changed files with 78 additions and 59 deletions

View file

@ -978,6 +978,7 @@ public class Key implements Comparable<Key> {
public static KeyParams newSpacer(final KeyboardParams params, final float relativeWidth) {
final KeyParams spacer = new KeyParams(params);
spacer.mRelativeWidth = relativeWidth;
spacer.mRelativeHeight = params.mDefaultRelativeRowHeight;
return spacer;
}

View file

@ -63,30 +63,14 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
return this
// todo: further plan
// migrate other languages/layouts to this style
// test whether the layouts really are the same
// comparing params with both parsers looks good, see list of detected differences below
// still need to check moreKeys, there will be many more differences that might just be minor
// write down a list of differences, ask users to open issues if they don't like them
// some keyboard_layout_set have supportedScript that is enum synced with script id in ScriptUtils
// that's one more reason for using language tags...
// but currently it's still read from xml outside the keyboard parser, so that's fine for now
// issues:
// armenian bottom row (and some more): functional keys could be narrower
// rtl parentheses hint label (urdu and more)
// urdu and others: no labels because the moreKeys are languageMoreKeys -> need the moreKeys setting soon (at least setting to show first language moreKey if no symbol)
// setting: symbol morekey(s): layout default, take from symbols, layout default but fill from symbols if empty
// setting: hint label: from symbol morekey only, symbol but language if none, first choice on long press
// (later): setting which moreKeys to prefer (default: symbol or important language, always symbol, always language)
// (later): setting whether to show duplicate moreKeys (describe properly what it actually does)
// and have some setting to enable configuring this per locale (in language settings -> potentially should not be a dialog any more but a fragment?)
// label flags are horrible to "decompile" when viewing a layout
// migrate pcqwerty to this style
// this will be more complicated...
// linked shift keys might be easy
// distance below number row with high row, but reduced key height?
// consider settings key needs to disappear if device is locked
// ignore number row setting?
// ignore number row setting to avoid duplicate number row?
// and test tablet layout!
// do the moreKeys thing (only now, because pc layout may change stuff)
// 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?
@ -100,9 +84,16 @@ 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
// 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?
// at least they should not make use of the KeyTextsSet/Table (and of the XmlKeyboardParser?)
// setting which moreKeys to prefer (default: symbol or important language, always symbol, always language)
// setting whether to show duplicate moreKeys (describe properly what it actually does)
// some keyboard_layout_set have supportedScript that is enum synced with script id in ScriptUtils
// that's one more reason for using language tags...
// currently it's still read from xml outside the keyboard parser, but should still go to some other place
// maybe use scriptUtils to determine, just make sure it's correct (also for hindi and serbian!)
// 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
@ -155,7 +146,7 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
// autoXScale: com key, action keys, some on phone layout, some non-latin languages
// autoScale: only one single letter in khmer layout (includes autoXScale)
// preserveCase: action key + more keys, com key, shift keys
// shiftedLetterActivated: period and some keys on pcqwerty, tablet only
// shiftedLetterActivated: period and some keys on pcqwerty, tablet only (wtf, when enabled can't open moreKeys -> remove? or what would be the use?)
// fromCustomActionLabel: action key with customLabelActionKeyStyle -> check parser where to get this info
// followFunctionalTextColor: number mode keys, action key
// keepBackgroundAspectRatio: lxx and rounded action more keys, lxx no-border action and emoji, moreKeys keyboard view
@ -189,18 +180,6 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
return@forEachIndexed
}
xmlRow2.forEachIndexed { index1, xmlParams ->
// todo: compare tablet layouts (how to best force it for both parsers?)
// just rename the sw600 folders to sw 360
// ->
// to shift symbols label should be ~ [ <
// last symbols row should be \ = * " ' : ; ! ? (but is * " ' : ; ! ? ! ?)
// last shift symbols row should have inverted ! and ?
// some different label flags
// ar: last symbols row should be \ = * " ' : ; ! ؟ (but is * « » : ; ! ؟ ! ?)
// ar: layout should not have ! and ? added (just empty space here...)
// ru, sr (both), others don't have a right shift key (come on...)
// but bulgarian (default) has -> not even per language
// armenian (and probably other 4 row layouts) messed up (delete key should be in first for, not x from bottom)
val keyParams = row[index1]
if (keyParams.mLabel != xmlParams.mLabel)
// currency keys (shift symbol) arranged differently

View file

@ -5,6 +5,7 @@ import android.content.res.Resources
import android.util.Log
import android.view.inputmethod.EditorInfo
import android.widget.Toast
import androidx.annotation.StringRes
import org.dslul.openboard.inputmethod.keyboard.Key
import org.dslul.openboard.inputmethod.keyboard.Key.KeyParams
import org.dslul.openboard.inputmethod.keyboard.KeyboardId
@ -12,7 +13,6 @@ 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.toTextKey
import org.dslul.openboard.inputmethod.latin.R
import org.dslul.openboard.inputmethod.latin.common.Constants
import org.dslul.openboard.inputmethod.latin.common.splitOnWhitespace
@ -75,28 +75,29 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
Toast.makeText(context, message, Toast.LENGTH_LONG).show()
}
}
val functionalKeysReversed = parseFunctionalKeys().reversed()
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) {
val row: List<KeyData> = if (i == 0 && isTablet()) {
// add bottom row extra keys
// todo: question mark might be different -> get it from localeKeyTexts
// also, maybe check device dimension int instead of getting this from resources, then using language labels is easier
// and in shift symbols it should be inverted question/exclamation marks
it + context.getString(R.string.key_def_extra_bottom_right)
.split(",").mapNotNull { if (it.isBlank()) null else it.trim().toTextKey(labelFlags = Key.LABEL_FLAGS_FONT_DEFAULT) }
val tabletExtraKeys = params.mLocaleKeyTexts.getTabletExtraKeys(params.mId.mElementId)
tabletExtraKeys.first + it + tabletExtraKeys.second
} else {
it
}
// parse functional keys for this row (if any)
val outerFunctionalKeyDefs = if (i == baseKeys.lastIndex && functionalKeysTop.isNotEmpty()) functionalKeysTop.first()
else emptyList<String>() to emptyList()
val functionalKeysDefs = if (i < functionalKeysReversed.size) functionalKeysReversed[i]
else emptyList<String>() to emptyList()
val functionalKeysLeft = functionalKeysDefs.first.map { getFunctionalKeyParams(it) }
val functionalKeysRight = functionalKeysDefs.second.map { getFunctionalKeyParams(it) }
// if we have a top row and top row entries from normal functional key defs, use top row as outer keys
val functionalKeysLeft = outerFunctionalKeyDefs.first.map { getFunctionalKeyParams(it) } + functionalKeysDefs.first.map { getFunctionalKeyParams(it) }
val functionalKeysRight = functionalKeysDefs.second.map { getFunctionalKeyParams(it) } + outerFunctionalKeyDefs.second.map { getFunctionalKeyParams(it) }
val paramsRow = ArrayList<KeyParams>(functionalKeysLeft)
// determine key width, maybe scale factor for keys, and spacers to add
@ -152,7 +153,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
// 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 { key -> key.forEach { it.mRelativeHeight *= heightRescale } }
keysInRows.forEach { row -> row.forEach { it.mRelativeHeight *= heightRescale } }
}
return keysInRows
@ -184,8 +185,8 @@ 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 parseFunctionalKeys(): List<Pair<List<String>, List<String>>> =
context.getString(R.string.key_def_functional).split("\n").mapNotNull { line ->
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
val p = line.split(";")
splitFunctionalKeyDefs(p.first()) to splitFunctionalKeyDefs(p.last())
@ -491,6 +492,17 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
moreKeys.add("$replacementText|${iconPrefixRemoved.substringAfter("|")}")
}
}
// remove emoji shortcut on enter in tablet mode (like original, because bottom row always has an emoji key)
// (probably not necessary, but whatever)
if (isTablet() && moreKeys.remove("!icon/emoji_action_key|!code/key_emoji")) {
val i = moreKeys.indexOfFirst { it.startsWith("!fixedColumnOrder") }
if (i > -1) {
val n = moreKeys[i].substringAfter("!fixedColumnOrder!").toIntOrNull()
if (n != null)
moreKeys[i] = moreKeys[i].replace(n.toString(), (n - 1).toString())
}
// remove emoji on enter, because tablet layout has a separate emoji key
}
return moreKeys.toTypedArray()
}
@ -531,7 +543,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
if (elementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED)
return params.mLocaleKeyTexts.labelSymbol
if (elementId == KeyboardId.ELEMENT_SYMBOLS)
return params.mLocaleKeyTexts.labelShiftSymbol
return params.mLocaleKeyTexts.getShiftSymbolLabel(isTablet())
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"
@ -569,8 +581,8 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
for (i in moreKeys.indices)
moreKeys[i] = moreKeys[i].rtlLabel(params) // for parentheses
}
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
if (isTablet() && moreKeys.contains("!") && moreKeys.contains("?")) {
// remove ! and ? keys and reduce number in autoColumnOrder
// this makes use of removal of empty moreKeys in MoreKeySpec.insertAdditionalMoreKeys
moreKeys[moreKeys.indexOf("!")] = ""
moreKeys[moreKeys.indexOf("?")] = ""
@ -581,6 +593,8 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
return moreKeys
}
private fun isTablet() = context.resources.getInteger(R.integer.config_screen_metrics) >= 3
companion object {
private val TAG = KeyboardParser::class.simpleName

View file

@ -3,6 +3,7 @@ package org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser
import android.content.Context
import org.dslul.openboard.inputmethod.keyboard.Key
import org.dslul.openboard.inputmethod.keyboard.KeyboardId
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
@ -20,12 +21,13 @@ class LocaleKeyTexts(dataStream: InputStream?, locale: Locale) {
private set
var labelAlphabet = "ABC"
private set
var labelShiftSymbol = "= \\\\ <"
private set
private var labelShiftSymbol = "= \\\\ <"
private var labelShiftSymbolTablet = "~ [ <"
var labelComma = ","
private set
var labelPeriod = "."
private set
private var labelQuestion = "?"
val currencyKey = getCurrencyKey(locale)
private var numberKeys = ((1..9) + 0).map { it.toString() }
private val numbersMoreKeys = arrayOf(
@ -51,8 +53,8 @@ class LocaleKeyTexts(dataStream: InputStream?, locale: Locale) {
moreKeys["\""] = arrayOf("!fixedColumnOrder!5", "", "", "", "«", "»")
if ("!" !in moreKeys)
moreKeys["!"] = arrayOf("¡")
if ("?" !in moreKeys)
moreKeys["?"] = arrayOf("¿")
if (labelQuestion !in moreKeys)
moreKeys[labelQuestion] = if (labelQuestion == "?") arrayOf("¿") else arrayOf("?", "¿")
if ("punctuation" !in moreKeys)
moreKeys["punctuation"] = arrayOf("${Key.MORE_KEYS_AUTO_COLUMN_ORDER}8", "\\,", "?", "!", "#", ")", "(", "/", ";", "'", "@", ":", "-", "\"", "+", "\\%", "&")
}
@ -80,6 +82,19 @@ class LocaleKeyTexts(dataStream: InputStream?, locale: Locale) {
}
}
/** Pair(extraKeysLeft, extraKeysRight) */
// todo: they should be optional, or will unexpectedly appear on custom layouts
fun getTabletExtraKeys(elementId: Int): Pair<List<KeyData>, List<KeyData>> {
val flags = Key.LABEL_FLAGS_FONT_DEFAULT
return when (elementId) {
KeyboardId.ELEMENT_SYMBOLS -> listOf("\\".toTextKey(labelFlags = flags), "=".toTextKey(labelFlags = flags)) to emptyList()
KeyboardId.ELEMENT_SYMBOLS_SHIFTED -> emptyList<KeyData>() to listOf("¡".toTextKey(labelFlags = flags), "¿".toTextKey(labelFlags = flags))
else -> emptyList<KeyData>() to listOf("!".toTextKey(labelFlags = flags), labelQuestion.toTextKey(labelFlags = flags)) // assume alphabet
}
}
fun getShiftSymbolLabel(isTablet: Boolean) = if (isTablet) labelShiftSymbolTablet else labelShiftSymbol
// need tp provide a copy because some functions like MoreKeySpec.insertAdditionalMoreKeys may modify the array
fun getMoreKeys(label: String): Array<String>? = moreKeys[label]?.copyOf()
@ -125,8 +140,10 @@ class LocaleKeyTexts(dataStream: InputStream?, locale: Locale) {
"symbol" -> labelSymbol = split.last()
"alphabet" -> labelAlphabet = split.last()
"shift_symbol" -> labelShiftSymbol = split.last() // never used, but could be...
"shift_symbol_tablet" -> labelShiftSymbolTablet = split.last() // never used, but could be...
"comma" -> labelComma = split.last()
"period" -> labelPeriod = split.last()
"question" -> labelQuestion = split.last()
}
}