Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
bcd07d0
chore: update README badges [skip ci]
github-actions[bot] Jul 4, 2026
f499cad
feat: add space preservation & custom translation
LeanBitLab Jul 4, 2026
e1d7398
chore: remove prepackaged english dictionaries
LeanBitLab Jul 4, 2026
7a7ed13
feat: redirect missing dictionary toolbar button directly to settings
LeanBitLab Jul 4, 2026
1541630
fix: allow deletion of downloaded main dictionary when asset is not p…
LeanBitLab Jul 4, 2026
8b7a46f
ux: replace redundant downloadable remove button with installed indic…
LeanBitLab Jul 4, 2026
b28cdcf
fix: allow deletion of downloaded emoji dictionary when asset is not …
LeanBitLab Jul 4, 2026
3c2f8bb
build: exclude all dictionary assets from standard flavors instead of…
LeanBitLab Jul 4, 2026
f7e4c3b
fix: reset word prediction context to beginning of sentence on new lines
LeanBitLab Jul 4, 2026
e58a14d
chore: update README badges [skip ci]
github-actions[bot] Jul 5, 2026
e532978
chore: update README badges [skip ci]
github-actions[bot] Jul 6, 2026
6ddedd4
chore: update README badges [skip ci]
github-actions[bot] Jul 7, 2026
9453570
fix: prevent non-emoji grouping on backspace
LeanBitLab Jul 5, 2026
315987f
feat: custom target language and multilingual proofread examples
LeanBitLab Jul 5, 2026
f092271
fix: use hitbox center for gesture mapping
LeanBitLab Jul 7, 2026
30a1333
perf: early exit on poor gesture matches
LeanBitLab Jul 7, 2026
7953256
style: wrap download button in centered layout
LeanBitLab Jul 7, 2026
cb451e3
style: wrap download button to wrap_content
LeanBitLab Jul 7, 2026
045262c
fix: correct dictionary download button height
LeanBitLab Jul 7, 2026
93cf650
fix: separate experimental dict and allow list delete
LeanBitLab Jul 7, 2026
65ce3d6
style: compact accent-colored delete button
LeanBitLab Jul 7, 2026
ed2192c
chore: bump version to 3.9.2 and add release notes
LeanBitLab Jul 7, 2026
2bb437f
chore: link to features.md on about page
LeanBitLab Jul 7, 2026
6b31be6
docs: document built-in gesture typing
LeanBitLab Jul 7, 2026
8a4e9e6
fix: reload on download and boost predictions
LeanBitLab Jul 7, 2026
0b3a5ee
fix: support variant fallbacks for english india
LeanBitLab Jul 7, 2026
453e8f4
feat: add download dict button toolbar toggle
LeanBitLab Jul 7, 2026
c7842c0
fix: remove direct download link from dialog
LeanBitLab Jul 7, 2026
7029a9f
feat: fallback to user/history unigrams for empty word predictions
LeanBitLab Jul 7, 2026
d0b2349
chore: bump version to 3.9.3
LeanBitLab Jul 7, 2026
2ac999a
perf: optimize SwipeGestureEngine allocations & path math
LeanBitLab Jul 7, 2026
d8e25f4
chore: update release notes & changelog for 3.9.3
LeanBitLab Jul 7, 2026
e3b51eb
fix: enforce segment match temporal key ordering
LeanBitLab Jul 7, 2026
971c6cd
fix: prioritize "to" over "too" when no loop drawn
LeanBitLab Jul 7, 2026
8c4b88e
feat: persist gesture boosts & adapt gesture paths
LeanBitLab Jul 7, 2026
10b76fb
fix: support loading custom locale dictionary files
LeanBitLab Jul 7, 2026
abcd860
fix: bind main dict enablement to layout locale
LeanBitLab Jul 7, 2026
ee5d90c
fix: auto-clear emoji block on alphabet switch
LeanBitLab Jul 7, 2026
9702659
fix: recognize locally imported main_user.dict as valid main dictionary
LeanBitLab Jul 7, 2026
f6ecd81
chore: update README badges [skip ci]
github-actions[bot] Jul 8, 2026
8e761e1
Merge commit '9702659d3' into merge/upstream-v3.9.3
AsafMah Jul 8, 2026
d220f12
chore: update README badges [skip ci]
github-actions[bot] Jul 9, 2026
195b677
fix: resolve blocked words, custom font, symbols number row
LeanBitLab Jul 8, 2026
0509297
feat: allow long-press to delete suggestions from MoreSuggestionsView
LeanBitLab Jul 8, 2026
588c9e3
fix: add window token and type to suggestion delete dialog to prevent…
LeanBitLab Jul 8, 2026
72e8538
style: wrap suggestion deletion dialog with platform dialog theme con…
LeanBitLab Jul 8, 2026
623ca1c
feat: add dynamic custom secondary layouts custom1-5
LeanBitLab Jul 8, 2026
9040f5b
feat: support deleting custom layout slots in settings
LeanBitLab Jul 8, 2026
b6bfeb3
feat: include text expander data in backup
LeanBitLab Jul 8, 2026
2a8e886
feat: add sequential placeholders support to text expander
LeanBitLab Jul 8, 2026
b22b359
fix: resolve initial placeholder synchronously in commitExpandedText
LeanBitLab Jul 8, 2026
1f779cb
fix: clear composing text before deleting text expander prefix
LeanBitLab Jul 8, 2026
4940f8c
fix: conditionally clear composing text only if text expander prefix …
LeanBitLab Jul 8, 2026
917363d
fix: reset composing state when committing suggestion expander
LeanBitLab Jul 8, 2026
f623c75
fix: finish composing text and reset composing state in tryJumpToNext…
LeanBitLab Jul 8, 2026
46ae1ea
fix: delete placeholders synchronously via deleteSurroundingText to a…
LeanBitLab Jul 8, 2026
32b7f91
fix: revert to setSelection for placeholder deletion in tryJumpToNext…
LeanBitLab Jul 8, 2026
0a3dbb1
perf: pack gesture path to longs to fix oom
LeanBitLab Jul 9, 2026
3523d9f
perf: stream dictionary words directly to avoid intermediate maps
LeanBitLab Jul 9, 2026
4efa653
fix: prevent blacklist leaks & auto-caps text selection
LeanBitLab Jul 9, 2026
878e445
doc: update screenshots in README
LeanBitLab Jul 9, 2026
0766f99
feat: add setting for auto-correct triggers
LeanBitLab Jul 9, 2026
6f790af
chore: bump version to 3.9.4
LeanBitLab Jul 9, 2026
56034a6
docs: update release notes and changelog for v3.9.4
LeanBitLab Jul 9, 2026
94516b8
chore: update README badges [skip ci]
github-actions[bot] Jul 10, 2026
18ad764
Merge commit '56034a695' into merge/upstream-v3.9.3
AsafMah Jul 10, 2026
f0f6b28
chore: update README badges [skip ci]
github-actions[bot] Jul 11, 2026
f09e335
fix(gesture): normalize fallback suggestion casing
AsafMah Jul 11, 2026
e2ceae9
feat: add SWITCH_TO_USER_IME keycode
LeanBitLab Jul 11, 2026
b626273
feat: map SWITCH_TO_USER_IME in printableCode
LeanBitLab Jul 11, 2026
7ea75dc
feat: add PREF_DIRECT_IME_SWITCH_TARGET to Settings.java
LeanBitLab Jul 11, 2026
62985f5
feat: add PREF_DIRECT_IME_SWITCH_TARGET to Defaults.kt
LeanBitLab Jul 11, 2026
a7ca940
feat: add string resources for Direct Switch Target IME
LeanBitLab Jul 11, 2026
ac036fe
feat: add Direct Switch Target IME preference UI
LeanBitLab Jul 11, 2026
3972423
feat: implement user IME switching logic in LatinIME
LeanBitLab Jul 11, 2026
da94e42
chore: bump version to 3.9.5
LeanBitLab Jul 11, 2026
c41e62b
docs: add release notes and changelog for v3.9.5
LeanBitLab Jul 11, 2026
974503b
docs: manually update release notes with user additions
LeanBitLab Jul 11, 2026
8cfe7f1
docs: document direct switch IME and custom layouts in README and FEA…
LeanBitLab Jul 11, 2026
72fa441
Merge commit '8cfe7f1fc' into merge/upstream-v3.9.3
AsafMah Jul 11, 2026
25293b3
test: isolate direct IME switch fixtures
AsafMah Jul 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ and this project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html)

## [Unreleased]

### Fixed
- **Fallback gesture suggestions no longer leak dictionary capitalization** when Shift is off; the Java gesture engine now emits canonical lowercase candidates before the existing suggestion presentation-casing layer. (#118)

### Upstream
- Merged **LeanBitLab/LeanType v3.9.5** (pinned at `8cfe7f1fc`, including v3.9.3/v3.9.4) — adds direct switching to a configured IME, persistent custom-layout state, multi-word suggestion controls, and the v3.9.5 release notes. Fork identity (`LeanTypeDual`, distinct `applicationId`, privacy tiers, and fork-specific features) is preserved.

## [3.10.0] - 2026-06-20

### Added
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Type with **both thumbs gliding at the same time**: LeanTypeDual aggregates mult
- **[🛡️ Offline AI (GGUF)](docs/FEATURES.md#5-offline-proofreading-privacy-focused)** - Private, on-device proofreading and translation using local **GGUF models** powered by `llama.cpp` (Offline build only).
- **🌐 AI Translation** - Translate selected text using your chosen provider, with a separate model selector.
- **[✍️ Handwriting Input](docs/FEATURES.md#8-handwriting-input)** - Draw characters directly on a handwriting recognition canvas (Standard version, requires [Leantype-Handwriting-Plugin](https://github.com/LeanBitLab/Leantype-Handwriting-Plugin)).
- **[👆 Built-in Gesture Typing](docs/FEATURES.md#9-built-in-gesture-typing)** - Gesture typing works out of the box using our new built-in pure-Java fallback engine, removing the strict dependency on native Google libraries.
- **[🧠 Custom AI Keys](docs/FEATURES.md#4-custom-ai-keys--keywords)** - Assign custom prompts, personas (#editor, #proofread), and labels/tags (themed capsules) to 10 customizable toolbar keys.
- **📝 Text Expander** - Shortcut → expansion with dynamic placeholders (`%clipboard%`, `%day%`, `%time12%`, `%cursor%`, lists), regex shortcuts, backspace-to-revert, and a guide.
- **🧠 Smarter learned words** - *graduated trust* keeps a just-learned word below real-dictionary suggestions until you've used it a few times (no premature autocorrect to half-typed words); flag unknown words to **Add** or **Block** them via a Blocklist screen.
Expand All @@ -34,6 +35,8 @@ Type with **both thumbs gliding at the same time**: LeanTypeDual aggregates mult
- **🪟 Floating Keyboard** - Detach the keyboard into a draggable, resizable window (true OS-level overlay), with an optional persistent mode.
- **⌨️ Dual Toolbar / Split Suggestions** - Split the suggestion strip and toolbar for easier reach.
- **🖱️ Touchpad Mode** - Swipe the spacebar up for a cursor touchpad with sensitivity controls and edge-scroll acceleration, including a full-screen laptop-style mode.
- **[⌨️ Direct Switch IME](docs/FEATURES.md#10-direct-switch-target-ime)** - Map custom keycode (`-10076`) to any toolbar key to switch directly to another input method.
- **[🎨 Custom Layouts](docs/FEATURES.md#11-custom-layouts-customization)** - Save up to five custom layout profiles with persistent slot index tracking.
- **✍️ Text editing mode** - A toolbar key opens a text-editing overlay for selection, cursor movement, and clipboard actions.
- **🎨 Modern UI** - "Squircle" key backgrounds, refined icons, and polished aesthetics.
- **🔄 Google Dictionary Import** - Import your personal dictionary words.
Expand Down Expand Up @@ -109,7 +112,7 @@ Type with **both thumbs gliding at the same time**: LeanTypeDual aggregates mult
<li>Customize keyboard themes (style, colors and background image)</li>
<li>Customize keyboard layouts</li>
<li>Multilingual typing</li>
<li>Glide typing (<i>requires library</i>)</li>
<li>Glide typing (works out of the box with built-in pure-Java fallback engine, or use native library)</li>
<li>Clipboard history</li>
<li>One-handed mode</li>
<li>Split keyboard</li>
Expand Down
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,11 @@ android {
variant.proguardFiles.add(project.layout.buildDirectory.file(project.buildFile.parent + "/proguard-rules.pro"))
}
if (variant.flavorName == "standard" || variant.flavorName == "standardfull") {
// ponytail: dynamically find all dict files to ignore in standard flavor except main_en-US.dict
// Ignore all dictionary assets in standard/standardfull flavors
val dictsDir = project.file("src/main/assets/dicts")
if (dictsDir.exists() && dictsDir.isDirectory) {
dictsDir.listFiles()?.forEach { file ->
if (file.name.endsWith(".dict") && file.name != "main_en-US.dict") {
if (file.name.endsWith(".dict")) {
patterns.add(file.name)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
override fun onCodeInput(primaryCode: Int, x: Int, y: Int, isKeyRepeat: Boolean) {
val isArrow = primaryCode == KeyCode.ARROW_LEFT || primaryCode == KeyCode.ARROW_RIGHT || primaryCode == KeyCode.ARROW_UP || primaryCode == KeyCode.ARROW_DOWN
if (isArrow) {
val isSelecting = keyboardSwitcher.keyboard?.mId?.isAlphabetShifted == true || sPersistentSelectionModeActive
val isSelecting = keyboardSwitcher.keyboard?.mId?.isAlphabetShiftedManually == true || sPersistentSelectionModeActive
if (isSelecting) {
val androidKeyCode = when (primaryCode) {
KeyCode.ARROW_LEFT -> KeyEvent.KEYCODE_DPAD_LEFT
Expand Down Expand Up @@ -219,7 +219,7 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
|| primaryCode == KeyCode.MOVE_START_OF_PAGE || primaryCode == KeyCode.MOVE_END_OF_PAGE
|| primaryCode == KeyCode.MOVE_START_OF_LINE || primaryCode == KeyCode.MOVE_END_OF_LINE
|| primaryCode == KeyCode.PAGE_UP || primaryCode == KeyCode.PAGE_DOWN
val eventMetaState = if (isEditingNav && (keyboardSwitcher.keyboard?.mId?.isAlphabetShifted == true || sPersistentSelectionModeActive)) {
val eventMetaState = if (isEditingNav && (keyboardSwitcher.keyboard?.mId?.isAlphabetShiftedManually == true || sPersistentSelectionModeActive)) {
metaState or KeyEvent.META_SHIFT_ON
} else {
metaState
Expand Down Expand Up @@ -391,7 +391,7 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
val rtl = RichInputMethodManager.getInstance().currentSubtype.isRtlSubtype
val steps = if (rtl) -rawSteps else rawSteps

val isSelecting = keyboardSwitcher.keyboard?.mId?.isAlphabetShifted == true || sPersistentSelectionModeActive
val isSelecting = keyboardSwitcher.keyboard?.mId?.isAlphabetShiftedManually == true || sPersistentSelectionModeActive
if (isSelecting) {
val code = if (steps < 0) {
gestureMoveBackHaptics()
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/java/helium314/keyboard/keyboard/KeyboardId.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ public final class KeyboardId {
public static final int ELEMENT_CLIPBOARD_BOTTOM_ROW = 30;
public static final int ELEMENT_HANDWRITING_BOTTOM_ROW = 31;
public static final int ELEMENT_TEXT_EDIT = 32;
public static final int ELEMENT_CUSTOM1 = 33;
public static final int ELEMENT_CUSTOM2 = 34;
public static final int ELEMENT_CUSTOM3 = 35;
public static final int ELEMENT_CUSTOM4 = 36;
public static final int ELEMENT_CUSTOM5 = 37;

public final RichInputMethodSubtype mSubtype;
public final int mWidth;
Expand Down Expand Up @@ -296,6 +301,11 @@ public static String elementIdToName(final int elementId) {
case ELEMENT_CLIPBOARD_BOTTOM_ROW -> "clipboardBottomRow";
case ELEMENT_HANDWRITING_BOTTOM_ROW -> "handwritingBottomRow";
case ELEMENT_TEXT_EDIT -> "editing";
case ELEMENT_CUSTOM1 -> "custom1";
case ELEMENT_CUSTOM2 -> "custom2";
case ELEMENT_CUSTOM3 -> "custom3";
case ELEMENT_CUSTOM4 -> "custom4";
case ELEMENT_CUSTOM5 -> "custom5";
default -> null;
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,22 @@ public void setSymbolsShiftedKeyboard() {
setKeyboard(KeyboardId.ELEMENT_SYMBOLS_SHIFTED, KeyboardSwitchState.SYMBOLS_SHIFTED);
}

@Override
public void setCustomKeyboard(int customIndex) {
if (DEBUG_ACTION) {
Log.d(TAG, "setCustomKeyboard: " + customIndex);
}
final int elementId = switch (customIndex) {
case 1 -> KeyboardId.ELEMENT_CUSTOM1;
case 2 -> KeyboardId.ELEMENT_CUSTOM2;
case 3 -> KeyboardId.ELEMENT_CUSTOM3;
case 4 -> KeyboardId.ELEMENT_CUSTOM4;
case 5 -> KeyboardId.ELEMENT_CUSTOM5;
default -> KeyboardId.ELEMENT_ALPHABET;
};
setKeyboard(elementId, KeyboardSwitchState.OTHER);
}

public boolean isImeSuppressedByHardwareKeyboard(
@NonNull final SettingsValues settingsValues,
@NonNull final KeyboardSwitchState toggleState) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,9 @@ public void onKeyReleased(@NonNull final Key key, final boolean withAnimation) {
private void dismissKeyPreview(@NonNull final Key key) {
if (isHardwareAccelerated()) {
mKeyPreviewChoreographer.dismissKeyPreview(key);
} else {
// ponytail: fallback if hardware acceleration is disabled
dismissKeyPreviewWithoutDelay(key);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class KeyboardState(private val switchActions: SwitchActions) {
fun toggleNumpad(withSliding: Boolean, autoCapsFlags: Int, recapitalizeMode: RecapitalizeMode?, forceReturnToAlpha: Boolean)
fun setSymbolsKeyboard()
fun setSymbolsShiftedKeyboard()
fun setCustomKeyboard(customIndex: Int)

/** Request to call back [KeyboardState.onUpdateShiftState]. */
fun requestUpdatingShiftState(autoCapsFlags: Int, recapitalizeMode: RecapitalizeMode?)
Expand All @@ -65,6 +66,8 @@ class KeyboardState(private val switchActions: SwitchActions) {

private var mode = Mode.ALPHABET
private var modeBeforeNumpad = Mode.ALPHABET
// ponytail: track active custom layout index, 0 means default
private var lastCustomIndex = 0
private var isSymbolShifted = false
private var prevMainKeyboardWasShiftLocked = false
private var prevSymbolsKeyboardWasShifted = false
Expand Down Expand Up @@ -109,6 +112,7 @@ class KeyboardState(private val switchActions: SwitchActions) {
savedKeyboardState.isValid = false
} else {
// Reset keyboard to alphabet mode.
lastCustomIndex = 0
setAlphabetKeyboard(autoCapsFlags, recapitalizeMode)
}
switchActions.setOneHandedModeEnabled(onHandedModeEnabled)
Expand Down Expand Up @@ -151,6 +155,11 @@ class KeyboardState(private val switchActions: SwitchActions) {
Mode.CLIPBOARD -> setClipboardKeyboard()
// don't overwrite toggle state if reloading from orientation change, etc.
Mode.NUMPAD -> setNumpadKeyboard(false, false, false)
Mode.CUSTOM1 -> setCustomKeyboard(1)
Mode.CUSTOM2 -> setCustomKeyboard(2)
Mode.CUSTOM3 -> setCustomKeyboard(3)
Mode.CUSTOM4 -> setCustomKeyboard(4)
Mode.CUSTOM5 -> setCustomKeyboard(5)
}
}

Expand Down Expand Up @@ -205,7 +214,7 @@ class KeyboardState(private val switchActions: SwitchActions) {
if (DebugFlags.DEBUG_ENABLED) {
Log.d(TAG, "toggleAlphabetAndSymbols: ${stateToString(autoCapsFlags, recapitalizeMode)}")
}
if (mode == Mode.ALPHABET) {
if (mode == Mode.ALPHABET || mode.isCustom) {
prevMainKeyboardWasShiftLocked = alphabetShiftState.isShiftLocked
if (prevSymbolsKeyboardWasShifted) setSymbolsShiftedKeyboard() else setSymbolsKeyboard()
prevSymbolsKeyboardWasShifted = false
Expand All @@ -223,7 +232,7 @@ class KeyboardState(private val switchActions: SwitchActions) {
if (DebugFlags.DEBUG_ENABLED) {
Log.d(TAG, "resetKeyboardStateToAlphabet: ${stateToString(autoCapsFlags, recapitalizeMode)}")
}
if (mode == Mode.ALPHABET) return
if (mode == Mode.ALPHABET || mode.isCustom) return

prevSymbolsKeyboardWasShifted = isSymbolShifted
setAlphabetKeyboard(autoCapsFlags, recapitalizeMode)
Expand All @@ -246,6 +255,12 @@ class KeyboardState(private val switchActions: SwitchActions) {
Log.d(TAG, "setAlphabetKeyboard: ${stateToString(autoCapsFlags, recapitalizeMode)}")
}

// ponytail: restore custom layout if active
if (lastCustomIndex != 0) {
setCustomKeyboard(lastCustomIndex)
return
}

switchActions.setAlphabetKeyboard()
mode = Mode.ALPHABET
isSymbolShifted = false
Expand All @@ -254,6 +269,23 @@ class KeyboardState(private val switchActions: SwitchActions) {
switchActions.requestUpdatingShiftState(autoCapsFlags, recapitalizeMode)
}

private fun setCustomKeyboard(customIndex: Int) {
if (DebugFlags.DEBUG_ENABLED) {
Log.d(TAG, "setCustomKeyboard: $customIndex")
}
mode = when (customIndex) {
1 -> Mode.CUSTOM1
2 -> Mode.CUSTOM2
3 -> Mode.CUSTOM3
4 -> Mode.CUSTOM4
5 -> Mode.CUSTOM5
else -> Mode.ALPHABET
}
lastCustomIndex = customIndex
recapitalizeMode = null
switchActions.setCustomKeyboard(customIndex)
}

private fun setSymbolsKeyboard() {
if (DebugFlags.DEBUG_ENABLED) {
Log.d(TAG, "setSymbolsKeyboard")
Expand Down Expand Up @@ -340,7 +372,7 @@ class KeyboardState(private val switchActions: SwitchActions) {
setNumpadKeyboard(withSliding, forceReturnToAlpha, rememberState)
return
}
if (modeBeforeNumpad == Mode.ALPHABET || forceReturnToAlpha) {
if (modeBeforeNumpad == Mode.ALPHABET || modeBeforeNumpad.isCustom || forceReturnToAlpha) {
setAlphabetKeyboard(autoCapsFlags, recapitalizeMode)
if (prevMainKeyboardWasShiftLocked) {
setShiftLocked(true)
Expand All @@ -355,6 +387,7 @@ class KeyboardState(private val switchActions: SwitchActions) {
Mode.EMOJI -> setEmojiKeyboard()
Mode.CLIPBOARD -> setClipboardKeyboard()
Mode.NUMPAD -> {}
else -> {}
}
if (withSliding) switchState = SwitchState.MOMENTARY_FROM_NUMPAD
}
Expand Down Expand Up @@ -510,6 +543,10 @@ class KeyboardState(private val switchActions: SwitchActions) {
if (recapitalizeMode != null) {
return
}
if (mode.isCustom) {
shiftKeyState.onPress()
return
}
if (mode != Mode.ALPHABET) {
// In symbol mode, just toggle symbol and symbol popup keyboard.
toggleShiftInSymbols()
Expand Down Expand Up @@ -555,6 +592,8 @@ class KeyboardState(private val switchActions: SwitchActions) {
if (this.recapitalizeMode != null) {
// We are recapitalizing. We should match the keyboard state to the recapitalize state in priority.
updateShiftStateForRecapitalize(this.recapitalizeMode)
} else if (mode.isCustom) {
shiftKeyState.onRelease()
} else if (mode != Mode.ALPHABET) {
// In symbol mode, switch back to the previous keyboard mode if the user chords the
// shift key and another key, then releases the shift key.
Expand Down Expand Up @@ -665,11 +704,19 @@ class KeyboardState(private val switchActions: SwitchActions) {
updateAlphabetShiftState(autoCapsFlags, recapitalizeMode)
} else when (code) {
KeyCode.EMOJI -> setEmojiKeyboard()
KeyCode.ALPHA -> setAlphabetKeyboard(autoCapsFlags, recapitalizeMode)
KeyCode.ALPHA -> {
lastCustomIndex = 0
setAlphabetKeyboard(autoCapsFlags, recapitalizeMode)
}
// Note: Printing clipboard content is handled in InputLogic.handleFunctionalEvent
KeyCode.CLIPBOARD -> if (Settings.getValues().mClipboardHistoryEnabled) setClipboardKeyboard()
KeyCode.NUMPAD -> toggleNumpad(false, autoCapsFlags, recapitalizeMode, false, true)
KeyCode.SYMBOL -> setSymbolsKeyboard()
KeyCode.CUSTOM1 -> setCustomKeyboard(1)
KeyCode.CUSTOM2 -> setCustomKeyboard(2)
KeyCode.CUSTOM3 -> setCustomKeyboard(3)
KeyCode.CUSTOM4 -> setCustomKeyboard(4)
KeyCode.CUSTOM5 -> setCustomKeyboard(5)
KeyCode.TOGGLE_ONE_HANDED_MODE -> setOneHandedModeEnabled(!Settings.getValues().mOneHandedModeEnabled)
KeyCode.SWITCH_ONE_HANDED_MODE -> switchOneHandedMode()
KeyCode.TOGGLE_FLOATING_KEYBOARD -> switchActions.toggleFloatingKeyboard()
Expand All @@ -679,6 +726,7 @@ class KeyboardState(private val switchActions: SwitchActions) {
override fun toString(): String {
val keyboard = when {
mode == Mode.ALPHABET -> alphabetShiftState.toString()
mode.isCustom -> mode.toString()
isSymbolShifted -> "SYMBOLS_SHIFTED"
else -> "SYMBOLS"
}
Expand Down Expand Up @@ -707,6 +755,13 @@ class KeyboardState(private val switchActions: SwitchActions) {
EMOJI,
CLIPBOARD,
NUMPAD,
CUSTOM1,
CUSTOM2,
CUSTOM3,
CUSTOM4,
CUSTOM5;

val isCustom: Boolean get() = this == CUSTOM1 || this == CUSTOM2 || this == CUSTOM3 || this == CUSTOM4 || this == CUSTOM5
}

private enum class ShiftMode {
Expand Down
Loading
Loading