abouttreesummaryrefslogcommitdiff
path: root/srcs
diff options
context:
space:
mode:
Diffstat (limited to 'srcs')
-rw-r--r--srcs/juloo.keyboard2/KeyEventHandler.java116
-rw-r--r--srcs/juloo.keyboard2/KeyValue.java20
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);
}
}