diff options
Diffstat (limited to 'srcs')
| -rw-r--r-- | srcs/juloo.keyboard2/KeyEventHandler.java | 116 | ||||
| -rw-r--r-- | srcs/juloo.keyboard2/KeyValue.java | 20 |
2 files changed, 104 insertions, 32 deletions
diff --git a/srcs/juloo.keyboard2/KeyEventHandler.java b/srcs/juloo.keyboard2/KeyEventHandler.java index 36f6819..97a6cd0 100644 --- a/srcs/juloo.keyboard2/KeyEventHandler.java +++ b/srcs/juloo.keyboard2/KeyEventHandler.java @@ -3,6 +3,8 @@ package juloo.keyboard2; import android.os.Looper; import android.view.KeyEvent; import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.ExtractedText; +import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; class KeyEventHandler implements Config.IKeyEventHandler @@ -39,33 +41,9 @@ class KeyEventHandler implements Config.IKeyEventHandler case Char: send_text(String.valueOf(key.getChar())); break; case String: send_text(key.getString()); break; case Event: _recv.handle_event_key(key.getEvent()); break; - case Keyevent: - handleKeyUpWithModifier(key.getKeyevent(), mods); - break; - case Modifier: - break; - case Editing: - send_context_menu_action(action_of_editing_key(key.getEditing())); - break; - } - } - - static int action_of_editing_key(KeyValue.Editing e) - { - switch (e) - { - case COPY: return android.R.id.copy; - case PASTE: return android.R.id.paste; - case CUT: return android.R.id.cut; - case SELECT_ALL: return android.R.id.selectAll; - case SHARE: return android.R.id.shareText; - case PASTE_PLAIN: return android.R.id.pasteAsPlainText; - case UNDO: return android.R.id.undo; - case REDO: return android.R.id.redo; - case REPLACE: return android.R.id.replaceText; - case ASSIST: return android.R.id.textAssist; - case AUTOFILL: return android.R.id.autofill; - default: return -1; // sad + case Keyevent: send_key_down_up(key.getKeyevent(), mods); break; + case Modifier: break; + case Editing: handle_editing_key(key.getEditing(), mods); break; } } @@ -108,7 +86,7 @@ class KeyEventHandler implements Config.IKeyEventHandler /* * Don't set KeyEvent.FLAG_SOFT_KEYBOARD. */ - void handleKeyUpWithModifier(int keyCode, Pointers.Modifiers mods) + void send_key_down_up(int keyCode, Pointers.Modifiers mods) { int metaState = 0; for (int i = 0; i < mods.size(); i++) @@ -147,6 +125,88 @@ class KeyEventHandler implements Config.IKeyEventHandler conn.performContextMenuAction(id); } + void handle_editing_key(KeyValue.Editing ev, Pointers.Modifiers mods) + { + switch (ev) + { + case COPY: send_context_menu_action(android.R.id.copy); break; + case PASTE: send_context_menu_action(android.R.id.paste); break; + case CUT: send_context_menu_action(android.R.id.cut); break; + case SELECT_ALL: send_context_menu_action(android.R.id.selectAll); break; + case SHARE: send_context_menu_action(android.R.id.shareText); break; + case PASTE_PLAIN: send_context_menu_action(android.R.id.pasteAsPlainText); break; + case UNDO: send_context_menu_action(android.R.id.undo); break; + case REDO: send_context_menu_action(android.R.id.redo); break; + case REPLACE: send_context_menu_action(android.R.id.replaceText); break; + case ASSIST: send_context_menu_action(android.R.id.textAssist); break; + case AUTOFILL: send_context_menu_action(android.R.id.autofill); break; + case CURSOR_LEFT: move_cursor(-1, mods); break; + case CURSOR_RIGHT: move_cursor(1, mods); break; + } + } + + static ExtractedTextRequest _move_cursor_req = null; + + /** Query the cursor position. The extracted text is empty. Returns [null] if + the editor doesn't support this operation. */ + ExtractedText get_cursor_pos(InputConnection conn) + { + if (_move_cursor_req == null) + { + _move_cursor_req = new ExtractedTextRequest(); + _move_cursor_req.hintMaxChars = 0; + } + return conn.getExtractedText(_move_cursor_req, 0); + } + + /** Move the cursor right or left, if possible without sending key events. + Unlike arrow keys, the selection is not removed even if shift is not on. */ + void move_cursor(int d, Pointers.Modifiers mods) + { + InputConnection conn = _recv.getCurrentInputConnection(); + if (conn == null) + return; + ExtractedText et = get_cursor_pos(conn); + if (et == null) // Editor doesn't support moving the cursor + { + move_cursor_fallback(d, mods); + return; + } + int sel_start = et.selectionStart; + int sel_end = et.selectionEnd; + // Continue expanding the selection even if shift is not pressed + if (sel_end != sel_start) + { + sel_end += d; + if (sel_end == sel_start) // Avoid making the selection empty + sel_end += d; + } + else + { + sel_end += d; + // Leave 'sel_start' where it is if shift is pressed + if (!mods.has(KeyValue.Modifier.SHIFT)) + sel_start = sel_end; + } + conn.setSelection(sel_start, sel_end); + } + + /** Send arrow keys as a fallback for editors that do not support + [getExtractedText] like Termux. */ + void move_cursor_fallback(int d, Pointers.Modifiers mods) + { + while (d < 0) + { + send_key_down_up(KeyEvent.KEYCODE_DPAD_LEFT, mods); + d++; + } + while (d > 0) + { + send_key_down_up(KeyEvent.KEYCODE_DPAD_RIGHT, mods); + d--; + } + } + public static interface IReceiver { public void handle_event_key(KeyValue.Event ev); diff --git a/srcs/juloo.keyboard2/KeyValue.java b/srcs/juloo.keyboard2/KeyValue.java index fe55b6d..0972214 100644 --- a/srcs/juloo.keyboard2/KeyValue.java +++ b/srcs/juloo.keyboard2/KeyValue.java @@ -70,6 +70,8 @@ final class KeyValue SHARE, ASSIST, AUTOFILL, + CURSOR_LEFT, + CURSOR_RIGHT, } public static enum Placeholder @@ -321,6 +323,7 @@ final class KeyValue case "\\@": return makeStringKey("@"); case "\\\\": return makeStringKey("\\"); + /* Modifiers and dead-keys */ case "shift": return modifierKey(0xE00A, Modifier.SHIFT, 0); case "ctrl": return modifierKey("Ctrl", Modifier.CTRL, 0); case "alt": return modifierKey("Alt", Modifier.ALT, 0); @@ -351,6 +354,7 @@ final class KeyValue case "fn": return modifierKey("Fn", Modifier.FN, 0); case "meta": return modifierKey("Meta", Modifier.META, 0); + /* Special event keys */ case "config": return eventKey(0xE004, Event.CONFIG, FLAG_SMALLER_FONT); case "switch_text": return eventKey("ABC", Event.SWITCH_TEXT, FLAG_SMALLER_FONT); case "switch_numeric": return eventKey("123+", Event.SWITCH_NUMERIC, FLAG_SMALLER_FONT); @@ -365,6 +369,7 @@ final class KeyValue case "capslock": return eventKey(0xE012, Event.CAPS_LOCK, 0); case "voice_typing": return eventKey(0xE015, Event.SWITCH_VOICE_TYPING, FLAG_SMALLER_FONT); + /* Key events */ case "esc": return keyeventKey("Esc", KeyEvent.KEYCODE_ESCAPE, FLAG_SMALLER_FONT); case "enter": return keyeventKey(0xE00E, KeyEvent.KEYCODE_ENTER, 0); case "up": return keyeventKey(0xE005, KeyEvent.KEYCODE_DPAD_UP, 0); @@ -392,6 +397,7 @@ final class KeyValue case "f12": return keyeventKey("F12", KeyEvent.KEYCODE_F12, FLAG_SMALLER_FONT); case "tab": return keyeventKey(0xE00F, KeyEvent.KEYCODE_TAB, FLAG_SMALLER_FONT); + /* Spaces */ case "\\t": return charKey("\\t", '\t', 0); // Send the tab character case "space": return charKey("\r", ' ', FLAG_KEY_FONT | FLAG_SECONDARY); case "nbsp": return charKey("\u237d", '\u00a0', FLAG_SMALLER_FONT); @@ -408,10 +414,6 @@ final class KeyValue case "blt": return charKey("<", '>', 0); case "bgt": return charKey(">", '<', 0); - case "removed": return placeholderKey(Placeholder.REMOVED); - case "f11_placeholder": return placeholderKey(Placeholder.F11); - case "f12_placeholder": return placeholderKey(Placeholder.F12); - /* hebrew niqqud */ case "qamats": return charKey("\u05E7\u05B8", '\u05B8', 0); // kamatz case "patah": return charKey("\u05E4\u05B7", '\u05B7', 0); // patach @@ -443,6 +445,7 @@ final class KeyValue case "zwj": return charKey("zwj", '\u200D', 0); // zero-width joiner (provides ligature) case "zwnj": return charKey("zwnj", '\u200C', 0); // zero-width non joiner (prevents unintended ligature) + /* Editing keys */ case "copy": return editingKey(0xE030, Editing.COPY); case "paste": return editingKey(0xE032, Editing.PASTE); case "cut": return editingKey(0xE031, Editing.CUT); @@ -454,6 +457,15 @@ final class KeyValue case "replaceText": return editingKey("repl", Editing.REPLACE); case "textAssist": return editingKey(0xE038, Editing.ASSIST); case "autofill": return editingKey("auto", Editing.AUTOFILL); + case "cursor_left": return editingKey(0xE008, Editing.CURSOR_LEFT); + case "cursor_right": return editingKey(0xE006, Editing.CURSOR_RIGHT); + + /* Placeholder keys */ + case "removed": return placeholderKey(Placeholder.REMOVED); + case "f11_placeholder": return placeholderKey(Placeholder.F11); + case "f12_placeholder": return placeholderKey(Placeholder.F12); + + /* Fallback to a string key that types its name */ default: return makeStringKey(name); } } |
