added support for Termux
This commit is contained in:
parent
e45744e0b4
commit
5314ed1320
4 changed files with 111 additions and 48 deletions
|
|
@ -36,7 +36,7 @@ import io.github.sspanak.tt9.ui.tray.SuggestionsBar;
|
|||
public class TraditionalT9 extends KeyPadHandler {
|
||||
// internal settings/data
|
||||
private boolean isActive = false;
|
||||
@NonNull private AppHacks appHacks = new AppHacks(null, null);
|
||||
@NonNull private AppHacks appHacks = new AppHacks(null,null, null, null);
|
||||
@NonNull private TextField textField = new TextField(null, null);
|
||||
@NonNull private InputType inputType = new InputType(null, null);
|
||||
@NonNull private final Handler autoAcceptHandler = new Handler(Looper.getMainLooper());
|
||||
|
|
@ -204,9 +204,9 @@ public class TraditionalT9 extends KeyPadHandler {
|
|||
protected void onStart(EditorInfo input) {
|
||||
inputType = new InputType(currentInputConnection, input);
|
||||
textField = new TextField(currentInputConnection, input);
|
||||
appHacks = new AppHacks(input, textField);
|
||||
appHacks = new AppHacks(settings, currentInputConnection, input, textField);
|
||||
|
||||
if (!inputType.isValid() || inputType.isLimited()) {
|
||||
if (!inputType.isValid() || (inputType.isLimited() && !appHacks.isTermux())) {
|
||||
// When the input is invalid or simple, let Android handle it.
|
||||
onStop();
|
||||
return;
|
||||
|
|
@ -245,14 +245,11 @@ public class TraditionalT9 extends KeyPadHandler {
|
|||
|
||||
|
||||
public boolean onBackspace() {
|
||||
if (appHacks.onBackspace(mInputMode)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 1. Dialer fields seem to handle backspace on their own and we must ignore it,
|
||||
// otherwise, keyDown race condition occur for all keys.
|
||||
// 2. Allow the assigned key to function normally, when there is no text (e.g. "Back" navigates back)
|
||||
if (mInputMode.isPassthrough() || !textField.isThereText()) {
|
||||
// 3. Some app may need special treatment, so let it be.
|
||||
if (mInputMode.isPassthrough() || !(textField.isThereText() || appHacks.onBackspace(mInputMode))) {
|
||||
Logger.d("onBackspace", "backspace ignored");
|
||||
mInputMode.reset();
|
||||
return false;
|
||||
|
|
@ -317,7 +314,8 @@ public class TraditionalT9 extends KeyPadHandler {
|
|||
cancelAutoAccept();
|
||||
|
||||
if (isSuggestionViewHidden()) {
|
||||
return performOKAction();
|
||||
int action = textField.getAction();
|
||||
return action == TextField.IME_ACTION_ENTER ? appHacks.onEnter() : textField.performAction(action);
|
||||
}
|
||||
|
||||
acceptCurrentSuggestion(KeyEvent.KEYCODE_ENTER);
|
||||
|
|
@ -741,41 +739,6 @@ public class TraditionalT9 extends KeyPadHandler {
|
|||
}
|
||||
|
||||
|
||||
private boolean performOKAction() {
|
||||
if (currentInputConnection == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int action = textField.getAction();
|
||||
switch (action) {
|
||||
case EditorInfo.IME_ACTION_NONE:
|
||||
return false;
|
||||
case TextField.IME_ACTION_ENTER:
|
||||
String oldText = textField.getTextBeforeCursor() + textField.getTextAfterCursor();
|
||||
|
||||
sendDownUpKeyEvents(KeyEvent.KEYCODE_DPAD_CENTER);
|
||||
|
||||
try {
|
||||
// In Android there is no strictly defined confirmation key, hence DPAD_CENTER may have done nothing.
|
||||
// If so, send an alternative key code as a final resort.
|
||||
Thread.sleep(80);
|
||||
String newText = textField.getTextBeforeCursor() + textField.getTextAfterCursor();
|
||||
if (newText.equals(oldText)) {
|
||||
sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
// This thread got interrupted. Assume it's because the connected application has taken an action
|
||||
// after receiving DPAD_CENTER, so we don't need to do anything else.
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
default:
|
||||
return currentInputConnection.performEditorAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* createSoftKeyView
|
||||
* Generates the actual UI of TT9.
|
||||
|
|
|
|||
|
|
@ -1,27 +1,51 @@
|
|||
package io.github.sspanak.tt9.ime.helpers;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import io.github.sspanak.tt9.ime.modes.InputMode;
|
||||
import io.github.sspanak.tt9.preferences.SettingsStore;
|
||||
|
||||
public class AppHacks {
|
||||
private final EditorInfo editorInfo;
|
||||
private final InputConnection inputConnection;
|
||||
private final SettingsStore settings;
|
||||
private final TextField textField;
|
||||
|
||||
|
||||
public AppHacks(EditorInfo inputField, TextField textField) {
|
||||
public AppHacks(SettingsStore settings, InputConnection inputConnection, EditorInfo inputField, TextField textField) {
|
||||
this.editorInfo = inputField;
|
||||
this.inputConnection = inputConnection;
|
||||
this.settings = settings;
|
||||
this.textField = textField;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* isKindleInvertedTextField
|
||||
* When sharing a document to the Amazon Kindle app. It displays a screen where one could edit the title and the author of the
|
||||
* document. These two fields do not support SpannableString, which is used for suggestion highlighting. When they receive one
|
||||
* weird side effects occur. Nevertheless, all other text fields in the app are fine, so we detect only these two particular ones.
|
||||
*/
|
||||
private boolean isKindleInvertedTextField() {
|
||||
return editorInfo != null && editorInfo.inputType == 1 && editorInfo.packageName.contains("com.amazon.kindle");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* isTermux
|
||||
* Termux is a terminal emulator and it naturally has a text input, but it incorrectly introduces itself as having a NULL input,
|
||||
* instead of a plain text input. However NULL inputs are usually, buttons and dropdown menus, which indeed can not read text
|
||||
* and are ignored by TT9 by default. In order not to ignore Termux, we need this.
|
||||
*/
|
||||
public boolean isTermux() {
|
||||
return editorInfo != null && editorInfo.inputType == 0 && editorInfo.fieldId > 0 && editorInfo.packageName.contains("com.termux");
|
||||
}
|
||||
|
||||
|
||||
public boolean setComposingTextWithHighlightedStem(@NonNull String word) {
|
||||
if (isKindleInvertedTextField()) {
|
||||
textField.setComposingText(word);
|
||||
|
|
@ -31,12 +55,76 @@ public class AppHacks {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* onBackspace
|
||||
* Performs extra Backspace operations and returns "false", or completely replaces Backspace and returns "true". When "true" is
|
||||
* returned, you must not attempt to delete text. This function has already done everything necessary.
|
||||
*/
|
||||
public boolean onBackspace(InputMode inputMode) {
|
||||
if (isKindleInvertedTextField()) {
|
||||
inputMode.clearWordStem();
|
||||
return true;
|
||||
} else if (isTermux()) {
|
||||
return settings.getKeyBackspace() != KeyEvent.KEYCODE_BACK;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* onEnter
|
||||
* Tries to guess and send the correct confirmation key code or sequence of key codes, depending on the connected application
|
||||
* and input field. On invalid connection or field, it does nothing.
|
||||
* This hack applies to all applications, not only selected ones.
|
||||
*/
|
||||
public boolean onEnter() {
|
||||
if (isTermux()) {
|
||||
sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
|
||||
return true;
|
||||
}
|
||||
|
||||
return onEnterDefault();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* onEnterDefault
|
||||
* This is the default "ENTER" routine for most applications that support send-with-enter functionality. It will attempt to
|
||||
* guess and send the correct confirmation key code, be it "ENTER" or "DPAD_CENTER".
|
||||
* On invalid textField, it does nothing.
|
||||
*/
|
||||
private boolean onEnterDefault() {
|
||||
if (textField == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String oldText = textField.getTextBeforeCursor() + textField.getTextAfterCursor();
|
||||
|
||||
sendDownUpKeyEvents(KeyEvent.KEYCODE_DPAD_CENTER);
|
||||
|
||||
try {
|
||||
// In Android there is no strictly defined confirmation key, hence DPAD_CENTER may have done nothing.
|
||||
// If so, send an alternative key code as a final resort.
|
||||
Thread.sleep(80);
|
||||
String newText = textField.getTextBeforeCursor() + textField.getTextAfterCursor();
|
||||
if (newText.equals(oldText)) {
|
||||
sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
// This thread got interrupted. Assume it's because the connected application has taken an action
|
||||
// after receiving DPAD_CENTER, so we don't need to do anything else.
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void sendDownUpKeyEvents(int keyCode) {
|
||||
if (inputConnection != null) {
|
||||
inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
|
||||
inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -309,7 +309,10 @@ public class TextField {
|
|||
return styledWord;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* getAction
|
||||
* Returns the most appropriate action for the "OK" key. It could be "send", "act as ENTER key", "go (to URL)" and so on.
|
||||
*/
|
||||
public int getAction() {
|
||||
if (field == null) {
|
||||
return EditorInfo.IME_ACTION_NONE;
|
||||
|
|
@ -333,4 +336,13 @@ public class TextField {
|
|||
return IME_ACTION_ENTER;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* performAction
|
||||
* Sends an action ID to the connected application. Usually, the action is determined with "this.getAction()".
|
||||
* Note that it is up to the app to decide what to do or ignore the action ID.
|
||||
*/
|
||||
public boolean performAction(int actionId) {
|
||||
return connection != null && actionId != EditorInfo.IME_ACTION_NONE && connection.performEditorAction(actionId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue