abouttreesummaryrefslogcommitdiff
path: root/srcs
diff options
context:
space:
mode:
Diffstat (limited to 'srcs')
-rw-r--r--srcs/juloo.keyboard2/Config.java27
-rw-r--r--srcs/juloo.keyboard2/EmojiGridView.java2
-rw-r--r--srcs/juloo.keyboard2/EmojiKeyButton.java2
-rw-r--r--srcs/juloo.keyboard2/KeyEventHandler.java71
-rw-r--r--srcs/juloo.keyboard2/KeyModifier.java430
-rw-r--r--srcs/juloo.keyboard2/KeyValue.java182
-rw-r--r--srcs/juloo.keyboard2/Keyboard2.java2
-rw-r--r--srcs/juloo.keyboard2/Keyboard2View.java22
-rw-r--r--srcs/juloo.keyboard2/Pointers.java106
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);
}
}