44
55package io .flutter .embedding .android ;
66
7+ import android .view .KeyCharacterMap ;
78import android .view .KeyEvent ;
89import androidx .annotation .NonNull ;
910import io .flutter .embedding .engine .systemchannels .KeyEventChannel ;
@@ -18,15 +19,66 @@ public class KeyChannelResponder implements KeyboardManager.Responder {
1819 private static final String TAG = "KeyChannelResponder" ;
1920
2021 @ NonNull private final KeyEventChannel keyEventChannel ;
21-
22- @ NonNull
23- private final KeyboardManager .CharacterCombiner characterCombiner =
24- new KeyboardManager .CharacterCombiner ();
22+ private int combiningCharacter ;
2523
2624 public KeyChannelResponder (@ NonNull KeyEventChannel keyEventChannel ) {
2725 this .keyEventChannel = keyEventChannel ;
2826 }
2927
28+ /**
29+ * Applies the given Unicode character in {@code newCharacterCodePoint} to a previously entered
30+ * Unicode combining character and returns the combination of these characters if a combination
31+ * exists.
32+ *
33+ * <p>This method mutates {@link #combiningCharacter} over time to combine characters.
34+ *
35+ * <p>One of the following things happens in this method:
36+ *
37+ * <ul>
38+ * <li>If no previous {@link #combiningCharacter} exists and the {@code newCharacterCodePoint}
39+ * is not a combining character, then {@code newCharacterCodePoint} is returned.
40+ * <li>If no previous {@link #combiningCharacter} exists and the {@code newCharacterCodePoint}
41+ * is a combining character, then {@code newCharacterCodePoint} is saved as the {@link
42+ * #combiningCharacter} and null is returned.
43+ * <li>If a previous {@link #combiningCharacter} exists and the {@code newCharacterCodePoint} is
44+ * also a combining character, then the {@code newCharacterCodePoint} is combined with the
45+ * existing {@link #combiningCharacter} and null is returned.
46+ * <li>If a previous {@link #combiningCharacter} exists and the {@code newCharacterCodePoint} is
47+ * not a combining character, then the {@link #combiningCharacter} is applied to the regular
48+ * {@code newCharacterCodePoint} and the resulting complex character is returned. The {@link
49+ * #combiningCharacter} is cleared.
50+ * </ul>
51+ *
52+ * <p>The following reference explains the concept of a "combining character":
53+ * https://en.wikipedia.org/wiki/Combining_character
54+ */
55+ Character applyCombiningCharacterToBaseCharacter (int newCharacterCodePoint ) {
56+ char complexCharacter = (char ) newCharacterCodePoint ;
57+ boolean isNewCodePointACombiningCharacter =
58+ (newCharacterCodePoint & KeyCharacterMap .COMBINING_ACCENT ) != 0 ;
59+ if (isNewCodePointACombiningCharacter ) {
60+ // If a combining character was entered before, combine this one with that one.
61+ int plainCodePoint = newCharacterCodePoint & KeyCharacterMap .COMBINING_ACCENT_MASK ;
62+ if (combiningCharacter != 0 ) {
63+ combiningCharacter = KeyCharacterMap .getDeadChar (combiningCharacter , plainCodePoint );
64+ } else {
65+ combiningCharacter = plainCodePoint ;
66+ }
67+ } else {
68+ // The new character is a regular character. Apply combiningCharacter to it, if
69+ // it exists.
70+ if (combiningCharacter != 0 ) {
71+ int combinedChar = KeyCharacterMap .getDeadChar (combiningCharacter , newCharacterCodePoint );
72+ if (combinedChar > 0 ) {
73+ complexCharacter = (char ) combinedChar ;
74+ }
75+ combiningCharacter = 0 ;
76+ }
77+ }
78+
79+ return complexCharacter ;
80+ }
81+
3082 @ Override
3183 public void handleEvent (
3284 @ NonNull KeyEvent keyEvent , @ NonNull OnKeyEventHandledCallback onKeyEventHandledCallback ) {
@@ -40,7 +92,7 @@ public void handleEvent(
4092 }
4193
4294 final Character complexCharacter =
43- characterCombiner . applyCombiningCharacterToBaseCharacter (keyEvent .getUnicodeChar ());
95+ applyCombiningCharacterToBaseCharacter (keyEvent .getUnicodeChar ());
4496 KeyEventChannel .FlutterKeyEvent flutterEvent =
4597 new KeyEventChannel .FlutterKeyEvent (keyEvent , complexCharacter );
4698
0 commit comments