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:
Jules Aguillon 2024-03-18 01:00:22 +01:00
parent dc3a303af1
commit e604f6fd57
5 changed files with 32 additions and 32 deletions

View File

@ -4,31 +4,26 @@ import java.util.Arrays;
public final class ComposeKey
{
/** Apply the pending compose sequence to [kv]. Returns [null] if [kv] is not
part of the pending sequence. */
/** Apply the pending compose sequence to [kv]. */
public static KeyValue apply(int state, KeyValue kv)
{
switch (kv.getKind())
{
case Char:
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)
return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
return res;
/* These keys must not be removed. */
/* These keys are not greyed. */
case Event:
case Modifier:
case Compose_pending:
return kv;
/* These keys cannot be part of sequences. */
case String:
case Keyevent:
case Editing:
case Placeholder:
/* Other keys cannot be part of sequences. */
default:
return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
case Compose_pending: return null;
}
return null;
}
/** Apply the pending compose sequence to char [c]. */

View File

@ -69,9 +69,6 @@ public final class KeyEventHandler implements Config.IKeyEventHandler
case META:
_autocap.stop();
break;
case COMPOSE_PENDING:
KeyModifier.set_compose_pending(0);
break;
}
break;
default: break;
@ -95,7 +92,6 @@ public final class KeyEventHandler implements Config.IKeyEventHandler
case Modifier: break;
case Editing: handle_editing_key(key.getEditing()); break;
case Compose_pending:
KeyModifier.set_compose_pending(key.getPendingCompose());
_recv.set_compose_pending(true);
break;
}

View File

@ -10,10 +10,6 @@ public final class KeyModifier
private static HashMap<KeyValue, HashMap<Pointers.Modifiers, KeyValue>> _cache =
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. */
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. */
if (r.getString().length() == 0)
return null;
if (mods.has(KeyValue.Modifier.COMPOSE_PENDING))
r = ComposeKey.apply(_compose_pending, r);
return r;
}
@ -44,6 +38,8 @@ public final class KeyModifier
{
case Modifier:
return modify(k, mod.getModifier());
case Compose_pending:
return ComposeKey.apply(mod.getPendingCompose(), 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)
{
switch (k.getKind())

View File

@ -26,7 +26,6 @@ public final class KeyValue implements Comparable<KeyValue>
// Must be evaluated in the reverse order of their values.
public static enum Modifier
{
COMPOSE_PENDING,
SHIFT,
CTRL,
ALT,
@ -89,8 +88,8 @@ public final class KeyValue implements Comparable<KeyValue>
public static enum Kind
{
Char, String, Keyevent, Event, Modifier, Editing, Placeholder,
Compose_pending
Char, String, Keyevent, Event, Compose_pending, Modifier, Editing,
Placeholder
}
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)
{
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
@ -505,7 +510,7 @@ public final class KeyValue implements Comparable<KeyValue>
case "autofill": return editingKey("auto", Editing.AUTOFILL);
/* 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 */
case "removed": return placeholderKey(Placeholder.REMOVED);

View File

@ -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_LOCKED = (1 << 4);
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 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)
{
// Latchable but non-special keys must clear latched.
if ((ptr.flags & FLAG_P_CLEAR_LATCHED) != 0)
clearLatched();
ptr.flags |= FLAG_P_LATCHED;
ptr.pointerId = -1;
_handler.onPointerFlagsChanged(false);
@ -395,6 +402,7 @@ public final class Pointers implements Handler.Callback
// Long press toggle lock on modifiers
if ((ptr.flags & FLAG_P_LATCHABLE) != 0)
{
if (!ptr.hasFlagsAny(FLAG_P_CANT_LOCK))
lockPointer(ptr, true);
return false;
}
@ -452,7 +460,12 @@ public final class Pointers implements Handler.Callback
{
int flags = 0;
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;
}
if (kv.hasFlagsAny(KeyValue.FLAG_LOCK))
flags |= FLAG_P_LOCKABLE;
return flags;