diff --git a/srcs/juloo.keyboard2/KeyModifier.java b/srcs/juloo.keyboard2/KeyModifier.java index 6982cba19..62c420e0e 100644 --- a/srcs/juloo.keyboard2/KeyModifier.java +++ b/srcs/juloo.keyboard2/KeyModifier.java @@ -39,17 +39,17 @@ public static KeyValue modify(KeyValue k, KeyValue.Modifier mod) case META: return turn_into_keyevent(k); case FN: return apply_fn(k); case SHIFT: return apply_shift(k); - case GRAVE: return apply_map_or_dead_char(k, map_char_grave, '\u02CB'); - case AIGU: return apply_map_or_dead_char(k, map_char_aigu, '\u00B4'); - case CIRCONFLEXE: return apply_map_or_dead_char(k, map_char_circonflexe, '\u02C6'); - case TILDE: return apply_map_or_dead_char(k, map_char_tilde, '\u02DC'); - case CEDILLE: return apply_map_or_dead_char(k, map_char_cedille, '\u00B8'); - case TREMA: return apply_map_or_dead_char(k, map_char_trema, '\u00A8'); - case CARON: return apply_map_or_dead_char(k, map_char_caron, '\u02C7'); - case RING: return apply_map_or_dead_char(k, map_char_ring, '\u02DA'); - case MACRON: return apply_map_or_dead_char(k, map_char_macron, '\u00AF'); - case OGONEK: return apply_map_or_dead_char(k, map_char_ogonek, '\u02DB'); - case DOT_ABOVE: return apply_map_or_dead_char(k, map_char_dot_above, '\u02D9'); + 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_dead_char(k, '\u02D8'); case DOUBLE_AIGU: return apply_map_char(k, map_char_double_aigu); case ORDINAL: return apply_map_char(k, map_char_ordinal); @@ -89,8 +89,10 @@ private static KeyValue apply_map_char(KeyValue k, Map_char map) { case Char: char kc = k.getChar(); - char c = map.apply(kc); - return (kc == c) ? k : k.withChar(c); + String modified = map.apply(kc); + if (modified == null) + return k; + return KeyValue.makeStringKey(modified, k.getFlags()); default: return k; } } @@ -107,27 +109,13 @@ private static KeyValue apply_dead_char(KeyValue k, char dead_char) } } - /** Apply a [Map_char] or fallback to [apply_dead_char]. */ - private static KeyValue apply_map_or_dead_char(KeyValue k, Map_char map, char dead_char) - { - switch (k.getKind()) - { - case Char: - char kc = k.getChar(); - char c = map.apply(kc); - if (kc == c) - return apply_dead_char(k, dead_char); - return k.withChar(c); - default: return k; - } - } - private static KeyValue apply_combining(KeyValue k, String combining) { switch (k.getKind()) { case Char: - return k.withString(String.valueOf(k.getChar()) + combining); + String s = String.valueOf(k.getChar()) + combining; + return KeyValue.makeStringKey(s, k.getFlags()); default: return k; } } @@ -143,7 +131,7 @@ private static KeyValue apply_shift(KeyValue k) c = Character.toUpperCase(kc); return (kc == c) ? k : k.withChar(c); case String: - return k.withString(k.getString().toUpperCase()); + return KeyValue.makeStringKey(k.getString().toUpperCase(), k.getFlags()); default: return k; } } @@ -464,7 +452,9 @@ private static HashMap cacheEntry(KeyValue k) private static abstract class Map_char { - public abstract char apply(char c); + /** 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 char map_char_shift(char c) @@ -500,470 +490,478 @@ private static char map_char_shift(char 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 char apply(char c) + public String apply(char c) { switch (c) { // Composite characters: 'j́' - case 'a': return 'á'; - case 'e': return 'é'; - case 'i': return 'í'; - case 'l': return 'ĺ'; - case 'o': return 'ó'; - case 'r': return 'ŕ'; - case 's': return 'ś'; - case 'u': return 'ú'; - case 'y': return 'ý'; - default: return c; + case 'a': return "á"; + case 'e': return "é"; + case 'i': return "í"; + case 'l': return "ĺ"; + case 'o': return "ó"; + case 'r': return "ŕ"; + case 's': return "ś"; + case 'u': return "ú"; + case 'y': return "ý"; + default: return map_dead_char(c, '\u00B4'); } } }; private static final Map_char map_char_caron = new Map_char() { - public char apply(char c) + public String apply(char c) { switch (c) { - case 'c': return 'č'; - case 'd': return 'ď'; - case 'e': return 'ě'; - case 'l': return 'ľ'; - case 'n': return 'ň'; - case 'r': return 'ř'; - case 's': return 'š'; - case 't': return 'ť'; - case 'z': return 'ž'; - default: return c; + case 'c': return "č"; + case 'd': return "ď"; + case 'e': return "ě"; + case 'l': return "ľ"; + case 'n': return "ň"; + case 'r': return "ř"; + case 's': return "š"; + case 't': return "ť"; + case 'z': return "ž"; + default: return map_dead_char(c, '\u02C7'); } } }; private static final Map_char map_char_cedille = new Map_char() { - public char apply(char c) + public String apply(char c) { switch (c) { - case 'c': return 'ç'; - case 's': return 'ş'; - case 'g': return 'ģ'; - default: return c; + case 'c': return "ç"; + case 's': return "ş"; + case 'g': return "ģ"; + default: return map_dead_char(c, '\u00B8'); } } }; private static final Map_char map_char_circonflexe = new Map_char() { - public char apply(char c) + public String apply(char c) { switch (c) { - case 'a': return 'â'; - case 'e': return 'ê'; - case 'i': return 'î'; - case 'o': return 'ô'; - case 'u': return 'û'; - default: return c; + case 'a': return "â"; + case 'e': return "ê"; + case 'i': return "î"; + case 'o': return "ô"; + case 'u': return "û"; + default: return map_dead_char(c, '\u02C6'); } } }; private static final Map_char map_char_dot_above = new Map_char() { - public char apply(char c) + public String apply(char c) { switch (c) { - case 'ė': return 'ė'; - default: return c; + case 'ė': return "ė"; + default: return map_dead_char(c, '\u02D9'); } } }; private static final Map_char map_char_grave = new Map_char() { - public char apply(char c) + public String apply(char c) { switch (c) { - case 'a': return 'à'; - case 'e': return 'è'; - case 'i': return 'ì'; - case 'o': return 'ò'; - case 'u': return 'ù'; - default: return c; + case 'a': return "à"; + case 'e': return "è"; + case 'i': return "ì"; + case 'o': return "ò"; + case 'u': return "ù"; + default: return map_dead_char(c, '\u02CB'); } } }; private static final Map_char map_char_macron = new Map_char() { - public char apply(char c) + public String apply(char c) { switch (c) { - case 'a': return 'ā'; - case 'e': return 'ē'; - case 'i': return 'ī'; - case 'u': return 'ū'; - default: return c; + case 'a': return "ā"; + case 'e': return "ē"; + case 'i': return "ī"; + case 'u': return "ū"; + default: return map_dead_char(c, '\u00AF'); } } }; private static final Map_char map_char_ogonek = new Map_char() { - public char apply(char c) + 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 'u': return 'ų'; - default: return c; + case 'a': return "ą"; + case 'e': return "ę"; + case 'i': return "į"; + case 'k': return "ķ"; + case 'l': return "ļ"; + case 'n': return "ņ"; + case 'u': return "ų"; + default: return map_dead_char(c, '\u02DB'); } } }; private static final Map_char map_char_ring = new Map_char() { - public char apply(char c) + public String apply(char c) { switch (c) { - case 'a': return 'å'; - case 'u': return 'ů'; - default: return 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 char apply(char c) + public String apply(char c) { switch (c) { - case 'a': return 'ã'; - case 'o': return 'õ'; - case 'n': return 'ñ'; - default: return c; + case 'a': return "ã"; + case 'o': return "õ"; + case 'n': return "ñ"; + default: return map_dead_char(c, '\u02DC'); } } }; private static final Map_char map_char_trema = new Map_char() { - public char apply(char c) + 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 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_double_aigu = new Map_char() { - public char apply(char c) + public String apply(char c) { switch (c) { // Composite characters: a̋ e̋ i̋ m̋ ӳ - case 'o': return 'ő'; - case 'u': return 'ű'; - case ' ': return '˝'; - default: return c; + case 'o': return "ő"; + case 'u': return "ű"; + case ' ': return "˝"; + default: return null; } } }; private static final Map_char map_char_ordinal = new Map_char() { - public char apply(char c) + 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 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 char apply(char c) + 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 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 char apply(char c) + 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 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 char apply(char c) + public String apply(char c) { switch (c) { - case '1': return '↙'; - case '2': return '↓'; - case '3': return '↘'; - case '4': return '←'; - case '6': return '→'; - case '7': return '↖'; - case '8': return '↑'; - case '9': return '↗'; - default: return c; + case '1': return "↙"; + case '2': return "↓"; + case '3': return "↘"; + case '4': return "←"; + case '6': return "→"; + case '7': return "↖"; + case '8': return "↑"; + case '9': return "↗"; + default: return null; } } }; private static final Map_char map_char_box = new Map_char() { - public char apply(char c) + 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 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 char apply(char c) + 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 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 char apply(char c) + 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 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 char 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 c; - } - } - }; + 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 char 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 c; - } - } - }; + 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 char 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 c; - } - } - }; + 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; + } + } + }; } diff --git a/srcs/juloo.keyboard2/KeyValue.java b/srcs/juloo.keyboard2/KeyValue.java index 09722141c..10ce481ec 100644 --- a/srcs/juloo.keyboard2/KeyValue.java +++ b/srcs/juloo.keyboard2/KeyValue.java @@ -182,11 +182,6 @@ public KeyValue withChar(char c) return new KeyValue(String.valueOf(c), Kind.Char, c, getFlags()); } - public KeyValue withString(String s) - { - return new KeyValue(s, Kind.String, 0, getFlags()); - } - public KeyValue withSymbol(String s) { return new KeyValue(s, (_code & KIND_BITS), (_code & VALUE_BITS), getFlags()); @@ -302,13 +297,19 @@ private static KeyValue placeholderKey(Placeholder id) return new KeyValue("", Kind.Placeholder, id.ordinal(), 0); } - /** Make a key that types a string. */ public static KeyValue makeStringKey(String str) + { + return makeStringKey(str, 0); + } + + /** Make a key that types a string. A char key is returned for a string of + length 1. */ + public static KeyValue makeStringKey(String str, int flags) { if (str.length() == 1) - return new KeyValue(str, Kind.Char, str.charAt(0), 0); + return new KeyValue(str, Kind.Char, str.charAt(0), flags); else - return new KeyValue(str, Kind.String, 0, FLAG_SMALLER_FONT); + return new KeyValue(str, Kind.String, 0, flags | FLAG_SMALLER_FONT); } public static KeyValue getKeyByName(String name)