More refractoring, add symbol meta key definition in XML

This commit is contained in:
2024-11-28 20:37:30 +01:00
parent c03c3f01c5
commit 3ab7bf1eba
11 changed files with 101 additions and 44 deletions
@@ -41,10 +41,8 @@ import eur.cfpifpsi.titanboard.views.InputView;
// TODO: Emojis with popup window
// TODO: Composing with diacritics, polytonic Greek as well
// TODO: Fix up the tweaks popup so it matches in style other UI elements
// TODO: Manual symbol cycling seems to break with the ) character, because we check if symbols are
// empty or something. It only happens in Arabic. This is because under some keys in Arabic, there
// are simply no symbols, even if the alt key has ones.
// TODO: Call answering/rejecting like in Pocketboard
// TODO: Floating input view
public class TitanboardIME extends InputMethodService {
private MetaKeyManager mMetaKeyManager;
@@ -96,7 +94,8 @@ public class TitanboardIME extends InputMethodService {
// TODO: make sure to return false if it's a key we don't really know, so that media keys
// etc. on some keyboards are handled correctly
if (mMetaKeyManager.updateMetaStateDown(keyCode)) {
if (mMetaKeyManager.updateMetaStateDown(keyCode,
mKeymapManager.getDeviceMetaSymbolKeyCodes(mPreferenceHolder.getDevice()))) {
mInputView.updateStateText();
return true;
}
@@ -110,7 +109,7 @@ public class TitanboardIME extends InputMethodService {
}
// Workaround for default Android behaviour that pisses people off.
if (keyCode == KeyEvent.KEYCODE_DEL && mMetaKeyManager.getAlt().isPressed()) {
if (keyCode == KeyEvent.KEYCODE_DEL && mMetaKeyManager.getSymbol().isPressed()) {
return true;
}
@@ -145,7 +144,7 @@ public class TitanboardIME extends InputMethodService {
}
// TODO: It's kind of a mess, isn't it? I have to rethink this.
if (event.getRepeatCount() == 0 && !symbols.isEmpty()) {
if (event.getRepeatCount() == 0) {
mMetaKeyManager.adjustMetaStateAfterKeypress();
mInputView.updateStateText();
mSymbolInputHandler.handleSymbolInput(conn, symbols, keyCode,
@@ -164,7 +163,8 @@ public class TitanboardIME extends InputMethodService {
mSymbolInputHandler.finishCycling(conn);
}
if (mMetaKeyManager.updateMetaStateUp(keyCode, event)) {
if (mMetaKeyManager.updateMetaStateUp(keyCode, event.getEventTime(),
mKeymapManager.getDeviceMetaSymbolKeyCodes(mPreferenceHolder.getDevice()))) {
mInputView.updateStateText();
return true;
}
@@ -37,12 +37,12 @@ public class MetaKey {
mLocked = false;
}
public void onUp(KeyEvent event) {
if (event.getEventTime() - mLastKeyUpTime < TOGGLE_DURATION) {
public void onUp(long eventTime) {
if (eventTime - mLastKeyUpTime < TOGGLE_DURATION) {
mLocked = true;
}
mLastKeyUpTime = event.getEventTime();
mLastKeyUpTime = eventTime;
mPressed = false;
mLatched = !mLatched && !mLocked && !mUsed;
}
@@ -21,19 +21,21 @@ package eur.cfpifpsi.titanboard.input;
import android.os.Vibrator;
import android.view.KeyEvent;
import java.util.ArrayList;
public class MetaKeyManager {
private static final int TOGGLE_VIBRATION_TIME = 30;
public final MetaKey mShift = new MetaKey();
public final MetaKey mAlt = new MetaKey();
public final MetaKey mSymbol = new MetaKey();
private final Vibrator mVibrator;
public MetaKeyManager(Vibrator vibrator) {
mVibrator = vibrator;
}
public boolean updateMetaStateDown(int keyCode) {
if (keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT) {
mAlt.onDown();
public boolean updateMetaStateDown(int keyCode, ArrayList<Integer> symbolMeta) {
if (symbolMeta.contains(keyCode)) {
mSymbol.onDown();
return true;
} else if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
mShift.onDown();
@@ -46,15 +48,15 @@ public class MetaKeyManager {
/**
* @noinspection FeatureEnvy
*/
public boolean updateMetaStateUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT) {
mAlt.onUp(event);
if (mAlt.isLocked()) {
public boolean updateMetaStateUp(int keyCode, long eventTime, ArrayList<Integer> symbolMeta) {
if (symbolMeta.contains(keyCode)) {
mSymbol.onUp(eventTime);
if (mSymbol.isLocked()) {
mVibrator.vibrate(TOGGLE_VIBRATION_TIME);
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
mShift.onUp(event);
mShift.onUp(eventTime);
if (mShift.isLocked()) {
mVibrator.vibrate(TOGGLE_VIBRATION_TIME);
}
@@ -66,19 +68,19 @@ public class MetaKeyManager {
public void adjustMetaStateAfterKeypress() {
mShift.afterKeypress();
mAlt.afterKeypress();
mSymbol.afterKeypress();
}
public void resetMetaKeyState() {
mShift.resetState();
mAlt.resetState();
mSymbol.resetState();
}
public MetaKey getShift() {
return mShift;
}
public MetaKey getAlt() {
return mAlt;
public MetaKey getSymbol() {
return mSymbol;
}
}
@@ -27,6 +27,10 @@ import java.util.ArrayList;
import eur.cfpifpsi.titanboard.views.InputView;
// TODO: This looks kind of weird. Think about refactoring it.
// TODO: Cycling doesn't stop when pressing a button that isn't defined or something. Strange...
// Only happens in manual mode.
public class SymbolInputHandler {
private final InputView mInputView;
private final SymbolCycler mSymbolCycler;
@@ -46,14 +50,15 @@ public class SymbolInputHandler {
public void handleSymbolInput(InputConnection inputConnection, ArrayList<String> symbols,
int keyCode, boolean isAlternateComposingOn, boolean isManual,
int cycleSpeed) {
mSymbolCycler.setInputParameters(inputConnection, isAlternateComposingOn, isManual, cycleSpeed);
mSymbolCycler.setInputParameters(inputConnection, isAlternateComposingOn, isManual,
cycleSpeed);
if (isManual) {
boolean isCycling = mHandler.hasMessages(0);
if (isCycling && keyCode == mLastSymbolKeyCode
&& mSymbolCycler.getList().size() > 1) {
mSymbolCycler.run();
} else {
} else if (!symbols.isEmpty()) {
finishCycling(inputConnection);
inputConnection.commitText(symbols.get(0), 1);
mSymbolCycler.prepare(symbols);
@@ -62,7 +67,7 @@ public class SymbolInputHandler {
mHandler.removeCallbacksAndMessages(null);
mHandler.postDelayed(() -> finishCycling(inputConnection), cycleSpeed);
mLastSymbolKeyCode = keyCode;
} else {
} else if (!symbols.isEmpty()) {
inputConnection.commitText(symbols.get(0), 1);
if (symbols.size() > 1) {
@@ -0,0 +1,33 @@
/*
* An input method for 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 eur.cfpifpsi.titanboard.keymapping;
import java.util.ArrayList;
public class DeviceKeymap extends Keymap {
private final ArrayList<Integer> mMetaSymbolKeyCodes = new ArrayList<>(2);
public ArrayList<Integer> getMetaSymbolKeyCodes() {
return mMetaSymbolKeyCodes;
}
public void addMetaSymbolKeyCode(Integer keyCode) {
mMetaSymbolKeyCodes.add(keyCode);
}
}
@@ -28,7 +28,7 @@ public class Keymap {
private final HashMap<Integer, KeySymbols> mMap = new HashMap<>(INITIAL_KEYMAP_SIZE);
public ArrayList<String> getSymbolsMeta(int keyCode, MetaKeyManager metaKeyManager) {
if (metaKeyManager.getAlt().isActive()) {
if (metaKeyManager.getSymbol().isActive()) {
return getSymbolsAlt(keyCode);
} else if (metaKeyManager.getShift().isActive()) {
return getSymbolsShift(keyCode);
@@ -42,6 +42,7 @@ public enum KeymapLoader {
private static final String TAG_LATCHED_CODE = "latched-code"; //NON-NLS
private static final String TAG_LOCKED_CODE = "locked-code"; //NON-NLS
private static final String TAG_ID = "id"; //NON-NLS
private static final String TAG_SYMBOLS_META_KEY = "symbol-meta-key-code"; //NON-NLS
public static void loadLanguageKeymaps(HashMap<String, LanguageKeymap> keymaps,
XmlPullParser parser) {
@@ -70,13 +71,11 @@ public enum KeymapLoader {
keymap.setCode(nextTextLowerApi(parser));
break;
case TAG_LATCHED_CODE:
assert keymap != null : "<latched-code> not preceded by " +
"<language-keymap>";
assert keymap != null : "<latched-code> not preceded by <language-keymap>";
keymap.setLatchedCode(nextTextLowerApi(parser));
break;
case TAG_LOCKED_CODE:
assert keymap != null : "<locked-code> not preceded by " +
"<language-keymap>";
assert keymap != null : "<locked-code> not preceded by <language-keymap>";
keymap.setLockedCode(nextTextLowerApi(parser));
break;
case TAG_SYMBOLS:
@@ -100,8 +99,7 @@ public enum KeymapLoader {
forSymbol = nextTextLowerApi(parser);
break;
case TAG_SYMBOL:
assert attachedSymbols != null : "<symbol> tag isn't preceded by " +
"<attached-symbols>";
assert attachedSymbols != null : "<symbol> tag isn't preceded by <attached-symbols>";
attachedSymbols.add(nextTextLowerApi(parser));
break;
}
@@ -133,9 +131,9 @@ public enum KeymapLoader {
}
}
public static void loadDeviceKeymaps(HashMap<String, Keymap> keymaps,
public static void loadDeviceKeymaps(HashMap<String, DeviceKeymap> keymaps,
XmlPullParser parser) {
Keymap keymap = null;
DeviceKeymap keymap = null;
int code = 0;
String id = null;
KeySymbols keySymbols = null;
@@ -150,11 +148,15 @@ public enum KeymapLoader {
if (eventType == XmlPullParser.START_TAG) {
switch (parser.getName()) {
case TAG_DEVICE_KEYMAP:
keymap = new Keymap();
keymap = new DeviceKeymap();
break;
case TAG_ID:
id = nextTextLowerApi(parser);
break;
case TAG_SYMBOLS_META_KEY:
assert keymap != null : "<device-keymap> tag not defined";
keymap.addMetaSymbolKeyCode(Integer.parseInt(nextTextLowerApi(parser)));
break;
case TAG_SYMBOLS:
keySymbols = new KeySymbols();
break;
@@ -29,7 +29,7 @@ import eur.cfpifpsi.titanboard.input.MetaKeyManager;
public class KeymapManager {
private final Context mContext;
private final HashMap<String, Keymap> mDeviceKeymaps;
private final HashMap<String, DeviceKeymap> mDeviceKeymaps;
private final HashMap<String, LanguageKeymap> mLanguageKeymaps;
private LanguageKeymap mCurrentLanguageKeymap;
@@ -95,6 +95,10 @@ public class KeymapManager {
}
}
public ArrayList<Integer> getDeviceMetaSymbolKeyCodes(String device) {
return mDeviceKeymaps.get(device).getMetaSymbolKeyCodes();
}
public String getCurrentCode() {
return mCurrentLanguageKeymap.getCode();
}
@@ -92,8 +92,8 @@ public final class InputView extends RelativeLayout {
});
mStateButton.setOnClickListener(button -> {
if (mMetaKeyManager.getAlt().isActive()) {
mMetaKeyManager.getAlt().resetState();
if (mMetaKeyManager.getSymbol().isActive()) {
mMetaKeyManager.getSymbol().resetState();
} else {
mKeymapManager.nextKeymap(mPreferenceHolder.getSelectedKeymaps());
}
@@ -139,9 +139,9 @@ public final class InputView extends RelativeLayout {
}
public void updateStateText() {
mStateButton.updateStateText(mMetaKeyManager.getShift(), mMetaKeyManager.getAlt(),
mStateButton.updateStateText(mMetaKeyManager.getShift(), mMetaKeyManager.getSymbol(),
mKeymapManager.getCurrentCode(), mKeymapManager.getCurrentLatchedCode(),
mKeymapManager.getCurrentLatchedCode());
mKeymapManager.getCurrentLockedCode());
}
public void updateTweaks() {
@@ -31,8 +31,8 @@ public class StateButton extends Button {
super(context, attrs);
}
public void updateStateText(MetaKey shift, MetaKey alt, String code, String lockedCode,
String latchedCode) {
public void updateStateText(MetaKey shift, MetaKey alt, String code, String latchedCode,
String lockedCode) {
setPaintFlags(getPaintFlags() & ~(Paint.UNDERLINE_TEXT_FLAG));
if (alt.isLocked() || shift.isLocked()) {
+12 -1
View File
@@ -22,8 +22,17 @@
<!-- This is used to differentiate keymaps. It can be any string, really, but keep it
short and descriptive. -->
<id>titan</id>
<!-- These are the keycodes for the key that's responsible for accessing alternate symbols.
On BlackBerries, this is the sym key, here on the Titan, it's the alt key. -->
<symbol-meta-key-code>57</symbol-meta-key-code> <!-- Left alt -->
<symbol-meta-key-code>58</symbol-meta-key-code> <!-- Right alt -->
<!-- Symbols, apart from the keycode and alt values, can also contain <base> and <shift>
values, which can be used for phones that have extra keys, such as a dot key. It's
useful that, like in this example, you add more than the default single alternate key,
so the user can type in more symbols that don't exist on the physical keyboard. Make
sure to group them in a sensible way, for example, the : key having the ; symbol also, etc.
-->
<symbols>
<for-code>45</for-code> <!-- Q -->
<alt>:</alt>
@@ -156,6 +165,8 @@
</device-keymap>
<device-keymap>
<id>titan_pocket_slim</id>
<symbol-meta-key-code>57</symbol-meta-key-code> <!-- Left alt -->
<symbol-meta-key-code>58</symbol-meta-key-code> <!-- Right alt -->
<symbols>
<for-code>45</for-code> <!-- Q -->