diff --git a/srcs/juloo.keyboard2/Config.java b/srcs/juloo.keyboard2/Config.java index da78f7f..bde4aea 100644 --- a/srcs/juloo.keyboard2/Config.java +++ b/srcs/juloo.keyboard2/Config.java @@ -9,8 +9,10 @@ import android.util.TypedValue; import android.view.KeyEvent; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; final class Config @@ -59,8 +61,8 @@ final class Config public int actionId; // Meaningful only when 'actionLabel' isn't 'null' public boolean swapEnterActionKey; // Swap the "enter" and "action" keys public ExtraKeys extra_keys_subtype; - public Set extra_keys_param; - public List extra_keys_custom; + public Map extra_keys_param; + public Map extra_keys_custom; public final IKeyEventHandler handler; public boolean orientation_landscape = false; @@ -174,16 +176,16 @@ final class Config final KeyValue action_key = action_key(); // Extra keys are removed from the set as they are encountered during the // first iteration then automatically added. - final Set extra_keys = new HashSet(); + final Map extra_keys = new HashMap(); final Set remove_keys = new HashSet(); - extra_keys.addAll(extra_keys_param); - extra_keys.addAll(extra_keys_custom); + extra_keys.putAll(extra_keys_param); + extra_keys.putAll(extra_keys_custom); if (extra_keys_subtype != null) { Set present = new HashSet(); present.addAll(kw.getKeys().keySet()); - present.addAll(extra_keys_param); - present.addAll(extra_keys_custom); + present.addAll(extra_keys_param.keySet()); + present.addAll(extra_keys_custom.keySet()); extra_keys_subtype.compute(extra_keys, new ExtraKeys.Query(kw.script, present)); } @@ -193,7 +195,7 @@ final class Config kw = kw.mapKeys(new KeyboardData.MapKeyValues() { public KeyValue apply(KeyValue key, boolean localized) { - boolean is_extra_key = extra_keys.contains(key); + boolean is_extra_key = extra_keys.containsKey(key); if (is_extra_key) extra_keys.remove(key); if (localized && !is_extra_key) @@ -246,7 +248,7 @@ final class Config if (number_row) kw = kw.addNumberRow(); if (extra_keys.size() > 0) - kw = kw.addExtraKeys(extra_keys.iterator()); + kw = kw.addExtraKeys(extra_keys.entrySet().iterator()); return kw; } diff --git a/srcs/juloo.keyboard2/CustomExtraKeysPreference.java b/srcs/juloo.keyboard2/CustomExtraKeysPreference.java index b17ff8d..d007bf7 100644 --- a/srcs/juloo.keyboard2/CustomExtraKeysPreference.java +++ b/srcs/juloo.keyboard2/CustomExtraKeysPreference.java @@ -10,8 +10,9 @@ import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; -import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.json.JSONArray; import org.json.JSONException; @@ -30,14 +31,15 @@ public class CustomExtraKeysPreference extends ListGroupPreference setKey(KEY); } - public static List get(SharedPreferences prefs) + public static Map get(SharedPreferences prefs) { - List kvs = new ArrayList(); + Map kvs = + new HashMap(); List key_names = load_from_preferences(KEY, prefs, null, SERIALIZER); if (key_names != null) { for (String key_name : key_names) - kvs.add(KeyValue.makeStringKey(key_name)); + kvs.put(KeyValue.makeStringKey(key_name), KeyboardData.PreferredPos.DEFAULT); } return kvs; } diff --git a/srcs/juloo.keyboard2/ExtraKeys.java b/srcs/juloo.keyboard2/ExtraKeys.java index cfac362..aa2e38f 100644 --- a/srcs/juloo.keyboard2/ExtraKeys.java +++ b/srcs/juloo.keyboard2/ExtraKeys.java @@ -22,7 +22,7 @@ class ExtraKeys /** Add the keys that should be added to the keyboard into [dst]. Keys already added to [dst] might have an impact, see [ExtraKey.compute]. */ - public void compute(Set dst, Query q) + public void compute(Map dst, Query q) { for (ExtraKey k : _ks) k.compute(dst, q); @@ -72,7 +72,7 @@ class ExtraKeys } /** Whether the key should be added to the keyboard. */ - public void compute(Set dst, Query q) + public void compute(Map dst, Query q) { // 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 @@ -80,11 +80,14 @@ class ExtraKeys // alternatives. // Selecting the dead key in the "Add key to the keyboard" option would // disable this behavior for a key. - boolean use_alternative = (alternatives.size() == 1 && !dst.contains(kv)); + boolean use_alternative = (alternatives.size() == 1 && !dst.containsKey(kv)); if ((q.script == null || script == null || q.script.equals(script)) && (alternatives.size() == 0 || !q.present.containsAll(alternatives))) - dst.add(use_alternative ? alternatives.get(0) : kv); + { + KeyValue kv_ = use_alternative ? alternatives.get(0) : kv; + dst.put(kv_, KeyboardData.PreferredPos.DEFAULT); + } } /** Return a new key from two. [kv] are expected to be equal. [script] is diff --git a/srcs/juloo.keyboard2/ExtraKeysPreference.java b/srcs/juloo.keyboard2/ExtraKeysPreference.java index 8dacdea..0bbf0ce 100644 --- a/srcs/juloo.keyboard2/ExtraKeysPreference.java +++ b/srcs/juloo.keyboard2/ExtraKeysPreference.java @@ -8,7 +8,8 @@ import android.preference.PreferenceCategory; import android.util.AttributeSet; import android.view.View; import android.widget.TextView; -import java.util.HashSet; +import java.util.HashMap; +import java.util.Map; import java.util.Set; /** This class implements the "extra keys" preference but also defines the @@ -100,14 +101,15 @@ public class ExtraKeysPreference extends PreferenceCategory } /** Get the set of enabled extra keys. */ - public static Set get_extra_keys(SharedPreferences prefs) + public static Map get_extra_keys(SharedPreferences prefs) { - HashSet ks = new HashSet(); + Map ks = + new HashMap(); for (String key_name : extra_keys) { if (prefs.getBoolean(pref_key_of_key_name(key_name), default_checked(key_name))) - ks.add(KeyValue.getKeyByName(key_name)); + ks.put(KeyValue.getKeyByName(key_name), KeyboardData.PreferredPos.DEFAULT); } return ks; } diff --git a/srcs/juloo.keyboard2/KeyboardData.java b/srcs/juloo.keyboard2/KeyboardData.java index 0083b38..94c1384 100644 --- a/srcs/juloo.keyboard2/KeyboardData.java +++ b/srcs/juloo.keyboard2/KeyboardData.java @@ -36,26 +36,68 @@ class KeyboardData return new KeyboardData(rows_, keysWidth, modmap, script); } - /** Add keys from the given iterator into the keyboard. Extra keys are added - * on the empty key4 corner of the second row, from right to left. If there's - * not enough room, key3 of the second row is tried then key2 and key1 of the - * third row. */ - public KeyboardData addExtraKeys(Iterator k) + /** Add keys from the given iterator into the keyboard. Preferred position is + specified via [PreferredPos]. */ + public KeyboardData addExtraKeys(Iterator> extra_keys) { + /* Keys that couldn't be placed at their preferred position. */ + ArrayList unplaced_keys = new ArrayList(); ArrayList rows = new ArrayList(this.rows); - addExtraKeys_to_row(rows, k, 1, 4); - addExtraKeys_to_row(rows, k, 1, 3); - addExtraKeys_to_row(rows, k, 2, 2); - addExtraKeys_to_row(rows, k, 2, 1); - if (k.hasNext()) + while (extra_keys.hasNext()) { - for (int r = 0; r < rows.size(); r++) - for (int c = 1; c <= 4; c++) - addExtraKeys_to_row(rows, k, r, c); + Map.Entry kp = extra_keys.next(); + if (!add_key_to_preferred_pos(rows, kp.getKey(), kp.getValue())) + unplaced_keys.add(kp.getKey()); } + for (KeyValue kv : unplaced_keys) + add_key_to_preferred_pos(rows, kv, PreferredPos.ANYWHERE); return new KeyboardData(rows, keysWidth, modmap, script); } + /** Place a key on the keyboard according to its preferred position. Mutates + [rows]. Returns [false] if it couldn't be placed. */ + boolean add_key_to_preferred_pos(List rows, KeyValue kv, PreferredPos pos) + { + for (KeyPos p : pos.positions) + if (add_key_to_pos(rows, kv, p)) + return true; + return false; + } + + /** Place a key on the keyboard. A value of [-1] in one of the coordinate + means that the key can be placed anywhere in that coordinate, see + [PreferredPos]. Mutates [rows]. Returns [false] if it couldn't be placed. + */ + boolean add_key_to_pos(List rows, KeyValue kv, KeyPos p) + { + int i_row = p.row; + int i_row_end = p.row; + if (p.row == -1) { i_row = 0; i_row_end = rows.size() - 1; } + for (; i_row <= i_row_end; i_row++) + { + Row row = rows.get(i_row); + int i_col = p.col; + int i_col_end = p.col; + if (p.col == -1) { i_col = 0; i_col_end = row.keys.size() - 1; } + for (; i_col <= i_col_end; i_col++) + { + Key col = row.keys.get(i_col); + int i_dir = p.dir; + int i_dir_end = p.dir; + if (p.dir == -1) { i_dir = 1; i_dir_end = 4; } + for (; i_dir <= i_dir_end; i_dir++) + { + if (col.getKeyValue(i_dir) == null) + { + row.keys.set(i_col, col.withKeyValue(i_dir, kv)); + return true; + } + } + } + } + return false; + } + public KeyboardData addNumPad(KeyboardData num_pad) { ArrayList extendedRows = new ArrayList(); @@ -107,20 +149,6 @@ class KeyboardData return _key_pos; } - private static void addExtraKeys_to_row(ArrayList rows, final Iterator extra_keys, int row_i, final int d) - { - if (!extra_keys.hasNext() || row_i >= rows.size()) - return; - rows.set(row_i, rows.get(row_i).mapKeys(new MapKey(){ - public Key apply(Key k) { - if (k.getKeyValue(d) == null && extra_keys.hasNext()) - return k.withKeyValue(d, extra_keys.next()); - else - return k; - } - })); - } - public static Row bottom_row; public static Row number_row; public static KeyboardData num_pad; @@ -263,6 +291,11 @@ class KeyboardData return new Row(keys, h, shift); } + public Row copy() + { + return new Row(new ArrayList(keys), height, shift); + } + public void getKeys(Map dst, int row) { for (int c = 0; c < keys.size(); c++) @@ -490,6 +523,36 @@ class KeyboardData } } + /** See [addExtraKeys()]. */ + public final static class PreferredPos + { + public static final PreferredPos DEFAULT; + public static final PreferredPos ANYWHERE; + + /** Array of positions to try in order. The special value [-1] as [row], + [col] or [dir] means that the field is unspecified. Every possible + values are tried for unspecified fields. Unspecified fields are + searched in this order: [dir], [col], [row]. */ + public KeyPos[] positions = ANYWHERE_POSITIONS; + + public PreferredPos() {} + + static final KeyPos[] ANYWHERE_POSITIONS = + new KeyPos[]{ new KeyPos(-1, -1, -1) }; + + static + { + DEFAULT = new PreferredPos(); + DEFAULT.positions = new KeyPos[]{ + new KeyPos(1, -1, 4), + new KeyPos(1, -1, 3), + new KeyPos(2, -1, 2), + new KeyPos(2, -1, 1) + }; + ANYWHERE = new PreferredPos(); + } + } + /** Parsing utils */ /** Returns [false] on [END_DOCUMENT] or [END_TAG], [true] otherwise. */