diff options
Diffstat (limited to 'srcs/juloo.keyboard2')
| -rw-r--r-- | srcs/juloo.keyboard2/Config.java | 27 | ||||
| -rw-r--r-- | srcs/juloo.keyboard2/EmojiGridView.java | 2 | ||||
| -rw-r--r-- | srcs/juloo.keyboard2/EmojiKeyButton.java | 2 | ||||
| -rw-r--r-- | srcs/juloo.keyboard2/KeyEventHandler.java | 71 | ||||
| -rw-r--r-- | srcs/juloo.keyboard2/KeyModifier.java | 430 | ||||
| -rw-r--r-- | srcs/juloo.keyboard2/KeyValue.java | 182 | ||||
| -rw-r--r-- | srcs/juloo.keyboard2/Keyboard2.java | 2 | ||||
| -rw-r--r-- | srcs/juloo.keyboard2/Keyboard2View.java | 22 | ||||
| -rw-r--r-- | srcs/juloo.keyboard2/Pointers.java | 106 |
9 files changed, 466 insertions, 378 deletions
diff --git a/srcs/juloo.keyboard2/Config.java b/srcs/juloo.keyboard2/Config.java index 278cbd2..8059b76 100644 --- a/srcs/juloo.keyboard2/Config.java +++ b/srcs/juloo.keyboard2/Config.java @@ -36,7 +36,7 @@ final class Config public float keyVerticalInterval; public float keyHorizontalInterval; public boolean preciseRepeat; - public int lockable_modifiers; + public Set<Integer> lockable_modifiers = new HashSet<Integer>(); public float characterSize; // Ratio public int accents; // Values are R.values.pref_accents_v_* public int theme; // Values are R.style.* @@ -127,15 +127,15 @@ final class Config keyHeight = dm.heightPixels * keyboardHeightPercent / 100 / 4; horizontalMargin = getDipPref(dm, prefs, "horizontal_margin", horizontalMargin) + res.getDimension(R.dimen.extra_horizontal_margin); preciseRepeat = prefs.getBoolean("precise_repeat", preciseRepeat); - lockable_modifiers = - (prefs.getBoolean("lockable_shift", true) ? KeyValue.FLAG_SHIFT : 0) - | (prefs.getBoolean("lockable_ctrl", false) ? KeyValue.FLAG_CTRL : 0) - | (prefs.getBoolean("lockable_alt", false) ? KeyValue.FLAG_ALT : 0) - | (prefs.getBoolean("lockable_fn", false) ? KeyValue.FLAG_FN : 0) - | (prefs.getBoolean("lockable_meta", false) ? KeyValue.FLAG_META : 0) - | (prefs.getBoolean("lockable_sup", false) ? KeyValue.FLAG_ACCENT_SUPERSCRIPT : 0) - | (prefs.getBoolean("lockable_sub", false) ? KeyValue.FLAG_ACCENT_SUBSCRIPT : 0) - | (prefs.getBoolean("lockable_box", false) ? KeyValue.FLAG_ACCENT_BOX : 0); + lockable_modifiers.clear(); + if (prefs.getBoolean("lockable_shift", true)) lockable_modifiers.add(KeyValue.MOD_SHIFT); + if (prefs.getBoolean("lockable_ctrl", false)) lockable_modifiers.add(KeyValue.MOD_CTRL); + if (prefs.getBoolean("lockable_alt", false)) lockable_modifiers.add(KeyValue.MOD_ALT); + if (prefs.getBoolean("lockable_fn", false)) lockable_modifiers.add(KeyValue.MOD_FN); + if (prefs.getBoolean("lockable_meta", false)) lockable_modifiers.add(KeyValue.MOD_META); + if (prefs.getBoolean("lockable_sup", false)) lockable_modifiers.add(KeyValue.MOD_SUPERSCRIPT); + if (prefs.getBoolean("lockable_sub", false)) lockable_modifiers.add(KeyValue.MOD_SUBSCRIPT); + if (prefs.getBoolean("lockable_box", false)) lockable_modifiers.add(KeyValue.MOD_BOX); characterSize = prefs.getFloat("character_size", characterSize); accents = Integer.valueOf(prefs.getString("accents", "1")); theme = getThemeId(res, prefs.getString("theme", "")); @@ -163,7 +163,7 @@ final class Config boolean is_extra_key = extra_keys.contains(key.name); if (is_extra_key) extra_keys.remove(key.name); - switch (key.eventCode) + switch (key.code) { case KeyValue.EVENT_CHANGE_METHOD: return shouldOfferSwitchingToNextInputMethod ? key : null; @@ -179,7 +179,8 @@ final class Config { if ((key.flags & KeyValue.FLAG_LOCALIZED) != 0 && !is_extra_key) return null; - if ((key.flags & lockable_modifiers) != 0) + if ((key.flags & KeyValue.FLAG_MODIFIER) != 0 + && lockable_modifiers.contains(key.code)) return key.withFlags(key.flags | KeyValue.FLAG_LOCK); } return key; @@ -275,6 +276,6 @@ final class Config public static interface IKeyEventHandler { - public void handleKeyUp(KeyValue value, int flags); + public void handleKeyUp(KeyValue value, Pointers.Modifiers flags); } } diff --git a/srcs/juloo.keyboard2/EmojiGridView.java b/srcs/juloo.keyboard2/EmojiGridView.java index eb2d6df..9f0a3a5 100644 --- a/srcs/juloo.keyboard2/EmojiGridView.java +++ b/srcs/juloo.keyboard2/EmojiGridView.java @@ -55,7 +55,7 @@ public class EmojiGridView extends GridView Config config = Config.globalConfig(); Integer used = _lastUsed.get(_emojiArray[pos]); _lastUsed.put(_emojiArray[pos], (used == null) ? 1 : used.intValue() + 1); - config.handler.handleKeyUp(_emojiArray[pos], 0); + config.handler.handleKeyUp(_emojiArray[pos], Pointers.Modifiers.EMPTY); saveLastUsed(); // TODO: opti } diff --git a/srcs/juloo.keyboard2/EmojiKeyButton.java b/srcs/juloo.keyboard2/EmojiKeyButton.java index 51ff14f..1f5a3a0 100644 --- a/srcs/juloo.keyboard2/EmojiKeyButton.java +++ b/srcs/juloo.keyboard2/EmojiKeyButton.java @@ -23,6 +23,6 @@ public class EmojiKeyButton extends Button public void onClick(View v) { Config config = Config.globalConfig(); - config.handler.handleKeyUp(_key, 0); + config.handler.handleKeyUp(_key, Pointers.Modifiers.EMPTY); } } diff --git a/srcs/juloo.keyboard2/KeyEventHandler.java b/srcs/juloo.keyboard2/KeyEventHandler.java index 8382737..691e40d 100644 --- a/srcs/juloo.keyboard2/KeyEventHandler.java +++ b/srcs/juloo.keyboard2/KeyEventHandler.java @@ -11,11 +11,11 @@ class KeyEventHandler implements Config.IKeyEventHandler _recv = recv; } - public void handleKeyUp(KeyValue key, int flags) + public void handleKeyUp(KeyValue key, Pointers.Modifiers mods) { - if (key == null || (key.flags & KeyValue.FLAG_NOCHAR) != 0) + if (key == null || (key.flags & KeyValue.FLAG_MODIFIER) != 0) return; - switch (key.eventCode) + switch (key.code) { case KeyValue.EVENT_CONFIG: _recv.showKeyboardConfig(); return; case KeyValue.EVENT_SWITCH_TEXT: _recv.switchMain(); return; @@ -26,12 +26,10 @@ class KeyEventHandler implements Config.IKeyEventHandler case KeyValue.EVENT_ACTION: _recv.performAction(); return; case KeyValue.EVENT_SWITCH_PROGRAMMING: _recv.switchProgramming(); return; default: - if ((flags & (KeyValue.FLAG_CTRL | KeyValue.FLAG_ALT | KeyValue.FLAG_META)) != 0) - handleKeyUpWithModifier(key, flags); + if (shouldSendEvents(key, mods)) + handleKeyUpWithModifier(key, mods); else if (key.char_ != KeyValue.CHAR_NONE) _recv.commitChar(key.char_); - else if (key.eventCode != KeyValue.EVENT_NONE) - handleKeyUpWithModifier(key, flags); else _recv.commitText(key.symbol); } @@ -57,33 +55,58 @@ class KeyEventHandler implements Config.IKeyEventHandler return updatedMetaState; } - /* Send key events corresponding to pressed modifier keys. */ - private int sendMetaKeys(int flags, int metaState, boolean down) + private int sendMetaKeyForModifier(int mod, int metaState, boolean down) { - if ((flags & KeyValue.FLAG_CTRL) != 0) - metaState = sendMetaKey(KeyEvent.KEYCODE_CTRL_LEFT, KeyEvent.META_CTRL_LEFT_ON | KeyEvent.META_CTRL_ON, metaState, down); - if ((flags & KeyValue.FLAG_ALT) != 0) - metaState = sendMetaKey(KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_ON, metaState, down); - if ((flags & KeyValue.FLAG_SHIFT) != 0) - metaState = sendMetaKey(KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON, metaState, down); - if ((flags & KeyValue.FLAG_META) != 0) - metaState = sendMetaKey(KeyEvent.KEYCODE_META_LEFT, KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_ON, metaState, down); - return metaState; + switch (mod) + { + case KeyValue.MOD_CTRL: + return sendMetaKey(KeyEvent.KEYCODE_CTRL_LEFT, KeyEvent.META_CTRL_LEFT_ON | KeyEvent.META_CTRL_ON, metaState, down); + case KeyValue.MOD_ALT: + return sendMetaKey(KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_ON, metaState, down); + case KeyValue.MOD_SHIFT: + return sendMetaKey(KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON, metaState, down); + case KeyValue.MOD_META: + return sendMetaKey(KeyEvent.KEYCODE_META_LEFT, KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_ON, metaState, down); + default: return metaState; + } } /* * Don't set KeyEvent.FLAG_SOFT_KEYBOARD. */ - private void handleKeyUpWithModifier(KeyValue key, int flags) + private void handleKeyUpWithModifier(KeyValue key, Pointers.Modifiers mods) { - if (key.eventCode == KeyValue.EVENT_NONE) + if (key.code == KeyValue.EVENT_NONE) return ; - int metaState = sendMetaKeys(flags, 0, true); - _recv.sendKeyEvent(KeyEvent.ACTION_DOWN, key.eventCode, metaState); - _recv.sendKeyEvent(KeyEvent.ACTION_UP, key.eventCode, metaState); - sendMetaKeys(flags, metaState, false); + int metaState = 0; + for (int i = 0; i < mods.size(); i++) + metaState = sendMetaKeyForModifier(mods.get(i), metaState, true); + _recv.sendKeyEvent(KeyEvent.ACTION_DOWN, key.code, metaState); + _recv.sendKeyEvent(KeyEvent.ACTION_UP, key.code, metaState); + for (int i = mods.size() - 1; i >= 0; i--) + metaState = sendMetaKeyForModifier(mods.get(i), metaState, false); } + /** Whether to send up and down events (true) or commit the text (false). */ + private boolean shouldSendEvents(KeyValue key, Pointers.Modifiers mods) + { + // Check for modifiers + for (int i = 0; i < mods.size(); i++) + { + switch (mods.get(i)) + { + case KeyValue.MOD_CTRL: + case KeyValue.MOD_ALT: + case KeyValue.MOD_META: return true; + default: break; + } + } + // Key has no char but has a key event + if (key.char_ == KeyValue.CHAR_NONE && key.code >= 0) + return true; + return false; + } + public static interface IReceiver { public void switchToNextInputMethod(); 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; + } + } } diff --git a/srcs/juloo.keyboard2/KeyValue.java b/srcs/juloo.keyboard2/KeyValue.java index d88f027..b29237e 100644 --- a/srcs/juloo.keyboard2/KeyValue.java +++ b/srcs/juloo.keyboard2/KeyValue.java @@ -6,6 +6,8 @@ import java.util.HashMap; class KeyValue { + /** Values for the [code] field. */ + public static final int EVENT_NONE = -1; public static final int EVENT_CONFIG = -2; public static final int EVENT_SWITCH_TEXT = -3; @@ -15,6 +17,35 @@ class KeyValue public static final int EVENT_CHANGE_METHOD = -7; public static final int EVENT_ACTION = -8; public static final int EVENT_SWITCH_PROGRAMMING = -9; + + // Modifiers + // Must be evaluated in the reverse order of their values. + public static final int MOD_SHIFT = -100; + public static final int MOD_FN = -101; + public static final int MOD_CTRL = -102; + public static final int MOD_ALT = -103; + public static final int MOD_META = -104; + + // Dead-keys + public static final int MOD_DOUBLE_AIGU = -200; + public static final int MOD_DOT_ABOVE = -201; + public static final int MOD_GRAVE = -202; + public static final int MOD_AIGU = -203; + public static final int MOD_CIRCONFLEXE = -204; + public static final int MOD_TILDE = -205; + public static final int MOD_CEDILLE = -206; + public static final int MOD_TREMA = -207; + public static final int MOD_SUPERSCRIPT = -208; + public static final int MOD_SUBSCRIPT = -209; + public static final int MOD_RING = -210; + public static final int MOD_CARON = -211; + public static final int MOD_MACRON = -212; + public static final int MOD_ORDINAL = -213; + public static final int MOD_ARROWS = -214; + public static final int MOD_BOX = -215; + public static final int MOD_OGONEK = -216; + + /** Special value for the [char_] field. */ public static final char CHAR_NONE = '\0'; // Behavior flags @@ -22,7 +53,7 @@ class KeyValue public static final int FLAG_LOCK = (1 << 1); // Special keys are not repeated and don't clear latched modifiers public static final int FLAG_SPECIAL = (1 << 2); - public static final int FLAG_NOCHAR = (1 << 3); + public static final int FLAG_MODIFIER = (1 << 3); public static final int FLAG_PRECISE_REPEAT = (1 << 4); // Rendering flags @@ -30,48 +61,25 @@ class KeyValue public static final int FLAG_SMALLER_FONT = (1 << 6); // Internal flags - public static final int FLAG_LOCKED = (1 << 8); - - // Modifier flags - public static final int FLAG_CTRL = (1 << 10); - public static final int FLAG_SHIFT = (1 << 11); - public static final int FLAG_ALT = (1 << 12); - public static final int FLAG_FN = (1 << 13); - public static final int FLAG_META = (1 << 14); - - // Accent flags - public static final int FLAG_ACCENT_DOUBLE_AIGU = (1 << 9); - public static final int FLAG_ACCENT_DOT_ABOVE = (1 << 15); - public static final int FLAG_ACCENT1 = (1 << 16); // Grave - public static final int FLAG_ACCENT2 = (1 << 17); // Aigu - public static final int FLAG_ACCENT3 = (1 << 18); // Circonflexe - public static final int FLAG_ACCENT4 = (1 << 19); // Tilde - public static final int FLAG_ACCENT5 = (1 << 20); // Cédille - public static final int FLAG_ACCENT6 = (1 << 21); // Tréma - public static final int FLAG_ACCENT_SUPERSCRIPT = (1 << 22); - public static final int FLAG_ACCENT_SUBSCRIPT = (1 << 23); - public static final int FLAG_ACCENT_RING = (1 << 24); - public static final int FLAG_ACCENT_CARON = (1 << 26); - public static final int FLAG_ACCENT_MACRON = (1 << 27); - public static final int FLAG_ACCENT_ORDINAL = (1 << 28); - public static final int FLAG_ACCENT_ARROWS = (1 << 29); - public static final int FLAG_ACCENT_BOX = (1 << 30); - public static final int FLAG_ACCENT_OGONEK = (1 << 31); - - public static final int FLAGS_ACCENTS = FLAG_ACCENT1 | FLAG_ACCENT2 | - FLAG_ACCENT3 | FLAG_ACCENT4 | FLAG_ACCENT5 | FLAG_ACCENT6 | - FLAG_ACCENT_CARON | FLAG_ACCENT_MACRON | FLAG_ACCENT_SUPERSCRIPT | - FLAG_ACCENT_SUBSCRIPT | FLAG_ACCENT_ORDINAL | FLAG_ACCENT_ARROWS | - FLAG_ACCENT_BOX | FLAG_ACCENT_RING | FLAG_ACCENT_OGONEK | - FLAG_ACCENT_DOT_ABOVE | FLAG_ACCENT_DOUBLE_AIGU; + public static final int FLAG_LOCKED = (1 << 7); // Language specific keys that are removed from the keyboard by default - public static final int FLAG_LOCALIZED = (1 << 25); + public static final int FLAG_LOCALIZED = (1 << 8); public final String name; public final String symbol; public final char char_; - public final int eventCode; + + /** Describe what the key does when it isn't a simple character. + Can be one of: + - When [FLAG_MODIFIER] is set, a modifier. See [KeyModifier]. + - [EVENT_NONE], no event is associated with the key. + - A positive integer, an Android [KeyEvent]. + - One of the [EVENT_*] constants, an action performed in [KeyEventHandler]. + A key can have both a character and a key event associated, the key event + is used when certain modifiers are active, the character is used + otherwise. See [KeyEventHandler]. */ + public final int code; public final int flags; /* Update the char and the symbol. */ @@ -82,17 +90,17 @@ class KeyValue public KeyValue withCharAndSymbol(String s, char c) { - return new KeyValue(name, s, c, eventCode, flags); + return new KeyValue(name, s, c, code, flags); } public KeyValue withNameAndSymbol(String n, String s) { - return new KeyValue(n, s, char_, eventCode, flags); + return new KeyValue(n, s, char_, code, flags); } public KeyValue withFlags(int f) { - return new KeyValue(name, symbol, char_, eventCode, f); + return new KeyValue(name, symbol, char_, code, f); } private static HashMap<String, KeyValue> keys = new HashMap<String, KeyValue>(); @@ -102,7 +110,7 @@ class KeyValue name = n; symbol = s; char_ = c; - eventCode = e; + code = e; flags = f; } @@ -136,26 +144,17 @@ class KeyValue keys.put(name, new KeyValue(name, symbol, c, event, flags)); } - private static void addCharKey(char c, int event, int flags) - { - String name = String.valueOf(c); - addKey(name, name, c, event, flags); - } - private static void addCharKey(char c, int event) { - addCharKey(c, event, 0); - } - - private static void addModifierKey(String name, String symbol, int extra_flags) - { - addKey(name, symbol, CHAR_NONE, EVENT_NONE, - FLAG_LATCH | FLAG_NOCHAR | FLAG_SPECIAL | extra_flags); + String name = String.valueOf(c); + addKey(name, name, c, event, 0); } - private static void addSpecialKey(String name, String symbol, int event) + private static void addModifierKey(String name, String symbol, int code, int extra_flags) { - addSpecialKey(name, symbol, event, 0); + assert(code >= 100 && code < 300); + addKey(name, symbol, CHAR_NONE, code, + FLAG_LATCH | FLAG_MODIFIER | FLAG_SPECIAL | extra_flags); } private static void addSpecialKey(String name, String symbol, int event, int flags) @@ -163,11 +162,6 @@ class KeyValue addKey(name, symbol, CHAR_NONE, event, flags | FLAG_SPECIAL); } - private static void addEventKey(String name, String symbol, int event) - { - addEventKey(name, symbol, event, 0); - } - private static void addEventKey(String name, String symbol, int event, int flags) { addKey(name, symbol, CHAR_NONE, event, flags); @@ -176,28 +170,28 @@ class KeyValue static { addModifierKey("shift", "\n", // Can't write u000A because Java is stupid - FLAG_SHIFT | FLAG_KEY_FONT | FLAG_SMALLER_FONT); - addModifierKey("ctrl", "Ctrl", FLAG_CTRL | FLAG_SMALLER_FONT); - addModifierKey("alt", "Alt", FLAG_ALT | FLAG_SMALLER_FONT); - addModifierKey("accent_aigu", "\u0050", FLAG_ACCENT2 | FLAG_KEY_FONT); - addModifierKey("accent_caron", "\u0051", FLAG_ACCENT_CARON | FLAG_KEY_FONT); - addModifierKey("accent_cedille", "\u0052", FLAG_ACCENT5 | FLAG_KEY_FONT); - addModifierKey("accent_circonflexe", "\u0053", FLAG_ACCENT3 | FLAG_KEY_FONT); - addModifierKey("accent_grave", "\u0054", FLAG_ACCENT1 | FLAG_KEY_FONT); - addModifierKey("accent_macron", "\u0055", FLAG_ACCENT_MACRON | FLAG_KEY_FONT); - addModifierKey("accent_ring", "\u0056", FLAG_ACCENT_RING | FLAG_KEY_FONT); - addModifierKey("accent_tilde", "\u0057", FLAG_ACCENT4 | FLAG_KEY_FONT); - addModifierKey("accent_trema", "\u0058", FLAG_ACCENT6 | FLAG_KEY_FONT); - addModifierKey("accent_ogonek", "\u0059", FLAG_ACCENT_OGONEK | FLAG_KEY_FONT); - addModifierKey("accent_dot_above", "\u005a", FLAG_ACCENT_DOT_ABOVE | FLAG_KEY_FONT); - addModifierKey("accent_double_aigu", "\u005b", FLAG_ACCENT_DOUBLE_AIGU | FLAG_KEY_FONT); - addModifierKey("superscript", "Sup", FLAG_ACCENT_SUPERSCRIPT | FLAG_SMALLER_FONT); - addModifierKey("subscript", "Sub", FLAG_ACCENT_SUBSCRIPT | FLAG_SMALLER_FONT); - addModifierKey("ordinal", "Ord", FLAG_ACCENT_ORDINAL | FLAG_SMALLER_FONT); - addModifierKey("arrows", "Arr", FLAG_ACCENT_ARROWS | FLAG_SMALLER_FONT); - addModifierKey("box", "Box", FLAG_ACCENT_BOX | FLAG_SMALLER_FONT); - addModifierKey("fn", "Fn", FLAG_FN | FLAG_SMALLER_FONT); - addModifierKey("meta", "Meta", FLAG_META | FLAG_SMALLER_FONT); + MOD_SHIFT, FLAG_KEY_FONT | FLAG_SMALLER_FONT); + addModifierKey("ctrl", "Ctrl", MOD_CTRL, FLAG_SMALLER_FONT); + addModifierKey("alt", "Alt", MOD_ALT, FLAG_SMALLER_FONT); + addModifierKey("accent_aigu", "\u0050", MOD_AIGU, FLAG_KEY_FONT); + addModifierKey("accent_caron", "\u0051", MOD_CARON, FLAG_KEY_FONT); + addModifierKey("accent_cedille", "\u0052", MOD_CEDILLE, FLAG_KEY_FONT); + addModifierKey("accent_circonflexe", "\u0053", MOD_CIRCONFLEXE, FLAG_KEY_FONT); + addModifierKey("accent_grave", "\u0054", MOD_GRAVE, FLAG_KEY_FONT); + addModifierKey("accent_macron", "\u0055", MOD_MACRON, FLAG_KEY_FONT); + addModifierKey("accent_ring", "\u0056", MOD_RING, FLAG_KEY_FONT); + addModifierKey("accent_tilde", "\u0057", MOD_TILDE, FLAG_KEY_FONT); + addModifierKey("accent_trema", "\u0058", MOD_TREMA, FLAG_KEY_FONT); + addModifierKey("accent_ogonek", "\u0059", MOD_OGONEK, FLAG_KEY_FONT); + addModifierKey("accent_dot_above", "\u005a", MOD_DOT_ABOVE, FLAG_KEY_FONT); + addModifierKey("accent_double_aigu", "\u005b", MOD_DOUBLE_AIGU, FLAG_KEY_FONT); + addModifierKey("superscript", "Sup", MOD_SUPERSCRIPT, FLAG_SMALLER_FONT); + addModifierKey("subscript", "Sub", MOD_SUBSCRIPT, FLAG_SMALLER_FONT); + addModifierKey("ordinal", "Ord", MOD_ORDINAL, FLAG_SMALLER_FONT); + addModifierKey("arrows", "Arr", MOD_ARROWS, FLAG_SMALLER_FONT); + addModifierKey("box", "Box", MOD_BOX, FLAG_SMALLER_FONT); + addModifierKey("fn", "Fn", MOD_FN, FLAG_SMALLER_FONT); + addModifierKey("meta", "Meta", MOD_META, FLAG_SMALLER_FONT); addCharKey('a', KeyEvent.KEYCODE_A); addCharKey('b', KeyEvent.KEYCODE_B); @@ -257,7 +251,7 @@ class KeyValue addSpecialKey("switch_text", "ABC", EVENT_SWITCH_TEXT, FLAG_SMALLER_FONT); addSpecialKey("switch_numeric", "123+", EVENT_SWITCH_NUMERIC, FLAG_SMALLER_FONT); addSpecialKey("switch_emoji", "\u0001" , EVENT_SWITCH_EMOJI, FLAG_KEY_FONT | FLAG_SMALLER_FONT); - addSpecialKey("switch_back_emoji", "ABC", EVENT_SWITCH_BACK_EMOJI); + addSpecialKey("switch_back_emoji", "ABC", EVENT_SWITCH_BACK_EMOJI, 0); addSpecialKey("switch_programming", "Prog", EVENT_SWITCH_PROGRAMMING, FLAG_SMALLER_FONT); addSpecialKey("change_method", "\u0009", EVENT_CHANGE_METHOD, FLAG_KEY_FONT | FLAG_SMALLER_FONT); addSpecialKey("action", "Action", EVENT_ACTION, FLAG_SMALLER_FONT); // Will always be replaced @@ -275,16 +269,16 @@ class KeyValue addEventKey("backspace", "\u0011", KeyEvent.KEYCODE_DEL, FLAG_KEY_FONT); addEventKey("delete", "\u0010", KeyEvent.KEYCODE_FORWARD_DEL, FLAG_KEY_FONT); addEventKey("insert", "Ins", KeyEvent.KEYCODE_INSERT, FLAG_SMALLER_FONT); - addEventKey("f1", "F1", KeyEvent.KEYCODE_F1); - addEventKey("f2", "F2", KeyEvent.KEYCODE_F2); - addEventKey("f3", "F3", KeyEvent.KEYCODE_F3); - addEventKey("f4", "F4", KeyEvent.KEYCODE_F4); - addEventKey("f5", "F5", KeyEvent.KEYCODE_F5); - addEventKey("f6", "F6", KeyEvent.KEYCODE_F6); - addEventKey("f7", "F7", KeyEvent.KEYCODE_F7); - addEventKey("f8", "F8", KeyEvent.KEYCODE_F8); - addEventKey("f9", "F9", KeyEvent.KEYCODE_F9); - addEventKey("f10", "F10", KeyEvent.KEYCODE_F10); + addEventKey("f1", "F1", KeyEvent.KEYCODE_F1, 0); + addEventKey("f2", "F2", KeyEvent.KEYCODE_F2, 0); + addEventKey("f3", "F3", KeyEvent.KEYCODE_F3, 0); + addEventKey("f4", "F4", KeyEvent.KEYCODE_F4, 0); + addEventKey("f5", "F5", KeyEvent.KEYCODE_F5, 0); + addEventKey("f6", "F6", KeyEvent.KEYCODE_F6, 0); + addEventKey("f7", "F7", KeyEvent.KEYCODE_F7, 0); + addEventKey("f8", "F8", KeyEvent.KEYCODE_F8, 0); + addEventKey("f9", "F9", KeyEvent.KEYCODE_F9, 0); + addEventKey("f10", "F10", KeyEvent.KEYCODE_F10, 0); addEventKey("f11", "F11", KeyEvent.KEYCODE_F11, FLAG_SMALLER_FONT); addEventKey("f12", "F12", KeyEvent.KEYCODE_F12, FLAG_SMALLER_FONT); addEventKey("tab", "\u000F", KeyEvent.KEYCODE_TAB, FLAG_KEY_FONT | FLAG_SMALLER_FONT); diff --git a/srcs/juloo.keyboard2/Keyboard2.java b/srcs/juloo.keyboard2/Keyboard2.java index 8ebf0b8..d0e56a2 100644 --- a/srcs/juloo.keyboard2/Keyboard2.java +++ b/srcs/juloo.keyboard2/Keyboard2.java @@ -298,7 +298,7 @@ public class Keyboard2 extends InputMethodService getLayout(_config.programming_layout).mapKeys(new KeyboardData.MapKeyValues() { public KeyValue apply(KeyValue key) { - if (key != null && key.eventCode == KeyValue.EVENT_SWITCH_PROGRAMMING) + if (key != null && key.code == KeyValue.EVENT_SWITCH_PROGRAMMING) return KeyValue.getKeyByName("switch_text"); return key; } diff --git a/srcs/juloo.keyboard2/Keyboard2View.java b/srcs/juloo.keyboard2/Keyboard2View.java index c0743bc..4863600 100644 --- a/srcs/juloo.keyboard2/Keyboard2View.java +++ b/srcs/juloo.keyboard2/Keyboard2View.java @@ -24,7 +24,7 @@ public class Keyboard2View extends View private Pointers _pointers; - private int _flags = 0; + private Pointers.Modifiers _mods; private Vibrator _vibratorService; private long _lastVibration = 0; @@ -90,15 +90,15 @@ public class Keyboard2View extends View public void reset() { - _flags = 0; + _mods = Pointers.Modifiers.EMPTY; _pointers.clear(); requestLayout(); invalidate(); } - public KeyValue modifyKey(KeyValue k, int flags) + public KeyValue modifyKey(KeyValue k, Pointers.Modifiers mods) { - return KeyModifier.handleFlags(k, flags); + return KeyModifier.modify(k, mods); } public void onPointerDown(boolean isSwipe) @@ -107,15 +107,15 @@ public class Keyboard2View extends View vibrate(); } - public void onPointerUp(KeyValue k, int flags) + public void onPointerUp(KeyValue k, Pointers.Modifiers mods) { - _config.handler.handleKeyUp(k, flags); + _config.handler.handleKeyUp(k, mods); invalidate(); } - public void onPointerHold(KeyValue k, int flags) + public void onPointerHold(KeyValue k, Pointers.Modifiers mods) { - _config.handler.handleKeyUp(k, flags); + _config.handler.handleKeyUp(k, mods); } public void onPointerFlagsChanged() @@ -125,7 +125,7 @@ public class Keyboard2View extends View private void updateFlags() { - _flags = _pointers.getFlags(); + _mods = _pointers.getModifiers(); } @Override @@ -284,7 +284,7 @@ public class Keyboard2View extends View private void drawLabel(Canvas canvas, KeyValue k, float x, float y, float keyH, boolean isKeyDown) { - k = KeyModifier.handleFlags(k, _flags); + k = KeyModifier.modify(k, _mods); if (k == null) return; float textSize = scaleTextSize(k, _config.labelTextSize, keyH); @@ -296,7 +296,7 @@ public class Keyboard2View extends View private void drawSubLabel(Canvas canvas, KeyValue k, float x, float y, float keyW, float keyH, Paint.Align a, Vertical v, boolean isKeyDown) { - k = KeyModifier.handleFlags(k, _flags); + k = KeyModifier.modify(k, _mods); if (k == null) return; float textSize = scaleTextSize(k, _config.sublabelTextSize, keyH); diff --git a/srcs/juloo.keyboard2/Pointers.java b/srcs/juloo.keyboard2/Pointers.java index 1011271..f6db9ac 100644 --- a/srcs/juloo.keyboard2/Pointers.java +++ b/srcs/juloo.keyboard2/Pointers.java @@ -2,6 +2,7 @@ package juloo.keyboard2; import android.os.Handler; import android.os.Message; +import java.util.Arrays; import java.util.ArrayList; /** @@ -22,21 +23,27 @@ public final class Pointers implements Handler.Callback _config = c; } - public int getFlags() + /** Return the list of modifiers currently activated. */ + public Modifiers getModifiers() { - return getFlags(false); + return getModifiers(false); } - /* When [skip_latched] is true, don't take flags of latched keys into account. */ - private int getFlags(boolean skip_latched) + /** When [skip_latched] is true, don't take flags of latched keys into account. */ + private Modifiers getModifiers(boolean skip_latched) { - int flags = 0; - for (Pointer p : _ptrs) + int size = _ptrs.size(); + int[] mods = new int[size]; + for (int i = 0; i < size; i++) { - if (!(skip_latched && p.pointerId == -1 && (p.flags & KeyValue.FLAG_LOCKED) == 0)) - flags |= p.flags; + Pointer p = _ptrs.get(i); + mods[i] = + ((skip_latched && p.pointerId == -1 + && (p.flags & KeyValue.FLAG_LOCKED) == 0) + || p.value == null) + ? 0 : p.value.code; } - return flags; + return Modifiers.ofArray(mods); } public void clear() @@ -90,7 +97,7 @@ public final class Pointers implements Handler.Callback else // Otherwise, unlatch { removePtr(latched); - _handler.onPointerUp(ptr.value, ptr.modifier_flags); + _handler.onPointerUp(ptr.value, ptr.modifiers); } } else if ((ptr.flags & KeyValue.FLAG_LATCH) != 0) @@ -103,7 +110,7 @@ public final class Pointers implements Handler.Callback { clearLatched(); removePtr(ptr); - _handler.onPointerUp(ptr.value, ptr.modifier_flags); + _handler.onPointerUp(ptr.value, ptr.modifiers); } } @@ -133,9 +140,11 @@ public final class Pointers implements Handler.Callback // keys. if (isModulatedKeyPressed()) return; - int mflags = getFlags(isOtherPointerDown()); - KeyValue value = _handler.modifyKey(key.key0, mflags); - Pointer ptr = new Pointer(pointerId, key, value, x, y, mflags); + // Don't take latched modifiers into account if an other key is pressed. + // The other key already "own" the latched modifiers and will clear them. + Modifiers mods = getModifiers(isOtherPointerDown()); + KeyValue value = _handler.modifyKey(key.key0, mods); + Pointer ptr = new Pointer(pointerId, key, value, x, y, mods); _ptrs.add(ptr); if (value != null && (value.flags & KeyValue.FLAG_SPECIAL) == 0) startKeyRepeat(ptr); @@ -153,14 +162,14 @@ public final class Pointers implements Handler.Callback private KeyValue getKeyAtDirection(Pointer ptr, int direction) { if (direction == 0) - return _handler.modifyKey(ptr.key.key0, ptr.modifier_flags); + return _handler.modifyKey(ptr.key.key0, ptr.modifiers); KeyValue k; for (int i = 0; i > -3; i = (~i>>31) - i) { int d = Math.floorMod(direction + i - 1, 8) + 1; // Don't make the difference between a key that doesn't exist and a key // that is removed by [_handler]. Triggers side effects. - k = _handler.modifyKey(ptr.key.getAtDirection(d), ptr.modifier_flags); + k = _handler.modifyKey(ptr.key.getAtDirection(d), ptr.modifiers); if (k != null) return k; } @@ -292,7 +301,7 @@ public final class Pointers implements Handler.Callback nextInterval = (long)((float)nextInterval / modulatePreciseRepeat(ptr)); } _keyrepeat_handler.sendEmptyMessageDelayed(msg.what, nextInterval); - _handler.onPointerHold(ptr.value, ptr.modifier_flags); + _handler.onPointerHold(ptr.value, ptr.modifiers); return (true); } } @@ -333,7 +342,7 @@ public final class Pointers implements Handler.Callback return Math.min(8.f, Math.max(0.1f, accel)); } - private final class Pointer + private static final class Pointer { /** -1 when latched. */ public int pointerId; @@ -341,14 +350,14 @@ public final class Pointers implements Handler.Callback public final KeyboardData.Key key; /** Current direction. */ public int selected_direction; - /** Selected value with [modifier_flags] applied. */ + /** Selected value with [modifiers] applied. */ public KeyValue value; public float downX; public float downY; /** Distance of the pointer to the initial press. */ public float ptrDist; /** Modifier flags at the time the key was pressed. */ - public int modifier_flags; + public Modifiers modifiers; /** Flags of the value. Latch, lock and locked flags are updated. */ public int flags; /** Identify timeout messages. */ @@ -356,7 +365,7 @@ public final class Pointers implements Handler.Callback /** ptrDist at the first repeat, -1 otherwise. */ public float repeatingPtrDist; - public Pointer(int p, KeyboardData.Key k, KeyValue v, float x, float y, int mflags) + public Pointer(int p, KeyboardData.Key k, KeyValue v, float x, float y, Modifiers m) { pointerId = p; key = k; @@ -365,30 +374,75 @@ public final class Pointers implements Handler.Callback downX = x; downY = y; ptrDist = 0.f; - modifier_flags = mflags; + modifiers = m; flags = (v == null) ? 0 : v.flags; timeoutWhat = -1; repeatingPtrDist = -1.f; } } + /** Represent modifiers currently activated. + Sorted in the order they should be evaluated. */ + public static final class Modifiers + { + private final int[] _mods; + private final int _size; + + private Modifiers(int[] m, int s) { _mods = m; _size = s; } + + public int get(int i) { return _mods[i]; } + public int size() { return _size; } + + @Override + public int hashCode() { return Arrays.hashCode(_mods); } + @Override + public boolean equals(Object obj) + { + return Arrays.equals(_mods, ((Modifiers)obj)._mods); + } + + public static final Modifiers EMPTY = new Modifiers(new int[0], 0); + + protected static Modifiers ofArray(int[] mods) + { + int size = mods.length; + // Sort and remove duplicates and [EVENT_NONE]s. + if (size > 1) + { + Arrays.sort(mods); + int j = 0; + for (int i = 0; i < size; i++) + { + int m = mods[i]; + if (m != 0 && (i + 1 >= size || m != mods[i + 1])) + { + mods[j] = m; + j++; + } + } + size = j; + } + return new Modifiers(mods, size); + } + } + public interface IPointerEventHandler { /** Key can be modified or removed by returning [null]. */ - public KeyValue modifyKey(KeyValue k, int flags); + public KeyValue modifyKey(KeyValue k, Modifiers flags); - /** A key is pressed. [getFlags()] is uptodate. Might be called after a + /** A key is pressed. [getModifiers()] is uptodate. Might be called after a press or a swipe to a different value. */ public void onPointerDown(boolean isSwipe); /** Key is released. [k] is the key that was returned by [modifySelectedKey] or [modifySelectedKey]. */ - public void onPointerUp(KeyValue k, int flags); + public void onPointerUp(KeyValue k, Modifiers flags); /** Flags changed because latched or locked keys or cancelled pointers. */ public void onPointerFlagsChanged(); /** Key is repeating. */ - public void onPointerHold(KeyValue k, int flags); + public void onPointerHold(KeyValue k, Modifiers flags); } } |
