Created
July 26, 2019 19:15
-
-
Save mzorz/54d3c5bc8ac2f979f8a8368b6bbdb23c to your computer and use it in GitHub Desktop.
InputConnectionWrapper used for logging
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.wordpress.aztec.ime; | |
/** | |
* Copyright (c) Facebook, Inc. and its affiliates. | |
* | |
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root | |
* directory of this source tree. | |
*/ | |
import android.view.KeyEvent; | |
import android.view.inputmethod.EditorInfo; | |
import android.view.inputmethod.InputConnection; | |
import android.view.inputmethod.InputConnectionWrapper; | |
import org.wordpress.android.util.AppLog; | |
import org.wordpress.aztec.AztecText; | |
/** | |
* A class to implement the TextInput 'onKeyPress' API on android for soft keyboards. It is | |
* instantiated in {@link ReactEditText#onCreateInputConnection(EditorInfo)}. | |
* | |
* <p>Android IMEs interface with EditText views through the {@link InputConnection} interface, so | |
* any observable change in state of the EditText via the soft-keyboard, should be a side effect of | |
* one or more of the methods in {@link InputConnectionWrapper}. | |
* | |
* <p>{@link InputConnection#setComposingText(CharSequence, int)} is used to set the composing | |
* region (the underlined text) in the {@link android.widget.EditText} view, i.e. when React | |
* Native's TextInput has the property 'autoCorrect' set to true. When text is being composed in the | |
* composing state within the EditText, each key press will result in a call to {@link | |
* InputConnection#setComposingText(CharSequence, int)} with a CharSequence argument equal to that | |
* of the entire composing region, rather than a single character diff. We can reason about the | |
* keyPress based on the resultant cursor position changes of the EditText after applying this | |
* change. For example if the cursor moved backwards by one character when composing, it's likely it | |
* was a delete; if it moves forward by a character, likely to be a key press of that character. | |
* | |
* <p>IMEs can also call {@link InputConnection#beginBatchEdit()} to signify a batch of operations. | |
* One such example is committing a word currently in composing state with the press of the space | |
* key. It is IME dependent but the stock Android keyboard behavior seems to be to commit the | |
* currently composing text with {@link InputConnection#setComposingText(CharSequence, int)} and | |
* commits a space character with a separate call to {@link | |
* InputConnection#setComposingText(CharSequence, int)}. Here we chose to emit the last input of a | |
* batch edit as that tends to be the user input, but it's completely arbitrary. | |
* | |
* <p>Another function of this class is to detect backspaces when the cursor at the beginning of the | |
* {@link android.widget.EditText}, i.e no text is deleted. | |
* | |
* <p>N.B. this class is only applicable for soft keyboards behavior. For hardware keyboards {@link | |
* android.view.View#onKeyDown(int, KeyEvent)} can be overridden to obtain the keycode of the key | |
* pressed. | |
*/ | |
public class AztecTextInputConnectionWrapper extends InputConnectionWrapper{ | |
public static final String NEWLINE_RAW_VALUE = "\n"; | |
public static final String BACKSPACE_KEY_VALUE = "Backspace"; | |
public static final String ENTER_KEY_VALUE = "Enter"; | |
private AztecText mEditText; | |
private boolean mIsBatchEdit; | |
private String mKey = null; | |
public AztecTextInputConnectionWrapper( | |
InputConnection target, final AztecText aztecText) { | |
super(target, false); | |
mEditText = aztecText; | |
AppLog.e(AppLog.T.EDITOR, "ATICW constructor"); | |
} | |
@Override | |
public boolean beginBatchEdit() { | |
mIsBatchEdit = true; | |
AppLog.e(AppLog.T.EDITOR, "ATICW beginBatchEdit"); | |
return super.beginBatchEdit(); | |
} | |
@Override | |
public boolean endBatchEdit() { | |
mIsBatchEdit = false; | |
if (mKey != null) { | |
AppLog.e(AppLog.T.EDITOR, "ATICW endBatchEdit: " + mKey); | |
mKey = null; | |
} else { | |
AppLog.e(AppLog.T.EDITOR, "ATICW endBatchEdit: (null)"); | |
} | |
return super.endBatchEdit(); | |
} | |
@Override | |
public boolean setComposingText(CharSequence text, int newCursorPosition) { | |
int previousSelectionStart = mEditText.getSelectionStart(); | |
int previousSelectionEnd = mEditText.getSelectionEnd(); | |
AppLog.e(AppLog.T.EDITOR, "ATICW setComposingText: newCursorPosition: " + newCursorPosition + " - text: " + text); | |
AppLog.e(AppLog.T.EDITOR, "ATICW setComposingText: previousSelectionStart: " + previousSelectionStart + " - previousSelectionEnd: " + previousSelectionEnd); | |
String key; | |
boolean consumed = super.setComposingText(text, newCursorPosition); | |
AppLog.e(AppLog.T.EDITOR, "ATICW setComposingText: consumed: " + consumed); | |
int currentSelectionStart = mEditText.getSelectionStart(); | |
AppLog.e(AppLog.T.EDITOR, "ATICW setComposingText: currentSelectionStart: " + currentSelectionStart); | |
boolean noPreviousSelection = previousSelectionStart == previousSelectionEnd; | |
boolean cursorDidNotMove = currentSelectionStart == previousSelectionStart; | |
boolean cursorMovedBackwardsOrAtBeginningOfInput = | |
(currentSelectionStart < previousSelectionStart) || currentSelectionStart <= 0; | |
AppLog.e(AppLog.T.EDITOR, "ATICW setComposingText: noPreviousSelection: " + noPreviousSelection); | |
AppLog.e(AppLog.T.EDITOR, "ATICW setComposingText: cursorDidNotMove: " + cursorDidNotMove); | |
AppLog.e(AppLog.T.EDITOR, "ATICW setComposingText: cursorMovedBackwardsOrAtBeginningOfInput: " + cursorMovedBackwardsOrAtBeginningOfInput); | |
if (cursorMovedBackwardsOrAtBeginningOfInput || (!noPreviousSelection && cursorDidNotMove)) { | |
AppLog.e(AppLog.T.EDITOR, "ATICW setComposingText: KEY is: (BACKSPACE)"); | |
key = BACKSPACE_KEY_VALUE; | |
} else { | |
key = String.valueOf(mEditText.getText().charAt(currentSelectionStart - 1)); | |
AppLog.e(AppLog.T.EDITOR, "ATICW setComposingText: KEY is: " + key); | |
} | |
return consumed; | |
} | |
@Override | |
public boolean commitText(CharSequence text, int newCursorPosition) { | |
String key = text.toString(); | |
AppLog.e(AppLog.T.EDITOR, "ATICW commitText: newCursorPosition: " + newCursorPosition + " - text: " + text + " - key.length(): " + key.length()); | |
// FIXME TEST CODE | |
int previousSelectionStart = mEditText.getSelectionStart(); | |
int previousSelectionEnd = mEditText.getSelectionEnd(); | |
AppLog.e(AppLog.T.EDITOR, "ATICW commitText: newCursorPosition: " + newCursorPosition + " - text: " + text); | |
AppLog.e(AppLog.T.EDITOR, "ATICW commitText: previousSelectionStart: " + previousSelectionStart + " - previousSelectionEnd: " + previousSelectionEnd); | |
// Assume not a keyPress if length > 1 (or 2 if unicode) | |
if (key.length() <= 2) { | |
if (key.equals("")) { | |
key = BACKSPACE_KEY_VALUE; | |
AppLog.e(AppLog.T.EDITOR, "ATICW commitText: assuming BACKSPACE_KEY_VALUE"); | |
} | |
} | |
//return super.commitText(text, newCursorPosition); | |
boolean result = super.commitText(text, newCursorPosition); | |
int currentSelectionStart = mEditText.getSelectionStart(); | |
AppLog.e(AppLog.T.EDITOR, "ATICW commitText: currentSelectionStart: " + currentSelectionStart); | |
// FIXME test CORRECTOR | |
if (currentSelectionStart == previousSelectionStart && newCursorPosition > 0) { | |
// if cursor did not advance, despite newCursorPosition being different than zero, let's make it advance | |
// otherwise it will be left pointing to a wrong position | |
AppLog.e(AppLog.T.EDITOR, "ATICW commitText: ABOUT TO SET SELECTION: " + previousSelectionStart+newCursorPosition); | |
mEditText.setSelection(previousSelectionStart+newCursorPosition); | |
AppLog.e(AppLog.T.EDITOR, "ATICW commitText: AFTER SET SELECTION: " + mEditText.getSelectionStart()); | |
} | |
boolean noPreviousSelection = previousSelectionStart == previousSelectionEnd; | |
boolean cursorDidNotMove = currentSelectionStart == previousSelectionStart; | |
boolean cursorMovedBackwardsOrAtBeginningOfInput = | |
(currentSelectionStart < previousSelectionStart) || currentSelectionStart <= 0; | |
AppLog.e(AppLog.T.EDITOR, "ATICW commitText: noPreviousSelection: " + noPreviousSelection); | |
AppLog.e(AppLog.T.EDITOR, "ATICW commitText: cursorDidNotMove: " + cursorDidNotMove); | |
AppLog.e(AppLog.T.EDITOR, "ATICW commitText: cursorMovedBackwardsOrAtBeginningOfInput: " + cursorMovedBackwardsOrAtBeginningOfInput); | |
return result; | |
} | |
// @Override | |
// public boolean commitText(CharSequence text, int newCursorPosition) { | |
// String key = text.toString(); | |
// AppLog.e(AppLog.T.EDITOR, "ATICW commitText: newCursorPosition: " + newCursorPosition + " - text: " + text + " - key.length(): " + key.length()); | |
// | |
// // Assume not a keyPress if length > 1 (or 2 if unicode) | |
// if (key.length() <= 2) { | |
// if (key.equals("")) { | |
// key = BACKSPACE_KEY_VALUE; | |
// AppLog.e(AppLog.T.EDITOR, "ATICW commitText: assuming BACKSPACE_KEY_VALUE"); | |
// } | |
// dispatchKeyEventOrEnqueue(key); | |
// } | |
// | |
// return super.commitText(text, newCursorPosition); | |
// } | |
@Override | |
public boolean deleteSurroundingText(int beforeLength, int afterLength) { | |
AppLog.e(AppLog.T.EDITOR, "ATICW deleteSurroundingText: beforeLength: " + beforeLength + " afterLength: " + afterLength); | |
return super.deleteSurroundingText(beforeLength, afterLength); | |
} | |
// Called by SwiftKey when cursor at beginning of input when there is a delete | |
// or when enter is pressed anywhere in the text. Whereas stock Android Keyboard calls | |
// {@link InputConnection#deleteSurroundingText} & {@link InputConnection#commitText} | |
// in each case, respectively. | |
@Override | |
public boolean sendKeyEvent(KeyEvent event) { | |
AppLog.e(AppLog.T.EDITOR, "ATICW sendKeyEvent: event: " + event); | |
return super.sendKeyEvent(event); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment