diff --git a/srcs/juloo.keyboard2/Config.java b/srcs/juloo.keyboard2/Config.java index 9c31a6f..4680f46 100644 --- a/srcs/juloo.keyboard2/Config.java +++ b/srcs/juloo.keyboard2/Config.java @@ -5,14 +5,9 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.util.DisplayMetrics; 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; import juloo.keyboard2.prefs.CustomExtraKeysPreference; import juloo.keyboard2.prefs.ExtraKeysPreference; import juloo.keyboard2.prefs.LayoutsPreference; @@ -28,10 +23,6 @@ public final class Config public final float labelTextSize; public final float sublabelTextSize; - public final KeyboardData.Row bottom_row; - public final KeyboardData.Row number_row; - public final KeyboardData num_pad; - // From preferences /** [null] represent the [system] layout. */ public List layouts; @@ -94,16 +85,6 @@ public final class Config keyPadding = res.getDimension(R.dimen.key_padding); labelTextSize = 0.33f; sublabelTextSize = 0.22f; - try - { - number_row = KeyboardData.load_number_row(res); - bottom_row = KeyboardData.load_bottom_row(res); - num_pad = KeyboardData.load_num_pad(res); - } - catch (Exception e) - { - throw new RuntimeException(e.getMessage()); // Not recoverable - } // from prefs refresh(res); // initialized later @@ -216,190 +197,6 @@ public final class Config _prefs.edit().putBoolean("clipboard_history_enabled", e).commit(); } - KeyValue action_key() - { - // Update the name to avoid caching in KeyModifier - return (actionLabel == null) ? null : KeyValue.makeActionKey(actionLabel); - } - - /** Update the layout according to the configuration. - * - Remove the switching key if it isn't needed - * - Remove "localized" keys from other locales (not in 'extra_keys') - * - Replace the action key to show the right label - * - Swap the enter and action keys - * - Add the optional numpad and number row - * - Add the extra keys - */ - public KeyboardData modify_layout(KeyboardData kw) - { - 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 Map extra_keys = new HashMap(); - final Set remove_keys = new HashSet(); - // Make sure the config key is accessible to avoid being locked in a custom - // layout. - extra_keys.put(KeyValue.getKeyByName("config"), KeyboardData.PreferredPos.ANYWHERE); - extra_keys.putAll(extra_keys_param); - extra_keys.putAll(extra_keys_custom); - if (extra_keys_subtype != null && kw.locale_extra_keys) - { - Set present = new HashSet(); - present.addAll(kw.getKeys().keySet()); - present.addAll(extra_keys_param.keySet()); - present.addAll(extra_keys_custom.keySet()); - extra_keys_subtype.compute(extra_keys, - new ExtraKeys.Query(kw.script, present)); - } - KeyboardData.Row added_number_row = null; - if (add_number_row && !show_numpad) - added_number_row = modify_number_row(number_row, kw); - if (added_number_row != null) - remove_keys.addAll(added_number_row.getKeys(0).keySet()); - if (kw.bottom_row) - kw = kw.insert_row(bottom_row, kw.rows.size()); - kw = kw.mapKeys(new KeyboardData.MapKeyValues() { - public KeyValue apply(KeyValue key, boolean localized) - { - boolean is_extra_key = extra_keys.containsKey(key); - if (is_extra_key) - extra_keys.remove(key); - if (localized && !is_extra_key) - return null; - if (remove_keys.contains(key)) - return null; - switch (key.getKind()) - { - case Event: - switch (key.getEvent()) - { - case CHANGE_METHOD_PICKER: - if (switch_input_immediate) - return KeyValue.getKeyByName("change_method_prev"); - return key; - case ACTION: - return (swapEnterActionKey && action_key != null) ? - KeyValue.getKeyByName("enter") : action_key; - case SWITCH_FORWARD: - return (layouts.size() > 1) ? key : null; - case SWITCH_BACKWARD: - return (layouts.size() > 2) ? key : null; - case SWITCH_VOICE_TYPING: - case SWITCH_VOICE_TYPING_CHOOSER: - return shouldOfferVoiceTyping ? key : null; - } - break; - case Keyevent: - switch (key.getKeyevent()) - { - case KeyEvent.KEYCODE_ENTER: - return (swapEnterActionKey && action_key != null) ? action_key : key; - } - break; - case Modifier: - switch (key.getModifier()) - { - case SHIFT: - if (double_tap_lock_shift) - return key.withFlags(key.getFlags() | KeyValue.FLAG_LOCK); - } - break; - } - return key; - } - }); - if (show_numpad) - kw = kw.addNumPad(modify_numpad(num_pad, kw)); - if (extra_keys.size() > 0) - kw = kw.addExtraKeys(extra_keys.entrySet().iterator()); - if (added_number_row != null) - kw = kw.insert_row(added_number_row, 0); - return kw; - } - - /** Handle the numpad layout. The [main_kw] is used to adapt the numpad to - the main layout's script. */ - public KeyboardData modify_numpad(KeyboardData kw, KeyboardData main_kw) - { - final KeyValue action_key = action_key(); - final int map_digit = KeyModifier.modify_numpad_script(main_kw.numpad_script); - return kw.mapKeys(new KeyboardData.MapKeyValues() { - public KeyValue apply(KeyValue key, boolean localized) - { - switch (key.getKind()) - { - case Event: - switch (key.getEvent()) - { - case ACTION: - return (swapEnterActionKey && action_key != null) ? - KeyValue.getKeyByName("enter") : action_key; - } - break; - case Keyevent: - switch (key.getKeyevent()) - { - case KeyEvent.KEYCODE_ENTER: - return (swapEnterActionKey && action_key != null) ? action_key : key; - } - break; - case Char: - char prev_c = key.getChar(); - char c = prev_c; - if (inverse_numpad) - c = inverse_numpad_char(c); - if (map_digit != -1) - { - KeyValue modified = ComposeKey.apply(map_digit, c); - if (modified != null) // Was modified by script - return modified; - } - if (prev_c != c) // Was inverted - return key.withChar(c); - break; - } - return key; - } - }); - } - - static KeyboardData.MapKeyValues numpad_script_map(String numpad_script) - { - final int map_digit = KeyModifier.modify_numpad_script(numpad_script); - if (map_digit == -1) - return null; - return new KeyboardData.MapKeyValues() { - public KeyValue apply(KeyValue key, boolean localized) - { - switch (key.getKind()) - { - case Char: - KeyValue modified = ComposeKey.apply(map_digit, key.getChar()); - if (modified != null) - return modified; - break; - } - return key; - } - }; - } - - /** Modify the pin entry layout. [main_kw] is used to map the digits into the - same script. */ - public KeyboardData modify_pinentry(KeyboardData kw, KeyboardData main_kw) - { - KeyboardData.MapKeyValues m = numpad_script_map(main_kw.numpad_script); - return m == null ? kw : kw.mapKeys(m); - } - - /** Modify the number row according to [main_kw]'s script. */ - public KeyboardData.Row modify_number_row(KeyboardData.Row row, - KeyboardData main_kw) - { - KeyboardData.MapKeyValues m = numpad_script_map(main_kw.numpad_script); - return m == null ? row : row.mapKeys(m); - } - private float get_dip_pref(DisplayMetrics dm, String pref_name, float def) { float value; @@ -446,20 +243,6 @@ public final class Config } } - char inverse_numpad_char(char c) - { - switch (c) - { - case '7': return '1'; - case '8': return '2'; - case '9': return '3'; - case '1': return '7'; - case '2': return '8'; - case '3': return '9'; - default: return c; - } - } - private static Config _globalConfig = null; public static void initGlobalConfig(SharedPreferences prefs, Resources res, @@ -467,6 +250,7 @@ public final class Config { migrate(prefs); _globalConfig = new Config(prefs, res, handler); + LayoutModifier.init(_globalConfig, res); } public static Config globalConfig() diff --git a/srcs/juloo.keyboard2/Keyboard2.java b/srcs/juloo.keyboard2/Keyboard2.java index 201449d..1179c73 100644 --- a/srcs/juloo.keyboard2/Keyboard2.java +++ b/srcs/juloo.keyboard2/Keyboard2.java @@ -62,7 +62,7 @@ public class Keyboard2 extends InputMethodService { if (_currentSpecialLayout != null) return _currentSpecialLayout; - return _config.modify_layout(current_layout_unmodified()); + return LayoutModifier.modify_layout(current_layout_unmodified()); } void setTextLayout(int l) @@ -92,13 +92,13 @@ public class Keyboard2 extends InputMethodService /** Load a layout that contains a numpad. */ KeyboardData loadNumpad(int layout_id) { - return _config.modify_numpad(KeyboardData.load(getResources(), layout_id), + return LayoutModifier.modify_numpad(KeyboardData.load(getResources(), layout_id), current_layout_unmodified()); } KeyboardData loadPinentry(int layout_id) { - return _config.modify_pinentry(KeyboardData.load(getResources(), layout_id), + return LayoutModifier.modify_pinentry(KeyboardData.load(getResources(), layout_id), current_layout_unmodified()); } diff --git a/srcs/juloo.keyboard2/LayoutModifier.java b/srcs/juloo.keyboard2/LayoutModifier.java new file mode 100644 index 0000000..1e49914 --- /dev/null +++ b/srcs/juloo.keyboard2/LayoutModifier.java @@ -0,0 +1,217 @@ +package juloo.keyboard2; + +import android.content.res.Resources; +import android.view.KeyEvent; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public final class LayoutModifier +{ + static Config globalConfig; + static KeyboardData.Row bottom_row; + static KeyboardData.Row number_row; + static KeyboardData num_pad; + + /** Update the layout according to the configuration. + * - Remove the switching key if it isn't needed + * - Remove "localized" keys from other locales (not in 'extra_keys') + * - Replace the action key to show the right label + * - Swap the enter and action keys + * - Add the optional numpad and number row + * - Add the extra keys + */ + public static KeyboardData modify_layout(KeyboardData kw) + { + // Extra keys are removed from the set as they are encountered during the + // first iteration then automatically added. + final Map extra_keys = new HashMap(); + final Set remove_keys = new HashSet(); + // Make sure the config key is accessible to avoid being locked in a custom + // layout. + extra_keys.put(KeyValue.getKeyByName("config"), KeyboardData.PreferredPos.ANYWHERE); + extra_keys.putAll(globalConfig.extra_keys_param); + extra_keys.putAll(globalConfig.extra_keys_custom); + if (globalConfig.extra_keys_subtype != null && kw.locale_extra_keys) + { + Set present = new HashSet(); + present.addAll(kw.getKeys().keySet()); + present.addAll(globalConfig.extra_keys_param.keySet()); + present.addAll(globalConfig.extra_keys_custom.keySet()); + globalConfig.extra_keys_subtype.compute(extra_keys, + new ExtraKeys.Query(kw.script, present)); + } + KeyboardData.Row added_number_row = null; + if (globalConfig.add_number_row && !globalConfig.show_numpad) + added_number_row = modify_number_row(number_row, kw); + if (added_number_row != null) + remove_keys.addAll(added_number_row.getKeys(0).keySet()); + if (kw.bottom_row) + kw = kw.insert_row(bottom_row, kw.rows.size()); + kw = kw.mapKeys(new KeyboardData.MapKeyValues() { + public KeyValue apply(KeyValue key, boolean localized) + { + boolean is_extra_key = extra_keys.containsKey(key); + if (is_extra_key) + extra_keys.remove(key); + if (localized && !is_extra_key) + return null; + if (remove_keys.contains(key)) + return null; + return modify_key(key); + } + }); + if (globalConfig.show_numpad) + kw = kw.addNumPad(modify_numpad(num_pad, kw)); + if (extra_keys.size() > 0) + kw = kw.addExtraKeys(extra_keys.entrySet().iterator()); + if (added_number_row != null) + kw = kw.insert_row(added_number_row, 0); + return kw; + } + + /** Handle the numpad layout. The [main_kw] is used to adapt the numpad to + the main layout's script. */ + public static KeyboardData modify_numpad(KeyboardData kw, KeyboardData main_kw) + { + final int map_digit = KeyModifier.modify_numpad_script(main_kw.numpad_script); + return kw.mapKeys(new KeyboardData.MapKeyValues() { + public KeyValue apply(KeyValue key, boolean localized) + { + switch (key.getKind()) + { + case Char: + char prev_c = key.getChar(); + char c = prev_c; + if (globalConfig.inverse_numpad) + c = inverse_numpad_char(c); + if (map_digit != -1) + { + KeyValue modified = ComposeKey.apply(map_digit, c); + if (modified != null) // Was modified by script + return modified; + } + if (prev_c != c) // Was inverted + return key.withChar(c); + return key; // Don't fallback into [modify_key] + } + return modify_key(key); + } + }); + } + + /** Modify the pin entry layout. [main_kw] is used to map the digits into the + same script. */ + public static KeyboardData modify_pinentry(KeyboardData kw, KeyboardData main_kw) + { + KeyboardData.MapKeyValues m = numpad_script_map(main_kw.numpad_script); + return m == null ? kw : kw.mapKeys(m); + } + + /** Modify the number row according to [main_kw]'s script. */ + static KeyboardData.Row modify_number_row(KeyboardData.Row row, + KeyboardData main_kw) + { + KeyboardData.MapKeyValues m = numpad_script_map(main_kw.numpad_script); + return m == null ? row : row.mapKeys(m); + } + + static KeyboardData.MapKeyValues numpad_script_map(String numpad_script) + { + final int map_digit = KeyModifier.modify_numpad_script(numpad_script); + if (map_digit == -1) + return null; + return new KeyboardData.MapKeyValues() { + public KeyValue apply(KeyValue key, boolean localized) + { + switch (key.getKind()) + { + case Char: + KeyValue modified = ComposeKey.apply(map_digit, key.getChar()); + if (modified != null) + return modified; + break; + } + return key; + } + }; + } + + /** Modify keys on the main layout and on the numpad according to the config. + */ + static KeyValue modify_key(KeyValue orig) + { + switch (orig.getKind()) + { + case Event: + switch (orig.getEvent()) + { + case CHANGE_METHOD_PICKER: + if (globalConfig.switch_input_immediate) + return KeyValue.getKeyByName("change_method_prev"); + break; + case ACTION: + if (globalConfig.swapEnterActionKey && globalConfig.actionLabel != null) + return KeyValue.getKeyByName("enter"); + return KeyValue.makeActionKey(globalConfig.actionLabel); + case SWITCH_FORWARD: + return (globalConfig.layouts.size() > 1) ? orig : null; + case SWITCH_BACKWARD: + return (globalConfig.layouts.size() > 2) ? orig : null; + case SWITCH_VOICE_TYPING: + case SWITCH_VOICE_TYPING_CHOOSER: + return globalConfig.shouldOfferVoiceTyping ? orig : null; + } + break; + case Keyevent: + switch (orig.getKeyevent()) + { + case KeyEvent.KEYCODE_ENTER: + if (globalConfig.swapEnterActionKey && globalConfig.actionLabel != null) + return KeyValue.makeActionKey(globalConfig.actionLabel); + break; + } + break; + case Modifier: + switch (orig.getModifier()) + { + case SHIFT: + if (globalConfig.double_tap_lock_shift) + return orig.withFlags(orig.getFlags() | KeyValue.FLAG_LOCK); + break; + } + break; + } + return orig; + } + + static char inverse_numpad_char(char c) + { + switch (c) + { + case '7': return '1'; + case '8': return '2'; + case '9': return '3'; + case '1': return '7'; + case '2': return '8'; + case '3': return '9'; + default: return c; + } + } + + public static void init(Config globalConfig_, Resources res) + { + globalConfig = globalConfig_; + try + { + number_row = KeyboardData.load_number_row(res); + bottom_row = KeyboardData.load_bottom_row(res); + num_pad = KeyboardData.load_num_pad(res); + } + catch (Exception e) + { + throw new RuntimeException(e.getMessage()); // Not recoverable + } + } +}