diff --git a/srcs/juloo.keyboard2/ExtraKeys.java b/srcs/juloo.keyboard2/ExtraKeys.java index 36acaf1..fb1f3e2 100644 --- a/srcs/juloo.keyboard2/ExtraKeys.java +++ b/srcs/juloo.keyboard2/ExtraKeys.java @@ -2,6 +2,8 @@ package juloo.keyboard2; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -9,35 +11,45 @@ import java.util.Set; class ExtraKeys { - List _ks; + public static final ExtraKeys EMPTY = new ExtraKeys(Collections.EMPTY_LIST); - public ExtraKeys() - { - _ks = new ArrayList(); - } + Collection _ks; - public void parse_and_add_keys_for_script(String script, String extra_keys_str) + public ExtraKeys(Collection ks) { - _ks.addAll(parse_extra_keys(script, extra_keys_str)); + _ks = ks; } /** Add the keys that should be added to the keyboard into [dst]. */ public void compute(Set dst, Query q) { for (ExtraKey k : _ks) - { - if (k.should_add(q)) - dst.add(k.kv); - } + k.compute(dst, q); } - public static List parse_extra_keys(String script, String str) + public static ExtraKeys parse(String script, String str) { - List dst = new ArrayList(); + Collection dst = new ArrayList(); String[] ks = str.split("\\|"); for (int i = 0; i < ks.length; i++) dst.add(ExtraKey.parse(ks[i], script)); - return dst; + return new ExtraKeys(dst); + } + + /** Merge identical keys. This is required to decide whether to add + alternatives. Script is generalized (set to null) on any conflict. */ + public static ExtraKeys merge(List kss) + { + Map merged_keys = new HashMap(); + for (ExtraKeys ks : kss) + for (ExtraKey k : ks._ks) + { + ExtraKey k2 = merged_keys.get(k.kv); + if (k2 != null) + k = k.merge_with(k2); + merged_keys.put(k.kv, k); + } + return new ExtraKeys(merged_keys.values()); } final static class ExtraKey @@ -59,11 +71,30 @@ class ExtraKeys } /** Whether the key should be added to the keyboard. */ - public boolean should_add(Query q) + public void compute(Set dst, Query q) { - return - (q.script == null || script == null || q.script.equals(script)) - && (alternatives.size() == 0 || !q.present.containsAll(alternatives)); + // Add the alternative if it's the only one. The list of alternatives is + // enforced to be complete by the merging step. The same [kv] will not + // appear again in the list of extra keys with a different list of + // alternatives. + KeyValue k = (alternatives.size() == 1) ? alternatives.get(0) : kv; + if + ((q.script == null || script == null || q.script.equals(script)) + && (alternatives.size() == 0 || !q.present.containsAll(alternatives))) + dst.add(k); + } + + /** Return a new key from two. [kv] are expected to be equal. [script] is + generalized to [null] on any conflict. [alternatives] are concatenated. + */ + public ExtraKey merge_with(ExtraKey k2) + { + String script_ = + (script != null && k2.script != null && script.equals(k2.script)) + ? script : null; + List alts = new ArrayList(alternatives); + alts.addAll(k2.alternatives); + return new ExtraKey(kv, script_, alts); } /** Extra keys are of the form "key name" or "key name:alt 1:alt 2". */ diff --git a/srcs/juloo.keyboard2/Keyboard2.java b/srcs/juloo.keyboard2/Keyboard2.java index 77c2c15..51026e1 100644 --- a/srcs/juloo.keyboard2/Keyboard2.java +++ b/srcs/juloo.keyboard2/Keyboard2.java @@ -18,6 +18,7 @@ import android.view.inputmethod.InputMethodSubtype; import android.widget.FrameLayout; import android.widget.LinearLayout; import java.util.AbstractMap.SimpleEntry; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -110,33 +111,34 @@ public class Keyboard2 extends InputMethodService return Arrays.asList(); } - private void extra_keys_of_subtype(ExtraKeys dst, InputMethodSubtype subtype) + private ExtraKeys extra_keys_of_subtype(InputMethodSubtype subtype) { String extra_keys = subtype.getExtraValueOf("extra_keys"); String script = subtype.getExtraValueOf("script"); if (extra_keys != null) - dst.parse_and_add_keys_for_script(script, extra_keys); + return ExtraKeys.parse(script, extra_keys); + return ExtraKeys.EMPTY; } private void refreshAccentsOption(InputMethodManager imm, InputMethodSubtype subtype) { - ExtraKeys extra_keys = new ExtraKeys(); List enabled_subtypes = getEnabledSubtypes(imm); + List extra_keys = new ArrayList(); switch (_config.accents) { // '3' was "all accents", now unused case 1: case 3: - extra_keys_of_subtype(extra_keys, subtype); + extra_keys.add(extra_keys_of_subtype(subtype)); for (InputMethodSubtype s : enabled_subtypes) - extra_keys_of_subtype(extra_keys, s); + extra_keys.add(extra_keys_of_subtype(s)); break; case 2: - extra_keys_of_subtype(extra_keys, subtype); + extra_keys.add(extra_keys_of_subtype(subtype)); break; case 4: break; default: throw new IllegalArgumentException(); } - _config.extra_keys_subtype = extra_keys; + _config.extra_keys_subtype = ExtraKeys.merge(extra_keys); if (enabled_subtypes.size() > 1) _config.shouldOfferSwitchingToNextInputMethod = true; }