(partially) remove workaround for key params

This commit is contained in:
Helium314 2024-05-18 10:30:46 +02:00
parent 5b4ba11fb7
commit 2466187eb3
4 changed files with 168 additions and 168 deletions

View file

@ -15,7 +15,7 @@ tl;dr:
**Describe the bug** **Describe the bug**
**To Reproduce** **To Reproduce**
If possible, provide all the necessary steps to reproduce your problem. If possible, provide all the necessary steps to reproduce your problem, including the involved apps or settings if relevant.
**Expected behavior** **Expected behavior**
If it's not obvious (e.g. not crash), describe how you think the app should behave. If it's not obvious (e.g. not crash), describe how you think the app should behave.

View file

@ -4,13 +4,9 @@ package helium314.keyboard.keyboard.internal.keyboard_parser
import android.content.Context import android.content.Context
import android.content.res.Configuration import android.content.res.Configuration
import helium314.keyboard.latin.utils.Log import helium314.keyboard.latin.utils.Log
import android.view.inputmethod.EditorInfo
import androidx.annotation.StringRes
import helium314.keyboard.keyboard.Key import helium314.keyboard.keyboard.Key
import helium314.keyboard.keyboard.Key.KeyParams import helium314.keyboard.keyboard.Key.KeyParams
import helium314.keyboard.keyboard.KeyboardId import helium314.keyboard.keyboard.KeyboardId
import helium314.keyboard.keyboard.KeyboardTheme
import helium314.keyboard.keyboard.internal.KeyboardIconsSet
import helium314.keyboard.keyboard.internal.KeyboardParams import helium314.keyboard.keyboard.internal.KeyboardParams
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyData import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyData
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyLabel import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyLabel
@ -18,20 +14,15 @@ import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyType
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.SimplePopups import helium314.keyboard.keyboard.internal.keyboard_parser.floris.SimplePopups
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.TextKeyData import helium314.keyboard.keyboard.internal.keyboard_parser.floris.TextKeyData
import helium314.keyboard.latin.R import helium314.keyboard.latin.R
import helium314.keyboard.latin.common.Constants
import helium314.keyboard.latin.common.LocaleUtils.constructLocale
import helium314.keyboard.latin.common.isEmoji import helium314.keyboard.latin.common.isEmoji
import helium314.keyboard.latin.define.DebugFlags import helium314.keyboard.latin.define.DebugFlags
import helium314.keyboard.latin.settings.Settings import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.spellcheck.AndroidSpellCheckerService
import helium314.keyboard.latin.utils.InputTypeUtils
import helium314.keyboard.latin.utils.POPUP_KEYS_LAYOUT import helium314.keyboard.latin.utils.POPUP_KEYS_LAYOUT
import helium314.keyboard.latin.utils.POPUP_KEYS_NUMBER import helium314.keyboard.latin.utils.POPUP_KEYS_NUMBER
import helium314.keyboard.latin.utils.ScriptUtils import helium314.keyboard.latin.utils.ScriptUtils
import helium314.keyboard.latin.utils.ScriptUtils.script import helium314.keyboard.latin.utils.ScriptUtils.script
import helium314.keyboard.latin.utils.removeFirst import helium314.keyboard.latin.utils.removeFirst
import helium314.keyboard.latin.utils.replaceFirst import helium314.keyboard.latin.utils.replaceFirst
import helium314.keyboard.latin.utils.runInLocale
import helium314.keyboard.latin.utils.splitAt import helium314.keyboard.latin.utils.splitAt
import helium314.keyboard.latin.utils.sumOf import helium314.keyboard.latin.utils.sumOf
@ -277,31 +268,12 @@ class KeyboardParser(private val params: KeyboardParams, private val context: Co
return functionalKeysLeft to functionalKeysRight return functionalKeysLeft to functionalKeysRight
} }
// this is not nice in here, but otherwise we'd need context, and defaultLabelFlags and infos for toKeyParams // todo: try moving defaultLabelFlags and layoutInfo into KeyboardParams
// improve it later, but currently this messy way is still ok
private fun KeyData.processFunctionalKeys(): KeyData? = when (label) { private fun KeyData.processFunctionalKeys(): KeyData? = when (label) {
// todo: why defaultLabelFlags exactly here? is this for armenian or bengali period labels? try removing also check in holo theme // todo: why defaultLabelFlags exactly here? is this for armenian or bengali period labels? try removing also check in holo theme
KeyLabel.PERIOD -> copy(newLabelFlags = labelFlags or defaultLabelFlags) KeyLabel.PERIOD -> copy(newLabelFlags = labelFlags or defaultLabelFlags)
KeyLabel.SHIFT -> if (infos.hasShiftKey) this else null KeyLabel.SHIFT -> if (infos.hasShiftKey) this else null
KeyLabel.ACTION -> copy( else -> this
// todo: evaluating the label should actually only happen in toKeyParams
// this label change already makes it necessary to provide the background in here too, because toKeyParams can't use action as label
newLabel = "${getActionKeyLabel()}|${getActionKeyCode()}",
newPopup = popup.merge(getActionKeyPopupKeys()?.let { SimplePopups(it) }),
// the label change is messing with toKeyParams, so we need to supply the appropriate BG type here
newType = type ?: KeyType.ENTER_EDITING,
newLabelFlags = Key.LABEL_FLAGS_PRESERVE_CASE or Key.LABEL_FLAGS_AUTO_X_SCALE or
Key.LABEL_FLAGS_FOLLOW_KEY_LABEL_RATIO or Key.LABEL_FLAGS_FOLLOW_FUNCTIONAL_TEXT_COLOR or
Key.LABEL_FLAGS_HAS_POPUP_HINT or KeyboardTheme.getThemeActionAndEmojiKeyLabelFlags(params.mThemeId)
)
else -> {
// this is ugly...
if (label.length > 8 && label.startsWith("!string/")) {
val id = context.resources.getIdentifier(label.substringAfter("!string/"), "string", context.packageName)
if (id != 0) copy(newLabel = getInLocale(id))
else this
} else this
}
} }
private fun addNumberRowOrPopupKeys(baseKeys: MutableList<MutableList<KeyData>>) { private fun addNumberRowOrPopupKeys(baseKeys: MutableList<MutableList<KeyData>>) {
@ -340,122 +312,6 @@ class KeyboardParser(private val params: KeyboardParams, private val context: Co
} }
} }
private fun getActionKeyLabel(): String {
if (params.mId.isMultiLine && (params.mId.mElementId == KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED || params.mId.mElementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED))
return "!icon/enter_key"
val iconName = when (params.mId.imeAction()) {
EditorInfo.IME_ACTION_GO -> KeyboardIconsSet.NAME_GO_KEY
EditorInfo.IME_ACTION_SEARCH -> KeyboardIconsSet.NAME_SEARCH_KEY
EditorInfo.IME_ACTION_SEND -> KeyboardIconsSet.NAME_SEND_KEY
EditorInfo.IME_ACTION_NEXT -> KeyboardIconsSet.NAME_NEXT_KEY
EditorInfo.IME_ACTION_DONE -> KeyboardIconsSet.NAME_DONE_KEY
EditorInfo.IME_ACTION_PREVIOUS -> KeyboardIconsSet.NAME_PREVIOUS_KEY
InputTypeUtils.IME_ACTION_CUSTOM_LABEL -> return params.mId.mCustomActionLabel
else -> return "!icon/enter_key"
}
val replacement = iconName.replaceIconWithLabelIfNoDrawable()
return if (iconName == replacement) // i.e. icon exists
"!icon/$iconName"
else
replacement
}
private fun getActionKeyCode() =
if (params.mId.isMultiLine && (params.mId.mElementId == KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED || params.mId.mElementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED))
"!code/key_shift_enter"
else "!code/key_enter"
private fun getActionKeyPopupKeys(): Collection<String>? {
val action = params.mId.imeAction()
val navigatePrev = params.mId.navigatePrevious()
val navigateNext = params.mId.navigateNext()
return when {
params.mId.passwordInput() -> when {
navigatePrev && action == EditorInfo.IME_ACTION_NEXT -> createPopupKeys(POPUP_EYS_NAVIGATE_PREVIOUS)
action == EditorInfo.IME_ACTION_NEXT -> null
navigateNext && action == EditorInfo.IME_ACTION_PREVIOUS -> createPopupKeys(POPUP_EYS_NAVIGATE_NEXT)
action == EditorInfo.IME_ACTION_PREVIOUS -> null
navigateNext && navigatePrev -> createPopupKeys(POPUP_EYS_NAVIGATE_PREVIOUS_NEXT)
navigateNext -> createPopupKeys(POPUP_EYS_NAVIGATE_NEXT)
navigatePrev -> createPopupKeys(POPUP_EYS_NAVIGATE_PREVIOUS)
else -> null
}
// could change definition of numbers to query a range, or have a pre-defined list, but not that crucial
params.mId.isNumberLayout || params.mId.mMode in listOf(KeyboardId.MODE_EMAIL, KeyboardId.MODE_DATE, KeyboardId.MODE_TIME, KeyboardId.MODE_DATETIME) -> when {
action == EditorInfo.IME_ACTION_NEXT && navigatePrev -> createPopupKeys(POPUP_EYS_NAVIGATE_PREVIOUS)
action == EditorInfo.IME_ACTION_NEXT -> null
action == EditorInfo.IME_ACTION_PREVIOUS && navigateNext -> createPopupKeys(POPUP_EYS_NAVIGATE_NEXT)
action == EditorInfo.IME_ACTION_PREVIOUS -> null
navigateNext && navigatePrev -> createPopupKeys(POPUP_EYS_NAVIGATE_PREVIOUS_NEXT)
navigateNext -> createPopupKeys(POPUP_EYS_NAVIGATE_NEXT)
navigatePrev -> createPopupKeys(POPUP_EYS_NAVIGATE_PREVIOUS)
else -> null
}
action == EditorInfo.IME_ACTION_NEXT && navigatePrev -> createPopupKeys(POPUP_EYS_NAVIGATE_EMOJI_PREVIOUS)
action == EditorInfo.IME_ACTION_NEXT -> createPopupKeys(POPUP_EYS_NAVIGATE_EMOJI)
action == EditorInfo.IME_ACTION_PREVIOUS && navigateNext -> createPopupKeys(POPUP_EYS_NAVIGATE_EMOJI_NEXT)
action == EditorInfo.IME_ACTION_PREVIOUS -> createPopupKeys(POPUP_EYS_NAVIGATE_EMOJI)
navigateNext && navigatePrev -> createPopupKeys(POPUP_EYS_NAVIGATE_EMOJI_PREVIOUS_NEXT)
navigateNext -> createPopupKeys(POPUP_EYS_NAVIGATE_EMOJI_NEXT)
navigatePrev -> createPopupKeys(POPUP_EYS_NAVIGATE_EMOJI_PREVIOUS)
else -> createPopupKeys(POPUP_EYS_NAVIGATE_EMOJI)
}
}
private fun createPopupKeys(popupKeysDef: String): List<String> {
val popupKeys = mutableListOf<String>()
for (popupKey in popupKeysDef.split(",")) {
val iconPrefixRemoved = popupKey.substringAfter("!icon/")
if (iconPrefixRemoved == popupKey) { // i.e. there is no !icon/
popupKeys.add(popupKey)
continue
}
val iconName = iconPrefixRemoved.substringBefore("|")
val replacementText = iconName.replaceIconWithLabelIfNoDrawable()
if (replacementText == iconName) { // i.e. we have the drawable
popupKeys.add(popupKey)
} else {
popupKeys.add(Key.POPUP_KEYS_HAS_LABELS)
popupKeys.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 (Settings.getInstance().isTablet && popupKeys.remove("!icon/emoji_action_key|!code/key_emoji")) {
val i = popupKeys.indexOfFirst { it.startsWith(Key.POPUP_KEYS_FIXED_COLUMN_ORDER) }
if (i > -1) {
val n = popupKeys[i].substringAfter(Key.POPUP_KEYS_FIXED_COLUMN_ORDER).toIntOrNull()
if (n != null)
popupKeys[i] = popupKeys[i].replace(n.toString(), (n - 1).toString())
}
}
return popupKeys
}
private fun String.replaceIconWithLabelIfNoDrawable(): String {
if (params.mIconsSet.getIconDrawable(this) != null) return this
if (params.mId.mWidth == AndroidSpellCheckerService.SPELLCHECKER_DUMMY_KEYBOARD_WIDTH
&& params.mId.mHeight == AndroidSpellCheckerService.SPELLCHECKER_DUMMY_KEYBOARD_HEIGHT
&& !params.mId.mSubtype.hasExtraValue(Constants.Subtype.ExtraValue.EMOJI_CAPABLE)
)
// fake keyboard that is used by spell checker (for key coordinates), but not shown to the user
// often this doesn't have any icons loaded, and there is no need to bother with this
return this
val id = context.resources.getIdentifier("label_$this", "string", context.packageName)
if (id == 0) {
Log.w(TAG, "no resource for label $this in ${params.mId}")
return this
}
return getInLocale(id)
}
private fun getInLocale(@StringRes id: Int): String {
// todo: hi-Latn strings instead of this workaround?
val locale = if (params.mId.locale.toLanguageTag() == "hi-Latn") "en_IN".constructLocale()
else params.mId.locale
return runInLocale(context, locale) { it.getString(id) }
}
companion object { companion object {
private const val TAG = "KeyboardParser" private const val TAG = "KeyboardParser"
@ -526,15 +382,6 @@ fun String.rtlLabel(params: KeyboardParams): String {
} }
} }
// could make arrays right away, but they need to be copied anyway as popupKeys arrays are modified when creating KeyParams
private const val POPUP_EYS_NAVIGATE_PREVIOUS = "!icon/previous_key|!code/key_action_previous,!icon/clipboard_action_key|!code/key_clipboard"
private const val POPUP_EYS_NAVIGATE_NEXT = "!icon/clipboard_action_key|!code/key_clipboard,!icon/next_key|!code/key_action_next"
private const val POPUP_EYS_NAVIGATE_PREVIOUS_NEXT = "!fixedColumnOrder!3,!needsDividers!,!icon/previous_key|!code/key_action_previous,!icon/clipboard_action_key|!code/key_clipboard,!icon/next_key|!code/key_action_next"
private const val POPUP_EYS_NAVIGATE_EMOJI_PREVIOUS = "!fixedColumnOrder!3,!needsDividers!,!icon/previous_key|!code/key_action_previous,!icon/clipboard_action_key|!code/key_clipboard,!icon/emoji_action_key|!code/key_emoji"
private const val POPUP_EYS_NAVIGATE_EMOJI = "!icon/clipboard_action_key|!code/key_clipboard,!icon/emoji_action_key|!code/key_emoji"
private const val POPUP_EYS_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 POPUP_EYS_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"
const val LAYOUT_SYMBOLS = "symbols" const val LAYOUT_SYMBOLS = "symbols"
const val LAYOUT_SYMBOLS_SHIFTED = "symbols_shifted" const val LAYOUT_SYMBOLS_SHIFTED = "symbols_shifted"
const val LAYOUT_SYMBOLS_ARABIC = "symbols_arabic" const val LAYOUT_SYMBOLS_ARABIC = "symbols_arabic"

View file

@ -5,6 +5,7 @@
*/ */
package helium314.keyboard.keyboard.internal.keyboard_parser.floris package helium314.keyboard.keyboard.internal.keyboard_parser.floris
import android.view.inputmethod.EditorInfo
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
@ -17,8 +18,12 @@ import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode.check
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyLabel.convertFlorisLabel import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyLabel.convertFlorisLabel
import helium314.keyboard.keyboard.internal.keyboard_parser.rtlLabel import helium314.keyboard.keyboard.internal.keyboard_parser.rtlLabel
import helium314.keyboard.latin.common.Constants import helium314.keyboard.latin.common.Constants
import helium314.keyboard.latin.common.LocaleUtils.constructLocale
import helium314.keyboard.latin.common.StringUtils import helium314.keyboard.latin.common.StringUtils
import helium314.keyboard.latin.settings.Settings import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.spellcheck.AndroidSpellCheckerService
import helium314.keyboard.latin.utils.InputTypeUtils
import helium314.keyboard.latin.utils.Log
// 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)
@ -84,6 +89,7 @@ sealed interface KeyData : AbstractKeyData {
KeyboardId.ELEMENT_SYMBOLS -> params.mLocaleKeyboardInfos.getShiftSymbolLabel(Settings.getInstance().isTablet) KeyboardId.ELEMENT_SYMBOLS -> params.mLocaleKeyboardInfos.getShiftSymbolLabel(Settings.getInstance().isTablet)
KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED, KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED, KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED, KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED,
KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED, KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED -> "!icon/${KeyboardIconsSet.NAME_SHIFT_KEY_SHIFTED}" KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED, KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED -> "!icon/${KeyboardIconsSet.NAME_SHIFT_KEY_SHIFTED}"
else -> "!icon/${KeyboardIconsSet.NAME_SHIFT_KEY}" else -> "!icon/${KeyboardIconsSet.NAME_SHIFT_KEY}"
} }
@ -138,6 +144,144 @@ sealed interface KeyData : AbstractKeyData {
} }
return popupKeys return popupKeys
} }
private fun String.resolveStringLabel(params: KeyboardParams): String {
if (length < 9 || !startsWith("!string/")) return this
val id = Settings.getInstance().getStringResIdByName(substringAfter("!string/"))
if (id == 0) return this
return getStringInLocale(id, params)
}
private fun getStringInLocale(id: Int, params: KeyboardParams): String {
// todo: hi-Latn strings instead of this workaround?
val locale = if (params.mId.locale.toLanguageTag() == "hi-Latn") "en_IN".constructLocale()
else params.mId.locale
return Settings.getInstance().getInLocale(id, locale)
}
// action key stuff below
// todo (later): should this be handled with metaState? but metaState shift would require LOTS of changes...
private fun getActionKeyCode(params: KeyboardParams) =
if (params.mId.isMultiLine && (params.mId.mElementId == KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED || params.mId.mElementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED))
"!code/key_shift_enter"
else "!code/key_enter"
private fun getActionKeyLabel(params: KeyboardParams): String {
if (params.mId.isMultiLine && (params.mId.mElementId == KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED || params.mId.mElementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED))
return "!icon/enter_key"
val iconName = when (params.mId.imeAction()) {
EditorInfo.IME_ACTION_GO -> KeyboardIconsSet.NAME_GO_KEY
EditorInfo.IME_ACTION_SEARCH -> KeyboardIconsSet.NAME_SEARCH_KEY
EditorInfo.IME_ACTION_SEND -> KeyboardIconsSet.NAME_SEND_KEY
EditorInfo.IME_ACTION_NEXT -> KeyboardIconsSet.NAME_NEXT_KEY
EditorInfo.IME_ACTION_DONE -> KeyboardIconsSet.NAME_DONE_KEY
EditorInfo.IME_ACTION_PREVIOUS -> KeyboardIconsSet.NAME_PREVIOUS_KEY
InputTypeUtils.IME_ACTION_CUSTOM_LABEL -> return params.mId.mCustomActionLabel
else -> return "!icon/enter_key"
}
val replacement = iconName.replaceIconWithLabelIfNoDrawable(params)
return if (iconName == replacement) // i.e. icon exists
"!icon/$iconName"
else
replacement
}
private fun getActionKeyPopupKeys(params: KeyboardParams): SimplePopups? =
getActionKeyPopupKeyString(params.mId)?.let { createActionPopupKeys(it, params) }
private fun getActionKeyPopupKeyString(keyboardId: KeyboardId): String? {
val action = keyboardId.imeAction()
val navigatePrev = keyboardId.navigatePrevious()
val navigateNext = keyboardId.navigateNext()
return when {
keyboardId.passwordInput() -> when {
navigatePrev && action == EditorInfo.IME_ACTION_NEXT -> POPUP_EYS_NAVIGATE_PREVIOUS
action == EditorInfo.IME_ACTION_NEXT -> null
navigateNext && action == EditorInfo.IME_ACTION_PREVIOUS -> POPUP_EYS_NAVIGATE_NEXT
action == EditorInfo.IME_ACTION_PREVIOUS -> null
navigateNext && navigatePrev -> POPUP_EYS_NAVIGATE_PREVIOUS_NEXT
navigateNext -> POPUP_EYS_NAVIGATE_NEXT
navigatePrev -> POPUP_EYS_NAVIGATE_PREVIOUS
else -> null
}
// could change definition of numbers to query a range, or have a pre-defined list, but not that crucial
keyboardId.isNumberLayout || keyboardId.mMode in listOf(KeyboardId.MODE_EMAIL, KeyboardId.MODE_DATE, KeyboardId.MODE_TIME, KeyboardId.MODE_DATETIME) -> when {
action == EditorInfo.IME_ACTION_NEXT && navigatePrev -> POPUP_EYS_NAVIGATE_PREVIOUS
action == EditorInfo.IME_ACTION_NEXT -> null
action == EditorInfo.IME_ACTION_PREVIOUS && navigateNext -> POPUP_EYS_NAVIGATE_NEXT
action == EditorInfo.IME_ACTION_PREVIOUS -> null
navigateNext && navigatePrev -> POPUP_EYS_NAVIGATE_PREVIOUS_NEXT
navigateNext -> POPUP_EYS_NAVIGATE_NEXT
navigatePrev -> POPUP_EYS_NAVIGATE_PREVIOUS
else -> null
}
action == EditorInfo.IME_ACTION_NEXT && navigatePrev -> POPUP_EYS_NAVIGATE_EMOJI_PREVIOUS
action == EditorInfo.IME_ACTION_NEXT -> POPUP_EYS_NAVIGATE_EMOJI
action == EditorInfo.IME_ACTION_PREVIOUS && navigateNext -> POPUP_EYS_NAVIGATE_EMOJI_NEXT
action == EditorInfo.IME_ACTION_PREVIOUS -> POPUP_EYS_NAVIGATE_EMOJI
navigateNext && navigatePrev -> POPUP_EYS_NAVIGATE_EMOJI_PREVIOUS_NEXT
navigateNext -> POPUP_EYS_NAVIGATE_EMOJI_NEXT
navigatePrev -> POPUP_EYS_NAVIGATE_EMOJI_PREVIOUS
else -> POPUP_EYS_NAVIGATE_EMOJI
}
}
private fun createActionPopupKeys(popupKeysDef: String, params: KeyboardParams): SimplePopups {
val popupKeys = mutableListOf<String>()
for (popupKey in popupKeysDef.split(",")) {
val iconPrefixRemoved = popupKey.substringAfter("!icon/")
if (iconPrefixRemoved == popupKey) { // i.e. there is no !icon/
popupKeys.add(popupKey)
continue
}
val iconName = iconPrefixRemoved.substringBefore("|")
val replacementText = iconName.replaceIconWithLabelIfNoDrawable(params)
if (replacementText == iconName) { // i.e. we have the drawable
popupKeys.add(popupKey)
} else {
popupKeys.add(Key.POPUP_KEYS_HAS_LABELS)
popupKeys.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 (Settings.getInstance().isTablet && popupKeys.remove("!icon/emoji_action_key|!code/key_emoji")) {
val i = popupKeys.indexOfFirst { it.startsWith(Key.POPUP_KEYS_FIXED_COLUMN_ORDER) }
if (i > -1) {
val n = popupKeys[i].substringAfter(Key.POPUP_KEYS_FIXED_COLUMN_ORDER).toIntOrNull()
if (n != null)
popupKeys[i] = popupKeys[i].replace(n.toString(), (n - 1).toString())
}
}
return SimplePopups(popupKeys)
}
private fun String.replaceIconWithLabelIfNoDrawable(params: KeyboardParams): String {
if (params.mIconsSet.getIconDrawable(this) != null) return this
if (params.mId.mWidth == AndroidSpellCheckerService.SPELLCHECKER_DUMMY_KEYBOARD_WIDTH
&& params.mId.mHeight == AndroidSpellCheckerService.SPELLCHECKER_DUMMY_KEYBOARD_HEIGHT
&& !params.mId.mSubtype.hasExtraValue(Constants.Subtype.ExtraValue.EMOJI_CAPABLE)
)
// fake keyboard that is used by spell checker (for key coordinates), but not shown to the user
// often this doesn't have any icons loaded, and there is no need to bother with this
return this
val id = Settings.getInstance().getStringResIdByName("label_$this")
if (id == 0) {
Log.w("TextKeyData", "no resource for label $this in ${params.mId}")
return this
}
return getStringInLocale(id, params)
}
// could make arrays right away, but they need to be copied anyway as popupKeys arrays are modified when creating KeyParams
private const val POPUP_EYS_NAVIGATE_PREVIOUS = "!icon/previous_key|!code/key_action_previous,!icon/clipboard_action_key|!code/key_clipboard"
private const val POPUP_EYS_NAVIGATE_NEXT = "!icon/clipboard_action_key|!code/key_clipboard,!icon/next_key|!code/key_action_next"
private const val POPUP_EYS_NAVIGATE_PREVIOUS_NEXT = "!fixedColumnOrder!3,!needsDividers!,!icon/previous_key|!code/key_action_previous,!icon/clipboard_action_key|!code/key_clipboard,!icon/next_key|!code/key_action_next"
private const val POPUP_EYS_NAVIGATE_EMOJI_PREVIOUS = "!fixedColumnOrder!3,!needsDividers!,!icon/previous_key|!code/key_action_previous,!icon/clipboard_action_key|!code/key_clipboard,!icon/emoji_action_key|!code/key_emoji"
private const val POPUP_EYS_NAVIGATE_EMOJI = "!icon/clipboard_action_key|!code/key_clipboard,!icon/emoji_action_key|!code/key_emoji"
private const val POPUP_EYS_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 POPUP_EYS_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"
} }
// make it non-nullable for simplicity, and to reflect current implementations // make it non-nullable for simplicity, and to reflect current implementations
@ -145,7 +289,7 @@ sealed interface KeyData : AbstractKeyData {
require(groupId <= GROUP_ENTER) { "only groups up to GROUP_ENTER are supported" } require(groupId <= GROUP_ENTER) { "only groups up to GROUP_ENTER are supported" }
require(label.isNotEmpty() || type == KeyType.PLACEHOLDER || code != KeyCode.UNSPECIFIED) { "non-placeholder key has no code and no label" } require(label.isNotEmpty() || type == KeyType.PLACEHOLDER || code != KeyCode.UNSPECIFIED) { "non-placeholder key has no code and no label" }
require(width >= 0f || width == -1f) { "illegal width $width" } require(width >= 0f || width == -1f) { "illegal width $width" }
val newLabel = label.convertFlorisLabel() val newLabel = label.convertFlorisLabel().resolveStringLabel(params)
val newCode = code.checkAndConvertCode() val newCode = code.checkAndConvertCode()
val newLabelFlags = if (labelFlags == 0 && params.mId.isNumberLayout) { val newLabelFlags = if (labelFlags == 0 && params.mId.isNumberLayout) {
if (type == KeyType.NUMERIC) { if (type == KeyType.NUMERIC) {
@ -224,7 +368,7 @@ sealed interface KeyData : AbstractKeyData {
) )
} else { } else {
Key.KeyParams( Key.KeyParams(
newLabel.rtlLabel(params), // todo (when supported): convert special labels to keySpec newLabel.rtlLabel(params),
params, params,
newWidth, newWidth,
newLabelFlags, newLabelFlags,
@ -251,7 +395,7 @@ sealed interface KeyData : AbstractKeyData {
KeyLabel.SYMBOL_ALPHA, KeyLabel.SYMBOL, KeyLabel.ALPHA, KeyLabel.COMMA, KeyLabel.PERIOD, KeyLabel.DELETE, KeyLabel.SYMBOL_ALPHA, KeyLabel.SYMBOL, KeyLabel.ALPHA, KeyLabel.COMMA, KeyLabel.PERIOD, KeyLabel.DELETE,
KeyLabel.EMOJI, KeyLabel.COM, KeyLabel.LANGUAGE_SWITCH, KeyLabel.NUMPAD -> return Key.BACKGROUND_TYPE_FUNCTIONAL KeyLabel.EMOJI, KeyLabel.COM, KeyLabel.LANGUAGE_SWITCH, KeyLabel.NUMPAD -> return Key.BACKGROUND_TYPE_FUNCTIONAL
KeyLabel.SPACE, KeyLabel.ZWNJ -> return Key.BACKGROUND_TYPE_SPACEBAR KeyLabel.SPACE, KeyLabel.ZWNJ -> return Key.BACKGROUND_TYPE_SPACEBAR
// KeyLabel.ACTION -> return Key.BACKGROUND_TYPE_ACTION KeyLabel.ACTION -> return Key.BACKGROUND_TYPE_ACTION
KeyLabel.SHIFT -> return getShiftBackground(params) KeyLabel.SHIFT -> return getShiftBackground(params)
} }
if (type == KeyType.PLACEHOLDER) return Key.BACKGROUND_TYPE_EMPTY if (type == KeyType.PLACEHOLDER) return Key.BACKGROUND_TYPE_EMPTY
@ -280,7 +424,7 @@ sealed interface KeyData : AbstractKeyData {
KeyLabel.COMMA -> params.mLocaleKeyboardInfos.labelComma KeyLabel.COMMA -> params.mLocaleKeyboardInfos.labelComma
KeyLabel.PERIOD -> getPeriodLabel(params) KeyLabel.PERIOD -> getPeriodLabel(params)
KeyLabel.SPACE -> getSpaceLabel(params) KeyLabel.SPACE -> getSpaceLabel(params)
// KeyLabel.ACTION -> "${getActionKeyLabel(params)}|${getActionKeyCode(params)}" would need context KeyLabel.ACTION -> "${getActionKeyLabel(params)}|${getActionKeyCode(params)}"
KeyLabel.DELETE -> "!icon/delete_key|!code/key_delete" KeyLabel.DELETE -> "!icon/delete_key|!code/key_delete"
KeyLabel.SHIFT -> "${getShiftLabel(params)}|!code/key_shift" KeyLabel.SHIFT -> "${getShiftLabel(params)}|!code/key_shift"
KeyLabel.EMOJI -> "!icon/emoji_normal_key|!code/key_emoji" KeyLabel.EMOJI -> "!icon/emoji_normal_key|!code/key_emoji"
@ -308,16 +452,16 @@ sealed interface KeyData : AbstractKeyData {
} }
} }
// todo (later): add explanations / reasoning, often this is just taken from conversion from AOSP layouts // todo (later): add explanations / reasoning, often this is just taken from conversion from OpenBoard / AOSP layouts
private fun getAdditionalLabelFlags(params: KeyboardParams): Int { private fun getAdditionalLabelFlags(params: KeyboardParams): Int {
return when (label) { return when (label) {
KeyLabel.ALPHA, KeyLabel.SYMBOL_ALPHA, KeyLabel.SYMBOL -> Key.LABEL_FLAGS_PRESERVE_CASE or Key.LABEL_FLAGS_FOLLOW_FUNCTIONAL_TEXT_COLOR KeyLabel.ALPHA, KeyLabel.SYMBOL_ALPHA, KeyLabel.SYMBOL -> Key.LABEL_FLAGS_PRESERVE_CASE or Key.LABEL_FLAGS_FOLLOW_FUNCTIONAL_TEXT_COLOR
KeyLabel.PERIOD, KeyLabel.COMMA -> Key.LABEL_FLAGS_HAS_POPUP_HINT // todo: period also has defaultLabelFlags -> when is this relevant? KeyLabel.PERIOD, KeyLabel.COMMA -> Key.LABEL_FLAGS_HAS_POPUP_HINT // todo: period also has defaultLabelFlags -> when is this relevant?
// KeyLabel.ACTION -> { KeyLabel.ACTION -> {
// Key.LABEL_FLAGS_PRESERVE_CASE or Key.LABEL_FLAGS_AUTO_X_SCALE or Key.LABEL_FLAGS_PRESERVE_CASE or Key.LABEL_FLAGS_AUTO_X_SCALE or
// Key.LABEL_FLAGS_FOLLOW_KEY_LABEL_RATIO or Key.LABEL_FLAGS_FOLLOW_FUNCTIONAL_TEXT_COLOR or Key.LABEL_FLAGS_FOLLOW_KEY_LABEL_RATIO or Key.LABEL_FLAGS_FOLLOW_FUNCTIONAL_TEXT_COLOR or
// Key.LABEL_FLAGS_HAS_POPUP_HINT or KeyboardTheme.getThemeActionAndEmojiKeyLabelFlags(params.mThemeId) Key.LABEL_FLAGS_HAS_POPUP_HINT or KeyboardTheme.getThemeActionAndEmojiKeyLabelFlags(params.mThemeId)
// } }
KeyLabel.SPACE -> if (params.mId.isNumberLayout) Key.LABEL_FLAGS_ALIGN_ICON_TO_BOTTOM else 0 KeyLabel.SPACE -> if (params.mId.isNumberLayout) Key.LABEL_FLAGS_ALIGN_ICON_TO_BOTTOM else 0
KeyLabel.SHIFT -> Key.LABEL_FLAGS_PRESERVE_CASE or if (!params.mId.isAlphabetKeyboard) Key.LABEL_FLAGS_FOLLOW_FUNCTIONAL_TEXT_COLOR else 0 KeyLabel.SHIFT -> Key.LABEL_FLAGS_PRESERVE_CASE or if (!params.mId.isAlphabetKeyboard) Key.LABEL_FLAGS_FOLLOW_FUNCTIONAL_TEXT_COLOR else 0
KeyLabel.EMOJI -> KeyboardTheme.getThemeActionAndEmojiKeyLabelFlags(params.mThemeId) KeyLabel.EMOJI -> KeyboardTheme.getThemeActionAndEmojiKeyLabelFlags(params.mThemeId)
@ -331,11 +475,11 @@ sealed interface KeyData : AbstractKeyData {
private fun getAdditionalPopupKeys(params: KeyboardParams): PopupSet<AbstractKeyData>? { private fun getAdditionalPopupKeys(params: KeyboardParams): PopupSet<AbstractKeyData>? {
if (groupId == GROUP_COMMA) return SimplePopups(getCommaPopupKeys(params)) if (groupId == GROUP_COMMA) return SimplePopups(getCommaPopupKeys(params))
if (groupId == GROUP_PERIOD) return SimplePopups(getPunctuationPopupKeys(params)) if (groupId == GROUP_PERIOD) return SimplePopups(getPunctuationPopupKeys(params))
// if (groupId == GROUP_ENTER) return getActionKeyPopupKeys(params)?.let { SimplePopups(it) } if (groupId == GROUP_ENTER) return getActionKeyPopupKeys(params)
return when (label) { return when (label) {
KeyLabel.COMMA -> SimplePopups(getCommaPopupKeys(params)) KeyLabel.COMMA -> SimplePopups(getCommaPopupKeys(params))
KeyLabel.PERIOD -> SimplePopups(getPunctuationPopupKeys(params)) KeyLabel.PERIOD -> SimplePopups(getPunctuationPopupKeys(params))
// KeyLabel.ACTION -> getActionKeyPopupKeys(params)?.let { SimplePopups(it) } KeyLabel.ACTION -> getActionKeyPopupKeys(params)
KeyLabel.SHIFT -> { KeyLabel.SHIFT -> {
if (params.mId.isAlphabetKeyboard) SimplePopups( if (params.mId.isAlphabetKeyboard) SimplePopups(
listOf( listOf(

View file

@ -23,6 +23,7 @@ import android.view.Gravity;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
@ -692,4 +693,12 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public boolean isTablet() { public boolean isTablet() {
return mContext.getResources().getInteger(R.integer.config_screen_metrics) >= 3; return mContext.getResources().getInteger(R.integer.config_screen_metrics) >= 3;
} }
public int getStringResIdByName(final String name) {
return mContext.getResources().getIdentifier(name, "string", mContext.getPackageName());
}
public String getInLocale(@StringRes final int resId, final Locale locale) {
return RunInLocaleKt.runInLocale(mContext, locale, (ctx) -> ctx.getString(resId));
}
} }