From 463beaf170db8c4c58ce40fd07798c3293c42f0d Mon Sep 17 00:00:00 2001 From: Emil Kosz Date: Tue, 22 Oct 2024 13:42:40 +0200 Subject: [PATCH] Don't remember --- .../cfpi_fpsi/eu/titanboard/InputMethod.java | 110 +++++++++++++----- .../cfpi_fpsi/eu/titanboard/SymbolCycler.java | 10 +- .../cfpi_fpsi/eu/titanboard/SymbolsView.java | 35 ++++++ app/src/main/res/drawable/triangle.xml | 27 +++++ app/src/main/res/layout/symbols.xml | 56 +++++++++ app/src/main/res/values/bools.xml | 2 +- app/src/main/res/values/strings.xml | 4 +- app/src/main/res/values/styles.xml | 9 ++ app/src/main/res/xml/keymaps_titan.xml | 26 ++++- app/src/main/res/xml/preferences.xml | 63 +++++----- 10 files changed, 274 insertions(+), 68 deletions(-) create mode 100644 app/src/main/java/cfpi_fpsi/eu/titanboard/SymbolsView.java create mode 100644 app/src/main/res/drawable/triangle.xml create mode 100644 app/src/main/res/layout/symbols.xml diff --git a/app/src/main/java/cfpi_fpsi/eu/titanboard/InputMethod.java b/app/src/main/java/cfpi_fpsi/eu/titanboard/InputMethod.java index 28eef4c..1761a8b 100644 --- a/app/src/main/java/cfpi_fpsi/eu/titanboard/InputMethod.java +++ b/app/src/main/java/cfpi_fpsi/eu/titanboard/InputMethod.java @@ -28,22 +28,23 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; // TODO: Implement auto-correct. -// TODO: Implement auto-caps. // TODO: Implement device recognition and a keymap picking based on it. +// TODO: Mode without the bottom input view, in case the user does not care about completions. +// This will involve making a popup screen and a shortcut for changing languages. -/** - * - */ public class InputMethod extends InputMethodService { public MetaKeyManager mMetaKeyManager; public KeymapManager mKeymapManager; public InputView mInputView; public Settings mSettings; + public int mCurrentCursorPosition; private SymbolCycler mSymbolCycler; private long mLastKeyTime; - private int mRegularKeyPressed = -1; + private int mSymbolPressed; @Override public void onCreate() { @@ -75,12 +76,6 @@ public class InputMethod extends InputMethodService { mMetaKeyManager.updateMetaStateDown(keyCode); mInputView.updateStateText(); - InputConnection conn = getCurrentInputConnection(); - - if (conn == null) { - return false; - } - switch (keyCode) { case KeyEvent.KEYCODE_BACK: if (isInputViewShown()) { @@ -93,13 +88,7 @@ public class InputMethod extends InputMethodService { mMetaKeyManager.adjustMetaStateAfterKeypress(); return false; case KeyEvent.KEYCODE_SPACE: - if (mSettings.isCyclingWithSpaceEnabled() && mRegularKeyPressed != -1 - && event.getEventTime() - mLastKeyTime > 200) { - mSymbolCycler.cycle(); - } else { - conn.commitText(" ", 1); - mMetaKeyManager.adjustMetaStateAfterKeypress(); - } + handleSpacebar(event); return true; default: ArrayList symbols = mKeymapManager.getSymbols(keyCode, mMetaKeyManager); @@ -109,11 +98,13 @@ public class InputMethod extends InputMethodService { } if (event.getRepeatCount() == 0 && !symbols.isEmpty()) { - conn.commitText(symbols.get(0), 1); - mRegularKeyPressed = keyCode; + getCurrentInputConnection().commitText(symbols.get(0), 1); + mMetaKeyManager.adjustMetaStateAfterKeypress(); + mInputView.updateStateText(); + mSymbolPressed = keyCode; mLastKeyTime = event.getEventTime(); mSymbolCycler.stopCycling(); - mSymbolCycler.startCycling(symbols, conn); + mSymbolCycler.startCycling(symbols, getCurrentInputConnection()); if (!mSettings.isCyclingWithSpaceEnabled()) { mSymbolCycler.startAutomaticCycling(); } @@ -123,27 +114,86 @@ public class InputMethod extends InputMethodService { } } + public void handleSpacebar(KeyEvent event) { + InputConnection conn = getCurrentInputConnection(); + + if (mSettings.isCyclingWithSpaceEnabled() + && mSymbolPressed != -1 && event.getEventTime() - mLastKeyTime > 200) { + mSymbolCycler.cycle(); + return; + } + + if (mSettings.isAutoPeriodsEnabled()) { + String text = getTextBeforeCursor(2); + + if (!text.isEmpty()) { + Pattern pattern = Pattern.compile("[^\\.… ]+ $"); + Matcher matcher = pattern.matcher(text); + if (matcher.find()) { + // InputConnection.replaceSelection needs a higher API, so we just do exactly + // what it does to support more devices. + conn.finishComposingText(); + conn.setSelection(mCurrentCursorPosition - 1, mCurrentCursorPosition); + conn.commitText(".", 1); + } + } + } + + conn.commitText(" ", 1); + mMetaKeyManager.adjustMetaStateAfterKeypress(); + } + public boolean onKeyUp(int keyCode, KeyEvent event) { - if (mRegularKeyPressed == keyCode) { - mMetaKeyManager.adjustMetaStateAfterKeypress(); + if (mSymbolPressed == keyCode) { + mSymbolPressed = -1; mSymbolCycler.stopCycling(); - mRegularKeyPressed = -1; mInputView.updateSymbolsView(null, 0); } - InputConnection conn = getCurrentInputConnection(); - - if (conn == null) { - return false; + // TODO: Not ideal. Should be handled on key down ideally. + if (keyCode == KeyEvent.KEYCODE_DEL) { + detectAutoCapitalization(); } - conn.finishComposingText(); + getCurrentInputConnection().finishComposingText(); mMetaKeyManager.updateMetaStateUp(keyCode, event); mInputView.updateStateText(); return false; } + @Override + public void onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd, + int candidatesStart, int candidatesEnd) { + mCurrentCursorPosition = newSelStart; + detectAutoCapitalization(); + } + + public String getTextBeforeCursor(int n) { + CharSequence chars = getCurrentInputConnection().getTextBeforeCursor(n, 0); + return chars == null ? "" : String.valueOf(chars); + } + + public void detectAutoCapitalization() { + if (!mSettings.isAutoCapsEnabled()) { + return; + } + // Get a bunch of text, run a regex through it, and bam. Is there a better way to do this? + String text = getTextBeforeCursor(16); + if (text.isEmpty()) { + mMetaKeyManager.getShift().setLatched(true); + mInputView.updateStateText(); + } else { + // If, on the other hand, we have some characters before the cursor, we scan. + Pattern pattern = Pattern.compile("[\\.…\\!\\?] +$"); + Matcher matcher = pattern.matcher(text); + if (matcher.find()) { + mMetaKeyManager.getShift().setLatched(true); + mInputView.updateStateText(); + } + } + } + @Override public View onCreateInputView() { return mInputView; @@ -152,6 +202,8 @@ public class InputMethod extends InputMethodService { @Override public void onStartInput(EditorInfo info, boolean restarting) { super.onStartInput(info, restarting); + + detectAutoCapitalization(); mKeymapManager.checkCurrentKeymap(mSettings.getSelectedKeymaps()); mInputView.updateStateText(); } diff --git a/app/src/main/java/cfpi_fpsi/eu/titanboard/SymbolCycler.java b/app/src/main/java/cfpi_fpsi/eu/titanboard/SymbolCycler.java index 1c262a7..f98c690 100644 --- a/app/src/main/java/cfpi_fpsi/eu/titanboard/SymbolCycler.java +++ b/app/src/main/java/cfpi_fpsi/eu/titanboard/SymbolCycler.java @@ -22,8 +22,6 @@ package cfpi_fpsi.eu.titanboard; import android.content.Context; import android.os.Handler; import android.os.Looper; -import android.view.inputmethod.ExtractedText; -import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; import java.util.ArrayList; @@ -55,7 +53,6 @@ public class SymbolCycler extends Handler { removeCallbacks(mRunnable); } - public void cycle() { mIndex++; if (mIndex == mSymbols.size()) { @@ -63,11 +60,8 @@ public class SymbolCycler extends Handler { } mInputMethod.mInputView.updateSymbolsView(mSymbols, mIndex); - ExtractedText text = mConn.getExtractedText(new ExtractedTextRequest(), 0); - if (text != null) { - mConn.setComposingRegion(text.selectionStart - 1, text.selectionStart); - mConn.setComposingText(mSymbols.get(mIndex), 1); - } + mConn.setComposingRegion(mInputMethod.mCurrentCursorPosition - 1, mInputMethod.mCurrentCursorPosition); + mConn.setComposingText(mSymbols.get(mIndex), 1); } private class SymbolCyclerRunnable implements Runnable { diff --git a/app/src/main/java/cfpi_fpsi/eu/titanboard/SymbolsView.java b/app/src/main/java/cfpi_fpsi/eu/titanboard/SymbolsView.java new file mode 100644 index 0000000..d3a0423 --- /dev/null +++ b/app/src/main/java/cfpi_fpsi/eu/titanboard/SymbolsView.java @@ -0,0 +1,35 @@ +/* + * An input method for the Unihertz Titan/physical keyboard phones + * Copyright (C) 2024 Emil Kosz + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package cfpi_fpsi.eu.titanboard; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.RelativeLayout; + +public class SymbolsView extends RelativeLayout { + public SymbolsView(Context context, AttributeSet attrs) { + super(context, attrs, 0); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + } +} diff --git a/app/src/main/res/drawable/triangle.xml b/app/src/main/res/drawable/triangle.xml new file mode 100644 index 0000000..ab389cf --- /dev/null +++ b/app/src/main/res/drawable/triangle.xml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/app/src/main/res/layout/symbols.xml b/app/src/main/res/layout/symbols.xml new file mode 100644 index 0000000..c44c667 --- /dev/null +++ b/app/src/main/res/layout/symbols.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/bools.xml b/app/src/main/res/values/bools.xml index cdc9cb6..b2e739f 100644 --- a/app/src/main/res/values/bools.xml +++ b/app/src/main/res/values/bools.xml @@ -20,6 +20,6 @@ true true - true + false false \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c47d3b3..9b53e01 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,10 +3,12 @@ Titanboard Titanboard preferences - Cycling speed + General Automatic capitalization Automatic periods Autocorrect + Editing and keymaps + Cycling speed Cycle symbols with the space key Keymaps diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index b736ea3..3448c64 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -32,4 +32,13 @@ #DDD bold + + \ No newline at end of file diff --git a/app/src/main/res/xml/keymaps_titan.xml b/app/src/main/res/xml/keymaps_titan.xml index ecdbb53..8124aa0 100644 --- a/app/src/main/res/xml/keymaps_titan.xml +++ b/app/src/main/res/xml/keymaps_titan.xml @@ -746,7 +746,7 @@ - + + + @@ -780,7 +782,9 @@ + + @@ -798,7 +802,9 @@ + + @@ -806,7 +812,12 @@ + + + + + @@ -834,9 +845,12 @@ + + + @@ -850,6 +864,7 @@ + @@ -877,9 +892,12 @@ + + + @@ -894,9 +912,15 @@ + + + + + + diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index dfaf5e7..8bda99e 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -19,32 +19,39 @@ - - - - - - + + + + + + + + + + + + \ No newline at end of file