mirror of
https://github.com/Julow/Unexpected-Keyboard.git
synced 2025-02-13 16:19:49 +01:00
The code expect that the payload is never null but there are now a lot of public constructor functions for KeyValue that don't check for this property.
795 lines
30 KiB
Java
795 lines
30 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,
|
||
DOUBLE_GRAVE,
|
||
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)
|
||
{
|
||
if (p == null)
|
||
throw new NullPointerException("KeyValue payload cannot be null");
|
||
_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);
|
||
}
|
||
|
||
public static KeyValue keyeventKey(String symbol, int code, int flags)
|
||
{
|
||
return new KeyValue(symbol, Kind.Keyevent, code, flags | FLAG_SECONDARY);
|
||
}
|
||
|
||
public 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 "accent_double_grave": return diacritic(0xE063, Modifier.DOUBLE_GRAVE);
|
||
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);
|
||
case "combining_arabic_v": return makeCharKey(0xE208, '\u065A', 0);
|
||
case "combining_arabic_inverted_v": return makeCharKey(0xE209, '\u065B', 0);
|
||
case "combining_shaddah": return makeCharKey(0xE210, '\u0651', 0);
|
||
case "combining_sukun": return makeCharKey(0xE211, '\u0652', 0);
|
||
case "combining_fatha": return makeCharKey(0xE212, '\u064E', 0);
|
||
case "combining_dammah": return makeCharKey(0xE213, '\u064F', 0);
|
||
case "combining_kasra": return makeCharKey(0xE214, '\u0650', 0);
|
||
case "combining_hamza_above": return makeCharKey(0xE215, '\u0654', 0);
|
||
case "combining_hamza_below": return makeCharKey(0xE216, '\u0655', 0);
|
||
case "combining_alef_above": return makeCharKey(0xE217, '\u0670', 0);
|
||
case "combining_fathatan": return makeCharKey(0xE218, '\u064B', 0);
|
||
case "combining_kasratan": return makeCharKey(0xE219, '\u064D', 0);
|
||
case "combining_dammatan": return makeCharKey(0xE220, '\u064C', 0);
|
||
case "combining_alef_below": return makeCharKey(0xE221, '\u0656', 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);
|
||
|
||
/* Tamil letters should be smaller on the keyboard. */
|
||
case "ஔ": case "ந": case "ல": case "ழ": case "௯": case "க":
|
||
case "ஷ": case "ே": case "௨": case "ஜ": case "ங": case "ன":
|
||
case "௦": case "ை": case "ூ": case "ம": case "ஆ": case "௭":
|
||
case "௪": case "ா": case "ஶ": case "௬": case "வ": case "ஸ":
|
||
case "௮": case "ட": case "ப": case "ஈ": case "௩": case "ஒ":
|
||
case "ௌ": case "உ": case "௫": case "ய": case "ர": case "ு":
|
||
case "இ": case "ோ": case "ஓ": case "ஃ": case "ற": case "த":
|
||
case "௧": case "ண": case "ஏ": case "ஊ": case "ொ": case "ஞ":
|
||
case "அ": case "எ": case "ச": case "ெ": case "ஐ": case "ி":
|
||
case "௹": case "ள": case "ஹ": case "௰": case "ௐ": case "௱":
|
||
case "௲": case "௳":
|
||
return makeStringKey(name, FLAG_SMALLER_FONT);
|
||
|
||
/* 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);
|
||
}
|
||
}
|
||
};
|
||
}
|