Files
Jules Aguillon 833b4a2154 Better suggestion with diacritics (#1223)
* Update cdict

* scripts/subst_of_compose.py: Compute substitutions

from compose mappings. They are used when building dictionaries.

* Add substitutions compose data

* Better suggestion with diacritics

This improves the suggestions for words that contain diacritics and
uppercase letters.

This works by stripping diacritics both when building the dictionaries
(using word aliases added in cdict: https://github.com/Julow/cdict/pull/3)
and during lookup. Cdict then takes care of resolving the correct word.

The substitutions are generated using mappings from `fn`, `shift` and
all the `accent_*` modifiers into srcs/compose/substitutions.json
This can be updated easily when more mappings are added.
2026-04-10 19:08:23 +02:00

110 lines
3.7 KiB
Java

package juloo.keyboard2;
import java.util.Arrays;
public final class ComposeKey
{
/** Apply the pending compose sequence to [kv]. Returns [null] if no sequence
matched. */
public static KeyValue apply(int state, KeyValue kv)
{
switch (kv.getKind())
{
case Char: return apply(state, kv.getChar());
case String: return apply(state, kv.getString());
case Editing:
switch (kv.getEditing())
{
case SPACE_BAR: return apply(state, ' ');
}
break;
}
return null;
}
/** Apply a char to the pending compose sequence. Returns [null] if no
sequence matched. */
public static KeyValue apply(int state, char c)
{
char[] states = ComposeKeyData.states;
char[] edges = ComposeKeyData.edges;
int state_length = edges[state];
int next = Arrays.binarySearch(states, state + 1, state + state_length, c);
if (next < 0)
return null;
next = edges[next];
int next_header = states[next];
if (next_header == 0) // Enter a new intermediate state.
return KeyValue.makeComposePending(String.valueOf(c), next, 0);
else if (next_header == 0xFFFF) // String final state
{
int next_length = edges[next];
return KeyValue.getKeyByName(
new String(states, next + 1, next_length - 1));
}
else // Character final state.
return KeyValue.makeCharKey((char)next_header);
}
/** Apply char [c] to the pending compose sequence. If the application resolves
to a final char state, return it, otherwise return [0]. This is faster
than [apply] but do not support sequences of more than 1 char. Used to
apply substitutions for word suggestions. */
public static char transform_char(int state, char c)
{
char[] states = ComposeKeyData.states;
char[] edges = ComposeKeyData.edges;
int state_length = edges[state];
int next = Arrays.binarySearch(states, state + 1, state + state_length, c);
if (next < 0)
return 0;
next = edges[next];
int next_header = states[next];
if (next_header == 0 || next_header == 0xFFFF)
return 0;
return (char)next_header;
}
/** Apply each char of a string to a sequence. Returns [null] if no sequence
matched. */
public static KeyValue apply(int prev, String s)
{
final int len = s.length();
int i = 0;
if (len == 0) return null;
while (true)
{
KeyValue k = apply(prev, s.charAt(i));
i++;
if (k == null) return null;
if (i >= len) return k;
if (k.getKind() != KeyValue.Kind.Compose_pending)
return null; // Found a final state before the end of [s].
prev = k.getPendingCompose();
}
}
/** The state machine is comprised of two arrays.
The [states] array represents the different states and the associated
transitions:
- The first cell is the header cell, [states[s]].
- If the header is equal to [0],
The remaining cells are the transitions characters, sorted
alphabetically.
- If the header is positive,
This is a final state, [states[s]] is the result of the sequence.
In this case, [edges[s]] must be equal to [1].
- If the header is equal to [-1],
This is a final state, the remaining cells represent the result string
which starts at index [s + 1] and has a length of [edges[s] - 1].
The [edges] array represents the transition state corresponding to each
accepted inputs.
- If [states[s]] is a header cell, [edges[s]] is the number of cells
occupied by the state [s], including the header cell.
- If [states[s]] is a transition, [edges[s]] is the index of the state to
jump into.
- If [states[s]] is a part of a final state, [edges[s]] is not used. */
}