Allow extending the compose key (#713)

This allows adding more compose sequences without modifying
en_US_UTF_8_Compose.pre.

This is done by grouping sequences files that should be merged together
into a directory. This also allows moving keysymdef.h into that
directory.
This commit is contained in:
Jules Aguillon 2024-07-21 23:37:07 +02:00 committed by GitHub
parent 84e10e0470
commit 2696f42144
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 43 additions and 12 deletions

View File

@ -190,6 +190,12 @@ As translations need to be updated regularly, you can subscribe to this issue
to receive a notification when an update is needed: to receive a notification when an update is needed:
https://github.com/Julow/Unexpected-Keyboard/issues/373 https://github.com/Julow/Unexpected-Keyboard/issues/373
### Adding Compose key sequences
New Compose sequences can be added into `srcs/compose/compose/extra.json`.
If a entirely new family of sequences were to be added, a new `.json` file can
be created in the same directory to host them.
### Adding key combinations ### Adding key combinations
Key combinations are defined in `srcs/juloo.keyboard2/KeyModifier.java`. Key combinations are defined in `srcs/juloo.keyboard2/KeyModifier.java`.

View File

@ -151,7 +151,7 @@ tasks.register('compileComposeSequences') {
println "\nGenerating ${out}" println "\nGenerating ${out}"
exec { exec {
def sequences = new File(projectDir, "srcs/compose").listFiles().findAll { def sequences = new File(projectDir, "srcs/compose").listFiles().findAll {
it.name.endsWith(".pre") || it.name.endsWith(".json") !it.name.endsWith(".py") && !it.name.endsWith(".md")
} }
workingDir = projectDir workingDir = projectDir
commandLine("python", "srcs/compose/compile.py", *sequences) commandLine("python", "srcs/compose/compile.py", *sequences)

View File

@ -3,6 +3,8 @@
The `compose.py` program parses the compose sequences found in this directory The `compose.py` program parses the compose sequences found in this directory
and generates `srcs/juloo.keyboard2/ComposeKeyData.java`. and generates `srcs/juloo.keyboard2/ComposeKeyData.java`.
## `en_US_UTF_8_Compose.pre` ## `compose/en_US_UTF_8_Compose.pre`
This file is copied from the `xorg` project. Copyright applies. This file is copied from the `xorg` project. Copyright applies.
## `compose/extra.json`

View File

@ -12,20 +12,18 @@ from array import array
# Parse symbol names from keysymdef.h. Many compose sequences in # Parse symbol names from keysymdef.h. Many compose sequences in
# en_US_UTF_8_Compose.pre reference theses. For example, all the sequences on # en_US_UTF_8_Compose.pre reference theses. For example, all the sequences on
# the Greek, Cyrillic and Hebrew scripts need these symbols. # the Greek, Cyrillic and Hebrew scripts need these symbols.
def parse_keysymdef_h(): def parse_keysymdef_h(fname):
with open(os.path.join(os.path.dirname(__file__), "keysymdef.h"), "r") as inp: with open(fname, "r") as inp:
keysym_re = re.compile(r'^#define XK_(\S+)\s+\S+\s*/\*.U\+([0-9a-fA-F]+)\s') keysym_re = re.compile(r'^#define XK_(\S+)\s+\S+\s*/\*.U\+([0-9a-fA-F]+)\s')
for line in inp: for line in inp:
m = re.match(keysym_re, line) m = re.match(keysym_re, line)
if m != None: if m != None:
yield (m.group(1), chr(int(m.group(2), 16))) yield (m.group(1), chr(int(m.group(2), 16)))
xkb_char_extra_names = dict(parse_keysymdef_h())
dropped_sequences = 0 dropped_sequences = 0
# Parse XKB's Compose.pre files # Parse XKB's Compose.pre files
def parse_sequences_file_xkb(fname): def parse_sequences_file_xkb(fname, xkb_char_extra_names):
# Parse a line of the form: # Parse a line of the form:
# <Multi_key> <minus> <space> : "~" asciitilde # TILDE # <Multi_key> <minus> <space> : "~" asciitilde # TILDE
# Sequences not starting with <Multi_key> are ignored. # Sequences not starting with <Multi_key> are ignored.
@ -99,13 +97,30 @@ def parse_sequences_file_json(fname):
return list(seqs.items()) return list(seqs.items())
# Format of the sequences file is determined by its extension # Format of the sequences file is determined by its extension
def parse_sequences_file(fname): def parse_sequences_file(fname, xkb_char_extra_names={}):
if fname.endswith(".pre"): if fname.endswith(".pre"):
return parse_sequences_file_xkb(fname) return parse_sequences_file_xkb(fname, xkb_char_extra_names)
if fname.endswith(".json"): if fname.endswith(".json"):
return parse_sequences_file_json(fname) return parse_sequences_file_json(fname)
raise Exception(fname + ": Unsupported format") raise Exception(fname + ": Unsupported format")
# A sequence directory can contain several sequence files as well as
# 'keysymdef.h'.
def parse_sequences_dir(dname):
compose_files = []
xkb_char_extra_names = {}
# Parse keysymdef.h first if present
for fbasename in os.listdir(dname):
fname = os.path.join(dname, fbasename)
if fbasename == "keysymdef.h":
xkb_char_extra_names = dict(parse_keysymdef_h(fname))
else:
compose_files.append(fname)
sequences = []
for fname in compose_files:
sequences.extend(parse_sequences_file(fname, xkb_char_extra_names))
return sequences
# Turn a list of sequences into a trie. # Turn a list of sequences into a trie.
def add_sequences_to_trie(seqs, trie): def add_sequences_to_trie(seqs, trie):
def add_seq_to_trie(t_, seq, result): def add_seq_to_trie(t_, seq, result):
@ -238,9 +253,12 @@ public final class ComposeKeyData
total_sequences = 0 total_sequences = 0
tries = {} # Orderred dict tries = {} # Orderred dict
for fname in sys.argv[1:]: for fname in sorted(sys.argv[1:]):
tname, _ = os.path.splitext(os.path.basename(fname)) tname, _ = os.path.splitext(os.path.basename(fname))
sequences = parse_sequences_file(fname) if os.path.isdir(fname):
sequences = parse_sequences_dir(fname)
else:
sequences = parse_sequences_file(fname)
add_sequences_to_trie(sequences, tries.setdefault(tname, {})) add_sequences_to_trie(sequences, tries.setdefault(tname, {}))
total_sequences += len(sequences) total_sequences += len(sequences)
entry_states, automata = make_automata(tries) entry_states, automata = make_automata(tries)

View File

@ -0,0 +1,5 @@
{
"V": {
"s": "Š"
}
}

View File

@ -570,7 +570,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 makeComposePending(0xE016, ComposeKeyData.en_US_UTF_8_Compose, FLAG_SECONDARY | FLAG_SMALLER_FONT | FLAG_SPECIAL); case "compose": return makeComposePending(0xE016, ComposeKeyData.compose, FLAG_SECONDARY | FLAG_SMALLER_FONT | FLAG_SPECIAL);
/* Placeholder keys */ /* Placeholder keys */
case "removed": return placeholderKey(Placeholder.REMOVED); case "removed": return placeholderKey(Placeholder.REMOVED);