package org.futo.inputmethod.v2keyboard import android.view.inputmethod.EditorInfo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.futo.inputmethod.keyboard.KeyboardId import org.futo.inputmethod.keyboard.internal.KeyboardIconsSet import org.futo.inputmethod.keyboard.internal.KeyboardParams import org.futo.inputmethod.latin.common.Constants import org.futo.inputmethod.latin.uix.actions.AllActionKeys import org.futo.inputmethod.latin.utils.InputTypeUtils val FunctionalAttributes = KeyAttributes( width = KeyWidth.FunctionalKey, style = KeyVisualStyle.Functional, anchored = true, showPopup = false, moreKeyMode = MoreKeyMode.OnlyExplicit, labelFlags = LabelFlags(followKeyLetterRatio = false, followKeyLargeLetterRatio = false, followKeyLabelRatio = false) ) private val ShiftMoreKeys = listOf("!noPanelAutoMoreKey!", " |!code/key_capslock") val TemplateShiftKey = CaseSelector( normal = BaseKey( spec = "!icon/shift_key|!code/key_shift", moreKeys = ShiftMoreKeys, attributes = FunctionalAttributes ), shifted = BaseKey( spec = "!icon/shift_key_shifted|!code/key_shift", moreKeys = ShiftMoreKeys, attributes = FunctionalAttributes ), shiftLocked = BaseKey( spec = "!icon/shift_key_shifted|!code/key_shift", moreKeys = ShiftMoreKeys, attributes = FunctionalAttributes.copy(style = KeyVisualStyle.StickyOn) ), symbols = BaseKey( spec = "!text/keylabel_to_more_symbol|!code/key_shift", attributes = FunctionalAttributes ), symbolsShifted = BaseKey( spec = "!text/keylabel_to_symbol|!code/key_shift", attributes = FunctionalAttributes ) ) val TemplateDeleteKey = BaseKey( spec = "!icon/delete_key|!code/key_delete", attributes = FunctionalAttributes.copy(repeatableEnabled = true) ) val TemplateSymbolsKey = BaseKey( spec = "!text/keylabel_to_symbol|!code/key_switch_alpha_symbol", attributes = FunctionalAttributes ) val TemplateAlphabetKey = BaseKey( spec = "!text/keylabel_to_alpha|!code/key_switch_alpha_symbol", attributes = FunctionalAttributes ) val TemplateNumberKey = BaseKey( spec = "!icon/numpad|!code/key_to_number_layout", attributes = KeyAttributes( showPopup = false ) ) val TemplateSpaceKey = BaseKey( spec = "!icon/space_key|!code/key_space", attributes = KeyAttributes( width = KeyWidth.Grow, style = KeyVisualStyle.Spacebar, showPopup = false, longPressEnabled = true, moreKeyMode = MoreKeyMode.OnlyExplicit ) ) val TemplateAlt0Key = BaseKey( spec = "0|!code/key_to_alt_0_layout", attributes = FunctionalAttributes ) val TemplateAlt1Key = BaseKey( spec = "1|!code/key_to_alt_1_layout", attributes = FunctionalAttributes ) val TemplateAlt2Key = BaseKey( spec = "2|!code/key_to_alt_2_layout", attributes = FunctionalAttributes ) @Serializable @SerialName("enter") data class EnterKey( val attributes: KeyAttributes = KeyAttributes(width = KeyWidth.FunctionalKey) ) : AbstractKey { override fun countsToKeyCoordinate(params: KeyboardParams, row: Row, keyboard: Keyboard): Boolean = false override fun computeData( params: KeyboardParams, row: Row, keyboard: Keyboard, coordinate: KeyCoordinate ): ComputedKeyData { val attributes = attributes.getEffectiveAttributes(row, keyboard) // Icon, etc depend on editorInfo. val icon = when(params.mId.imeAction()) { EditorInfo.IME_ACTION_UNSPECIFIED -> KeyboardIconsSet.NAME_ENTER_KEY EditorInfo.IME_ACTION_NONE -> KeyboardIconsSet.NAME_ENTER_KEY 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 -> KeyboardIconsSet.NAME_ENTER_KEY else -> KeyboardIconsSet.NAME_ENTER_KEY } val moreKeys = if(params.mId.navigateNext() || params.mId.navigatePrevious()) { "!text/keyspec_emoji_action_key_navigation" } else { "!text/keyspec_emoji_action_key" }.let { MoreKeysBuilder( code = Constants.CODE_ENTER, mode = attributes.moreKeyMode!!, coordinate = coordinate, row = row, keyboard = keyboard, params = params ).insertMoreKeys(it).build(false) } return ComputedKeyData( label = "", code = Constants.CODE_ENTER, outputText = null, width = attributes.width ?: KeyWidth.FunctionalKey, icon = icon, style = KeyVisualStyle.Action, anchored = true, showPopup = false, moreKeys = moreKeys.specs, longPressEnabled = true, repeatable = false, moreKeyFlags = moreKeys.flags, countsToKeyCoordinate = false, hint = " ", labelFlags = 0 ) } } @Serializable @SerialName("action") data class ActionKey( val attributes: KeyAttributes = KeyAttributes() ) : AbstractKey { override fun countsToKeyCoordinate(params: KeyboardParams, row: Row, keyboard: Keyboard): Boolean = false override fun computeData( params: KeyboardParams, row: Row, keyboard: Keyboard, coordinate: KeyCoordinate ): ComputedKeyData? { if(!params.mId.mBottomEmojiKeyEnabled) { return null } val attributes = attributes.getEffectiveAttributes(row, keyboard) val actionId = params.mId.mBottomActionKeyId val actionName = AllActionKeys[actionId] return ComputedKeyData( label = "", code = Constants.CODE_ACTION_0 + actionId, outputText = null, width = attributes.width ?: KeyWidth.Regular, icon = "action_$actionName", style = attributes.style ?: KeyVisualStyle.Functional, anchored = true, showPopup = false, moreKeys = listOf(), longPressEnabled = true, repeatable = false, moreKeyFlags = 0, countsToKeyCoordinate = false, hint = "", labelFlags = 0 ) } } @Serializable @SerialName("contextual") data class ContextualKey( val attributes: KeyAttributes = KeyAttributes(), val fallbackKey: Key? = null ) : AbstractKey { val keys = mapOf( KeyboardId.MODE_EMAIL to BaseKey(spec = "@", attributes = attributes), KeyboardId.MODE_URL to BaseKey(spec = "/", attributes = attributes), KeyboardId.MODE_DATETIME to BaseKey(spec = "/", moreKeys = listOf(":"), attributes = attributes), KeyboardId.MODE_DATE to BaseKey(spec = "/", attributes = attributes), KeyboardId.MODE_TIME to BaseKey(spec = ":", attributes = attributes), ) private fun selectKey(params: KeyboardParams, keyboard: Keyboard): Key? { if(keyboard.useZWNJKey) { return TemplateZWNJKey } val key = keys[params.mId.mMode] ?: fallbackKey return key } override fun countsToKeyCoordinate(params: KeyboardParams, row: Row, keyboard: Keyboard): Boolean { return selectKey(params, keyboard)?.countsToKeyCoordinate(params, row, keyboard) ?: false } override fun computeData( params: KeyboardParams, row: Row, keyboard: Keyboard, coordinate: KeyCoordinate ): ComputedKeyData? { return selectKey(params, keyboard)?.computeData(params, row, keyboard, coordinate) } } val TemplateEnterKey = EnterKey() val TemplateActionKey = ActionKey() val TemplateContextualKey = ContextualKey() val TemplateGapKey = GapKey() val TemplateZWNJKey = BaseKey( spec = "!icon/zwnj_key|\u200C", moreKeys = listOf("!icon/zwj_key|\u200D"), attributes = KeyAttributes( showPopup = false, moreKeyMode = MoreKeyMode.OnlyExplicit ) ) val TemplateKeys = mapOf( "shift" to TemplateShiftKey, "delete" to TemplateDeleteKey, "space" to TemplateSpaceKey, "enter" to TemplateEnterKey, "symbols" to TemplateSymbolsKey, "alphabet" to TemplateAlphabetKey, "action" to TemplateActionKey, "number" to TemplateNumberKey, "contextual" to TemplateContextualKey, "zwnj" to TemplateZWNJKey, "gap" to TemplateGapKey, "alt0" to TemplateAlt0Key, "alt1" to TemplateAlt1Key, "alt2" to TemplateAlt2Key, )