diff options
| author | Jules Aguillon | 2022-06-05 01:38:42 +0200 |
|---|---|---|
| committer | Jules Aguillon | 2022-06-05 01:43:58 +0200 |
| commit | 4127aa6f033a258aa89ff3704a952505c8c056cb (patch) | |
| tree | 5a1dcada711e1ed85c28d626abf0b2e484f7fcff /srcs/juloo.keyboard2/KeyModifier.java | |
| parent | 4f9375373e3ce9514550fa0470b40ae7f0ff19b2 (diff) | |
| download | unexpected-keyboard-4127aa6f033a258aa89ff3704a952505c8c056cb.tar.gz unexpected-keyboard-4127aa6f033a258aa89ff3704a952505c8c056cb.zip | |
Stop using flags for modifiers
There was no free bits left to add new modifiers. Instead of increasing
the width of the 'flags' field, refactor the way modifiers are
represented and used.
Modifers are now represented as independent values and stored in the
'code' field. A flag is added to distinguish between modifiers and keys
with a key event.
The most notable change is that modifiers can no longer be or-ed into a
single value but have to be represented as an array.
Diffstat (limited to 'srcs/juloo.keyboard2/KeyModifier.java')
| -rw-r--r-- | srcs/juloo.keyboard2/KeyModifier.java | 430 |
1 files changed, 223 insertions, 207 deletions
diff --git a/srcs/juloo.keyboard2/KeyModifier.java b/srcs/juloo.keyboard2/KeyModifier.java index 2f24874..15bb89f 100644 --- a/srcs/juloo.keyboard2/KeyModifier.java +++ b/srcs/juloo.keyboard2/KeyModifier.java @@ -1,6 +1,5 @@ package juloo.keyboard2; -import android.util.SparseArray; import android.view.KeyCharacterMap; import android.view.KeyEvent; import java.util.HashMap; @@ -8,234 +7,86 @@ import java.util.HashMap; class KeyModifier { /** Cache key is KeyValue's name */ - private static HashMap<String, SparseArray<KeyValue>> _cache = - new HashMap<String, SparseArray<KeyValue>>(); + private static HashMap<String, HashMap<Pointers.Modifiers, KeyValue>> _cache = + new HashMap<String, HashMap<Pointers.Modifiers, KeyValue>>(); /** Represents a removed key, because a cache entry can't be [null]. */ private static final KeyValue removed_key = KeyValue.getKeyByName("removed"); /** Modify a key according to modifiers. */ - public static KeyValue handleFlags(KeyValue k, int flags) + public static KeyValue modify(KeyValue k, Pointers.Modifiers mods) { if (k == null) return null; - SparseArray<KeyValue> ks = cacheEntry(k); - KeyValue r = ks.get(flags); - if (r == null) // Cold cache + int n_mods = mods.size(); + HashMap<Pointers.Modifiers, KeyValue> ks = cacheEntry(k); + KeyValue r = ks.get(mods); + if (r == null) { r = k; - r = handleFn(r, flags); - r = handleShift(r, flags); - r = handleAccents(r, flags); - ks.put(flags, r); + /* Order: Fn, Shift, accents */ + for (int i = 0; i < n_mods; i++) + r = modify(r, mods.get(i)); + r = remove_placeholders(r); + ks.put(mods, r); } return (r == removed_key) ? null : r; } - private static KeyValue handleAccents(KeyValue k, int flags) + public static KeyValue modify(KeyValue k, int mod) { - if (k.char_ == KeyValue.CHAR_NONE || (flags & KeyValue.FLAGS_ACCENTS) == 0) - return k; - char c = handleAccentChar(k.char_, flags); - if (c == 0 || c == k.char_) - return k; - return k.withCharAndSymbol(c); + switch (mod) + { + case KeyValue.MOD_FN: return apply_fn(k); + case KeyValue.MOD_SHIFT: return apply_shift(k); + case KeyValue.MOD_GRAVE: return apply_dead_char(k, '\u02CB'); + case KeyValue.MOD_AIGU: return apply_dead_char(k, '\u00B4'); + case KeyValue.MOD_CIRCONFLEXE: return apply_dead_char(k, '\u02C6'); + case KeyValue.MOD_TILDE: return apply_dead_char(k, '\u02DC'); + case KeyValue.MOD_CEDILLE: return apply_dead_char(k, '\u00B8'); + case KeyValue.MOD_TREMA: return apply_dead_char(k, '\u00A8'); + case KeyValue.MOD_CARON: return apply_dead_char(k, '\u02C7'); + case KeyValue.MOD_RING: return apply_dead_char(k, '\u02DA'); + case KeyValue.MOD_MACRON: return apply_dead_char(k, '\u00AF'); + case KeyValue.MOD_OGONEK: return apply_dead_char(k, '\u02DB'); + case KeyValue.MOD_DOT_ABOVE: return apply_dead_char(k, '\u02D9'); + case KeyValue.MOD_DOUBLE_AIGU: + return maybe_modify_char(k, map_char_double_aigu(k.char_)); + case KeyValue.MOD_ORDINAL: + return maybe_modify_char(k, map_char_ordinal(k.char_)); + case KeyValue.MOD_SUPERSCRIPT: + return maybe_modify_char(k, map_char_superscript(k.char_)); + case KeyValue.MOD_SUBSCRIPT: + return maybe_modify_char(k, map_char_subscript(k.char_)); + case KeyValue.MOD_ARROWS: + return maybe_modify_char(k, map_char_arrows(k.char_)); + case KeyValue.MOD_BOX: + return maybe_modify_char(k, map_char_box(k.char_)); + default: return k; + } } - private static KeyValue handleShift(KeyValue k, int flags) + private static KeyValue apply_dead_char(KeyValue k, char dead_char) { - if ((flags & KeyValue.FLAG_SHIFT) == 0) - return k; char c = k.char_; - if (k.char_ != KeyValue.CHAR_NONE) - c = Character.toUpperCase(c); - if (c == k.char_) // Used to have more rules if toUpperCase() did nothing - return k; - return k.withCharAndSymbol(c); + if (c != KeyValue.CHAR_NONE) + c = (char)KeyCharacterMap.getDeadChar(dead_char, c); + return maybe_modify_char(k, c); } - private static char handleAccentChar(char c, int flags) + private static KeyValue apply_shift(KeyValue k) { - switch ((flags & KeyValue.FLAGS_ACCENTS)) - { - case KeyValue.FLAG_ACCENT1: - return (char)KeyCharacterMap.getDeadChar('\u02CB', c); - case KeyValue.FLAG_ACCENT2: - return (char)KeyCharacterMap.getDeadChar('\u00B4', c); - case KeyValue.FLAG_ACCENT3: - return (char)KeyCharacterMap.getDeadChar('\u02C6', c); - case KeyValue.FLAG_ACCENT4: - return (char)KeyCharacterMap.getDeadChar('\u02DC', c); - case KeyValue.FLAG_ACCENT5: - return (char)KeyCharacterMap.getDeadChar('\u00B8', c); - case KeyValue.FLAG_ACCENT6: - return (char)KeyCharacterMap.getDeadChar('\u00A8', c); - case KeyValue.FLAG_ACCENT_CARON: - return (char)KeyCharacterMap.getDeadChar('\u02C7', c); - case KeyValue.FLAG_ACCENT_RING: - return (char)KeyCharacterMap.getDeadChar('\u02DA', c); - case KeyValue.FLAG_ACCENT_MACRON: - return (char)KeyCharacterMap.getDeadChar('\u00AF', c); - case KeyValue.FLAG_ACCENT_OGONEK: - return (char)KeyCharacterMap.getDeadChar('\u02DB', c); - case KeyValue.FLAG_ACCENT_DOT_ABOVE: - return (char)KeyCharacterMap.getDeadChar('\u02D9', c); - case KeyValue.FLAG_ACCENT_DOUBLE_AIGU: - switch (c) - { - // Composite characters: a̋ e̋ i̋ m̋ ӳ - case 'o': return 'ő'; - case 'u': return 'ű'; - case ' ': return '˝'; - default: return c; - } - case KeyValue.FLAG_ACCENT_ORDINAL: - 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 KeyValue.FLAG_ACCENT_SUPERSCRIPT: - 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 'i': return 'ⁱ'; - case '+': return '⁺'; - case '-': return '⁻'; - case '=': return '⁼'; - case '(': return '⁽'; - case ')': return '⁾'; - case 'n': return 'ⁿ'; - default: return c; - } - case KeyValue.FLAG_ACCENT_SUBSCRIPT: - 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 'e': return 'ₑ'; - case 'a': return 'ₐ'; - case 'x': return 'ₓ'; - case 'o': return 'ₒ'; - default: return c; - } - case KeyValue.FLAG_ACCENT_ARROWS: - if ((flags & KeyValue.FLAG_SHIFT) == 0) - { - 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; - } - } - else - { - 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 KeyValue.FLAG_ACCENT_BOX: - if ((flags & KeyValue.FLAG_SHIFT) == 0) - { - 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; - } - } - else - { - 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; - } - } - default: return c; // Can't happen - } + char c = k.char_; + if (c == KeyValue.CHAR_NONE) + return k; + c = map_char_shift(c); + if (c == k.char_) + c = Character.toUpperCase(c); + return maybe_modify_char(k, c); } - private static KeyValue handleFn(KeyValue k, int flags) + private static KeyValue apply_fn(KeyValue k) { - if ((flags & KeyValue.FLAG_FN) == 0) - { - switch (k.name) - { - // Remove some keys when Fn is *not* activated - case "f11_placeholder": - case "f12_placeholder": return removed_key; - default: return k; - } - } String name; switch (k.name) { @@ -302,15 +153,180 @@ class KeyModifier return KeyValue.getKeyByName(name); } + /** Remove placeholder keys that haven't been modified into something. */ + private static KeyValue remove_placeholders(KeyValue k) + { + switch (k.name) + { + case "f11_placeholder": + case "f12_placeholder": return removed_key; + default: return k; + } + } + + /** Helper, update [k] with the char [c] if it's not [0]. */ + private static KeyValue maybe_modify_char(KeyValue k, char c) + { + if (c == 0 || c == KeyValue.CHAR_NONE || c == k.char_) + return k; + return k.withCharAndSymbol(c); + } + /* Lookup the cache entry for a key. Create it needed. */ - private static SparseArray<KeyValue> cacheEntry(KeyValue k) + private static HashMap<Pointers.Modifiers, KeyValue> cacheEntry(KeyValue k) { - SparseArray<KeyValue> ks = _cache.get(k.name); + HashMap<Pointers.Modifiers, KeyValue> ks = _cache.get(k.name); if (ks == null) { - ks = new SparseArray<KeyValue>(); + ks = new HashMap<Pointers.Modifiers, KeyValue>(); _cache.put(k.name, ks); } return ks; } + + 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 '║'; + default: return c; + } + } + + private static char map_char_double_aigu(char c) + { + switch (c) + { + // Composite characters: a̋ e̋ i̋ m̋ ӳ + case 'o': return 'ő'; + case 'u': return 'ű'; + case ' ': return '˝'; + default: return c; + } + } + + private static char map_char_ordinal(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; + } + } + + private static char map_char_superscript(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 'i': return 'ⁱ'; + case '+': return '⁺'; + case '-': return '⁻'; + case '=': return '⁼'; + case '(': return '⁽'; + case ')': return '⁾'; + case 'n': return 'ⁿ'; + default: return c; + } + } + + private static char map_char_subscript(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 'e': return 'ₑ'; + case 'a': return 'ₐ'; + case 'x': return 'ₓ'; + case 'o': return 'ₒ'; + default: return c; + } + } + + private static char map_char_arrows(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; + } + } + + private static char map_char_box(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; + } + } } |
