diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyboardBuilder.kt b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyboardBuilder.kt index 673bcf26..2331f735 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyboardBuilder.kt +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyboardBuilder.kt @@ -64,20 +64,20 @@ open class KeyboardBuilder(protected val mContext: Context, // todo: further plan // migrate other languages/layouts to this style - // may be tricky in some cases, like additional row, or no shift key - // also the integrated number row is weird together with the number row setting, and should be removed / ignored - // at least some of these layouts will need more complicated definition and have separate shift layouts + // integrated number rows should be removed / ignored when migrating // test the zwnj key - // label flags: some should be set by keyboard, not by row/letter - // e.g. arabic looks weird with number row in holo being bold, but all other letters normal - // careful with korean, iirc the layouts are copied somewhere in the code -> try reading them instead of having them duplicate hardcoded - // check the kbd_files for thing like touchPositionCorrectionData + // test whether the layouts really are the same (screenshots for everything added, compare old and new parser) + // check all the keyboard_layout_set and kbd_files for things like touchPositionCorrectionData + // some keyboard_layout_set have supportedScript that is enum synced with script id in ScriptUtils + // that's one more reason for using language tags... // issues: - // armenian has label flag fontNormal on all keys -> how to do? define on every letter, or have some other way of doing this? - // add such a label flag to languageKeyTexts (apply only to alphabet layouts) - // fontNormal: armenian, urdu, thai, ... // armenian bottom row: functional keys should be narrower - // urdu: no labels because the moreKeys are languageMoreKeys -> need the moreKeys setting soon (at least setting to show first language moreKey if no symbol) + // 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 morekeys(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) + // and have some setting to enable configuring this per locale (in language settings -> potentially should not be a dialog any more but a fragment?) // migrate pcqwerty to this style // this will be more complicated... // linked shift keys might be easy @@ -95,6 +95,8 @@ open class KeyboardBuilder(protected val mContext: Context, // parsing could be done into a single row, which is then split as needed // this might help with split layout (no change in key size, but in number of rows) // 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 // migrate moreKeys and moreSuggestions to this style? // at least they should not make use of the KeyTextsSet/Table (and of the XmlKeyboardParser?) // remove the old parser @@ -162,7 +164,7 @@ open class KeyboardBuilder(protected val mContext: Context, fun loadFromXml(xmlId: Int, id: KeyboardId): KeyboardBuilder { if (Settings.getInstance().current.mUseNewKeyboardParsing - && id.mElementId != KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED && id.mElementId != KeyboardId.ELEMENT_SYMBOLS_SHIFTED +// && id.mElementId != KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED && id.mElementId != KeyboardId.ELEMENT_SYMBOLS_SHIFTED && this::class == KeyboardBuilder::class // otherwise this will apply to moreKeys and moreSuggestions, and then some parameters are off ) { if (loadFromAssets(id) != null) diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/KeyboardParser.kt b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/KeyboardParser.kt index 6243372f..523e6227 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/KeyboardParser.kt +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/KeyboardParser.kt @@ -7,6 +7,8 @@ import android.view.inputmethod.EditorInfo import android.widget.Toast import org.dslul.openboard.inputmethod.keyboard.Key import org.dslul.openboard.inputmethod.keyboard.Key.KeyParams +import org.dslul.openboard.inputmethod.keyboard.Key.LABEL_FLAGS_AUTO_X_SCALE +import org.dslul.openboard.inputmethod.keyboard.Key.LABEL_FLAGS_FONT_NORMAL import org.dslul.openboard.inputmethod.keyboard.KeyboardId import org.dslul.openboard.inputmethod.keyboard.KeyboardTheme import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardIconsSet @@ -34,7 +36,8 @@ import org.dslul.openboard.inputmethod.latin.utils.sumOf * Currently the number, phone and numpad layouts are not compatible with this parser. */ abstract class KeyboardParser(private val params: KeyboardParams, private val context: Context) { - private val defaultLabelFlags = if (!params.mId.isAlphabetKeyboard) + private val infos = layoutInfos(params) + private val defaultLabelFlags = infos.defaultLabelFlags or if (!params.mId.isAlphabetKeyboard) Key.LABEL_FLAGS_DISABLE_HINT_LABEL // reproduce the no-hints in symbol layouts, todo: add setting else 0 @@ -47,15 +50,20 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co fun parseLayoutString(layoutContent: String): ArrayList> { params.readAttributes(context, null) - val keysInRows = ArrayList>() + if (infos.touchPositionCorrectionData == null) // need to set correctly, as it's not properly done in readAttributes with attr = null + params.mTouchPositionCorrection.load(emptyArray()) + else + params.mTouchPositionCorrection.load(context.resources.getStringArray(infos.touchPositionCorrectionData)) + val keysInRows = ArrayList>() val baseKeys: MutableList> = parseCoreLayout(layoutContent) 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) { + } else if (!params.mId.mNumberRowEnabled && params.mId.isAlphabetKeyboard && params.mId.locale.language != "ko") { // add number to the first 10 keys in first row // setting the correct moreKeys is handled in PopupSet + // not for korean layouts, todo: should be decided in the layout, not in the parser baseKeys.first().take(10).forEachIndexed { index, keyData -> keyData.popup.numberIndex = index } } val functionalKeysReversed = parseFunctionalKeys().reversed() @@ -166,10 +174,14 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co context.getString(R.string.key_def_functional).split("\n").mapNotNull { line -> if (line.isBlank()) return@mapNotNull null val p = line.split(";") - p.first().let { if (it.isBlank()) emptyList() else it.split(",") } to - p.last().let { if (it.isBlank()) emptyList() else it.split(",") } + splitFunctionalKeyDefs(p.first()) to splitFunctionalKeyDefs(p.last()) } + private fun splitFunctionalKeyDefs(def: String): List { + if (def.isBlank()) return emptyList() + return def.split(",").filter { infos.hasShiftKey || !it.startsWith("shift") } + } + private fun getBottomRowAndAdjustBaseKeys(baseKeys: MutableList>): ArrayList { val adjustableKeyCount = when (params.mId.mElementId) { KeyboardId.ELEMENT_SYMBOLS -> 3 @@ -225,7 +237,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co if (params.mId.mEmojiKeyEnabled) bottomRow.add(getFunctionalKeyParams(FunctionalKey.EMOJI)) bottomRow.add(keyParams) - if (params.mId.locale.language in languagesThatNeedZwnjKey) + if (infos.hasZwnjKey) bottomRow.add(getFunctionalKeyParams(FunctionalKey.ZWNJ)) } } else { @@ -571,6 +583,40 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co "south_slavic", "east_slavic" -> params.mId.locale.language // layouts split per language now, much less convoluted else -> layoutName } + + // todo: layoutInfos should be stored in method.xml (imeSubtypeExtraValue) + // or somewhere else... some replacement for keyboard_layout_set xml maybe + // move it after old parser is removed + // currently only labelFlags are used + // touchPositionCorrectionData needs to be loaded, currently always holo is applied in readAttributes + private fun layoutInfos(params: KeyboardParams): LayoutInfos { + val name = params.mId.mSubtype.keyboardLayoutSetName + val labelFlags = if (!params.mId.isAlphabetKeyboard) 0 else when (name) { + "armenian_phonetic", "arabic", "arabic_pc", "bengali", "bengali_akkhor", "bengali_unijoy", + "farsi", "hindi", "hindi_compact", "lao", "marathi", "nepali_romanized", "nepali_traditional", + "thai", "urdu" -> LABEL_FLAGS_FONT_NORMAL + "kannada", "khmer", "malayalam", "sinhala", "tamil", "telugu" -> LABEL_FLAGS_FONT_NORMAL or LABEL_FLAGS_AUTO_X_SCALE + else -> 0 + } + // only for alphabet, but some exceptions for shift layouts + val enableProximityCharsCorrection = params.mId.isAlphabetKeyboard && when (name) { + // todo: test effect on correction (just add qwerty to the list for testing) + "akkhor", "georgian", "hindi", "lao", "nepali_romanized", "nepali_traditional", "sinhala", "thai" -> + params.mId.mElementId == KeyboardId.ELEMENT_ALPHABET + else -> true + } + // this is weird... + val allowRedundantMoreKeys = name != "nordic" && name != "serbian_qwertz" + // essentially this is default for 4 row and non-alphabet layouts, maybe this could be determined automatically instead of using a list + // todo: check the difference between default (i.e. none) and holo (test behavior on keyboard) + // todo: null for MoreKeysKeyboard only + val touchPositionCorrectionData = if (params.mId.isAlphabetKeyboard && name in listOf("armenian_phonetic", "khmer", "lao", "malayalam", "pcqwerty", "thai")) + R.array.touch_position_correction_data_default + else R.array.touch_position_correction_data_holo + val hasZwnjKey = params.mId.locale.language in listOf("fa", "ne", "kn", "te") // determine from language, user might have custom layout + val hasShiftKey = name !in listOf("hindi_compact", "arabic", "arabic_pc", "hebrew", "kannada", "malayalam", "marathi", "farsi", "tamil", "telugu") + return LayoutInfos(labelFlags, enableProximityCharsCorrection, allowRedundantMoreKeys, touchPositionCorrectionData, hasZwnjKey, hasShiftKey) + } } protected enum class FunctionalKey { @@ -579,6 +625,20 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co } +data class LayoutInfos( + val defaultLabelFlags: Int = 0, + // disabled by default, but enabled for all alphabet layouts + // currently set in keyboardLayoutSet + val enableProximityCharsCorrection: Boolean = false, + val allowRedundantMoreKeys: Boolean = true, // only false for nordic and serbian_qwertz, could add a setting when doing the moreKeys customizing + // there is holo, default and null + // null only for moreKeys keyboard + // currently read as part of readAttributes, and thus wrong with the new parser + val touchPositionCorrectionData: Int? = null, + val hasZwnjKey: Boolean = false, + val hasShiftKey: Boolean = true, +) + fun String.rtlLabel(params: KeyboardParams): String { if (!params.mId.mSubtype.isRtlSubtype) return this return when (this) { @@ -610,6 +670,3 @@ private const val MORE_KEYS_NAVIGATE_EMOJI_PREVIOUS = "!fixedColumnOrder!3,!need private const val MORE_KEYS_NAVIGATE_EMOJI = "!icon/clipboard_action_key|!code/key_clipboard,!icon/emoji_action_key|!code/key_emoji" private const val MORE_KEYS_NAVIGATE_EMOJI_NEXT = "!fixedColumnOrder!3,!needsDividers!,!icon/clipboard_action_key|!code/key_clipboard,!icon/emoji_action_key|!code/key_emoji,!icon/next_key|!code/key_action_next" private const val MORE_KEYS_NAVIGATE_EMOJI_PREVIOUS_NEXT = "!fixedColumnOrder!4,!needsDividers!,!icon/previous_key|!code/key_action_previous,!icon/clipboard_action_key|!code/key_clipboard,!icon/emoji_action_key|!code/key_emoji,!icon/next_key|!code/key_action_next" - -// farsi|kannada|nepali_romanized|nepali_traditional|telugu" -private val languagesThatNeedZwnjKey = listOf("fa", "ne", "kn", "te") diff --git a/layouts.md b/layouts.md index 5a6e3bab..a5ae6820 100644 --- a/layouts.md +++ b/layouts.md @@ -7,3 +7,6 @@ One key per line, two consecutive newlines mark a row end. Key format: [label] [moreKeys], all separated by space, e.g. `a 0 + *` will create a key with text a, and the keys `0`, `+`, and `*` on long press. Some characters currently require escape using `\` (todo: add the list, or better add them in code instead of requiring it in the layouts). Special symbols: `%` (only for language-dependent moreKeys, not user defined, also better use sth like `%%%`) acts as placeholder for normal moreKeys. `$$$` will be replaced by currency (or default to `$`). Language-dependent moreKeys should never contain "special" moreKeys, i.e. those starting with `!` (exception for `punctuation`) + +## json +Character layouts from FlorisBoard, but missing code or label will be determined automatically. And not everything supported...