Unexpected-Keyboard/srcs/juloo.keyboard2/KeyModifier.java
Jules Aguillon 69ab869079
Hangul support (#595)
* Hangul support

This works with two new kinds of keys (Hangul_initial and Hangul_medial)
that carry a precomposed hangul syllable and act as modifiers.

The hangul syllables are composed algorithmically.

* Add shift layer to Dubeolsik layout
2024-05-02 20:52:18 +02:00

1348 lines
40 KiB
Java
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package juloo.keyboard2;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import java.util.HashMap;
public final class KeyModifier
{
/** Cache key is KeyValue's name */
private static HashMap<KeyValue, HashMap<Pointers.Modifiers, KeyValue>> _cache =
new HashMap<KeyValue, HashMap<Pointers.Modifiers, KeyValue>>();
/** The optional modmap takes priority over modifiers usual behaviors. Set to
[null] to disable. */
private static KeyboardData.Modmap _modmap = null;
public static void set_modmap(KeyboardData.Modmap mm)
{
// Clear the cache when switching to or from a layout that contain a modmap
// as the cache would otherwise override the modmap.
if (_modmap != null || mm != null)
_cache.clear();
_modmap = mm;
}
/** Modify a key according to modifiers. */
public static KeyValue modify(KeyValue k, Pointers.Modifiers mods)
{
if (k == null)
return null;
int n_mods = mods.size();
HashMap<Pointers.Modifiers, KeyValue> ks = cacheEntry(k);
KeyValue r = ks.get(mods);
if (r == null)
{
r = k;
/* Order: Fn, Shift, accents */
for (int i = 0; i < n_mods; i++)
r = modify(r, mods.get(i));
ks.put(mods, r);
}
/* Keys with an empty string are placeholder keys. */
if (r.getString().length() == 0)
return null;
return r;
}
public static KeyValue modify(KeyValue k, KeyValue mod)
{
switch (mod.getKind())
{
case Modifier:
return modify(k, mod.getModifier());
case Compose_pending:
return ComposeKey.apply(mod.getPendingCompose(), k);
case Hangul_initial:
if (k.equals(mod)) // Allow typing the initial in letter form
return KeyValue.makeStringKey(k.getString(), KeyValue.FLAG_GREYED);
return combine_hangul_initial(k, mod.getHangulPrecomposed());
case Hangul_medial:
return combine_hangul_medial(k, mod.getHangulPrecomposed());
}
return k;
}
public static KeyValue modify(KeyValue k, KeyValue.Modifier mod)
{
switch (mod)
{
case CTRL:
case ALT:
case META: return turn_into_keyevent(k);
case FN: return apply_fn(k);
case SHIFT: return apply_shift(k);
case GRAVE: return apply_map_char(k, map_char_grave);
case AIGU: return apply_map_char(k, map_char_aigu);
case CIRCONFLEXE: return apply_map_char(k, map_char_circonflexe);
case TILDE: return apply_map_char(k, map_char_tilde);
case CEDILLE: return apply_map_char(k, map_char_cedille);
case TREMA: return apply_map_char(k, map_char_trema);
case CARON: return apply_map_char(k, map_char_caron);
case RING: return apply_map_char(k, map_char_ring);
case MACRON: return apply_map_char(k, map_char_macron);
case OGONEK: return apply_map_char(k, map_char_ogonek);
case DOT_ABOVE: return apply_map_char(k, map_char_dot_above);
case BREVE: return apply_map_char(k, map_char_breve);
case DOUBLE_AIGU: return apply_map_char(k, map_char_double_aigu);
case ORDINAL: return apply_map_char(k, map_char_ordinal);
case SUPERSCRIPT: return apply_map_char(k, map_char_superscript);
case SUBSCRIPT: return apply_map_char(k, map_char_subscript);
case ARROWS: return apply_map_char(k, map_char_arrows);
case BOX: return apply_map_char(k, map_char_box);
case SLASH: return apply_map_char(k, map_char_slash);
case BAR: return apply_map_char(k, map_char_bar);
case ARROW_RIGHT: return apply_map_char(k, map_char_arrow_right);
case DOT_BELOW: return apply_map_char(k, map_char_dot_below);
case HORN: return apply_map_char(k, map_char_horn);
case HOOK_ABOVE: return apply_map_char(k, map_char_hook_above);
default: return k;
}
}
/** Modify a key after a long press. */
public static KeyValue modify_long_press(KeyValue k)
{
switch (k.getKind())
{
case Event:
switch (k.getEvent())
{
case CHANGE_METHOD_AUTO:
return KeyValue.getKeyByName("change_method");
case SWITCH_VOICE_TYPING:
return KeyValue.getKeyByName("voice_typing_chooser");
}
break;
}
return k;
}
public static Map_char modify_numpad_script(String numpad_script)
{
if (numpad_script == null)
return map_char_none;
switch (numpad_script)
{
case "hindu-arabic": return map_char_numpad_hindu;
case "bengali": return map_char_numpad_bengali;
case "devanagari": return map_char_numpad_devanagari;
case "persian": return map_char_numpad_persian;
case "gujarati": return map_char_numpad_gujarati;
default: return map_char_none;
}
}
private static KeyValue apply_map_char(KeyValue k, Map_char map)
{
switch (k.getKind())
{
case Char:
char kc = k.getChar();
String modified = map.apply(kc);
if (modified == null)
return k;
return KeyValue.makeStringKey(modified, k.getFlags());
default: return k;
}
}
private static KeyValue apply_shift(KeyValue k)
{
if (_modmap != null)
{
KeyValue mapped = _modmap.shift.get(k);
if (mapped != null)
return mapped;
}
switch (k.getKind())
{
case Char:
char kc = k.getChar();
char c = map_char_shift(kc);
if (kc == c)
c = Character.toUpperCase(kc);
return (kc == c) ? k : k.withChar(c);
case String:
String s = Utils.capitalize_string(k.getString());
return KeyValue.makeStringKey(s, k.getFlags());
default: return k;
}
}
private static KeyValue apply_fn(KeyValue k)
{
if (_modmap != null)
{
KeyValue mapped = _modmap.fn.get(k);
if (mapped != null)
return mapped;
}
String name = null;
switch (k.getKind())
{
case Char: name = apply_fn_char(k.getChar()); break;
case Keyevent: name = apply_fn_keyevent(k.getKeyevent()); break;
case Event: name = apply_fn_event(k.getEvent()); break;
case Placeholder: name = apply_fn_placeholder(k.getPlaceholder()); break;
}
return (name == null) ? k : KeyValue.getKeyByName(name);
}
private static String apply_fn_keyevent(int code)
{
switch (code)
{
case KeyEvent.KEYCODE_DPAD_UP: return "page_up";
case KeyEvent.KEYCODE_DPAD_DOWN: return "page_down";
case KeyEvent.KEYCODE_DPAD_LEFT: return "home";
case KeyEvent.KEYCODE_DPAD_RIGHT: return "end";
case KeyEvent.KEYCODE_ESCAPE: return "insert";
case KeyEvent.KEYCODE_TAB: return "\\t";
case KeyEvent.KEYCODE_PAGE_UP:
case KeyEvent.KEYCODE_PAGE_DOWN:
case KeyEvent.KEYCODE_MOVE_HOME:
case KeyEvent.KEYCODE_MOVE_END: return "removed";
default: return null;
}
}
private static String apply_fn_event(KeyValue.Event ev)
{
switch (ev)
{
case SWITCH_NUMERIC: return "switch_greekmath";
default: return null;
}
}
private static String apply_fn_placeholder(KeyValue.Placeholder p)
{
switch (p)
{
case F11: return "f11";
case F12: return "f12";
case SHINDOT: return "shindot";
case SINDOT: return "sindot";
case OLE: return "ole";
case METEG: return "meteg";
default: return null;
}
}
/** Return the name of modified key, or [null]. */
private static String apply_fn_char(char c)
{
switch (c)
{
case '1': return "f1";
case '2': return "f2";
case '3': return "f3";
case '4': return "f4";
case '5': return "f5";
case '6': return "f6";
case '7': return "f7";
case '8': return "f8";
case '9': return "f9";
case '0': return "f10";
case '<': return "«";
case '>': return "»";
case '{': return "";
case '}': return "";
case '[': return "";
case ']': return "";
case '(': return "";
case ')': return "";
case '\'': return "";
case '"': return "";
case '-': return "";
case '_': return "";
case '^': return "¬";
case '%': return "";
case '=': return "";
case 'u': return "µ";
case 'a': return "æ";
case 'o': return "œ";
case '*': return "°";
case '.': return "";
case ',': return "·";
case '!': return "¡";
case '?': return "¿";
case '|': return "¦";
case '§': return "";
case '†': return "";
case '×': return "";
case ' ': return "nbsp";
// arrows
case '↖': return "";
case '↑': return "";
case '↗': return "";
case '←': return "";
case '→': return "";
case '↙': return "";
case '↓': return "";
case '↘': return "";
case '↔': return "";
case '↕': return "";
// Currency symbols
case 'e': return "";
case 'l': return "£";
case 'r': return "";
case 'y': return "¥";
case 'c': return "¢";
case 'p': return "";
case 'b': return "";
case 'h': return "";
case 'z': return "";
case '€': case '£': return "removed"; // Avoid showing these twice
// alternating greek letters
case 'π': return "ϖ";
case 'θ': return "ϑ";
case 'Θ': return "ϴ";
case 'ε': return "ϵ";
case 'β': return "ϐ";
case 'ρ': return "ϱ";
case 'σ': return "ς";
case 'γ': return "ɣ";
case 'φ': return "ϕ";
case 'υ': return "ϒ";
case 'κ': return "ϰ";
// alternating math characters
case '': return "";
case '∩': return "";
case '∃': return "";
case '∈': return "";
case '∫': return "";
case 'Π': return "";
case 'Σ': return "";
case '': return "";
case '∧': return "";
case '⊷': return "";
case '⊂': return "";
case '⊃': return "";
case '±': return "";
// hebrew niqqud
case 'ק': return "qamats"; // kamatz
case 'ר': return "hataf_qamats"; // reduced kamatz
case 'ו': return "holam";
case 'ם': return "rafe";
case 'פ': return "patah"; // patach
case 'ש': return "sheva";
case 'ד': return "dagesh"; // or mapiq
case 'ח': return "hiriq";
case 'ף': return "hataf_patah"; // reduced patach
case 'ז': return "qubuts"; // kubuts
case 'ס': return "segol";
case 'ב': return "hataf_segol"; // reduced segol
case 'צ': return "tsere";
// Devanagari symbols
case 'ए': return "";
case 'े': return "";
case 'ऐ': return "";
case 'ै': return "";
case 'ऋ': return "";
case 'ृ': return "";
case 'ळ': return "";
case 'र': return "";
case 'क': return "";
case 'ख': return "";
case 'ग': return "";
case 'घ': return "";
case 'ढ': return "";
case 'न': return "";
case 'ड': return "";
case 'ट': return "";
case 'ण': return "";
case 'फ': return "";
case 'ऌ': return "";
case 'ॢ': return "";
case 'औ': return "";
case 'ौ': return "";
case 'ओ': return "";
case 'ो': return "";
case 'च': return "";
case 'ज': return "";
case 'ब': return "ॿ";
case 'व': return "";
case 'य': return "";
case 'अ': return "";
case 'आ': return "";
case 'ा': return "";
case 'झ': return "";
case 'ई': return "";
case 'ी': return "";
case 'इ': return "";
case 'ि': return "";
case 'उ': return "";
case 'ऊ': return "";
case 'ु': return "";
case 'ष': return "क्ष";
case 'थ': return "त्र";
case 'द': return "द्र";
case 'प': return "प्र";
case 'श': return "श्र";
case 'छ': return "श्च";
case 'ँ': return "";
case '₹': return "";
case 'ॖ': return "";
case '॓': return "";
case '॰': return "";
case '।': return "";
case 'ं': return "";
case '़': return "";
case 'ऽ': return "";
// Persian numbers
case '۱': return "f1";
case '۲': return "f2";
case '۳': return "f3";
case '۴': return "f4";
case '۵': return "f5";
case '۶': return "f6";
case '۷': return "f7";
case '۸': return "f8";
case '۹': return "f9";
case '۰': return "f10";
// Arabic numbers
case '١': return "f1";
case '٢': return "f2";
case '٣': return "f3";
case '٤': return "f4";
case '٥': return "f5";
case '٦': return "f6";
case '٧': return "f7";
case '٨': return "f8";
case '٩': return "f9";
case '٠': return "f10";
default: return null;
}
}
private static KeyValue turn_into_keyevent(KeyValue k)
{
if (k.getKind() != KeyValue.Kind.Char)
return k;
int e;
switch (k.getChar())
{
case 'a': e = KeyEvent.KEYCODE_A; break;
case 'b': e = KeyEvent.KEYCODE_B; break;
case 'c': e = KeyEvent.KEYCODE_C; break;
case 'd': e = KeyEvent.KEYCODE_D; break;
case 'e': e = KeyEvent.KEYCODE_E; break;
case 'f': e = KeyEvent.KEYCODE_F; break;
case 'g': e = KeyEvent.KEYCODE_G; break;
case 'h': e = KeyEvent.KEYCODE_H; break;
case 'i': e = KeyEvent.KEYCODE_I; break;
case 'j': e = KeyEvent.KEYCODE_J; break;
case 'k': e = KeyEvent.KEYCODE_K; break;
case 'l': e = KeyEvent.KEYCODE_L; break;
case 'm': e = KeyEvent.KEYCODE_M; break;
case 'n': e = KeyEvent.KEYCODE_N; break;
case 'o': e = KeyEvent.KEYCODE_O; break;
case 'p': e = KeyEvent.KEYCODE_P; break;
case 'q': e = KeyEvent.KEYCODE_Q; break;
case 'r': e = KeyEvent.KEYCODE_R; break;
case 's': e = KeyEvent.KEYCODE_S; break;
case 't': e = KeyEvent.KEYCODE_T; break;
case 'u': e = KeyEvent.KEYCODE_U; break;
case 'v': e = KeyEvent.KEYCODE_V; break;
case 'w': e = KeyEvent.KEYCODE_W; break;
case 'x': e = KeyEvent.KEYCODE_X; break;
case 'y': e = KeyEvent.KEYCODE_Y; break;
case 'z': e = KeyEvent.KEYCODE_Z; break;
case '0': e = KeyEvent.KEYCODE_0; break;
case '1': e = KeyEvent.KEYCODE_1; break;
case '2': e = KeyEvent.KEYCODE_2; break;
case '3': e = KeyEvent.KEYCODE_3; break;
case '4': e = KeyEvent.KEYCODE_4; break;
case '5': e = KeyEvent.KEYCODE_5; break;
case '6': e = KeyEvent.KEYCODE_6; break;
case '7': e = KeyEvent.KEYCODE_7; break;
case '8': e = KeyEvent.KEYCODE_8; break;
case '9': e = KeyEvent.KEYCODE_9; break;
case '`': e = KeyEvent.KEYCODE_GRAVE; break;
case '-': e = KeyEvent.KEYCODE_MINUS; break;
case '=': e = KeyEvent.KEYCODE_EQUALS; break;
case '[': e = KeyEvent.KEYCODE_LEFT_BRACKET; break;
case ']': e = KeyEvent.KEYCODE_RIGHT_BRACKET; break;
case '\\': e = KeyEvent.KEYCODE_BACKSLASH; break;
case ';': e = KeyEvent.KEYCODE_SEMICOLON; break;
case '\'': e = KeyEvent.KEYCODE_APOSTROPHE; break;
case '/': e = KeyEvent.KEYCODE_SLASH; break;
case '@': e = KeyEvent.KEYCODE_AT; break;
case '+': e = KeyEvent.KEYCODE_PLUS; break;
case ',': e = KeyEvent.KEYCODE_COMMA; break;
case '.': e = KeyEvent.KEYCODE_PERIOD; break;
case '*': e = KeyEvent.KEYCODE_STAR; break;
case '#': e = KeyEvent.KEYCODE_POUND; break;
case '(': e = KeyEvent.KEYCODE_NUMPAD_LEFT_PAREN; break;
case ')': e = KeyEvent.KEYCODE_NUMPAD_RIGHT_PAREN; break;
case ' ': e = KeyEvent.KEYCODE_SPACE; break;
default: return k;
}
return k.withKeyevent(e);
}
/* Lookup the cache entry for a key. Create it needed. */
private static HashMap<Pointers.Modifiers, KeyValue> cacheEntry(KeyValue k)
{
HashMap<Pointers.Modifiers, KeyValue> ks = _cache.get(k);
if (ks == null)
{
ks = new HashMap<Pointers.Modifiers, KeyValue>();
_cache.put(k, ks);
}
return ks;
}
public static abstract class Map_char
{
/** Modify a char or return [null] if the modifier do not apply. Return a
[String] that can contains combining diacritics. */
public abstract String apply(char c);
}
private static final Map_char map_char_none =
new Map_char() {
public String apply(char _c) { return null; }
};
private static char map_char_shift(char c)
{
switch (c)
{
case '↙': return '⇙';
case '↓': return '⇓';
case '↘': return '⇘';
case '←': return '⇐';
case '→': return '⇒';
case '↖': return '⇖';
case '↑': return '⇑';
case '↗': return '⇗';
case '└': return '╚';
case '┴': return '╩';
case '┘': return '╝';
case '├': return '╠';
case '┼': return '╬';
case '┤': return '╣';
case '┌': return '╔';
case '┬': return '╦';
case '┐': return '╗';
case '─': return '═';
case '│': return '║';
case 'ß': return 'ẞ';
/* In Turkish, upper case of 'iı' is 'İI' but Java's toUpperCase will
return 'II'. To make 'İ' accessible, make it the shift of 'ı'. This
has the inconvenient of swapping i and ı on the keyboard. */
case 'ı': return 'İ';
case '₹': return '₨';
// Gujarati alternate characters
case 'અ': return 'આ';
case 'ઇ': return 'ઈ';
case 'િ': return 'ી';
case 'ઉ': return 'ઊ';
case 'ુ': return 'ૂ';
case 'એ': return 'ઐ';
case 'ે': return 'ૈ';
case 'ઓ': return 'ઔ';
case 'ો': return 'ૌ';
case 'ક': return 'ખ';
case 'ગ': return 'ઘ';
case 'ચ': return 'છ';
case 'જ': return 'ઝ';
case 'ટ': return 'ઠ';
case 'ડ': return 'ઢ';
case 'ન': return 'ણ';
case 'ત': return 'થ';
case 'દ': return 'ધ';
case 'પ': return 'ફ';
case 'બ': return 'ભ';
case 'મ': return 'ં';
case 'લ': return 'ળ';
case 'સ': return 'શ';
case 'હ': return '';
default: return c;
}
}
/** Return [null] if the dead char do not apply. */
private static String map_dead_char(char c, char dead_char)
{
char modified = (char)KeyCharacterMap.getDeadChar(dead_char, c);
return (modified == 0 || modified == c) ? null : String.valueOf(modified);
}
private static final Map_char map_char_aigu =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case 'a': return "á";
case 'c': return "ć";
case 'e': return "é";
case 'i': return "í";
case 'l': return "ĺ";
case 'ń': return "ń";
case 'o': return "ó";
case 'r': return "ŕ";
case 's': return "ś";
case 'u': return "ú";
case 'y': return "ý";
case 'z': return "ź";
// used in Pinyin
case 'ü': return "ǘ";
// Combining diacritic
case 'j':
// Russian vowels
case 'у': case 'е': case 'а': case 'о': case 'и':
case 'ы': case 'э': case 'ю': case 'я':
return c + "\u0301";
default: return map_dead_char(c, '\u00B4');
}
}
};
private static final Map_char map_char_caron =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case 'a': return "ǎ";
case 'c': return "č";
case 'd': return "ď";
case 'e': return "ě";
case 'i': return "ǐ";
case 'l': return "ľ";
case 'n': return "ň";
case 'o': return "ǒ";
case 'r': return "ř";
case 's': return "š";
case 't': return "ť";
case 'u': return "ǔ";
case 'z': return "ž";
// used in Pinyin
case 'ü': return "ǚ";
default: return map_dead_char(c, '\u02C7');
}
}
};
private static final Map_char map_char_cedille =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case 'c': return "ç";
case 'd': return "";
case 'e': return "ȩ";
case 'g': return "ģ";
case 'h': return "";
case 'k': return "ķ";
case 'l': return "ļ";
case 'n': return "ņ";
case 'r': return "ŗ";
case 's': return "ş";
case 't': return "ţ";
default: return map_dead_char(c, '\u00B8');
}
}
};
private static final Map_char map_char_circonflexe =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case 'a': return "â";
case 'c': return "ĉ";
case 'e': return "ê";
case 'g': return "ĝ";
case 'h': return "ĥ";
case 'i': return "î";
case 'j': return "ĵ";
case 'o': return "ô";
case 'ŝ': return "ŝ";
case 'u': return "û";
case 'z': return "";
default: return map_dead_char(c, '\u02C6');
}
}
};
private static final Map_char map_char_dot_above =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case 'a': return "ȧ";
case 'b': return "";
case 'c': return "ċ";
case 'd': return "";
case 'e': return "ė";
case 'f': return "";
case 'g': return "ġ";
case 'h': return "";
// Turkish ı / İ is handled elsewhere
case 'm': return "";
case 'n': return "";
case 'o': return "ȯ";
case 'p': return "";
case 'r': return "";
case 's': return "";
case 't': return "";
case 'w': return "";
case 'x': return "";
case 'y': return "";
case 'z': return "ż";
default: return map_dead_char(c, '\u02D9');
}
}
};
private static final Map_char map_char_grave =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case 'a': return "à";
case 'e': return "è";
case 'i': return "ì";
case 'o': return "ò";
case 'u': return "ù";
// used in Pinyin
case 'ü': return "ǜ";
default: return map_dead_char(c, '\u02CB');
}
}
};
private static final Map_char map_char_macron =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case 'a': return "ā";
case 'e': return "ē";
case 'i': return "ī";
case 'o': return "ō";
case 'u': return "ū";
// used in Pinyin
case 'ü': return "ǖ";
default: return map_dead_char(c, '\u00AF');
}
}
};
private static final Map_char map_char_ogonek =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case 'a': return "ą";
case 'e': return "ę";
case 'i': return "į";
case 'k': return "ķ";
case 'l': return "ļ";
case 'n': return "ņ";
case 'o': return "ǫ";
case 'u': return "ų";
default: return map_dead_char(c, '\u02DB');
}
}
};
private static final Map_char map_char_ring =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case 'a': return "å";
case 'u': return "ů";
default: return map_dead_char(c, '\u02DA');
}
}
};
private static final Map_char map_char_tilde =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case 'a': return "ã";
case 'e': return "";
case 'i': return "ĩ";
case 'n': return "ñ";
case 'o': return "õ";
case 'u': return "ũ";
// Vietnamese
case 'ă': return "";
case 'â': return "";
case 'ê': return "";
case 'ơ': return "";
case 'ư': return "";
default: return map_dead_char(c, '\u02DC');
}
}
};
private static final Map_char map_char_trema =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case 'a': return "ä";
case 'e': return "ë";
case 'i': return "ï";
case 'o': return "ö";
case 'u': return "ü";
case 'y': return "ÿ";
default: return map_dead_char(c, '\u00A8');
}
}
};
private static final Map_char map_char_breve =
new Map_char() {
public String apply(char c)
{
switch (c)
{
default: return map_dead_char(c, '\u02D8');
}
}
};
private static final Map_char map_char_double_aigu =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case 'o': return "ő";
case 'u': return "ű";
case ' ': return "˝";
// Combining diacritic
case 'a':
case 'e':
case 'i':
case 'm':
case 'y':
return c + "\u030b";
default: return null;
}
}
};
private static final Map_char map_char_ordinal =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case 'a': return "ª";
case 'o': return "º";
case '1': return "ª";
case '2': return "º";
case '3': return "";
case '4': return "";
case '5': return "";
case '6': return "ʳ";
case '7': return "ˢ";
case '8': return "";
case '9': return "ʰ";
case '*': return "°";
default: return null;
}
}
};
private static final Map_char map_char_superscript =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case '1': return "¹";
case '2': return "²";
case '3': return "³";
case '4': return "";
case '5': return "";
case '6': return "";
case '7': return "";
case '8': return "";
case '9': return "";
case '0': return "";
case '+': return "";
case '-': return "";
case '=': return "";
case '(': return "";
case ')': return "";
case 'a': return "";
case 'b': return "";
case 'c': return "";
case 'd': return "";
case 'e': return "";
case 'f': return "";
case 'g': return "";
case 'h': return "ʰ";
case 'i': return "";
case 'j': return "ʲ";
case 'k': return "";
case 'l': return "ˡ";
case 'm': return "";
case 'n': return "";
case 'o': return "";
case 'p': return "";
case 'r': return "ʳ";
case 's': return "ˢ";
case 't': return "";
case 'u': return "";
case 'v': return "";
case 'w': return "ʷ";
case 'x': return "ˣ";
case 'y': return "ʸ";
case 'z': return "";
default: return null;
}
}
};
private static final Map_char map_char_subscript =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case '1': return "";
case '2': return "";
case '3': return "";
case '4': return "";
case '5': return "";
case '6': return "";
case '7': return "";
case '8': return "";
case '9': return "";
case '0': return "";
case '+': return "";
case '-': return "";
case '=': return "";
case '(': return "";
case ')': return "";
case 'a': return "";
case 'e': return "";
case 'h': return "";
case 'i': return "";
case 'j': return "";
case 'k': return "";
case 'l': return "";
case 'm': return "";
case 'n': return "";
case 'o': return "";
case 'p': return "";
case 'r': return "";
case 's': return "";
case 't': return "";
case 'u': return "";
case 'v': return "";
case 'x': return "";
default: return null;
}
}
};
private static final Map_char map_char_arrows =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case '0': return "";
case '1': return "";
case '2': return "";
case '3': return "";
case '4': return "";
case '5': return "";
case '6': return "";
case '7': return "";
case '8': return "";
case '9': return "";
case '.': return "";
default: return null;
}
}
};
private static final Map_char map_char_arrow_right =
new Map_char() {
public String apply(char c)
{
switch (c)
{
default: return c + "\u20D7";
}
}
};
private static final Map_char map_char_box =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case '1': return "";
case '2': return "";
case '3': return "";
case '4': return "";
case '5': return "";
case '6': return "";
case '7': return "";
case '8': return "";
case '9': return "";
case '0': return "";
case '.': return "";
default: return null;
}
}
};
private static final Map_char map_char_slash =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case 'a': return "";
case 'b': return "";
case 'c': return "ȼ";
case 'e': return "ɇ";
case 'g': return "";
case 'k': return "";
case 'l': return "ł";
case 'n': return "";
case 'o': return "ø";
case 'r': return "";
case 's': return "";
case 't': return "";
default: return null;
}
}
};
private static final Map_char map_char_bar =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case 'b': return "ƀ";
case 'c': return "";
case 'd': return "đ";
case 'g': return "ǥ";
case 'i': return "ɨ";
case 'j': return "ɉ";
case 'k': return "";
case 'l': return "ƚ";
case 'o': return "ɵ";
case 'p': return "";
case 'q': return "";
case 'r': return "ɍ";
case 't': return "ŧ";
case 'u': return "ʉ";
case 'y': return "ɏ";
case 'z': return "ƶ";
default: return null;
}
}
};
private static final Map_char map_char_dot_below =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case 'a': return "";
case 'ă': return "";
case 'â': return "";
case 'e': return "";
case 'ê': return "";
case 'i': return "";
case 'o': return "";
case 'ô': return "";
case 'ơ': return "";
case 'u': return "";
case 'ư': return "";
case 'y': return "";
default: return null;
}
}
};
private static final Map_char map_char_horn =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case 'o': return "ơ";
case 'ó': return "";
case 'ò': return "";
case 'ỏ': return "";
case 'õ': return "";
case 'ọ': return "";
case 'u': return "ư";
case 'ú': return "";
case 'ù': return "";
case 'ủ': return "";
case 'ũ': return "";
case 'ụ': return "";
default: return null;
}
}
};
private static final Map_char map_char_hook_above =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case 'a': return "";
case 'ă': return "";
case 'â': return "";
case 'e': return "";
case 'ê': return "";
case 'i': return "";
case 'o': return "";
case 'ô': return "";
case 'ơ': return "";
case 'u': return "";
case 'ư': return "";
case 'y': return "";
default: return null;
}
}
};
// Used with Arabic despite the name; called "Hindi numerals" in Arabic
// map_char_numpad_devanagari is used in Hindi
private static final Map_char map_char_numpad_hindu =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case '0': return "٠";
case '1': return "١";
case '2': return "٢";
case '3': return "٣";
case '4': return "٤";
case '5': return "٥";
case '6': return "٦";
case '7': return "٧";
case '8': return "٨";
case '9': return "٩";
default: return null;
}
}
};
private static final Map_char map_char_numpad_bengali =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case '0': return "";
case '1': return "";
case '2': return "";
case '3': return "";
case '4': return "";
case '5': return "";
case '6': return "";
case '7': return "";
case '8': return "";
case '9': return "";
default: return null;
}
}
};
private static final Map_char map_char_numpad_devanagari =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case '0': return "";
case '1': return "";
case '2': return "";
case '3': return "";
case '4': return "";
case '5': return "";
case '6': return "";
case '7': return "";
case '8': return "";
case '9': return "";
default: return null;
}
}
};
private static final Map_char map_char_numpad_persian =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case '0': return "۰";
case '1': return "۱";
case '2': return "۲";
case '3': return "۳";
case '4': return "۴";
case '5': return "۵";
case '6': return "۶";
case '7': return "۷";
case '8': return "۸";
case '9': return "۹";
default: return null;
}
}
};
private static final Map_char map_char_numpad_gujarati =
new Map_char() {
public String apply(char c)
{
switch (c)
{
case '0': return "";
case '1': return "";
case '2': return "";
case '3': return "";
case '4': return "";
case '5': return "";
case '6': return "";
case '7': return "";
case '8': return "";
case '9': return "";
default: return null;
}
}
};
/** Compose the precomposed initial with the medial [kv]. */
private static KeyValue combine_hangul_initial(KeyValue kv, int precomposed)
{
switch (kv.getKind())
{
case Char:
return combine_hangul_initial(kv, kv.getChar(), precomposed);
case Hangul_initial:
// No initials are expected to compose, grey out
return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
default:
return kv;
}
}
private static KeyValue combine_hangul_initial(KeyValue kv, char medial,
int precomposed)
{
int medial_idx;
switch (medial)
{
// Vowels
case 'ㅏ': medial_idx = 0; break;
case 'ㅐ': medial_idx = 1; break;
case 'ㅑ': medial_idx = 2; break;
case 'ㅒ': medial_idx = 3; break;
case 'ㅓ': medial_idx = 4; break;
case 'ㅔ': medial_idx = 5; break;
case 'ㅕ': medial_idx = 6; break;
case 'ㅖ': medial_idx = 7; break;
case 'ㅗ': medial_idx = 8; break;
case 'ㅘ': medial_idx = 9; break;
case 'ㅙ': medial_idx = 10; break;
case 'ㅚ': medial_idx = 11; break;
case 'ㅛ': medial_idx = 12; break;
case 'ㅜ': medial_idx = 13; break;
case 'ㅝ': medial_idx = 14; break;
case 'ㅞ': medial_idx = 15; break;
case 'ㅟ': medial_idx = 16; break;
case 'ㅠ': medial_idx = 17; break;
case 'ㅡ': medial_idx = 18; break;
case 'ㅢ': medial_idx = 19; break;
case 'ㅣ': medial_idx = 20; break;
// Grey-out uncomposable characters
default: return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
}
return KeyValue.makeHangulMedial(precomposed, medial_idx);
}
/** Combine the precomposed medial with the final [kv]. */
private static KeyValue combine_hangul_medial(KeyValue kv, int precomposed)
{
switch (kv.getKind())
{
case Char:
return combine_hangul_medial(kv, kv.getChar(), precomposed);
case Hangul_initial:
// Finals that can also be initials have this kind.
return combine_hangul_medial(kv, kv.getString().charAt(0), precomposed);
default:
return kv;
}
}
private static KeyValue combine_hangul_medial(KeyValue kv, char c,
int precomposed)
{
int final_idx;
switch (c)
{
case ' ': final_idx = 0; break;
case 'ㄱ': final_idx = 1; break;
case 'ㄲ': final_idx = 2; break;
case 'ㄳ': final_idx = 3; break;
case 'ㄴ': final_idx = 4; break;
case 'ㄵ': final_idx = 5; break;
case 'ㄶ': final_idx = 6; break;
case 'ㄷ': final_idx = 7; break;
case 'ㄹ': final_idx = 8; break;
case 'ㄺ': final_idx = 9; break;
case 'ㄻ': final_idx = 10; break;
case 'ㄼ': final_idx = 11; break;
case 'ㄽ': final_idx = 12; break;
case 'ㄾ': final_idx = 13; break;
case 'ㄿ': final_idx = 14; break;
case 'ㅀ': final_idx = 15; break;
case 'ㅁ': final_idx = 16; break;
case 'ㅂ': final_idx = 17; break;
case 'ㅄ': final_idx = 18; break;
case 'ㅅ': final_idx = 19; break;
case 'ㅆ': final_idx = 20; break;
case 'ㅇ': final_idx = 21; break;
case 'ㅈ': final_idx = 22; break;
case 'ㅊ': final_idx = 23; break;
case 'ㅋ': final_idx = 24; break;
case 'ㅌ': final_idx = 25; break;
case 'ㅍ': final_idx = 26; break;
case 'ㅎ': final_idx = 27; break;
// Grey-out uncomposable characters
default: return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
}
return KeyValue.makeHangulFinal(precomposed, final_idx);
}
}