Accelerated backspace measures the wrong code point and can split an emoji
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 65/100
Research direction
Read app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java around lines 2019–2026, starting with the accelerated backspace logic and how it reads the code point before the cursor. Check the deletion length for both a plain character followed by an emoji and an emoji followed by a plain character; done means the second deletion uses the re-read code point and does not split an emoji or over-delete a plain character.
Written by the indexing model from the issue text.
Description
Summary
In InputLogic.handleBackspaceEvent, the accelerated (held-backspace) second deletion measures its length from the first code point instead of the one it is actually about to delete. When the second character back is a multi-code-point emoji, this deletes the wrong number of chars and can split the emoji, leaving an orphaned surrogate or a stray variation selector / ZWJ.
Present at tag v4.1.2 (f0ff166ae).
Location
app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java, around lines 2019–2026:
final int codePointBeforeCursorToDeleteAgain = mConnection.getCodePointBeforeCursor();
if (codePointBeforeCursorToDeleteAgain != Constants.NOT_A_CODE) {
final int lengthToDeleteAgain = codePointBeforeCursor > 0xFE00 // <-- first code point
|| StringUtils.mightBeEmoji(codePointBeforeCursor) // <-- first code point
? mConnection.getCharCountToDeleteBeforeCursor()
: 1;
mConnection.deleteTextBeforeCursor(lengthToDeleteAgain);
totalDeletedLength += lengthToDeleteAgain;
}
The guard correctly re-reads the cursor into codePointBeforeCursorToDeleteAgain, but the ternary that decides the delete length still tests codePointBeforeCursor — the value from before the first deletion.
Consequences
Both directions are wrong:
- First char plain, second an emoji → the branch evaluates
false, solengthToDeleteAgainis1. A singlecharis removed from a multi-charemoji, splitting it. - First char an emoji, second plain → the branch evaluates
true, sogetCharCountToDeleteBeforeCursor()is used against a plain character and may remove more than intended.
Only reachable once mDeleteCount > Constants.DELETE_ACCELERATE_AT, i.e. while holding backspace, which is probably why it has gone unnoticed.
Suggested fix
Use the re-read value in the condition, so it describes the character actually being deleted:
final int lengthToDeleteAgain = codePointBeforeCursorToDeleteAgain > 0xFE00
|| StringUtils.mightBeEmoji(codePointBeforeCursorToDeleteAgain)
? mConnection.getCharCountToDeleteBeforeCursor()
: 1;
Notes
Found while merging v4.1.2 into a downstream fork. This almost certainly predates LeanType — the surrounding accelerated-delete code comes from the HeliBoard/AOSP lineage — so it may be worth forwarding to Helium314/HeliBoard as well.
I have no reproduction on a physical device; this is from reading the code, so please sanity-check the emoji-splitting claim against real input before acting on it.
- Dominant language
- Kotlin
- Stars
- 1k
- Forks
- 59
- Avg merge
- 14h 37m
- Merged PRs (30d)
- 54
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from LeanBitLab/LeanType
-
Voice input fails in browser address bars due to incorrect password field detection (v4.2.9, follow-up to #516)Possibly taken @LeanBitLab claimed this 3 days ago. Openbug
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
LeanBitLab/LeanType#713 · 1 comment · 1 assignee ·
Maintainers usually reply within 1 day
-
bug
Difficulty 3/5 1-2 days Newbie friendliness 66/100
LeanBitLab/LeanType#732 ·
Maintainers usually reply within 1 day
-
enhancement
Difficulty 3/5 1-2 days Newbie friendliness 70/100
LeanBitLab/LeanType#724 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 3/5 1-2 days Newbie friendliness 55/100
LeanBitLab/LeanType#723 ·
Maintainers usually reply within 1 day
-
enhancement
Difficulty 3/5 1-2 days Newbie friendliness 56/100
LeanBitLab/LeanType#721 ·
Maintainers usually reply within 1 day
All issues in LeanBitLab/LeanType
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
open-learning-exchange/myplanet#18392 ·
Maintainers usually reply within 2 days
-
Currency RequestOpenenhancement
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
saisaharsh3/Leftovers#28 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
sameerasw/essentials#1579 ·
Maintainers usually reply within 1 day
-
bug: instrumented batch loaders throw from Object methodsPossibly taken @blihio claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 79/100
Netflix/dgs-framework#2366 ·
Maintainers usually reply within 2 days
-
JavalinVue throws when a JAR omits the marker class's package directory entryPossibly taken @blihio claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 83/100
Maintainers usually reply within 2 days