forked from extern/Unexpected-Keyboard
refactor: Implement Compose without global state
Thanks to the previous commit, a modifier key can now be more complex than just a KeyValue.Modifier. This allows a more elegant implementation of the compose key, that could be taken as a base for other features (eg. unicode hex entry, hangul) The COMPOSE_PENDING modifier is removed as keys of kind Compose_pending can act as a modifier. This has the advantage of highlighting the key that was last pressed in the sequence. Rules are added to Pointers: Non-special but latchable keys must clear latches and cannot be locked with a long press. These rules were not needed before but were intended.
This commit is contained in:
parent
dc3a303af1
commit
e604f6fd57
@ -4,31 +4,26 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
public final class ComposeKey
|
public final class ComposeKey
|
||||||
{
|
{
|
||||||
/** Apply the pending compose sequence to [kv]. Returns [null] if [kv] is not
|
/** Apply the pending compose sequence to [kv]. */
|
||||||
part of the pending sequence. */
|
|
||||||
public static KeyValue apply(int state, KeyValue kv)
|
public static KeyValue apply(int state, KeyValue kv)
|
||||||
{
|
{
|
||||||
switch (kv.getKind())
|
switch (kv.getKind())
|
||||||
{
|
{
|
||||||
case Char:
|
case Char:
|
||||||
KeyValue res = apply(state, kv.getChar());
|
KeyValue res = apply(state, kv.getChar());
|
||||||
// Dim characters not part of any sequence instead of removing them.
|
// Grey-out characters not part of any sequence.
|
||||||
if (res == null)
|
if (res == null)
|
||||||
return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
|
return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
|
||||||
return res;
|
return res;
|
||||||
/* These keys must not be removed. */
|
/* These keys are not greyed. */
|
||||||
case Event:
|
case Event:
|
||||||
case Modifier:
|
case Modifier:
|
||||||
|
case Compose_pending:
|
||||||
return kv;
|
return kv;
|
||||||
/* These keys cannot be part of sequences. */
|
/* Other keys cannot be part of sequences. */
|
||||||
case String:
|
default:
|
||||||
case Keyevent:
|
|
||||||
case Editing:
|
|
||||||
case Placeholder:
|
|
||||||
return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
|
return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
|
||||||
case Compose_pending: return null;
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Apply the pending compose sequence to char [c]. */
|
/** Apply the pending compose sequence to char [c]. */
|
||||||
|
@ -69,9 +69,6 @@ public final class KeyEventHandler implements Config.IKeyEventHandler
|
|||||||
case META:
|
case META:
|
||||||
_autocap.stop();
|
_autocap.stop();
|
||||||
break;
|
break;
|
||||||
case COMPOSE_PENDING:
|
|
||||||
KeyModifier.set_compose_pending(0);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: break;
|
default: break;
|
||||||
@ -95,7 +92,6 @@ public final class KeyEventHandler implements Config.IKeyEventHandler
|
|||||||
case Modifier: break;
|
case Modifier: break;
|
||||||
case Editing: handle_editing_key(key.getEditing()); break;
|
case Editing: handle_editing_key(key.getEditing()); break;
|
||||||
case Compose_pending:
|
case Compose_pending:
|
||||||
KeyModifier.set_compose_pending(key.getPendingCompose());
|
|
||||||
_recv.set_compose_pending(true);
|
_recv.set_compose_pending(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,6 @@ public final class KeyModifier
|
|||||||
private static HashMap<KeyValue, HashMap<Pointers.Modifiers, KeyValue>> _cache =
|
private static HashMap<KeyValue, HashMap<Pointers.Modifiers, KeyValue>> _cache =
|
||||||
new HashMap<KeyValue, HashMap<Pointers.Modifiers, KeyValue>>();
|
new HashMap<KeyValue, HashMap<Pointers.Modifiers, KeyValue>>();
|
||||||
|
|
||||||
/** The current compose state. Whether a compose is pending is signaled by
|
|
||||||
the [COMPOSE_PENDING] modifier. */
|
|
||||||
static int _compose_pending = -1;
|
|
||||||
|
|
||||||
/** Modify a key according to modifiers. */
|
/** Modify a key according to modifiers. */
|
||||||
public static KeyValue modify(KeyValue k, Pointers.Modifiers mods)
|
public static KeyValue modify(KeyValue k, Pointers.Modifiers mods)
|
||||||
{
|
{
|
||||||
@ -33,8 +29,6 @@ public final class KeyModifier
|
|||||||
/* Keys with an empty string are placeholder keys. */
|
/* Keys with an empty string are placeholder keys. */
|
||||||
if (r.getString().length() == 0)
|
if (r.getString().length() == 0)
|
||||||
return null;
|
return null;
|
||||||
if (mods.has(KeyValue.Modifier.COMPOSE_PENDING))
|
|
||||||
r = ComposeKey.apply(_compose_pending, r);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,6 +38,8 @@ public final class KeyModifier
|
|||||||
{
|
{
|
||||||
case Modifier:
|
case Modifier:
|
||||||
return modify(k, mod.getModifier());
|
return modify(k, mod.getModifier());
|
||||||
|
case Compose_pending:
|
||||||
|
return ComposeKey.apply(mod.getPendingCompose(), k);
|
||||||
}
|
}
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
@ -118,11 +114,6 @@ public final class KeyModifier
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void set_compose_pending(int state)
|
|
||||||
{
|
|
||||||
_compose_pending = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static KeyValue apply_map_char(KeyValue k, Map_char map)
|
private static KeyValue apply_map_char(KeyValue k, Map_char map)
|
||||||
{
|
{
|
||||||
switch (k.getKind())
|
switch (k.getKind())
|
||||||
|
@ -26,7 +26,6 @@ public final class KeyValue implements Comparable<KeyValue>
|
|||||||
// Must be evaluated in the reverse order of their values.
|
// Must be evaluated in the reverse order of their values.
|
||||||
public static enum Modifier
|
public static enum Modifier
|
||||||
{
|
{
|
||||||
COMPOSE_PENDING,
|
|
||||||
SHIFT,
|
SHIFT,
|
||||||
CTRL,
|
CTRL,
|
||||||
ALT,
|
ALT,
|
||||||
@ -89,8 +88,8 @@ public final class KeyValue implements Comparable<KeyValue>
|
|||||||
|
|
||||||
public static enum Kind
|
public static enum Kind
|
||||||
{
|
{
|
||||||
Char, String, Keyevent, Event, Modifier, Editing, Placeholder,
|
Char, String, Keyevent, Event, Compose_pending, Modifier, Editing,
|
||||||
Compose_pending
|
Placeholder
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int FLAGS_OFFSET = 19;
|
private static final int FLAGS_OFFSET = 19;
|
||||||
@ -340,7 +339,13 @@ public final class KeyValue implements Comparable<KeyValue>
|
|||||||
public static KeyValue makeComposePending(String symbol, int state, int flags)
|
public static KeyValue makeComposePending(String symbol, int state, int flags)
|
||||||
{
|
{
|
||||||
return new KeyValue(symbol, Kind.Compose_pending, state,
|
return new KeyValue(symbol, Kind.Compose_pending, state,
|
||||||
flags | FLAG_SPECIAL);
|
flags | FLAG_LATCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyValue makeComposePending(int symbol, int state, int flags)
|
||||||
|
{
|
||||||
|
return makeComposePending(String.valueOf((char)symbol), state,
|
||||||
|
flags | FLAG_KEY_FONT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Make a key that types a string. A char key is returned for a string of
|
/** Make a key that types a string. A char key is returned for a string of
|
||||||
@ -505,7 +510,7 @@ public final class KeyValue implements Comparable<KeyValue>
|
|||||||
case "autofill": return editingKey("auto", Editing.AUTOFILL);
|
case "autofill": return editingKey("auto", Editing.AUTOFILL);
|
||||||
|
|
||||||
/* The compose key */
|
/* The compose key */
|
||||||
case "compose": return modifierKey(0xE016, Modifier.COMPOSE_PENDING, FLAG_SECONDARY | FLAG_SMALLER_FONT);
|
case "compose": return makeComposePending(0xE016, 0, FLAG_SECONDARY | FLAG_SMALLER_FONT | FLAG_SPECIAL);
|
||||||
|
|
||||||
/* Placeholder keys */
|
/* Placeholder keys */
|
||||||
case "removed": return placeholderKey(Placeholder.REMOVED);
|
case "removed": return placeholderKey(Placeholder.REMOVED);
|
||||||
|
@ -19,6 +19,10 @@ public final class Pointers implements Handler.Callback
|
|||||||
public static final int FLAG_P_LOCKABLE = (1 << 3);
|
public static final int FLAG_P_LOCKABLE = (1 << 3);
|
||||||
public static final int FLAG_P_LOCKED = (1 << 4);
|
public static final int FLAG_P_LOCKED = (1 << 4);
|
||||||
public static final int FLAG_P_SLIDING = (1 << 5);
|
public static final int FLAG_P_SLIDING = (1 << 5);
|
||||||
|
/** Clear latched (only if also FLAG_P_LATCHABLE set). */
|
||||||
|
public static final int FLAG_P_CLEAR_LATCHED = (1 << 6);
|
||||||
|
/** Can't be locked, even when long pressing. */
|
||||||
|
public static final int FLAG_P_CANT_LOCK = (1 << 7);
|
||||||
|
|
||||||
private Handler _keyrepeat_handler;
|
private Handler _keyrepeat_handler;
|
||||||
private ArrayList<Pointer> _ptrs = new ArrayList<Pointer>();
|
private ArrayList<Pointer> _ptrs = new ArrayList<Pointer>();
|
||||||
@ -153,6 +157,9 @@ public final class Pointers implements Handler.Callback
|
|||||||
}
|
}
|
||||||
else if ((ptr.flags & FLAG_P_LATCHABLE) != 0)
|
else if ((ptr.flags & FLAG_P_LATCHABLE) != 0)
|
||||||
{
|
{
|
||||||
|
// Latchable but non-special keys must clear latched.
|
||||||
|
if ((ptr.flags & FLAG_P_CLEAR_LATCHED) != 0)
|
||||||
|
clearLatched();
|
||||||
ptr.flags |= FLAG_P_LATCHED;
|
ptr.flags |= FLAG_P_LATCHED;
|
||||||
ptr.pointerId = -1;
|
ptr.pointerId = -1;
|
||||||
_handler.onPointerFlagsChanged(false);
|
_handler.onPointerFlagsChanged(false);
|
||||||
@ -395,7 +402,8 @@ public final class Pointers implements Handler.Callback
|
|||||||
// Long press toggle lock on modifiers
|
// Long press toggle lock on modifiers
|
||||||
if ((ptr.flags & FLAG_P_LATCHABLE) != 0)
|
if ((ptr.flags & FLAG_P_LATCHABLE) != 0)
|
||||||
{
|
{
|
||||||
lockPointer(ptr, true);
|
if (!ptr.hasFlagsAny(FLAG_P_CANT_LOCK))
|
||||||
|
lockPointer(ptr, true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Stop repeating: Latched key, no key
|
// Stop repeating: Latched key, no key
|
||||||
@ -452,7 +460,12 @@ public final class Pointers implements Handler.Callback
|
|||||||
{
|
{
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
if (kv.hasFlagsAny(KeyValue.FLAG_LATCH))
|
if (kv.hasFlagsAny(KeyValue.FLAG_LATCH))
|
||||||
|
{
|
||||||
|
// Non-special latchable key must clear modifiers and can't be locked
|
||||||
|
if (!kv.hasFlagsAny(KeyValue.FLAG_SPECIAL))
|
||||||
|
flags |= FLAG_P_CLEAR_LATCHED | FLAG_P_CANT_LOCK;
|
||||||
flags |= FLAG_P_LATCHABLE;
|
flags |= FLAG_P_LATCHABLE;
|
||||||
|
}
|
||||||
if (kv.hasFlagsAny(KeyValue.FLAG_LOCK))
|
if (kv.hasFlagsAny(KeyValue.FLAG_LOCK))
|
||||||
flags |= FLAG_P_LOCKABLE;
|
flags |= FLAG_P_LOCKABLE;
|
||||||
return flags;
|
return flags;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user