Don't remember

This commit is contained in:
2024-10-22 13:42:40 +02:00
parent 6d63f53919
commit 463beaf170
10 changed files with 274 additions and 68 deletions
@@ -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<String> 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();
}
@@ -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 {
@@ -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 <https://www.gnu.org/licenses/>.
*
*/
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();
}
}
+27
View File
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ 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 <https://www.gnu.org/licenses/>.
~
-->
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="45"
android:pivotX="100%"
android:pivotY="-50%">
<shape android:shape="rectangle">
<solid android:color="#333" />
</shape>
</rotate>
+56
View File
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ 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 <https://www.gnu.org/licenses/>.
~
-->
<cfpi_fpsi.eu.titanboard.SymbolsView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/imageView"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_below="@id/textView"
android:src="@drawable/triangle" />
<TextView
android:id="@+id/textView"
style="@style/SymbolsViewSymbol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:text="A" />
<TextView
android:id="@+id/textView2"
style="@style/SymbolsViewSymbol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/textView"
android:text="B" />
<TextView
android:id="@+id/textView3"
style="@style/SymbolsViewSymbol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/textView2"
android:text="C" />
</cfpi_fpsi.eu.titanboard.SymbolsView>
+1 -1
View File
@@ -20,6 +20,6 @@
<resources>
<bool name="auto_caps_default">true</bool>
<bool name="auto_periods_default">true</bool>
<bool name="autocorrect_default">true</bool>
<bool name="autocorrect_default">false</bool>
<bool name="cycle_with_space_default">false</bool>
</resources>
+3 -1
View File
@@ -3,10 +3,12 @@
<string name="ime_label">Titanboard</string>
<string name="preferences_label">Titanboard preferences</string>
<string name="preferences_cycle_speed">Cycling speed</string>
<string name="preferences_general_settings">General</string>
<string name="preferences_auto_caps">Automatic capitalization</string>
<string name="preferences_auto_periods">Automatic periods</string>
<string name="preferences_auto_correct">Autocorrect</string>
<string name="preferences_editing_settings">Editing and keymaps</string>
<string name="preferences_cycle_speed">Cycling speed</string>
<string name="preferences_cycle_with_space">Cycle symbols with the space key</string>
<string name="preferences_keymaps">Keymaps</string>
+9
View File
@@ -32,4 +32,13 @@
<item name="android:textColor">#DDD</item>
<item name="android:textStyle">bold</item>
</style>
<style name="SymbolsViewSymbol">
<item name="android:background">#333</item>
<item name="android:textColor">#AAA</item>
<item name="android:textSize">16sp</item>
<item name="android:textAlignment">center</item>
<item name="android:padding">8dp</item>
<item name="android:layout_gravity">center_vertical</item>
</style>
</resources>
+25 -1
View File
@@ -746,7 +746,7 @@
<alt value="!" />
</key>
</keymap>
<!-- Greek -->
<!-- Modern Greek, monotonic orthography -->
<!-- https://en.wikipedia.org/wiki/List_of_QWERTY_keyboard_language_variants#/media/File:Greek_keyboard_mono_3b.png -->
<!-- TODO: add diacritics -->
<keymap
@@ -755,7 +755,9 @@
locked-name="EL">
<key code="29"> <!-- A -->
<base value="α" />
<base value="ά" />
<shift value="Α" />
<shift value="Ά" />
<alt value="@" />
</key>
<key code="30"> <!-- B -->
@@ -780,7 +782,9 @@
</key>
<key code="33"> <!-- E -->
<base value="ε" />
<base value="έ" />
<shift value="E" />
<shift value="Έ" />
<alt value="_" />
<alt value="~" />
</key>
@@ -798,7 +802,9 @@
</key>
<key code="36"> <!-- H -->
<base value="η" />
<base value="ή" />
<shift value="H" />
<shift value="Ή" />
<alt value="#" />
<alt value="₽" />
<alt value="€" />
@@ -806,7 +812,12 @@
</key>
<key code="37"> <!-- I -->
<base value="ι" />
<base value="ί" />
<base value="ϊ" />
<base value="ΐ" />
<shift value="I" />
<shift value="Ί" />
<shift value="Ϊ" />
<alt value="2" />
</key>
<key code="38"> <!-- J -->
@@ -834,9 +845,12 @@
<shift value="Ν" />
<alt value="8" />
</key>
<!-- Lots of diacritics -->
<key code="43"> <!-- O -->
<base value="o" />
<base value="ό" />
<shift value="O" />
<shift value="Ό" />
<alt value="3" />
</key>
<key code="44"> <!-- P -->
@@ -850,6 +864,7 @@
<alt value=":" />
<alt value=";" />
</key>
<!-- One diacritic -->
<key code="46"> <!-- R -->
<base value="ρ" />
<shift value="Ρ" />
@@ -877,9 +892,12 @@
<shift value="Θ" />
<alt value="1" />
</key>
<!-- Lots of diacritics -->
<key code="50"> <!-- V -->
<base value="ω" />
<base value="ώ" />
<shift value="Ω" />
<shift value="Ώ" />
<alt value="." />
<alt value="…" />
</key>
@@ -894,9 +912,15 @@
<shift value="X" />
<alt value="?" />
</key>
<!-- Lots of diacritics -->
<key code="53"> <!-- Y -->
<base value="υ" />
<base value="ύ" />
<base value="ϋ" />
<base value="ΰ" />
<shift value="Y" />
<shift value="Ύ" />
<shift value="Ϋ" />
<alt value=")" />
<alt value="&gt;" />
<alt value="]" />
+35 -28
View File
@@ -19,32 +19,39 @@
<!--suppress DeprecatedClassUsageInspection -->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<SwitchPreference
android:defaultValue="@bool/auto_caps_default"
android:key="auto_caps"
android:title="@string/preferences_auto_caps" />
<SwitchPreference
android:defaultValue="@bool/auto_periods_default"
android:key="auto_periods"
android:title="@string/preferences_auto_periods" />
<SwitchPreference
android:defaultValue="@bool/autocorrect_default"
android:key="autocorrect"
android:title="@string/preferences_auto_correct" />
<SwitchPreference
android:defaultValue="@bool/cycle_with_space_default"
android:key="cycle_with_space"
android:title="@string/preferences_cycle_with_space" />
<ListPreference
android:defaultValue="@string/cycle_speed_default"
android:entries="@array/cycle_speed_labels"
android:entryValues="@array/cycle_speeds"
android:key="cycle_speed"
android:title="@string/preferences_cycle_speed" />
<MultiSelectListPreference
android:defaultValue="@array/selected_keymap_defaults"
android:entries="@array/available_keymap_labels"
android:entryValues="@array/available_keymaps"
android:key="selected_keymaps"
android:title="@string/preferences_keymaps" />
<PreferenceCategory android:title="@string/preferences_general_settings">
<SwitchPreference
android:defaultValue="@bool/auto_caps_default"
android:key="auto_caps"
android:title="@string/preferences_auto_caps" />
<SwitchPreference
android:defaultValue="@bool/auto_periods_default"
android:key="auto_periods"
android:title="@string/preferences_auto_periods" />
<SwitchPreference
android:defaultValue="@bool/autocorrect_default"
android:enabled="false"
android:key="autocorrect"
android:title="@string/preferences_auto_correct" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/preferences_editing_settings">
<MultiSelectListPreference
android:defaultValue="@array/selected_keymap_defaults"
android:entries="@array/available_keymap_labels"
android:entryValues="@array/available_keymaps"
android:key="selected_keymaps"
android:title="@string/preferences_keymaps" />
<SwitchPreference
android:defaultValue="@bool/cycle_with_space_default"
android:key="cycle_with_space"
android:title="@string/preferences_cycle_with_space" />
<ListPreference
android:defaultValue="@string/cycle_speed_default"
android:entries="@array/cycle_speed_labels"
android:entryValues="@array/cycle_speeds"
android:key="cycle_speed"
android:title="@string/preferences_cycle_speed" />
</PreferenceCategory>
</PreferenceScreen>