Unexpected-Keyboard/srcs/juloo.keyboard2/KeyValue.java
Jules Aguillon 46408572bc font: Use standard symbols for home and end
The glyphs are taken from DejaVuSans, the lines are thickened to improve
readability.
2024-11-16 12:08:36 +01:00

763 lines
28 KiB
Java

package juloo.keyboard2;
import android.view.KeyEvent;
import java.util.HashMap;
public final class KeyValue implements Comparable<KeyValue>
{
public static enum Event
{
CONFIG,
SWITCH_TEXT,
SWITCH_NUMERIC,
SWITCH_EMOJI,
SWITCH_BACK_EMOJI,
SWITCH_CLIPBOARD,
SWITCH_BACK_CLIPBOARD,
CHANGE_METHOD_PICKER,
CHANGE_METHOD_AUTO,
ACTION,
SWITCH_FORWARD,
SWITCH_BACKWARD,
SWITCH_GREEKMATH,
CAPS_LOCK,
SWITCH_VOICE_TYPING,
SWITCH_VOICE_TYPING_CHOOSER,
}
// Must be evaluated in the reverse order of their values.
public static enum Modifier
{
SHIFT,
GESTURE,
CTRL,
ALT,
META,
DOUBLE_AIGU,
DOT_ABOVE,
DOT_BELOW,
GRAVE,
AIGU,
CIRCONFLEXE,
TILDE,
CEDILLE,
TREMA,
HORN,
HOOK_ABOVE,
SUPERSCRIPT,
SUBSCRIPT,
RING,
CARON,
MACRON,
ORDINAL,
ARROWS,
BOX,
OGONEK,
SLASH,
ARROW_RIGHT,
BREVE,
BAR,
FN,
} // Last is be applied first
public static enum Editing
{
COPY,
PASTE,
CUT,
SELECT_ALL,
PASTE_PLAIN,
UNDO,
REDO,
// Android context menu actions
REPLACE,
SHARE,
ASSIST,
AUTOFILL,
}
public static enum Placeholder
{
REMOVED,
F11,
F12,
SHINDOT,
SINDOT,
OLE,
METEG
}
public static enum Kind
{
Char, String, Keyevent, Event, Compose_pending, Hangul_initial,
Hangul_medial, Modifier, Editing, Placeholder,
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;
private static final int KIND_OFFSET = 28;
// Behavior flags.
public static final int FLAG_LATCH = (1 << FLAGS_OFFSET << 0);
// Key can be locked by typing twice
public static final int FLAG_LOCK = (1 << FLAGS_OFFSET << 1);
// Special keys are not repeated and don't clear latched modifiers.
public static final int FLAG_SPECIAL = (1 << FLAGS_OFFSET << 2);
// Whether the symbol should be greyed out. For example, keys that are not
// part of the pending compose sequence.
public static final int FLAG_GREYED = (1 << FLAGS_OFFSET << 3);
// Rendering flags.
public static final int FLAG_KEY_FONT = (1 << FLAGS_OFFSET << 4); // special font file
public static final int FLAG_SMALLER_FONT = (1 << FLAGS_OFFSET << 5); // 25% smaller symbols
public static final int FLAG_SECONDARY = (1 << FLAGS_OFFSET << 6); // dimmer
// Used by [Pointers].
// Free: (1 << FLAGS_OFFSET << 7)
// Free: (1 << FLAGS_OFFSET << 8)
// Ranges for the different components
private static final int FLAGS_BITS =
FLAG_LATCH | FLAG_LOCK | FLAG_SPECIAL | FLAG_GREYED | FLAG_KEY_FONT |
FLAG_SMALLER_FONT | FLAG_SECONDARY;
private static final int KIND_BITS = (0b1111 << KIND_OFFSET); // 4 bits wide
private static final int VALUE_BITS = ~(FLAGS_BITS | KIND_BITS); // 20 bits wide
static
{
check((FLAGS_BITS & KIND_BITS) == 0); // No overlap
check((FLAGS_BITS | KIND_BITS | VALUE_BITS) == ~0); // No holes
// No kind is out of range
check((((Kind.values().length - 1) << KIND_OFFSET) & ~KIND_BITS) == 0);
}
/**
* 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;
public Kind getKind()
{
return Kind.values()[(_code & KIND_BITS) >>> KIND_OFFSET];
}
public int getFlags()
{
return (_code & FLAGS_BITS);
}
public boolean hasFlagsAny(int has)
{
return ((_code & has) != 0);
}
/** The string to render on the keyboard.
When [getKind() == Kind.String], also the string to send. */
public String getString()
{
if (getKind() == Kind.Complex)
return ((Complex)_payload).getSymbol();
return (String)_payload;
}
/** Defined only when [getKind() == Kind.Char]. */
public char getChar()
{
return (char)(_code & VALUE_BITS);
}
/** Defined only when [getKind() == Kind.Keyevent]. */
public int getKeyevent()
{
return (_code & VALUE_BITS);
}
/** Defined only when [getKind() == Kind.Event]. */
public Event getEvent()
{
return Event.values()[(_code & VALUE_BITS)];
}
/** Defined only when [getKind() == Kind.Modifier]. */
public Modifier getModifier()
{
return Modifier.values()[(_code & VALUE_BITS)];
}
/** Defined only when [getKind() == Kind.Editing]. */
public Editing getEditing()
{
return Editing.values()[(_code & VALUE_BITS)];
}
/** Defined only when [getKind() == Kind.Placeholder]. */
public Placeholder getPlaceholder()
{
return Placeholder.values()[(_code & VALUE_BITS)];
}
/** Defined only when [getKind() == Kind.Compose_pending]. */
public int getPendingCompose()
{
return (_code & VALUE_BITS);
}
/** Defined only when [getKind()] is [Kind.Hangul_initial] or
[Kind.Hangul_medial]. */
public int getHangulPrecomposed()
{
return (_code & VALUE_BITS);
}
/** Defined only when [getKind() == Kind.Cursor_move]. */
public short getCursorMove()
{
return (short)(_code & VALUE_BITS);
}
/** Defined only when [getKind() == Kind.Complex]. */
public Complex getComplex()
{
return (Complex)_payload;
}
/** Defined only when [getKind() == Kind.Complex]. */
public Complex.Kind getComplexKind()
{
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(getString(), Kind.Keyevent, code, getFlags());
}
public KeyValue withFlags(int f)
{
return new KeyValue(_payload, (_code & KIND_BITS), (_code & VALUE_BITS), f);
}
@Override
public boolean equals(Object obj)
{
return sameKey((KeyValue)obj);
}
public int compareTo(KeyValue snd)
{
// Compare the kind and value first, then the flags.
int d = (_code & ~FLAGS_BITS) - (snd._code & ~FLAGS_BITS);
if (d != 0)
return d;
d = _code - snd._code;
if (d != 0)
return d;
if (getKind() == Kind.Complex)
return ((Complex)_payload).compareTo((Complex)snd._payload);
return ((String)_payload).compareTo((String)snd._payload);
}
/** Type-safe alternative to [equals]. */
public boolean sameKey(KeyValue snd)
{
if (snd == null)
return false;
return _code == snd._code && _payload.equals(snd._payload);
}
@Override
public int hashCode()
{
return _payload.hashCode() + _code;
}
public String toString()
{
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(Complex p, Complex.Kind value, int flags)
{
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)
{
return new KeyValue(symbol, Kind.Char, c, flags);
}
private static KeyValue charKey(int symbol, char c, int flags)
{
return charKey(String.valueOf((char)symbol), c, flags);
}
private static KeyValue modifierKey(String symbol, Modifier m, int flags)
{
if (symbol.length() > 1)
flags |= FLAG_SMALLER_FONT;
return new KeyValue(symbol, Kind.Modifier, m.ordinal(),
FLAG_LATCH | FLAG_SPECIAL | FLAG_SECONDARY | flags);
}
private static KeyValue modifierKey(int symbol, Modifier m, int flags)
{
return modifierKey(String.valueOf((char)symbol), m, flags | FLAG_KEY_FONT);
}
private static KeyValue diacritic(int symbol, Modifier m)
{
return new KeyValue(String.valueOf((char)symbol), Kind.Modifier, m.ordinal(),
FLAG_LATCH | FLAG_SPECIAL | FLAG_KEY_FONT);
}
private static KeyValue eventKey(String symbol, Event e, int flags)
{
return new KeyValue(symbol, Kind.Event, e.ordinal(), flags | FLAG_SPECIAL | FLAG_SECONDARY);
}
private static KeyValue eventKey(int symbol, Event e, int flags)
{
return eventKey(String.valueOf((char)symbol), e, flags | FLAG_KEY_FONT);
}
private static KeyValue keyeventKey(String symbol, int code, int flags)
{
return new KeyValue(symbol, Kind.Keyevent, code, flags | FLAG_SECONDARY);
}
private static KeyValue keyeventKey(int symbol, int code, int flags)
{
return keyeventKey(String.valueOf((char)symbol), code, flags | FLAG_KEY_FONT);
}
private static KeyValue editingKey(String symbol, Editing action, int flags)
{
return new KeyValue(symbol, Kind.Editing, action.ordinal(),
flags | FLAG_SPECIAL | FLAG_SECONDARY);
}
private static KeyValue editingKey(String symbol, Editing action)
{
return editingKey(symbol, action, FLAG_SMALLER_FONT);
}
private static KeyValue editingKey(int symbol, Editing action)
{
return editingKey(String.valueOf((char)symbol), action, FLAG_KEY_FONT);
}
/** A key that moves the cursor [d] times to the right. If [d] is negative,
it moves the cursor [abs(d)] times to the left. */
public static KeyValue cursorMoveKey(int d)
{
int symbol = (d < 0) ? 0xE008 : 0xE006;
return new KeyValue(String.valueOf((char)symbol), Kind.Cursor_move,
((short)d) & 0xFFFF,
FLAG_SPECIAL | FLAG_SECONDARY | FLAG_KEY_FONT);
}
/** A key that do nothing but has a unique ID. */
private static KeyValue placeholderKey(Placeholder id)
{
return new KeyValue("", Kind.Placeholder, id.ordinal(), 0);
}
public static KeyValue makeStringKey(String str)
{
return makeStringKey(str, 0);
}
public static KeyValue makeCharKey(char c)
{
return makeCharKey(c, null, 0);
}
public static KeyValue makeCharKey(char c, String symbol, int flags)
{
if (symbol == null)
symbol = String.valueOf(c);
return new KeyValue(symbol, Kind.Char, c, flags);
}
public static KeyValue makeCharKey(int symbol, char c, int flags)
{
return makeCharKey(c, String.valueOf((char)symbol), flags | FLAG_KEY_FONT);
}
public static KeyValue makeComposePending(String symbol, int state, int flags)
{
return new KeyValue(symbol, Kind.Compose_pending, state,
flags | FLAG_LATCH);
}
public static KeyValue makeComposePending(int symbol, int state, int flags)
{
return makeComposePending(String.valueOf((char)symbol), state,
flags | FLAG_KEY_FONT);
}
public static KeyValue makeHangulInitial(String symbol, int initial_idx)
{
return new KeyValue(symbol, Kind.Hangul_initial, initial_idx * 588 + 44032,
FLAG_LATCH);
}
public static KeyValue makeHangulMedial(int precomposed, int medial_idx)
{
precomposed += medial_idx * 28;
return new KeyValue(String.valueOf((char)precomposed), Kind.Hangul_medial,
precomposed, FLAG_LATCH);
}
public static KeyValue makeHangulFinal(int precomposed, int final_idx)
{
precomposed += final_idx;
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)
{
if (str.length() == 1)
return new KeyValue(str, Kind.Char, str.charAt(0), flags);
else
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)
{
/* These symbols have special meaning when in `srcs/layouts` and are
escaped in standard layouts. The backslash is not stripped when parsed
from the custom layout option. */
case "\\?": return makeStringKey("?");
case "\\#": return makeStringKey("#");
case "\\@": return makeStringKey("@");
case "\\\\": return makeStringKey("\\");
/* Modifiers and dead-keys */
case "shift": return modifierKey(0xE00A, Modifier.SHIFT, 0);
case "ctrl": return modifierKey("Ctrl", Modifier.CTRL, 0);
case "alt": return modifierKey("Alt", Modifier.ALT, 0);
case "accent_aigu": return diacritic(0xE050, Modifier.AIGU);
case "accent_caron": return diacritic(0xE051, Modifier.CARON);
case "accent_cedille": return diacritic(0xE052, Modifier.CEDILLE);
case "accent_circonflexe": return diacritic(0xE053, Modifier.CIRCONFLEXE);
case "accent_grave": return diacritic(0xE054, Modifier.GRAVE);
case "accent_macron": return diacritic(0xE055, Modifier.MACRON);
case "accent_ring": return diacritic(0xE056, Modifier.RING);
case "accent_tilde": return diacritic(0xE057, Modifier.TILDE);
case "accent_trema": return diacritic(0xE058, Modifier.TREMA);
case "accent_ogonek": return diacritic(0xE059, Modifier.OGONEK);
case "accent_dot_above": return diacritic(0xE05A, Modifier.DOT_ABOVE);
case "accent_double_aigu": return diacritic(0xE05B, Modifier.DOUBLE_AIGU);
case "accent_slash": return diacritic(0xE05C, Modifier.SLASH);
case "accent_arrow_right": return diacritic(0xE05D, Modifier.ARROW_RIGHT);
case "accent_breve": return diacritic(0xE05E, Modifier.BREVE);
case "accent_bar": return diacritic(0xE05F, Modifier.BAR);
case "accent_dot_below": return diacritic(0xE060, Modifier.DOT_BELOW);
case "accent_horn": return diacritic(0xE061, Modifier.HORN);
case "accent_hook_above": return diacritic(0xE062, Modifier.HOOK_ABOVE);
case "superscript": return modifierKey("Sup", Modifier.SUPERSCRIPT, 0);
case "subscript": return modifierKey("Sub", Modifier.SUBSCRIPT, 0);
case "ordinal": return modifierKey("Ord", Modifier.ORDINAL, 0);
case "arrows": return modifierKey("Arr", Modifier.ARROWS, 0);
case "box": return modifierKey("Box", Modifier.BOX, 0);
case "fn": return modifierKey("Fn", Modifier.FN, 0);
case "meta": return modifierKey("Meta", Modifier.META, 0);
/* Combining diacritics */
/* Glyphs is the corresponding dead-key + 0x0100. */
case "combining_dot_above": return makeCharKey(0xE15A, '\u0307', 0);
case "combining_double_aigu": return makeCharKey(0xE15B, '\u030B', 0);
case "combining_slash": return makeCharKey(0xE15C, '\u0337', 0);
case "combining_arrow_right": return makeCharKey(0xE15D, '\u20D7', 0);
case "combining_breve": return makeCharKey(0xE15E, '\u0306', 0);
case "combining_bar": return makeCharKey(0xE15F, '\u0335', 0);
case "combining_aigu": return makeCharKey(0xE150, '\u0301', 0);
case "combining_caron": return makeCharKey(0xE151, '\u030C', 0);
case "combining_cedille": return makeCharKey(0xE152, '\u0327', 0);
case "combining_circonflexe": return makeCharKey(0xE153, '\u0302', 0);
case "combining_grave": return makeCharKey(0xE154, '\u0300', 0);
case "combining_macron": return makeCharKey(0xE155, '\u0304', 0);
case "combining_ring": return makeCharKey(0xE156, '\u030A', 0);
case "combining_tilde": return makeCharKey(0xE157, '\u0303', 0);
case "combining_trema": return makeCharKey(0xE158, '\u0308', 0);
case "combining_ogonek": return makeCharKey(0xE159, '\u0328', 0);
case "combining_dot_below": return makeCharKey(0xE160, '\u0323', 0);
case "combining_horn": return makeCharKey(0xE161, '\u031B', 0);
case "combining_hook_above": return makeCharKey(0xE162, '\u0309', 0);
/* Combining diacritics that do not have a corresponding dead keys start
at 0xE200. */
case "combining_vertical_tilde": return makeCharKey(0xE200, '\u033E', 0);
case "combining_inverted_breve": return makeCharKey(0xE201, '\u0311', 0);
case "combining_pokrytie": return makeCharKey(0xE202, '\u0487', 0);
case "combining_slavonic_psili": return makeCharKey(0xE203, '\u0486', 0);
case "combining_slavonic_dasia": return makeCharKey(0xE204, '\u0485', 0);
case "combining_payerok": return makeCharKey(0xE205, '\uA67D', 0);
case "combining_titlo": return makeCharKey(0xE206, '\u0483', 0);
case "combining_vzmet": return makeCharKey(0xE207, '\uA66F', 0);
/* Special event keys */
case "config": return eventKey(0xE004, Event.CONFIG, FLAG_SMALLER_FONT);
case "switch_text": return eventKey("ABC", Event.SWITCH_TEXT, FLAG_SMALLER_FONT);
case "switch_numeric": return eventKey("123+", Event.SWITCH_NUMERIC, FLAG_SMALLER_FONT);
case "switch_emoji": return eventKey(0xE001, Event.SWITCH_EMOJI, FLAG_SMALLER_FONT);
case "switch_back_emoji": return eventKey("ABC", Event.SWITCH_BACK_EMOJI, 0);
case "switch_clipboard": return eventKey(0xE017, Event.SWITCH_CLIPBOARD, 0);
case "switch_back_clipboard": return eventKey("ABC", Event.SWITCH_BACK_CLIPBOARD, 0);
case "switch_forward": return eventKey(0xE013, Event.SWITCH_FORWARD, FLAG_SMALLER_FONT);
case "switch_backward": return eventKey(0xE014, Event.SWITCH_BACKWARD, FLAG_SMALLER_FONT);
case "switch_greekmath": return eventKey("πλ∇¬", Event.SWITCH_GREEKMATH, FLAG_SMALLER_FONT);
case "change_method": return eventKey(0xE009, Event.CHANGE_METHOD_PICKER, FLAG_SMALLER_FONT);
case "change_method_prev": return eventKey(0xE009, Event.CHANGE_METHOD_AUTO, FLAG_SMALLER_FONT);
case "action": return eventKey("Action", Event.ACTION, FLAG_SMALLER_FONT); // Will always be replaced
case "capslock": return eventKey(0xE012, Event.CAPS_LOCK, 0);
case "voice_typing": return eventKey(0xE015, Event.SWITCH_VOICE_TYPING, FLAG_SMALLER_FONT);
case "voice_typing_chooser": return eventKey(0xE015, Event.SWITCH_VOICE_TYPING_CHOOSER, FLAG_SMALLER_FONT);
/* Key events */
case "esc": return keyeventKey("Esc", KeyEvent.KEYCODE_ESCAPE, FLAG_SMALLER_FONT);
case "enter": return keyeventKey(0xE00E, KeyEvent.KEYCODE_ENTER, 0);
case "up": return keyeventKey(0xE005, KeyEvent.KEYCODE_DPAD_UP, 0);
case "right": return keyeventKey(0xE006, KeyEvent.KEYCODE_DPAD_RIGHT, 0);
case "down": return keyeventKey(0xE007, KeyEvent.KEYCODE_DPAD_DOWN, 0);
case "left": return keyeventKey(0xE008, KeyEvent.KEYCODE_DPAD_LEFT, 0);
case "page_up": return keyeventKey(0xE002, KeyEvent.KEYCODE_PAGE_UP, 0);
case "page_down": return keyeventKey(0xE003, KeyEvent.KEYCODE_PAGE_DOWN, 0);
case "home": return keyeventKey(0xE00B, KeyEvent.KEYCODE_MOVE_HOME, FLAG_SMALLER_FONT);
case "end": return keyeventKey(0xE00C, KeyEvent.KEYCODE_MOVE_END, FLAG_SMALLER_FONT);
case "backspace": return keyeventKey(0xE011, KeyEvent.KEYCODE_DEL, 0);
case "delete": return keyeventKey(0xE010, KeyEvent.KEYCODE_FORWARD_DEL, 0);
case "insert": return keyeventKey("Ins", KeyEvent.KEYCODE_INSERT, FLAG_SMALLER_FONT);
case "f1": return keyeventKey("F1", KeyEvent.KEYCODE_F1, 0);
case "f2": return keyeventKey("F2", KeyEvent.KEYCODE_F2, 0);
case "f3": return keyeventKey("F3", KeyEvent.KEYCODE_F3, 0);
case "f4": return keyeventKey("F4", KeyEvent.KEYCODE_F4, 0);
case "f5": return keyeventKey("F5", KeyEvent.KEYCODE_F5, 0);
case "f6": return keyeventKey("F6", KeyEvent.KEYCODE_F6, 0);
case "f7": return keyeventKey("F7", KeyEvent.KEYCODE_F7, 0);
case "f8": return keyeventKey("F8", KeyEvent.KEYCODE_F8, 0);
case "f9": return keyeventKey("F9", KeyEvent.KEYCODE_F9, 0);
case "f10": return keyeventKey("F10", KeyEvent.KEYCODE_F10, 0);
case "f11": return keyeventKey("F11", KeyEvent.KEYCODE_F11, FLAG_SMALLER_FONT);
case "f12": return keyeventKey("F12", KeyEvent.KEYCODE_F12, FLAG_SMALLER_FONT);
case "tab": return keyeventKey(0xE00F, KeyEvent.KEYCODE_TAB, FLAG_SMALLER_FONT);
case "menu": return keyeventKey("Menu", KeyEvent.KEYCODE_MENU, FLAG_SMALLER_FONT);
case "scroll_lock": return keyeventKey("Scrl", KeyEvent.KEYCODE_SCROLL_LOCK, FLAG_SMALLER_FONT);
/* Spaces */
case "\\t": return charKey("\\t", '\t', 0); // Send the tab character
case "\\n": return charKey("\\n", '\n', 0); // Send the newline character
case "space": return charKey(0xE00D, ' ', FLAG_KEY_FONT | FLAG_SMALLER_FONT | FLAG_GREYED);
case "nbsp": return charKey("\u237d", '\u00a0', FLAG_SMALLER_FONT);
case "nnbsp": return charKey("\u2423", '\u202F', FLAG_SMALLER_FONT);
/* bidi */
case "lrm": return charKey("", '\u200e', 0); // Send left-to-right mark
case "rlm": return charKey("", '\u200f', 0); // Send right-to-left mark
case "b(": return charKey("(", ')', 0);
case "b)": return charKey(")", '(', 0);
case "b[": return charKey("[", ']', 0);
case "b]": return charKey("]", '[', 0);
case "b{": return charKey("{", '}', 0);
case "b}": return charKey("}", '{', 0);
case "blt": return charKey("<", '>', 0);
case "bgt": return charKey(">", '<', 0);
/* hebrew niqqud */
case "qamats": return charKey("\u05E7\u05B8", '\u05B8', 0); // kamatz
case "patah": return charKey("\u05E4\u05B7", '\u05B7', 0); // patach
case "sheva": return charKey("\u05E9\u05B0", '\u05B0', 0);
case "dagesh": return charKey("\u05D3\u05BC", '\u05BC', 0); // or mapiq
case "hiriq": return charKey("\u05D7\u05B4", '\u05B4', 0);
case "segol": return charKey("\u05E1\u05B6", '\u05B6', 0);
case "tsere": return charKey("\u05E6\u05B5", '\u05B5', 0);
case "holam": return charKey("\u05D5\u05B9", '\u05B9', 0);
case "qubuts": return charKey("\u05E7\u05BB", '\u05BB', 0); // kubuts
case "hataf_patah": return charKey("\u05D7\u05B2\u05E4\u05B7", '\u05B2', 0); // reduced patach
case "hataf_qamats": return charKey("\u05D7\u05B3\u05E7\u05B8", '\u05B3', 0); // reduced kamatz
case "hataf_segol": return charKey("\u05D7\u05B1\u05E1\u05B6", '\u05B1', 0); // reduced segol
case "shindot": return charKey("\u05E9\u05C1", '\u05C1', 0);
case "shindot_placeholder": return placeholderKey(Placeholder.SHINDOT);
case "sindot": return charKey("\u05E9\u05C2", '\u05C2', 0);
case "sindot_placeholder": return placeholderKey(Placeholder.SINDOT);
/* hebrew punctuation */
case "geresh": return charKey("\u05F3", '\u05F3', 0);
case "gershayim": return charKey("\u05F4", '\u05F4', 0);
case "maqaf": return charKey("\u05BE", '\u05BE', 0);
/* hebrew biblical */
case "rafe": return charKey("\u05E4\u05BF", '\u05BF', 0);
case "ole": return charKey("\u05E2\u05AB", '\u05AB', 0);
case "ole_placeholder": return placeholderKey(Placeholder.OLE);
case "meteg": return charKey("\u05DE\u05BD", '\u05BD', 0); // or siluq or sof-pasuq
case "meteg_placeholder": return placeholderKey(Placeholder.METEG);
/* intending/preventing ligature - supported by many scripts*/
case "zwj": return charKey("zwj", '\u200D', 0); // zero-width joiner (provides ligature)
case "zwnj":
case "halfspace": return charKey("", '\u200C', 0); // zero-width non joiner
/* Editing keys */
case "copy": return editingKey(0xE030, Editing.COPY);
case "paste": return editingKey(0xE032, Editing.PASTE);
case "cut": return editingKey(0xE031, Editing.CUT);
case "selectAll": return editingKey(0xE033, Editing.SELECT_ALL);
case "shareText": return editingKey(0xE034, Editing.SHARE);
case "pasteAsPlainText": return editingKey(0xE035, Editing.PASTE_PLAIN);
case "undo": return editingKey(0xE036, Editing.UNDO);
case "redo": return editingKey(0xE037, Editing.REDO);
case "cursor_left": return cursorMoveKey(-1);
case "cursor_right": return cursorMoveKey(1);
// These keys are not used
case "replaceText": return editingKey("repl", Editing.REPLACE);
case "textAssist": return editingKey(0xE038, Editing.ASSIST);
case "autofill": return editingKey("auto", Editing.AUTOFILL);
/* The compose key */
case "compose": return makeComposePending(0xE016, ComposeKeyData.compose, FLAG_SECONDARY | FLAG_SMALLER_FONT | FLAG_SPECIAL);
/* Placeholder keys */
case "removed": return placeholderKey(Placeholder.REMOVED);
case "f11_placeholder": return placeholderKey(Placeholder.F11);
case "f12_placeholder": return placeholderKey(Placeholder.F12);
// Korean Hangul
case "": return makeHangulInitial("", 0);
case "": return makeHangulInitial("", 1);
case "": return makeHangulInitial("", 2);
case "": return makeHangulInitial("", 3);
case "": return makeHangulInitial("", 4);
case "": return makeHangulInitial("", 5);
case "": return makeHangulInitial("", 6);
case "": return makeHangulInitial("", 7);
case "": return makeHangulInitial("", 8);
case "": return makeHangulInitial("", 9);
case "": return makeHangulInitial("", 10);
case "": return makeHangulInitial("", 11);
case "": return makeHangulInitial("", 12);
case "": return makeHangulInitial("", 13);
case "": return makeHangulInitial("", 14);
case "": return makeHangulInitial("", 15);
case "": return makeHangulInitial("", 16);
case "": return makeHangulInitial("", 17);
case "": return makeHangulInitial("", 18);
/* The key is not one of the special ones. */
default: return parseKeyDefinition(name);
}
}
// Substitute for [assert], which has no effect on Android.
private static void check(boolean b)
{
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);
}
}
};
}