mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-04-22 23:29:10 +00:00
properly determine length of emojis when deleting
fixes issue described in https://github.com/Helium314/HeliBoard/issues/426#issuecomment-1944132643, but not the initial problem
This commit is contained in:
parent
fe5aa2c33c
commit
4b52f2d51d
5 changed files with 65 additions and 23 deletions
|
@ -1046,6 +1046,14 @@ public final class RichInputConnection implements PrivateCommandPerformer {
|
||||||
return mCommittedTextBeforeComposingText.indexOf(" ") != -1;
|
return mCommittedTextBeforeComposingText.indexOf(" ") != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getCharCountToDeleteBeforeCursor() {
|
||||||
|
final int lastCodePoint = getCodePointBeforeCursor();
|
||||||
|
if (!Character.isSupplementaryCodePoint(lastCodePoint)) return 1;
|
||||||
|
if (!StringUtils.mightBeEmoji(lastCodePoint)) return 2;
|
||||||
|
final String text = mCommittedTextBeforeComposingText.toString() + mComposingText;
|
||||||
|
return StringUtilsKt.getFullEmojiAtEnd(text).length();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasLetterBeforeLastSpaceBeforeCursor() {
|
public boolean hasLetterBeforeLastSpaceBeforeCursor() {
|
||||||
return StringUtilsKt.hasLetterBeforeLastSpaceBeforeCursor(mCommittedTextBeforeComposingText);
|
return StringUtilsKt.hasLetterBeforeLastSpaceBeforeCursor(mCommittedTextBeforeComposingText);
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,6 +191,8 @@ public final class Constants {
|
||||||
|
|
||||||
public static final String REGEXP_PERIOD = "\\.";
|
public static final String REGEXP_PERIOD = "\\.";
|
||||||
public static final String STRING_SPACE = " ";
|
public static final String STRING_SPACE = " ";
|
||||||
|
public static final int CODE_ZWNJ = '\u200C';
|
||||||
|
public static final int CODE_ZWJ = '\u200D';
|
||||||
|
|
||||||
public static boolean isLetterCode(final int code) {
|
public static boolean isLetterCode(final int code) {
|
||||||
return code >= CODE_SPACE;
|
return code >= CODE_SPACE;
|
||||||
|
|
|
@ -53,6 +53,29 @@ fun hasLetterBeforeLastSpaceBeforeCursor(s: CharSequence): Boolean {
|
||||||
return letter
|
return letter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** get the complete emoji at end of [s], considering that emojis can be joined with ZWJ resulting in different emojis */
|
||||||
|
fun getFullEmojiAtEnd(s: CharSequence): String {
|
||||||
|
val text = if (s is String) s else s.toString()
|
||||||
|
var offset = text.length
|
||||||
|
while (offset > 0) {
|
||||||
|
val codepoint = text.codePointBefore(offset)
|
||||||
|
// stop if codepoint can't be emoji
|
||||||
|
if (!mightBeEmoji(codepoint)) return ""
|
||||||
|
offset -= Character.charCount(codepoint)
|
||||||
|
if (offset > 0 && text[offset - 1].code == Constants.CODE_ZWJ) {
|
||||||
|
// continue if ZWJ
|
||||||
|
offset -= 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// check the whole text after offset
|
||||||
|
val textToCheck = text.substring(offset)
|
||||||
|
if (isEmoji(textToCheck)) {
|
||||||
|
return textToCheck
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
/** split the string on the first of consecutive space only, further consecutive spaces are added to the next split */
|
/** split the string on the first of consecutive space only, further consecutive spaces are added to the next split */
|
||||||
fun String.splitOnFirstSpacesOnly(): List<String> {
|
fun String.splitOnFirstSpacesOnly(): List<String> {
|
||||||
val out = mutableListOf<String>()
|
val out = mutableListOf<String>()
|
||||||
|
|
|
@ -1253,12 +1253,8 @@ public final class InputLogic {
|
||||||
// TODO: Add a new StatsUtils method onBackspaceWhenNoText()
|
// TODO: Add a new StatsUtils method onBackspaceWhenNoText()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (StringUtils.mightBeEmoji(codePointBeforeCursor)) {
|
final int lengthToDelete = Character.isSupplementaryCodePoint(codePointBeforeCursor)
|
||||||
// emoji length varies, so we'd need to find out length to delete correctly
|
? mConnection.getCharCountToDeleteBeforeCursor() : 1;
|
||||||
// the solution is not optimal, but a reasonable workaround for issues when trying to delete emojis
|
|
||||||
sendDownUpKeyEvent(KeyEvent.KEYCODE_DEL);
|
|
||||||
} else {
|
|
||||||
final int lengthToDelete = Character.isSupplementaryCodePoint(codePointBeforeCursor) ? 2 : 1;
|
|
||||||
mConnection.deleteTextBeforeCursor(lengthToDelete);
|
mConnection.deleteTextBeforeCursor(lengthToDelete);
|
||||||
int totalDeletedLength = lengthToDelete;
|
int totalDeletedLength = lengthToDelete;
|
||||||
if (mDeleteCount > Constants.DELETE_ACCELERATE_AT) {
|
if (mDeleteCount > Constants.DELETE_ACCELERATE_AT) {
|
||||||
|
@ -1270,8 +1266,8 @@ public final class InputLogic {
|
||||||
final int codePointBeforeCursorToDeleteAgain =
|
final int codePointBeforeCursorToDeleteAgain =
|
||||||
mConnection.getCodePointBeforeCursor();
|
mConnection.getCodePointBeforeCursor();
|
||||||
if (codePointBeforeCursorToDeleteAgain != Constants.NOT_A_CODE) {
|
if (codePointBeforeCursorToDeleteAgain != Constants.NOT_A_CODE) {
|
||||||
final int lengthToDeleteAgain = Character.isSupplementaryCodePoint(
|
final int lengthToDeleteAgain = Character.isSupplementaryCodePoint(codePointBeforeCursorToDeleteAgain)
|
||||||
codePointBeforeCursorToDeleteAgain) ? 2 : 1;
|
? mConnection.getCharCountToDeleteBeforeCursor() : 1;
|
||||||
mConnection.deleteTextBeforeCursor(lengthToDeleteAgain);
|
mConnection.deleteTextBeforeCursor(lengthToDeleteAgain);
|
||||||
totalDeletedLength += lengthToDeleteAgain;
|
totalDeletedLength += lengthToDeleteAgain;
|
||||||
}
|
}
|
||||||
|
@ -1279,7 +1275,6 @@ public final class InputLogic {
|
||||||
StatsUtils.onBackspacePressed(totalDeletedLength);
|
StatsUtils.onBackspacePressed(totalDeletedLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!hasUnlearnedWordBeingDeleted) {
|
if (!hasUnlearnedWordBeingDeleted) {
|
||||||
// Consider unlearning the word being deleted (if we have not done so already).
|
// Consider unlearning the word being deleted (if we have not done so already).
|
||||||
unlearnWordBeingDeleted(
|
unlearnWordBeingDeleted(
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
package helium314.keyboard.latin
|
package helium314.keyboard.latin
|
||||||
|
|
||||||
import helium314.keyboard.latin.common.StringUtils
|
import helium314.keyboard.latin.common.StringUtils
|
||||||
|
import helium314.keyboard.latin.common.getFullEmojiAtEnd
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
// todo: actually this test could/should be significantly expanded...
|
// todo: actually this test could/should be significantly expanded...
|
||||||
|
@ -39,6 +41,18 @@ class StringUtilsTest {
|
||||||
assert(StringUtils.isInsideDoubleQuoteOrAfterDigit("hello \"yes\", \"h"))
|
assert(StringUtils.isInsideDoubleQuoteOrAfterDigit("hello \"yes\", \"h"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test fun detectEmojisAtEnd() {
|
||||||
|
assertEquals("\uD83C\uDF83", getFullEmojiAtEnd("\uD83C\uDF83"))
|
||||||
|
assertEquals("ℹ️", getFullEmojiAtEnd("ℹ️"))
|
||||||
|
assertEquals("ℹ️", getFullEmojiAtEnd("ℹ️ℹ️"))
|
||||||
|
assertEquals("\uD83D\uDE22", getFullEmojiAtEnd("x\uD83D\uDE22"))
|
||||||
|
assertEquals("", getFullEmojiAtEnd("x\uD83D\uDE22 "))
|
||||||
|
assertEquals("\uD83C\uDFF4\u200D☠️", getFullEmojiAtEnd("ok \uD83C\uDFF4\u200D☠️"))
|
||||||
|
assertEquals("\uD83C\uDFF3️\u200D\uD83C\uDF08", getFullEmojiAtEnd("\uD83C\uDFF3️\u200D\uD83C\uDF08"))
|
||||||
|
assertEquals("\uD83C\uDFF3️\u200D\uD83C\uDF08", getFullEmojiAtEnd("\uD83C\uDFF4\u200D☠️\uD83C\uDFF3️\u200D\uD83C\uDF08"))
|
||||||
|
assertEquals("\uD83C\uDFF3️\u200D⚧️", getFullEmojiAtEnd("hello there🏳️⚧️"))
|
||||||
|
}
|
||||||
|
|
||||||
// todo: add tests for emoji detection?
|
// todo: add tests for emoji detection?
|
||||||
// could help towards fully fixing https://github.com/Helium314/HeliBoard/issues/22
|
// could help towards fully fixing https://github.com/Helium314/HeliBoard/issues/22
|
||||||
// though this might be tricky, as some emojis will show as one on new Android versions, and
|
// though this might be tricky, as some emojis will show as one on new Android versions, and
|
||||||
|
|
Loading…
Add table
Reference in a new issue