From 3f42c61ead715884ac6b1f85c0b6054ff437646d Mon Sep 17 00:00:00 2001 From: Javier Date: Thu, 1 Nov 2018 13:01:39 +0100 Subject: Initial import --- .../com/javispedro/vndroid/KeyEventOutput.java | 286 +++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 app/src/main/java/com/javispedro/vndroid/KeyEventOutput.java (limited to 'app/src/main/java/com/javispedro/vndroid/KeyEventOutput.java') diff --git a/app/src/main/java/com/javispedro/vndroid/KeyEventOutput.java b/app/src/main/java/com/javispedro/vndroid/KeyEventOutput.java new file mode 100644 index 0000000..597942a --- /dev/null +++ b/app/src/main/java/com/javispedro/vndroid/KeyEventOutput.java @@ -0,0 +1,286 @@ +package com.javispedro.vndroid; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.util.Log; +import android.view.accessibility.AccessibilityNodeInfo; + +import com.javispedro.vndroid.keymaps.KeyActionHandler; +import com.javispedro.vndroid.keymaps.KeyHandler; + +import java.util.ArrayList; +import java.util.List; + +public class KeyEventOutput implements KeyActionHandler { + private final String TAG = KeyEventOutput.class.getSimpleName(); + + private final List handlers = new ArrayList(); + + @Nullable + private AccessibilityNodeInfo getFocusNode() { + ControlService service = ControlService.getInstance(); + if (service != null) { + return service.findFocus(AccessibilityNodeInfo.FOCUS_INPUT); + } + return null; + } + + public void addHandler(KeyHandler handler) { + handler.setActionHandler(this); + handlers.add(handler); + } + + public void postKeyEvent(int key, boolean state) { + if (state) Log.d(TAG, "keysym pressed: " + Integer.toHexString(key)); + for (KeyHandler handler : handlers) { + boolean handled; + if (state) { + handled = handler.keyDown(key); + } else { + handled = handler.keyUp(key); + } + if (handled) { + break; + } + } + } + + @Override + public void postText(CharSequence text) { + AccessibilityNodeInfo node = getFocusNode(); + if (node == null || !node.isEditable()) { + Log.d(TAG, "no input focus or not editable"); + return; + } + + final CharSequence curText = node.getText(); + final int curTextLen = curText != null ? curText.length() : 0; + final int textLen = text.length(); + int selStart = node.getTextSelectionStart(); + int selEnd = node.getTextSelectionEnd(); + StringBuilder builder = new StringBuilder(curTextLen + textLen); + + Log.d(TAG, " cur text: " + curText + " start=" + selStart + " end=" + selEnd); + + if (selStart == -1 || selEnd == -1 || curTextLen == 0) { + // No selection, no cursor + if (curTextLen > 0) builder.append(curText); + builder.append(text); + } else { + builder.append(curText.subSequence(0, selStart)); + builder.append(text); + builder.append(curText.subSequence(selEnd, curText.length())); + + selStart = selEnd + textLen; + selEnd = selStart; + } + + Log.d(TAG, " new text: " + builder.toString() + " start=" + selStart + " end=" + selEnd); + + Bundle args = new Bundle(); + args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, + builder.toString()); + node.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args); + + if (selStart != -1 && selEnd != -1 && selStart != builder.length()) { + args = new Bundle(); + args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, selStart); + args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, selEnd); + node.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, args); + } + } + + @Override + public void postChar(char c) { + AccessibilityNodeInfo node = getFocusNode(); + if (node == null || !node.isEditable()) { + Log.d(TAG, "no input focus or not editable"); + return; + } + + final CharSequence curText = node.getText(); + final int curTextLen = curText != null ? curText.length() : 0; + int selStart = node.getTextSelectionStart(); + int selEnd = node.getTextSelectionEnd(); + StringBuilder builder = new StringBuilder(curTextLen + 1); + + Log.d(TAG, " cur text: " + curText + " start=" + selStart + " end=" + selEnd); + + if (selStart == -1 || selEnd == -1 || curTextLen == 0) { + // No selection, no cursor + if (curTextLen > 0) builder.append(curText); + builder.append(c); + } else { + builder.append(curText.subSequence(0, selStart)); + builder.append(c); + builder.append(curText.subSequence(selEnd, curText.length())); + + selStart = selEnd + 1; + selEnd = selStart; + } + + Log.d(TAG, " new text: " + builder.toString() + " start=" + selStart + " end=" + selEnd); + + Bundle args = new Bundle(); + args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, + builder.toString()); + node.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args); + + if (selStart != -1 && selEnd != -1 && selStart != builder.length()) { + args = new Bundle(); + args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, selStart); + args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, selEnd); + node.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, args); + } + } + + @Override + public void postLocalAction(int action) { + AccessibilityNodeInfo node = getFocusNode(); + if (node == null || !node.isEditable()) { + Log.d(TAG, "no input focus or not editable"); + return; + } + + final CharSequence curText = node.getText(); + final int curTextLen = curText != null ? curText.length() : 0; + int selStart = node.getTextSelectionStart(); + int selEnd = node.getTextSelectionEnd(); + StringBuilder builder = null; + + Log.d(TAG, " cur text: " + curText + " start=" + selStart + " end=" + selEnd); + + switch (action) { + case KeyActionHandler.ACTION_BACKSPACE: + if (selStart == -1 || selEnd == -1 || curTextLen == 0) { + return; + } + builder = new StringBuilder(curTextLen - 1); + if (selStart == selEnd && selStart > 0) { + builder.append(curText.subSequence(0, selStart - 1)); + builder.append(curText.subSequence(selEnd, curTextLen)); + selStart = selStart - 1; + selEnd = selStart; + } else if (selStart != selEnd) { + builder.append(curText.subSequence(0, selStart)); + builder.append(curText.subSequence(selEnd, curTextLen)); + selEnd = selStart; + } else { + return; + } + break; + case KeyActionHandler.ACTION_DEL: + if (selStart == -1 || selEnd == -1 || curTextLen == 0) { + return; + } + builder = new StringBuilder(curTextLen - 1); + if (selStart == selEnd && selStart < curTextLen) { + builder.append(curText.subSequence(0, selStart)); + builder.append(curText.subSequence(selEnd + 1, curTextLen)); + selStart = selStart; + selEnd = selStart; + } else if (selStart != selEnd) { + builder.append(curText.subSequence(0, selStart)); + builder.append(curText.subSequence(selEnd, curTextLen)); + selEnd = selStart; + } else { + return; + } + break; + case KeyActionHandler.ACTION_MOVE_LEFT: + if (selStart == -1 || selEnd == -1 || curTextLen == 0) { + return; + } + if (selStart > 0) { + selStart = selStart - 1; + selEnd = selStart; + } else { + return; + } + break; + case KeyActionHandler.ACTION_MOVE_RIGHT: + if (selStart == -1 || selEnd == -1 || curTextLen == 0) { + return; + } + if (selEnd < curTextLen) { + selStart = selEnd + 1; + selEnd = selStart; + } else { + return; + } + break; + case KeyActionHandler.ACTION_MOVE_LEFTMOST: + selStart = 0; + selEnd = 0; + break; + case KeyActionHandler.ACTION_MOVE_RIGHTMOST: + if (curTextLen == 0) { + return; + } + selStart = curTextLen; + selEnd = curTextLen; + break; + case KeyActionHandler.ACTION_SELECT_LEFT: + if (selStart == -1 || selEnd == -1 || curTextLen == 0) { + return; + } + if (selStart > 0) { + selStart = selStart - 1; + } else { + return; + } + break; + case KeyActionHandler.ACTION_SELECT_RIGHT: + if (selStart == -1 || selEnd == -1 || curTextLen == 0) { + return; + } + if (selEnd < curTextLen) { + selEnd = selEnd + 1; + } else { + return; + } + break; + case KeyActionHandler.ACTION_SELECT_LEFTMOST: + selStart = 0; + break; + case KeyActionHandler.ACTION_SELECT_RIGHTMOST: + if (curTextLen == 0) { + return; + } + selEnd = curTextLen; + break; + default: + return; + } + + if (builder != null) { + Log.d(TAG, " new text: " + builder.toString() + " start=" + selStart + " end=" + selEnd); + } else { + Log.d(TAG, " new start=" + selStart + " end=" + selEnd); + } + + if (builder != null && builder.toString() != curText) { + Bundle args = new Bundle(); + args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, + builder.toString()); + node.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args); + } + + if (selStart != -1 && selEnd != -1 && (builder == null || selStart != builder.length())) { + Bundle args = new Bundle(); + args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, selStart); + args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, selEnd); + node.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, args); + } + } + + @Override + public void postGlobalAction(int action) { + ControlService service = ControlService.getInstance(); + if (service != null) { + if (!service.performGlobalAction(action)) { + Log.e(TAG, "could not perform global action: " + action); + } + } + } +} -- cgit v1.2.3