mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-05-17 07:22:45 +00:00
use new parser for number layouts (tablet/landscape still missing some keys)
This commit is contained in:
parent
100da1beae
commit
4406f1b224
10 changed files with 347 additions and 46 deletions
49
app/src/main/assets/layouts/number.json
Normal file
49
app/src/main/assets/layouts/number.json
Normal file
|
@ -0,0 +1,49 @@
|
|||
[
|
||||
[
|
||||
{ "label": "1", "type": "numeric" },
|
||||
{ "label": "2", "type": "numeric" },
|
||||
{ "label": "3", "type": "numeric" },
|
||||
{ "label": "-", "popup": { "main": { "label": "+" } }, "labelFlags": 1073742336 }
|
||||
],
|
||||
[
|
||||
{ "label": "4", "type": "numeric" },
|
||||
{ "label": "5", "type": "numeric" },
|
||||
{ "label": "6", "type": "numeric" },
|
||||
{ "label": "space" }
|
||||
],
|
||||
[
|
||||
{ "label": "7", "type": "numeric" },
|
||||
{ "label": "8", "type": "numeric" },
|
||||
{ "label": "9", "type": "numeric" },
|
||||
{ "label": "delete" }
|
||||
],
|
||||
[
|
||||
{ "$": "variation_selector",
|
||||
"default": { "label": "," },
|
||||
"date": { "label": "." },
|
||||
"time": { "time": ".", "popup": { "relevant": [
|
||||
{ "label": "!fixedColumnOrder!2" },
|
||||
{ "label": "!hasLabels!" },
|
||||
{ "label": "AM" },
|
||||
{ "label": "PM" }
|
||||
] } },
|
||||
"datetime": { "time": ".", "popup": { "relevant": [
|
||||
{ "label": "!fixedColumnOrder!2" },
|
||||
{ "label": "!hasLabels!" },
|
||||
{ "label": "AM" },
|
||||
{ "label": "PM" }
|
||||
] } }
|
||||
},
|
||||
{ "label": "0", "type": "numeric" },
|
||||
{ "$": "variation_selector",
|
||||
"default": { "label": "." },
|
||||
"date": { "label": "/" },
|
||||
"time": { "time": ":" },
|
||||
"datetime": { "time": "/ :|/", "popup": { "relevant": [
|
||||
{ "label": "!noPanelAutoMoreKey!" },
|
||||
{ "label": "," }
|
||||
] } }
|
||||
},
|
||||
{ "label": "enter"}
|
||||
]
|
||||
]
|
50
app/src/main/assets/layouts/numpad.json
Normal file
50
app/src/main/assets/layouts/numpad.json
Normal file
|
@ -0,0 +1,50 @@
|
|||
[
|
||||
[
|
||||
{ "label": "+", "popup": {
|
||||
"relevant": [
|
||||
{ "label": "(" },
|
||||
{ "label": "<" },
|
||||
{ "label": "±" }
|
||||
]
|
||||
}, "labelFlags": 512 },
|
||||
{ "label": "1", "type": "numeric" },
|
||||
{ "label": "2", "type": "numeric" },
|
||||
{ "label": "3", "type": "numeric" },
|
||||
{ "label": "%", "popup": { "main": { "label": "$$$"} }, "labelFlags": 512 }
|
||||
],
|
||||
[
|
||||
{ "label": "-", "popup": {
|
||||
"relevant": [
|
||||
{ "label": ")" },
|
||||
{ "label": ">" },
|
||||
{ "label": "~" }
|
||||
]
|
||||
}, "labelFlags": 512 },
|
||||
{ "label": "4", "type": "numeric" },
|
||||
{ "label": "5", "type": "numeric" },
|
||||
{ "label": "6", "type": "numeric" },
|
||||
{ "label": "space" }
|
||||
],
|
||||
[
|
||||
{ "label": "*", "popup": {
|
||||
"relevant": [
|
||||
{ "label": "/" },
|
||||
{ "label": "×" },
|
||||
{ "label": "÷" }
|
||||
]
|
||||
}, "labelFlags": 512 },
|
||||
{ "label": "7", "type": "numeric" },
|
||||
{ "label": "8", "type": "numeric" },
|
||||
{ "label": "9", "type": "numeric" },
|
||||
{ "label": "delete" }
|
||||
],
|
||||
[
|
||||
{ "label": "alpha" },
|
||||
{ "label": "comma" },
|
||||
{ "label": "symbol" },
|
||||
{ "label": "0", "type": "numeric" },
|
||||
{ "label": "=", "popup": { "relevant": [ { "label": "≠"}, { "label": "≈"} ] } },
|
||||
{ "label": "period" },
|
||||
{ "label": "enter" }
|
||||
]
|
||||
]
|
26
app/src/main/assets/layouts/phone.json
Normal file
26
app/src/main/assets/layouts/phone.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
[
|
||||
[
|
||||
{ "label": "1", "type": "numeric" },
|
||||
{ "label": "2", "type": "numeric", "popup": { "main": { "label": "ABC" } } },
|
||||
{ "label": "3", "type": "numeric", "popup": { "main": { "label": "DEF" } } },
|
||||
{ "label": "-", "popup": { "main": { "label": "+" } }, "labelFlags": 1073742336 }
|
||||
],
|
||||
[
|
||||
{ "label": "4", "type": "numeric", "popup": { "main": { "label": "GHI" } } },
|
||||
{ "label": "5", "type": "numeric", "popup": { "main": { "label": "JKL" } } },
|
||||
{ "label": "6", "type": "numeric", "popup": { "main": { "label": "MNO" } } },
|
||||
{ "label": "space" }
|
||||
],
|
||||
[
|
||||
{ "label": "7", "type": "numeric", "popup": { "main": { "label": "PQRS" } } },
|
||||
{ "label": "8", "type": "numeric", "popup": { "main": { "label": "TUV" } } },
|
||||
{ "label": "9", "type": "numeric", "popup": { "main": { "label": "WXYZ" } } },
|
||||
{ "label": "delete" }
|
||||
],
|
||||
[
|
||||
{ "label": "*#|!code/key_switch_alpha_symbol", "labelFlags": 524432 },
|
||||
{ "label": "0 +|0", "type": "numeric", "popup": { "relevant": [ { "label": "!noPanelAutoMoreKey!" }, { "label": "+" } ] } },
|
||||
{ "label": "." },
|
||||
{ "label": "action" }
|
||||
]
|
||||
]
|
26
app/src/main/assets/layouts/phone_symbols.json
Normal file
26
app/src/main/assets/layouts/phone_symbols.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
[
|
||||
[
|
||||
{ "label": "(", "type": "numeric" },
|
||||
{ "label": "/", "type": "numeric" },
|
||||
{ "label": ")", "type": "numeric" },
|
||||
{ "label": "-", "popup": { "main": { "label": "+" } } }
|
||||
],
|
||||
[
|
||||
{ "label": "N", "type": "numeric" },
|
||||
{ "label": "!string/label_pause_key|,", "type": "numeric" },
|
||||
{ "label": ",", "type": "numeric" },
|
||||
{ "label": "space" }
|
||||
],
|
||||
[
|
||||
{ "label": "*|*", "type": "numeric" },
|
||||
{ "label": "!string/label_wait_key|;", "type": "numeric" },
|
||||
{ "label": "\\#", "type": "numeric" },
|
||||
{ "label": "delete" }
|
||||
],
|
||||
[
|
||||
{ "label": "123|!code/key_switch_alpha_symbol", "labelFlags": 524432 },
|
||||
{ "label": "+", "type": "numeric" },
|
||||
{ "label": "." },
|
||||
{ "label": "action" }
|
||||
]
|
||||
]
|
|
@ -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!"))
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
"{" -> "{|}"
|
||||
"}" -> "}|{"
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue