From 9f22e53a3ba8f064e69e3a84c371a7f29ee9e05c Mon Sep 17 00:00:00 2001 From: Jules Aguillon Date: Sun, 29 Sep 2024 21:58:22 +0200 Subject: Add complex keys (#774) This allows to add new kinds of keys that need more data without making KeyValue's footprint bigger for common keys. This changes the [_symbol] field into [_payload], which holds the same as the previous field for more common keys but can hold bigger objects for keys of the new "Complex" kind. This also adds a complex key: String keys with a symbol different than the outputted string. Unit tests are added as the Java language is not helpful in making robust code.--- srcs/juloo.keyboard2/KeyValue.java | 142 ++++++++++++++++++++++++++++++++----- 1 file changed, 123 insertions(+), 19 deletions(-) (limited to 'srcs/juloo.keyboard2/KeyValue.java') diff --git a/srcs/juloo.keyboard2/KeyValue.java b/srcs/juloo.keyboard2/KeyValue.java index 2a329df..8adacf0 100644 --- a/srcs/juloo.keyboard2/KeyValue.java +++ b/srcs/juloo.keyboard2/KeyValue.java @@ -91,7 +91,8 @@ public final class KeyValue implements Comparable { Char, String, Keyevent, Event, Compose_pending, Hangul_initial, Hangul_medial, Modifier, Editing, Placeholder, - Cursor_move // Value is encoded as a 16-bit integer + Cursor_move, // Value is encoded as a 16-bit integer. + Complex, // [_payload] is a [KeyValue.Complex], value is [Complex.Kind]. } private static final int FLAGS_OFFSET = 19; @@ -129,7 +130,13 @@ public final class KeyValue implements Comparable check((((Kind.values().length - 1) << KIND_OFFSET) & ~KIND_BITS) == 0); } - private final String _symbol; + /** + * The symbol that is rendered on the keyboard as a [String]. + * Except for keys of kind: + * - [String], this is also the string to output. + * - [Complex], this is an instance of [KeyValue.Complex]. + */ + private final Object _payload; /** This field encodes three things: Kind, flags and value. */ private final int _code; @@ -153,7 +160,9 @@ public final class KeyValue implements Comparable When [getKind() == Kind.String], also the string to send. */ public String getString() { - return _symbol; + if (getKind() == Kind.Complex) + return ((Complex)_payload).getSymbol(); + return (String)_payload; } /** Defined only when [getKind() == Kind.Char]. */ @@ -211,25 +220,32 @@ public final class KeyValue implements Comparable return (short)(_code & VALUE_BITS); } - /* Update the char and the symbol. */ - public KeyValue withChar(char c) + /** Defined only when [getKind() == Kind.Complex]. */ + public Complex getComplex() { - return new KeyValue(String.valueOf(c), Kind.Char, c, getFlags()); + return (Complex)_payload; } - public KeyValue withSymbol(String s) + /** Defined only when [getKind() == Kind.Complex]. */ + public Complex.Kind getComplexKind() { - return new KeyValue(s, (_code & KIND_BITS), (_code & VALUE_BITS), getFlags()); + return Complex.Kind.values()[(_code & VALUE_BITS)]; + } + + /* Update the char and the symbol. */ + public KeyValue withChar(char c) + { + return new KeyValue(String.valueOf(c), Kind.Char, c, getFlags()); } public KeyValue withKeyevent(int code) { - return new KeyValue(_symbol, Kind.Keyevent, code, getFlags()); + return new KeyValue(getString(), Kind.Keyevent, code, getFlags()); } public KeyValue withFlags(int f) { - return new KeyValue(_symbol, (_code & KIND_BITS), (_code & VALUE_BITS), f); + return new KeyValue(getString(), (_code & KIND_BITS), (_code & VALUE_BITS), f); } @Override @@ -247,7 +263,9 @@ public final class KeyValue implements Comparable d = _code - snd._code; if (d != 0) return d; - return _symbol.compareTo(snd._symbol); + if (getKind() == Kind.Complex) + return ((Complex)_payload).compareTo((Complex)snd._payload); + return ((String)_payload).compareTo((String)snd._payload); } /** Type-safe alternative to [equals]. */ @@ -255,24 +273,36 @@ public final class KeyValue implements Comparable { if (snd == null) return false; - return _symbol.equals(snd._symbol) && _code == snd._code; + return _code == snd._code && _payload.equals(snd._payload); } @Override public int hashCode() { - return _symbol.hashCode() + _code; + return _payload.hashCode() + _code; } - public KeyValue(String s, int kind, int value, int flags) + public String toString() { - _symbol = s; + int value = _code & VALUE_BITS; + return "[KeyValue " + getKind().toString() + "+" + getFlags() + "+" + value + " \"" + getString() + "\"]"; + } + + private KeyValue(Object p, int kind, int value, int flags) + { + _payload = p; _code = (kind & KIND_BITS) | (flags & FLAGS_BITS) | (value & VALUE_BITS); } - public KeyValue(String s, Kind k, int v, int f) + public KeyValue(Complex p, Complex.Kind value, int flags) { - this(s, (k.ordinal() << KIND_OFFSET), v, f); + this((Object)p, (Kind.Complex.ordinal() << KIND_OFFSET), value.ordinal(), + flags); + } + + public KeyValue(String p, Kind k, int v, int f) + { + this(p, (k.ordinal() << KIND_OFFSET), v, f); } private static KeyValue charKey(String symbol, char c, int flags) @@ -397,6 +427,11 @@ public final class KeyValue implements Comparable return KeyValue.makeCharKey((char)precomposed); } + public static KeyValue makeActionKey(String symbol) + { + return eventKey(symbol, Event.ACTION, FLAG_SMALLER_FONT); + } + /** Make a key that types a string. A char key is returned for a string of length 1. */ public static KeyValue makeStringKey(String str, int flags) @@ -407,12 +442,36 @@ public final class KeyValue implements Comparable return new KeyValue(str, Kind.String, 0, flags | FLAG_SMALLER_FONT); } + public static KeyValue makeStringKeyWithSymbol(String str, String symbol, int flags) + { + return new KeyValue(new Complex.StringWithSymbol(str, symbol), + Complex.Kind.StringWithSymbol, flags); + } + /** Make a modifier key for passing to [KeyModifier]. */ public static KeyValue makeInternalModifier(Modifier mod) { return new KeyValue("", Kind.Modifier, mod.ordinal(), 0); } + public static KeyValue parseKeyDefinition(String str) + { + if (str.length() < 2 || str.charAt(0) != ':') + return makeStringKey(str); + try + { + return KeyValueParser.parse(str); + } + catch (KeyValueParser.ParseError _e) + { + return makeStringKey(str); + } + } + + /** + * Return a key by its name. If the given name doesn't correspond to a key + * defined in this function, it is passed to [parseStringKey] as a fallback. + */ public static KeyValue getKeyByName(String name) { switch (name) @@ -599,8 +658,8 @@ public final class KeyValue implements Comparable case "ㅍ": return makeHangulInitial("ㅍ", 17); case "ㅎ": return makeHangulInitial("ㅎ", 18); - /* Fallback to a string key that types its name */ - default: return makeStringKey(name); + /* The key is not one of the special ones. */ + default: return parseKeyDefinition(name); } } @@ -610,4 +669,49 @@ public final class KeyValue implements Comparable if (!b) throw new RuntimeException("Assertion failure"); } + + public static abstract class Complex + { + public abstract String getSymbol(); + + /** [compareTo] can assume that [snd] is an instance of the same class. */ + public abstract int compareTo(Complex snd); + + public boolean equals(Object snd) + { + if (snd instanceof Complex) + return compareTo((Complex)snd) == 0; + return false; + } + + /** [hashCode] will be called on this class. */ + + /** The kind is stored in the [value] field of the key. */ + public static enum Kind + { + StringWithSymbol, + } + + public static final class StringWithSymbol extends Complex + { + public final String str; + private final String _symbol; + + public StringWithSymbol(String _str, String _sym) + { + str = _str; + _symbol = _sym; + } + + public String getSymbol() { return _symbol; } + + public int compareTo(Complex _snd) + { + StringWithSymbol snd = (StringWithSymbol)_snd; + int d = str.compareTo(snd.str); + if (d != 0) return d; + return _symbol.compareTo(snd._symbol); + } + } + }; } -- cgit v1.2.3