Refactor: Remove KeyValue.name

This makes KeyValue objects smaller. 'equals' and 'hashCode' are now
implemented too. Key names are still used to recognise keys with special
meaning, but not for comparing keys anymore.
This commit is contained in:
Jules Aguillon 2022-06-06 00:23:45 +02:00
parent 7462955507
commit 31d6a70dfb
6 changed files with 143 additions and 121 deletions

View File

@ -47,7 +47,7 @@ final class Config
public String actionLabel; // Might be 'null'
public int actionId; // Meaningful only when 'actionLabel' isn't 'null'
public boolean swapEnterActionKey; // Swap the "enter" and "action" keys
public Set<String> extra_keys; // 'null' means all the keys
public Set<KeyValue> extra_keys; // 'null' means all the keys
public final IKeyEventHandler handler;
@ -151,18 +151,18 @@ final class Config
{
// Update the name to avoid caching in KeyModifier
final KeyValue action_key = (actionLabel == null) ? null :
KeyValue.getKeyByName("action").withNameAndSymbol(actionLabel, actionLabel);
KeyValue.getKeyByName("action").withSymbol(actionLabel);
// Extra keys are removed from the set as they are encountered during the
// first iteration then automatically added.
final Set<String> extra_keys = new HashSet<String>(this.extra_keys);
final Set<KeyValue> extra_keys = new HashSet<KeyValue>(this.extra_keys);
KeyboardData kw = original_kw.mapKeys(new KeyboardData.MapKeyValues() {
public KeyValue apply(KeyValue key)
{
if (key == null)
return null;
boolean is_extra_key = extra_keys.contains(key.name);
boolean is_extra_key = extra_keys.contains(key);
if (is_extra_key)
extra_keys.remove(key.name);
extra_keys.remove(key);
int flags = key.getFlags();
if ((flags & KeyValue.FLAG_LOCALIZED) != 0 && !is_extra_key)
return null;
@ -196,15 +196,7 @@ final class Config
}
});
if (extra_keys.size() > 0)
{
final Iterator<String> extra_keys_it = extra_keys.iterator();
kw = kw.addExtraKeys(
new Iterator<KeyValue>()
{
public boolean hasNext() { return extra_keys_it.hasNext(); }
public KeyValue next() { return KeyValue.getKeyByName(extra_keys_it.next()); }
});
}
kw = kw.addExtraKeys(extra_keys.iterator());
return kw;
}

View File

@ -10,6 +10,7 @@ import java.util.HashMap;
public class Emoji
{
private final String _name;
private final KeyValue _kv;
private final String _desc;
@ -17,14 +18,15 @@ public class Emoji
protected Emoji(String name, String bytecode, String desc)
{
_kv = new KeyValue(name, bytecode, KeyValue.KIND_STRING, 0, 0);
_name = name;
_kv = new KeyValue(bytecode, KeyValue.KIND_STRING, 0, 0);
_desc = desc;
emojis_by_name.put(name, this);
}
public String name()
{
return _kv.name;
return _name;
}
public KeyValue kv()

View File

@ -7,11 +7,8 @@ import java.util.HashMap;
class KeyModifier
{
/** Cache key is KeyValue's name */
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");
private static HashMap<KeyValue, HashMap<Pointers.Modifiers, KeyValue>> _cache =
new HashMap<KeyValue, HashMap<Pointers.Modifiers, KeyValue>>();
/** Modify a key according to modifiers. */
public static KeyValue modify(KeyValue k, Pointers.Modifiers mods)
@ -27,10 +24,10 @@ class KeyModifier
/* 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;
/* Keys with an empty string are placeholder keys. */
return (r.getString().length() == 0) ? null : r;
}
public static KeyValue modify(KeyValue k, KeyValue.Modifier mod)
@ -117,70 +114,97 @@ class KeyModifier
private static KeyValue apply_fn(KeyValue k)
{
String name;
switch (k.name)
String name = null;
switch (k.getKind())
{
case "1": name = "f1"; break;
case "2": name = "f2"; break;
case "3": name = "f3"; break;
case "4": name = "f4"; break;
case "5": name = "f5"; break;
case "6": name = "f6"; break;
case "7": name = "f7"; break;
case "8": name = "f8"; break;
case "9": name = "f9"; break;
case "0": name = "f10"; break;
case "f11_placeholder": name = "f11"; break;
case "f12_placeholder": name = "f12"; break;
case "up": name = "page_up"; break;
case "down": name = "page_down"; break;
case "left": name = "home"; break;
case "right": name = "end"; break;
case "<": name = "«"; break;
case ">": name = "»"; break;
case "{": name = ""; break;
case "}": name = ""; break;
case "[": name = ""; break;
case "]": name = ""; break;
case "(": name = ""; break;
case ")": name = ""; break;
case "'": name = ""; break;
case "\"": name = ""; break;
case "-": name = ""; break;
case "_": name = ""; break;
case "^": name = "¬"; break;
case "%": name = ""; break;
case "=": name = ""; break;
case "u": name = "µ"; break;
case "a": name = "æ"; break;
case "o": name = "œ"; break;
case "esc": name = "insert"; break;
case "*": name = "°"; break;
case ".": name = ""; break;
case ",": name = "·"; break;
case "!": name = "¡"; break;
case "?": name = "¿"; break;
case "tab": name = "\\t"; break;
case "space": name = "nbsp"; break;
case "": name = ""; break;
case "": name = ""; break;
case "": name = ""; break;
case "": name = ""; break;
case "": name = ""; break;
case "": name = ""; break;
case "": name = ""; break;
case "": name = ""; break;
// Currency symbols
case "e": name = ""; break;
case "l": name = "£"; break;
case "r": name = ""; break;
case "y": name = "¥"; break;
case "c": name = "¢"; break;
case "p": name = ""; break;
case "": case "£": return removed_key; // Avoid showing these twice
default: return k;
case Char: name = apply_fn_char(k.getChar()); break;
case Keyevent: name = apply_fn_keyevent(k.getKeyevent()); break;
case String:
switch (k.getString())
{
case "":
if (k == KeyValue.getKeyByName("f11_placeholder"))
name = "f11";
else if (k == KeyValue.getKeyByName("f12_placeholder"))
name = "f12";
break;
}
break;
}
return (name == null) ? k : KeyValue.getKeyByName(name);
}
private static String apply_fn_keyevent(int code)
{
switch (code)
{
case KeyEvent.KEYCODE_DPAD_UP: return "page_up";
case KeyEvent.KEYCODE_DPAD_DOWN: return "page_down";
case KeyEvent.KEYCODE_DPAD_LEFT: return "home";
case KeyEvent.KEYCODE_DPAD_RIGHT: return "end";
case KeyEvent.KEYCODE_ESCAPE: return "insert";
default: return null;
}
}
/** Return the name of modified key, or [null]. */
private static String apply_fn_char(char c)
{
switch (c)
{
case '1': return "f1";
case '2': return "f2";
case '3': return "f3";
case '4': return "f4";
case '5': return "f5";
case '6': return "f6";
case '7': return "f7";
case '8': return "f8";
case '9': return "f9";
case '0': return "f10";
case '<': return "«";
case '>': return "»";
case '{': return "";
case '}': return "";
case '[': return "";
case ']': return "";
case '(': return "";
case ')': return "";
case '\'': return "";
case '"': return "";
case '-': return "";
case '_': return "";
case '^': return "¬";
case '%': return "";
case '=': return "";
case 'u': return "µ";
case 'a': return "æ";
case 'o': return "œ";
case '*': return "°";
case '.': return "";
case ',': return "·";
case '!': return "¡";
case '?': return "¿";
case '↖': return "";
case '↑': return "";
case '↗': return "";
case '←': return "";
case '→': return "";
case '↙': return "";
case '↓': return "";
case '↘': return "";
// Currency symbols
case 'e': return "";
case 'l': return "£";
case 'r': return "";
case 'y': return "¥";
case 'c': return "¢";
case 'p': return "";
case '€': case '£': return "removed"; // Avoid showing these twice
case '\t': return "\\t";
case ' ': return "nbsp";
default: return null;
}
return KeyValue.getKeyByName(name);
}
private static KeyValue turn_into_keyevent(KeyValue k)
@ -249,25 +273,14 @@ class KeyModifier
return k.withKeyevent(e);
}
/** 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;
}
}
/* Lookup the cache entry for a key. Create it needed. */
private static HashMap<Pointers.Modifiers, KeyValue> cacheEntry(KeyValue k)
{
HashMap<Pointers.Modifiers, KeyValue> ks = _cache.get(k.name);
HashMap<Pointers.Modifiers, KeyValue> ks = _cache.get(k);
if (ks == null)
{
ks = new HashMap<Pointers.Modifiers, KeyValue>();
_cache.put(k.name, ks);
_cache.put(k, ks);
}
return ks;
}

View File

@ -78,7 +78,6 @@ final class KeyValue
check((FLAGS_BITS | KIND_BITS | VALUE_BITS) == ~0); // No holes
}
public final String name;
private final String _symbol;
/** This field encodes three things:
@ -150,37 +149,49 @@ final class KeyValue
/* Update the char and the symbol. */
public KeyValue withChar(char c)
{
return new KeyValue(name, String.valueOf(c), KIND_CHAR, c, getFlags());
return new KeyValue(String.valueOf(c), KIND_CHAR, c, getFlags());
}
public KeyValue withString(String s)
{
return new KeyValue(name, s, KIND_STRING, 0, getFlags());
return new KeyValue(s, KIND_STRING, 0, getFlags());
}
public KeyValue withNameAndSymbol(String n, String s)
public KeyValue withSymbol(String s)
{
return new KeyValue(n, s, (_code & KIND_BITS), (_code & VALUE_BITS), getFlags());
return new KeyValue(s, (_code & KIND_BITS), (_code & VALUE_BITS), getFlags());
}
public KeyValue withKeyevent(int code)
{
return new KeyValue(name, _symbol, KIND_KEYEVENT, code, getFlags());
return new KeyValue(_symbol, KIND_KEYEVENT, code, getFlags());
}
public KeyValue withFlags(int f)
{
return new KeyValue(name, _symbol, (_code & KIND_BITS), (_code & VALUE_BITS), f);
return new KeyValue(_symbol, (_code & KIND_BITS), (_code & VALUE_BITS), f);
}
@Override
public boolean equals(Object obj)
{
KeyValue snd = (KeyValue)obj;
return _symbol.equals(snd._symbol) && _code == snd._code;
}
@Override
public int hashCode()
{
return _symbol.hashCode() + _code;
}
private static HashMap<String, KeyValue> keys = new HashMap<String, KeyValue>();
public KeyValue(String n, String s, int kind, int value, int flags)
public KeyValue(String s, int kind, int value, int flags)
{
check((kind & ~KIND_BITS) == 0);
check((flags & ~FLAGS_BITS) == 0);
check((value & ~VALUE_BITS) == 0);
name = n;
_symbol = s;
_code = kind | flags | value;
}
@ -207,14 +218,14 @@ final class KeyValue
return kv.withFlags(kv.getFlags() | FLAG_LOCALIZED);
}
if (name.length() == 1)
return new KeyValue(name, name, KIND_CHAR, name.charAt(0), 0);
return new KeyValue(name, KIND_CHAR, name.charAt(0), 0);
else
return new KeyValue(name, name, KIND_STRING, 0, 0);
return new KeyValue(name, KIND_STRING, 0, 0);
}
private static void addKey(String name, String symbol, int kind, int code, int flags)
{
keys.put(name, new KeyValue(name, symbol, kind, code, flags));
keys.put(name, new KeyValue(symbol, kind, code, flags));
}
private static void addCharKey(String name, String symbol, char c, int flags)
@ -238,6 +249,11 @@ final class KeyValue
addKey(name, symbol, KIND_KEYEVENT, code, flags);
}
private static void addPlaceholderKey(String name)
{
addKey(name, "", KIND_STRING, 0, 0);
}
static
{
addModifierKey("shift", "\n", // Can't write u000A because Java is stupid
@ -307,7 +323,9 @@ final class KeyValue
addCharKey("space", "\r", ' ', FLAG_KEY_FONT);
addCharKey("nbsp", "\u237d", '\u00a0', FLAG_KEY_FONT | FLAG_SMALLER_FONT);
addKey("removed", "", KIND_STRING, 0, 0); // Dummy key used in [KeyModifier]
addPlaceholderKey("removed");
addPlaceholderKey("f11_placeholder");
addPlaceholderKey("f12_placeholder");
}
// Substitute for [assert], which has no effect on Android.

View File

@ -80,19 +80,19 @@ public class Keyboard2 extends InputMethodService
_currentTextLayout = l;
}
private void extra_keys_of_subtype(Set<String> dst, InputMethodSubtype subtype)
private void extra_keys_of_subtype(Set<KeyValue> dst, InputMethodSubtype subtype)
{
String extra_keys = subtype.getExtraValueOf("extra_keys");
if (extra_keys == null)
return;
String[] ks = extra_keys.split("\\|");
for (int i = 0; i < ks.length; i++)
dst.add(ks[i]);
dst.add(KeyValue.getKeyByName(ks[i]));
}
private void refreshAccentsOption(InputMethodManager imm, InputMethodSubtype subtype)
{
HashSet<String> extra_keys = new HashSet<String>();
HashSet<KeyValue> extra_keys = new HashSet<KeyValue>();
List<InputMethodSubtype> enabled_subtypes = getEnabledSubtypes(imm);
switch (_config.accents)
{
@ -119,7 +119,7 @@ public class Keyboard2 extends InputMethodService
switch (_config.accents)
{
case 1: case 2: case 3: _config.extra_keys = null; break;
case 4: _config.extra_keys = new HashSet<String>(); break;
case 4: _config.extra_keys = new HashSet<KeyValue>(); break;
}
// Fallback for the layout option: Use qwerty in the "system settings" case
_currentTextLayout = (_config.layout == -1) ? R.xml.qwerty : _config.layout;

View File

@ -68,11 +68,8 @@ public final class Pointers implements Handler.Callback
*/
public int getKeyFlags(KeyValue kv)
{
// Comparing names because the keys might have been modified.
// Physical equality works because names are never computed or shared.
String name = kv.name;
for (Pointer p : _ptrs)
if (p.value != null && p.value.name == name)
if (p.value != null && p.value.equals(kv))
return p.flags;
return -1;
}
@ -214,7 +211,7 @@ public final class Pointers implements Handler.Callback
{
ptr.selected_direction = direction;
KeyValue newValue = getKeyAtDirection(ptr, direction);
if (newValue != null && (ptr.value == null || newValue.name != ptr.value.name))
if (newValue != null && (ptr.value == null || !newValue.equals(ptr.value)))
{
int old_flags = ptr.flags;
ptr.value = newValue;
@ -253,7 +250,7 @@ public final class Pointers implements Handler.Callback
if (v == null)
return null;
for (Pointer p : _ptrs)
if (p.key == k && p.pointerId == -1 && p.value != null && p.value.name == v.name)
if (p.key == k && p.pointerId == -1 && p.value != null && p.value.equals(v))
return p;
return null;
}