Skip to content

Commit c3643b9

Browse files
author
Jeff Brown
committed
Add more dead keys. Use NFC tables for composition.
Bug: 6110399 Change-Id: I343d24df21dac2c069136b016e70e39f0feb6df9
1 parent accce94 commit c3643b9

File tree

1 file changed

+86
-135
lines changed

1 file changed

+86
-135
lines changed

core/java/android/view/KeyCharacterMap.java

Lines changed: 86 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import android.hardware.input.InputManager;
2525

2626
import java.lang.Character;
27+
import java.text.Normalizer;
2728

2829
/**
2930
* Describes the keys provided by a keyboard device and their associated labels.
@@ -149,9 +150,22 @@ public class KeyCharacterMap implements Parcelable {
149150

150151
/* Characters used to display placeholders for dead keys. */
151152
private static final int ACCENT_ACUTE = '\u00B4';
153+
private static final int ACCENT_BREVE = '\u02D8';
154+
private static final int ACCENT_CARON = '\u02C7';
155+
private static final int ACCENT_CEDILLA = '\u00B8';
156+
private static final int ACCENT_COMMA_ABOVE = '\u1FBD';
157+
private static final int ACCENT_COMMA_ABOVE_RIGHT = '\u02BC';
158+
private static final int ACCENT_DOT_ABOVE = '\u02D9';
159+
private static final int ACCENT_DOUBLE_ACUTE = '\u02DD';
152160
private static final int ACCENT_GRAVE = '\u02CB';
153161
private static final int ACCENT_CIRCUMFLEX = '\u02C6';
162+
private static final int ACCENT_MACRON = '\u00AF';
163+
private static final int ACCENT_MACRON_BELOW = '\u02CD';
164+
private static final int ACCENT_OGONEK = '\u02DB';
165+
private static final int ACCENT_REVERSED_COMMA_ABOVE = '\u02BD';
166+
private static final int ACCENT_RING_ABOVE = '\u02DA';
154167
private static final int ACCENT_TILDE = '\u02DC';
168+
private static final int ACCENT_TURNED_COMMA_ABOVE = '\u02BB';
155169
private static final int ACCENT_UMLAUT = '\u00A8';
156170

157171
/* Legacy dead key display characters used in previous versions of the API.
@@ -161,136 +175,66 @@ public class KeyCharacterMap implements Parcelable {
161175
private static final int ACCENT_TILDE_LEGACY = '~';
162176

163177
/**
164-
* Maps Unicode combining diacritical to display-form dead key
165-
* (display character shifted left 16 bits).
178+
* Maps Unicode combining diacritical to display-form dead key.
166179
*/
167-
private static final SparseIntArray COMBINING = new SparseIntArray();
180+
private static final SparseIntArray sCombiningToAccent = new SparseIntArray();
181+
private static final SparseIntArray sAccentToCombining = new SparseIntArray();
168182
static {
169-
COMBINING.put('\u0300', ACCENT_GRAVE);
170-
COMBINING.put('\u0301', ACCENT_ACUTE);
171-
COMBINING.put('\u0302', ACCENT_CIRCUMFLEX);
172-
COMBINING.put('\u0303', ACCENT_TILDE);
173-
COMBINING.put('\u0308', ACCENT_UMLAUT);
183+
addCombining('\u0300', ACCENT_GRAVE);
184+
addCombining('\u0301', ACCENT_ACUTE);
185+
addCombining('\u0302', ACCENT_CIRCUMFLEX);
186+
addCombining('\u0303', ACCENT_TILDE);
187+
addCombining('\u0304', ACCENT_MACRON);
188+
addCombining('\u0306', ACCENT_BREVE);
189+
addCombining('\u0307', ACCENT_DOT_ABOVE);
190+
addCombining('\u0308', ACCENT_UMLAUT);
191+
//addCombining('\u0309', ACCENT_HOOK_ABOVE);
192+
addCombining('\u030A', ACCENT_RING_ABOVE);
193+
addCombining('\u030B', ACCENT_DOUBLE_ACUTE);
194+
addCombining('\u030C', ACCENT_CARON);
195+
//addCombining('\u030D', ACCENT_VERTICAL_LINE_ABOVE);
196+
//addCombining('\u030E', ACCENT_DOUBLE_VERTICAL_LINE_ABOVE);
197+
//addCombining('\u030F', ACCENT_DOUBLE_GRAVE);
198+
//addCombining('\u0310', ACCENT_CANDRABINDU);
199+
//addCombining('\u0311', ACCENT_INVERTED_BREVE);
200+
addCombining('\u0312', ACCENT_TURNED_COMMA_ABOVE);
201+
addCombining('\u0313', ACCENT_COMMA_ABOVE);
202+
addCombining('\u0314', ACCENT_REVERSED_COMMA_ABOVE);
203+
addCombining('\u0315', ACCENT_COMMA_ABOVE_RIGHT);
204+
//addCombining('\u031B', ACCENT_HORN);
205+
//addCombining('\u0323', ACCENT_DOT_BELOW);
206+
//addCombining('\u0326', ACCENT_COMMA_BELOW);
207+
addCombining('\u0327', ACCENT_CEDILLA);
208+
addCombining('\u0328', ACCENT_OGONEK);
209+
//addCombining('\u0329', ACCENT_VERTICAL_LINE_BELOW);
210+
addCombining('\u0331', ACCENT_MACRON_BELOW);
211+
//addCombining('\u0342', ACCENT_PERISPOMENI);
212+
//addCombining('\u0344', ACCENT_DIALYTIKA_TONOS);
213+
//addCombining('\u0345', ACCENT_YPOGEGRAMMENI);
214+
215+
// One-way mappings to equivalent preferred accents.
216+
sCombiningToAccent.append('\u0340', ACCENT_GRAVE);
217+
sCombiningToAccent.append('\u0341', ACCENT_ACUTE);
218+
sCombiningToAccent.append('\u0343', ACCENT_COMMA_ABOVE);
219+
220+
// One-way legacy mappings to preserve compatibility with older applications.
221+
sAccentToCombining.append(ACCENT_GRAVE_LEGACY, '\u0300');
222+
sAccentToCombining.append(ACCENT_CIRCUMFLEX_LEGACY, '\u0302');
223+
sAccentToCombining.append(ACCENT_TILDE_LEGACY, '\u0303');
224+
}
225+
226+
private static void addCombining(int combining, int accent) {
227+
sCombiningToAccent.append(combining, accent);
228+
sAccentToCombining.append(accent, combining);
174229
}
175230

176231
/**
177-
* Maps combinations of (display-form) dead key and second character
232+
* Maps combinations of (display-form) combining key and second character
178233
* to combined output character.
234+
* These mappings are derived from the Unicode NFC tables as needed.
179235
*/
180-
private static final SparseIntArray DEAD = new SparseIntArray();
181-
static {
182-
addDeadChar(ACCENT_ACUTE, 'A', '\u00C1');
183-
addDeadChar(ACCENT_ACUTE, 'C', '\u0106');
184-
addDeadChar(ACCENT_ACUTE, 'E', '\u00C9');
185-
addDeadChar(ACCENT_ACUTE, 'G', '\u01F4');
186-
addDeadChar(ACCENT_ACUTE, 'I', '\u00CD');
187-
addDeadChar(ACCENT_ACUTE, 'K', '\u1E30');
188-
addDeadChar(ACCENT_ACUTE, 'L', '\u0139');
189-
addDeadChar(ACCENT_ACUTE, 'M', '\u1E3E');
190-
addDeadChar(ACCENT_ACUTE, 'N', '\u0143');
191-
addDeadChar(ACCENT_ACUTE, 'O', '\u00D3');
192-
addDeadChar(ACCENT_ACUTE, 'P', '\u1E54');
193-
addDeadChar(ACCENT_ACUTE, 'R', '\u0154');
194-
addDeadChar(ACCENT_ACUTE, 'S', '\u015A');
195-
addDeadChar(ACCENT_ACUTE, 'U', '\u00DA');
196-
addDeadChar(ACCENT_ACUTE, 'W', '\u1E82');
197-
addDeadChar(ACCENT_ACUTE, 'Y', '\u00DD');
198-
addDeadChar(ACCENT_ACUTE, 'Z', '\u0179');
199-
addDeadChar(ACCENT_ACUTE, 'a', '\u00E1');
200-
addDeadChar(ACCENT_ACUTE, 'c', '\u0107');
201-
addDeadChar(ACCENT_ACUTE, 'e', '\u00E9');
202-
addDeadChar(ACCENT_ACUTE, 'g', '\u01F5');
203-
addDeadChar(ACCENT_ACUTE, 'i', '\u00ED');
204-
addDeadChar(ACCENT_ACUTE, 'k', '\u1E31');
205-
addDeadChar(ACCENT_ACUTE, 'l', '\u013A');
206-
addDeadChar(ACCENT_ACUTE, 'm', '\u1E3F');
207-
addDeadChar(ACCENT_ACUTE, 'n', '\u0144');
208-
addDeadChar(ACCENT_ACUTE, 'o', '\u00F3');
209-
addDeadChar(ACCENT_ACUTE, 'p', '\u1E55');
210-
addDeadChar(ACCENT_ACUTE, 'r', '\u0155');
211-
addDeadChar(ACCENT_ACUTE, 's', '\u015B');
212-
addDeadChar(ACCENT_ACUTE, 'u', '\u00FA');
213-
addDeadChar(ACCENT_ACUTE, 'w', '\u1E83');
214-
addDeadChar(ACCENT_ACUTE, 'y', '\u00FD');
215-
addDeadChar(ACCENT_ACUTE, 'z', '\u017A');
216-
addDeadChar(ACCENT_CIRCUMFLEX, 'A', '\u00C2');
217-
addDeadChar(ACCENT_CIRCUMFLEX, 'C', '\u0108');
218-
addDeadChar(ACCENT_CIRCUMFLEX, 'E', '\u00CA');
219-
addDeadChar(ACCENT_CIRCUMFLEX, 'G', '\u011C');
220-
addDeadChar(ACCENT_CIRCUMFLEX, 'H', '\u0124');
221-
addDeadChar(ACCENT_CIRCUMFLEX, 'I', '\u00CE');
222-
addDeadChar(ACCENT_CIRCUMFLEX, 'J', '\u0134');
223-
addDeadChar(ACCENT_CIRCUMFLEX, 'O', '\u00D4');
224-
addDeadChar(ACCENT_CIRCUMFLEX, 'S', '\u015C');
225-
addDeadChar(ACCENT_CIRCUMFLEX, 'U', '\u00DB');
226-
addDeadChar(ACCENT_CIRCUMFLEX, 'W', '\u0174');
227-
addDeadChar(ACCENT_CIRCUMFLEX, 'Y', '\u0176');
228-
addDeadChar(ACCENT_CIRCUMFLEX, 'Z', '\u1E90');
229-
addDeadChar(ACCENT_CIRCUMFLEX, 'a', '\u00E2');
230-
addDeadChar(ACCENT_CIRCUMFLEX, 'c', '\u0109');
231-
addDeadChar(ACCENT_CIRCUMFLEX, 'e', '\u00EA');
232-
addDeadChar(ACCENT_CIRCUMFLEX, 'g', '\u011D');
233-
addDeadChar(ACCENT_CIRCUMFLEX, 'h', '\u0125');
234-
addDeadChar(ACCENT_CIRCUMFLEX, 'i', '\u00EE');
235-
addDeadChar(ACCENT_CIRCUMFLEX, 'j', '\u0135');
236-
addDeadChar(ACCENT_CIRCUMFLEX, 'o', '\u00F4');
237-
addDeadChar(ACCENT_CIRCUMFLEX, 's', '\u015D');
238-
addDeadChar(ACCENT_CIRCUMFLEX, 'u', '\u00FB');
239-
addDeadChar(ACCENT_CIRCUMFLEX, 'w', '\u0175');
240-
addDeadChar(ACCENT_CIRCUMFLEX, 'y', '\u0177');
241-
addDeadChar(ACCENT_CIRCUMFLEX, 'z', '\u1E91');
242-
addDeadChar(ACCENT_GRAVE, 'A', '\u00C0');
243-
addDeadChar(ACCENT_GRAVE, 'E', '\u00C8');
244-
addDeadChar(ACCENT_GRAVE, 'I', '\u00CC');
245-
addDeadChar(ACCENT_GRAVE, 'N', '\u01F8');
246-
addDeadChar(ACCENT_GRAVE, 'O', '\u00D2');
247-
addDeadChar(ACCENT_GRAVE, 'U', '\u00D9');
248-
addDeadChar(ACCENT_GRAVE, 'W', '\u1E80');
249-
addDeadChar(ACCENT_GRAVE, 'Y', '\u1EF2');
250-
addDeadChar(ACCENT_GRAVE, 'a', '\u00E0');
251-
addDeadChar(ACCENT_GRAVE, 'e', '\u00E8');
252-
addDeadChar(ACCENT_GRAVE, 'i', '\u00EC');
253-
addDeadChar(ACCENT_GRAVE, 'n', '\u01F9');
254-
addDeadChar(ACCENT_GRAVE, 'o', '\u00F2');
255-
addDeadChar(ACCENT_GRAVE, 'u', '\u00F9');
256-
addDeadChar(ACCENT_GRAVE, 'w', '\u1E81');
257-
addDeadChar(ACCENT_GRAVE, 'y', '\u1EF3');
258-
addDeadChar(ACCENT_TILDE, 'A', '\u00C3');
259-
addDeadChar(ACCENT_TILDE, 'E', '\u1EBC');
260-
addDeadChar(ACCENT_TILDE, 'I', '\u0128');
261-
addDeadChar(ACCENT_TILDE, 'N', '\u00D1');
262-
addDeadChar(ACCENT_TILDE, 'O', '\u00D5');
263-
addDeadChar(ACCENT_TILDE, 'U', '\u0168');
264-
addDeadChar(ACCENT_TILDE, 'V', '\u1E7C');
265-
addDeadChar(ACCENT_TILDE, 'Y', '\u1EF8');
266-
addDeadChar(ACCENT_TILDE, 'a', '\u00E3');
267-
addDeadChar(ACCENT_TILDE, 'e', '\u1EBD');
268-
addDeadChar(ACCENT_TILDE, 'i', '\u0129');
269-
addDeadChar(ACCENT_TILDE, 'n', '\u00F1');
270-
addDeadChar(ACCENT_TILDE, 'o', '\u00F5');
271-
addDeadChar(ACCENT_TILDE, 'u', '\u0169');
272-
addDeadChar(ACCENT_TILDE, 'v', '\u1E7D');
273-
addDeadChar(ACCENT_TILDE, 'y', '\u1EF9');
274-
addDeadChar(ACCENT_UMLAUT, 'A', '\u00C4');
275-
addDeadChar(ACCENT_UMLAUT, 'E', '\u00CB');
276-
addDeadChar(ACCENT_UMLAUT, 'H', '\u1E26');
277-
addDeadChar(ACCENT_UMLAUT, 'I', '\u00CF');
278-
addDeadChar(ACCENT_UMLAUT, 'O', '\u00D6');
279-
addDeadChar(ACCENT_UMLAUT, 'U', '\u00DC');
280-
addDeadChar(ACCENT_UMLAUT, 'W', '\u1E84');
281-
addDeadChar(ACCENT_UMLAUT, 'X', '\u1E8C');
282-
addDeadChar(ACCENT_UMLAUT, 'Y', '\u0178');
283-
addDeadChar(ACCENT_UMLAUT, 'a', '\u00E4');
284-
addDeadChar(ACCENT_UMLAUT, 'e', '\u00EB');
285-
addDeadChar(ACCENT_UMLAUT, 'h', '\u1E27');
286-
addDeadChar(ACCENT_UMLAUT, 'i', '\u00EF');
287-
addDeadChar(ACCENT_UMLAUT, 'o', '\u00F6');
288-
addDeadChar(ACCENT_UMLAUT, 't', '\u1E97');
289-
addDeadChar(ACCENT_UMLAUT, 'u', '\u00FC');
290-
addDeadChar(ACCENT_UMLAUT, 'w', '\u1E85');
291-
addDeadChar(ACCENT_UMLAUT, 'x', '\u1E8D');
292-
addDeadChar(ACCENT_UMLAUT, 'y', '\u00FF');
293-
}
236+
private static final SparseIntArray sDeadKeyCache = new SparseIntArray();
237+
private static final StringBuilder sDeadKeyBuilder = new StringBuilder();
294238

295239
public static final Parcelable.Creator<KeyCharacterMap> CREATOR =
296240
new Parcelable.Creator<KeyCharacterMap>() {
@@ -387,7 +331,7 @@ public int get(int keyCode, int metaState) {
387331
metaState = KeyEvent.normalizeMetaState(metaState);
388332
char ch = nativeGetCharacter(mPtr, keyCode, metaState);
389333

390-
int map = COMBINING.get(ch);
334+
int map = sCombiningToAccent.get(ch);
391335
if (map != 0) {
392336
return map | COMBINING_ACCENT;
393337
} else {
@@ -503,14 +447,25 @@ public char getDisplayLabel(int keyCode) {
503447
* @return The combined character, or 0 if the characters cannot be combined.
504448
*/
505449
public static int getDeadChar(int accent, int c) {
506-
if (accent == ACCENT_CIRCUMFLEX_LEGACY) {
507-
accent = ACCENT_CIRCUMFLEX;
508-
} else if (accent == ACCENT_GRAVE_LEGACY) {
509-
accent = ACCENT_GRAVE;
510-
} else if (accent == ACCENT_TILDE_LEGACY) {
511-
accent = ACCENT_TILDE;
450+
int combining = sAccentToCombining.get(accent);
451+
if (combining == 0) {
452+
return 0;
512453
}
513-
return DEAD.get((accent << 16) | c);
454+
455+
final int combination = (combining << 16) | c;
456+
int combined;
457+
synchronized (sDeadKeyCache) {
458+
combined = sDeadKeyCache.get(combination, -1);
459+
if (combined == -1) {
460+
sDeadKeyBuilder.setLength(0);
461+
sDeadKeyBuilder.append((char)c);
462+
sDeadKeyBuilder.append((char)combining);
463+
String result = Normalizer.normalize(sDeadKeyBuilder, Normalizer.Form.NFC);
464+
combined = result.length() == 1 ? result.charAt(0) : 0;
465+
sDeadKeyCache.put(combination, combined);
466+
}
467+
}
468+
return combined;
514469
}
515470

516471
/**
@@ -723,10 +678,6 @@ public int describeContents() {
723678
return 0;
724679
}
725680

726-
private static void addDeadChar(int accent, int c, char combinedResult) {
727-
DEAD.put((accent << 16) | c, combinedResult);
728-
}
729-
730681
/**
731682
* Thrown by {@link KeyCharacterMap#load} when a key character map could not be loaded.
732683
*/

0 commit comments

Comments
 (0)