More refractoring, add symbol meta key definition in XML
This commit is contained in:
@@ -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()) {
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
Reference in New Issue
Block a user