diff options
| author | Jules Aguillon | 2026-05-02 19:32:21 +0200 |
|---|---|---|
| committer | GitHub | 2026-05-02 19:32:21 +0200 |
| commit | 9c23e6c5f3459240a87898762cbfa90cef766ad7 (patch) | |
| tree | 7b632f324e5d14431105ae87ea4e65dbda463d4f | |
| parent | d164820bca8d2182869108f8a015ce3d987d048d (diff) | |
| download | unexpected-keyboard-9c23e6c5f3459240a87898762cbfa90cef766ad7.tar.gz unexpected-keyboard-9c23e6c5f3459240a87898762cbfa90cef766ad7.zip | |
Emoji suggestion (#1235)
Suggest an emoji in addition to the 3 suggested words when the
current word matches an alias in the emoji dictionary, if
available.
| -rw-r--r-- | res/layout/keyboard.xml | 7 | ||||
| -rw-r--r-- | res/values/styles.xml | 11 | ||||
| -rw-r--r-- | srcs/juloo.keyboard2/Config.java | 1 | ||||
| -rw-r--r-- | srcs/juloo.keyboard2/KeyEventHandler.java | 4 | ||||
| -rw-r--r-- | srcs/juloo.keyboard2/Keyboard2.java | 7 | ||||
| -rw-r--r-- | srcs/juloo.keyboard2/suggestions/CandidatesView.java | 32 | ||||
| -rw-r--r-- | srcs/juloo.keyboard2/suggestions/Suggestions.java | 88 | ||||
| m--------- | vendor/cdict | 0 |
8 files changed, 100 insertions, 50 deletions
diff --git a/res/layout/keyboard.xml b/res/layout/keyboard.xml index 3fb611f..712c48a 100644 --- a/res/layout/keyboard.xml +++ b/res/layout/keyboard.xml @@ -1,9 +1,10 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:hardwareAccelerated="false" android:orientation="vertical" android:background="?attr/colorKeyboard"> <juloo.keyboard2.suggestions.CandidatesView android:id="@+id/candidates_view" style="@style/candidates_view"> - <TextView android:id="@+id/candidates_left" style="@style/candidates_item" android:layout_width="match_parent"/> - <TextView android:id="@+id/candidates_middle" style="@style/candidates_item" android:layout_width="match_parent"/> - <TextView android:id="@+id/candidates_right" style="@style/candidates_item" android:layout_width="match_parent"/> + <TextView android:id="@+id/candidates_emoji" style="@style/candidates_emoji"/> + <TextView android:id="@+id/candidates_left" style="@style/candidates_item"/> + <TextView android:id="@+id/candidates_middle" style="@style/candidates_item"/> + <TextView android:id="@+id/candidates_right" style="@style/candidates_item"/> </juloo.keyboard2.suggestions.CandidatesView> <juloo.keyboard2.Keyboard2View android:id="@+id/keyboard_view" android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout> diff --git a/res/values/styles.xml b/res/values/styles.xml index ce8894a..9963c9e 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -13,8 +13,19 @@ <item name="android:layout_weight">1</item> <item name="android:gravity">center</item> <item name="android:textColor">?attr/colorLabel</item> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">match_parent</item> + <item name="android:layout_weight">1</item> + <item name="android:textColor">?attr/colorLabel</item> <item name="android:maxLines">1</item> + </style> + <style name="candidates_emoji"> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">match_parent</item> + <item name="android:layout_marginLeft">12dp</item> + <item name="android:layout_weight">0</item> <item name="android:paddingHorizontal">@dimen/candidates_padding</item> + <item name="android:gravity">center</item> </style> <style name="candidates_status"> <item name="android:layout_width">match_parent</item> diff --git a/srcs/juloo.keyboard2/Config.java b/srcs/juloo.keyboard2/Config.java index 98bb72b..e4694e8 100644 --- a/srcs/juloo.keyboard2/Config.java +++ b/srcs/juloo.keyboard2/Config.java @@ -84,6 +84,7 @@ public final class Config public Map<KeyValue, KeyboardData.PreferredPos> extra_keys_param; public Map<KeyValue, KeyboardData.PreferredPos> extra_keys_custom; public Cdict current_dictionary = null; // Might be 'null'. + public Cdict emoji_dictionary = null; // Might be 'null'. public IKeyEventHandler handler; public boolean orientation_landscape = false; public boolean foldable_unfolded = false; diff --git a/srcs/juloo.keyboard2/KeyEventHandler.java b/srcs/juloo.keyboard2/KeyEventHandler.java index 66a10df..78a4095 100644 --- a/srcs/juloo.keyboard2/KeyEventHandler.java +++ b/srcs/juloo.keyboard2/KeyEventHandler.java @@ -532,10 +532,10 @@ public final class KeyEventHandler /** Implement autocorrect when enabled in the settings. */ void handle_space_bar() { - if (_space_bar_auto_complete && _suggestions.best_suggestion != null + if (_space_bar_auto_complete && _suggestions.count > 0 && !_typedword.is_selection_not_empty() && _typedword.cursor_relative() == 0) - suggestion_entered(_suggestions.best_suggestion); + suggestion_entered(_suggestions.suggestions[0]); else send_text(" "); } diff --git a/srcs/juloo.keyboard2/Keyboard2.java b/srcs/juloo.keyboard2/Keyboard2.java index d0d6047..137103e 100644 --- a/srcs/juloo.keyboard2/Keyboard2.java +++ b/srcs/juloo.keyboard2/Keyboard2.java @@ -23,11 +23,12 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; +import juloo.cdict.Cdict; import juloo.keyboard2.dict.Dictionaries; import juloo.keyboard2.dict.DictionariesActivity; import juloo.keyboard2.prefs.LayoutsPreference; import juloo.keyboard2.suggestions.CandidatesView; -import juloo.cdict.Cdict; +import juloo.keyboard2.suggestions.Suggestions; public class Keyboard2 extends InputMethodService implements SharedPreferences.OnSharedPreferenceChangeListener @@ -173,6 +174,7 @@ public class Keyboard2 extends InputMethodService private void refresh_current_dictionary() { _config.current_dictionary = null; + _config.emoji_dictionary = null; String current = _device_locales.default_.dictionary; if (current == null) return; @@ -180,6 +182,7 @@ public class Keyboard2 extends InputMethodService if (dicts == null) return; _config.current_dictionary = Dictionaries.find_by_name(dicts, "main"); + _config.emoji_dictionary = Dictionaries.find_by_name(dicts, "emoji"); } private void refresh_candidates_view() @@ -490,7 +493,7 @@ public class Keyboard2 extends InputMethodService return _handler; } - public void set_suggestions(List<String> suggestions) + public void set_suggestions(Suggestions suggestions) { _candidates_view.set_candidates(suggestions); } diff --git a/srcs/juloo.keyboard2/suggestions/CandidatesView.java b/srcs/juloo.keyboard2/suggestions/CandidatesView.java index 6eba62a..5485ccf 100644 --- a/srcs/juloo.keyboard2/suggestions/CandidatesView.java +++ b/srcs/juloo.keyboard2/suggestions/CandidatesView.java @@ -17,10 +17,12 @@ import juloo.keyboard2.R; public class CandidatesView extends LinearLayout { - static final int NUM_CANDIDATES = 3; + static final int NUM_CANDIDATES = 4; /** Candidates currently visible. Entries can be [null] when there are less - than [NUM_CANDIDATES] suggestions. */ + than [NUM_CANDIDATES] suggestions. + - Entries at indexes [0] to [2] are word suggestions. + - Entry at index [3] is the emoji suggestion. */ String[] _items = new String[NUM_CANDIDATES]; /** Text views showing the candidates in [_items]. Text views visibility is @@ -43,35 +45,45 @@ public class CandidatesView extends LinearLayout setup_item_view(0, R.id.candidates_middle); setup_item_view(1, R.id.candidates_right); setup_item_view(2, R.id.candidates_left); + setup_item_view(3, R.id.candidates_emoji); } - public void set_candidates(List<String> suggestions) + public void set_candidates(Suggestions s) { - int s_count = suggestions.size(); + int s_count = s.count; + for (int i = 0; i < Suggestions.MAX_COUNT; i++) + _items[i] = (i < s_count) ? s.suggestions[i] : null; + _items[3] = s.emoji_suggestion; // Hide the status message when showing candidates. if (s_count != 0 && _status_no_dict != null) _status_no_dict.setVisibility(View.GONE); for (int i = 0; i < _item_views.length; i++) { TextView v = _item_views[i]; - if (i < s_count) + if (_items[i] != null) { - String it = suggestions.get(i); - _items[i] = it; - v.setText(it); + v.setText(_items[i]); v.setVisibility(View.VISIBLE); } else { - _items[i] = null; v.setVisibility(View.GONE); } } } + public void clear_candidates() + { + for (int i = 0; i < _item_views.length; i++) + { + _items[i] = null; + _item_views[i].setVisibility(View.GONE); + } + } + public void refresh_config(Config config) { - set_candidates(Suggestions.NO_SUGGESTIONS); + clear_candidates(); // The status message indicates whether the dictionaries should be // installed. _status_no_dict = inflate_and_show(_status_no_dict, diff --git a/srcs/juloo.keyboard2/suggestions/Suggestions.java b/srcs/juloo.keyboard2/suggestions/Suggestions.java index 41a7941..f72257b 100644 --- a/srcs/juloo.keyboard2/suggestions/Suggestions.java +++ b/srcs/juloo.keyboard2/suggestions/Suggestions.java @@ -16,9 +16,14 @@ public final class Suggestions Config _config; boolean _enabled; - /** The suggestion displayed at the center of the candidates view and entered - by the space bar. */ - public String best_suggestion = null; + /** Current suggestions. The best suggestion is at index [0]. */ + public String[] suggestions = new String[MAX_COUNT]; + /** Number of suggestions at the beginning of the [suggestions] array that + are not [null]. */ + public int count = 0; + public String emoji_suggestion = null; + /** Number of suggestions in [suggestions]. */ + public static final int MAX_COUNT = 3; public Suggestions(Callback c, Config conf) { @@ -29,55 +34,74 @@ public final class Suggestions public void started() { _enabled = _config.editor_config.should_show_candidates_view; - best_suggestion = null; + clear(); } public void currently_typed_word(String word) { if (!_enabled) return; - Cdict dict = _config.current_dictionary; - if (word.length() < 2 || dict == null) - { - set_suggestions(NO_SUGGESTIONS); - } + if (word.length() < 2 || _config.current_dictionary == null) + clear(); else - { - String[] dst = new String[3]; - query_suggestions(dict, word, dst, 3); - set_suggestions(Arrays.asList(dst)); - } + query_suggestions(word); + set_suggestions(); + } + + void clear() + { + count = 0; + suggestions[0] = null; + emoji_suggestion = null; } - int query_suggestions(Cdict dict, String word, String[] dst, int max_count) + int query_suggestions(String word) { + Cdict dict = _config.current_dictionary; boolean first_char_upper = Character.isUpperCase(word.charAt(0)); word = apply_substitutions(word); Cdict.Result r = dict.find(word); int i = 0; if (r.found) - dst[i++] = dict.word(r.index); - int[] suffixes = dict.suffixes(r, max_count); + suggestions[i++] = dict.word(r.index); + int[] suffixes = dict.suffixes(r, MAX_COUNT); // Disable distance search for small words - int[] dist = (word.length() < 3 || i + 1 >= max_count) ? NO_RESULTS : - dict.distance(word, 1, max_count); - for (int j = 0; j < max_count && i < max_count; j++) + int[] dist = (word.length() < 3 || i + 1 >= MAX_COUNT) ? NO_RESULTS : + dict.distance(word, 1, MAX_COUNT); + for (int j = 0; j < MAX_COUNT && i < MAX_COUNT; j++) { if (suffixes.length > j) - dst[i++] = dict.word(suffixes[j]); - if (dist.length > j && i < max_count) - dst[i++] = dict.word(dist[j]); + suggestions[i++] = dict.word(suffixes[j]); + if (dist.length > j && i < MAX_COUNT) + suggestions[i++] = dict.word(dist[j]); } if (first_char_upper) - capitalize_results(dst); + capitalize_results(); + emoji_suggestion = query_emoji(word); // word with substitutions applied + count = i; return i; } - void capitalize_results(String[] rs) + void capitalize_results() { - for (int i = 0; i < rs.length; i++) - if (rs[i] != null) - rs[i] = rs[i].substring(0, 1).toUpperCase() + rs[i].substring(1); + for (int i = 0; i < count; i++) + suggestions[i] = suggestions[i].substring(0, 1).toUpperCase() + + suggestions[i].substring(1); + } + + String query_emoji(String word) + { + Cdict dict = _config.emoji_dictionary; + // Disable emoji suggestion for short words + if (dict == null || word.length() < 3) + return null; + Cdict.Result r = dict.find(word); + if (r.found) + return dict.word(r.index); + int[] s = dict.suffixes(r, 1); + if (s.length > 0) + return dict.word(s[0]); + return null; } /** Apply the same substitutions that were used when building the @@ -96,17 +120,15 @@ public final class Suggestions return b.toString(); } - void set_suggestions(List<String> ws) + void set_suggestions() { - _callback.set_suggestions(ws); - best_suggestion = (ws.size() > 0) ? ws.get(0) : null; + _callback.set_suggestions(this); } - static final List<String> NO_SUGGESTIONS = Arrays.asList(); static final int[] NO_RESULTS = new int[0]; public static interface Callback { - public void set_suggestions(List<String> suggestions); + public void set_suggestions(Suggestions suggestions); } } diff --git a/vendor/cdict b/vendor/cdict -Subproject 0b772b9db9762a141afbb18cc14d407a8fb3b2b +Subproject 4e29981795f6d143337511108f4e030269f3fab |
