1
0
Fork 0

Fixed on-screen keys holding

* Backspace works properly

	* holding 0-key now types '+' in 123 mode

	* holding the punctuation keys now allows for typing ',' and '.' in 123 mode
This commit is contained in:
Dimo Karaivanov 2023-04-20 13:51:02 +03:00
parent 6173291a1c
commit b8b05c6d1b
4 changed files with 184 additions and 97 deletions

View file

@ -2,15 +2,10 @@ package io.github.sspanak.tt9.ui.main.keys;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import io.github.sspanak.tt9.Logger;
import io.github.sspanak.tt9.preferences.SettingsStore;
public class SoftBackspaceKey extends SoftKey {
private SettingsStore settings;
long lastBackspaceCall = 0;
public SoftBackspaceKey(Context context) {
super(context);
@ -24,52 +19,23 @@ public class SoftBackspaceKey extends SoftKey {
super(context, attrs, defStyleAttr);
}
private SettingsStore getSettings() {
if (settings == null) {
settings = new SettingsStore(getContext());
}
return settings;
@Override
final protected boolean handlePress() {
return handleHold();
}
@Override
final public boolean onTouch(View view, MotionEvent event) {
final protected boolean handleHold() {
if (tt9 == null) {
Logger.w(getClass().getCanonicalName(), "Traditional T9 handler is not set. Ignoring key press.");
return false;
}
int action = event.getAction() & MotionEvent.ACTION_MASK;
if (action == MotionEvent.AXIS_PRESSURE) {
handleHold();
} else if (action == MotionEvent.ACTION_UP) {
handleUp();
} else if (action == MotionEvent.ACTION_DOWN) {
// Fallback for phones that do not report AXIS_PRESSURE, when a key is being held
handlePress(-1);
}
return true;
}
private void handleHold() {
if (System.currentTimeMillis() - lastBackspaceCall < getSettings().getSoftKeyRepeatDelay()) {
return;
}
handlePress(-1);
long now = System.currentTimeMillis();
lastBackspaceCall = lastBackspaceCall == 0 ? getSettings().getSoftKeyInitialDelay() + now : now;
}
private void handleUp() {
lastBackspaceCall = 0;
return tt9.onBackspace();
}
@Override
final protected boolean handlePress(int b) {
return tt9.onBackspace();
final protected boolean handleRelease() {
return false;
}
}

View file

@ -2,6 +2,8 @@ package io.github.sspanak.tt9.ui.main.keys;
import android.content.Context;
import android.graphics.Typeface;
import android.os.Handler;
import android.os.Looper;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.RelativeSizeSpan;
@ -16,11 +18,17 @@ import io.github.sspanak.tt9.Logger;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.ime.TraditionalT9;
public class SoftKey extends androidx.appcompat.widget.AppCompatButton implements View.OnTouchListener {
public class SoftKey extends androidx.appcompat.widget.AppCompatButton implements View.OnTouchListener, View.OnLongClickListener {
protected TraditionalT9 tt9;
protected float COMPLEX_LABEL_TITLE_SIZE = 0.55f;
protected float COMPLEX_LABEL_SUB_TITLE_SIZE = 0.8f;
private boolean hold = false;
private boolean repeat = false;
private final Handler repeatHandler = new Handler(Looper.getMainLooper());
public SoftKey(Context context) {
super(context);
}
@ -33,6 +41,7 @@ public class SoftKey extends androidx.appcompat.widget.AppCompatButton implement
super(context, attrs, defStyleAttr);
}
public void setTT9(TraditionalT9 tt9) {
this.tt9 = tt9;
}
@ -50,25 +59,82 @@ public class SoftKey extends androidx.appcompat.widget.AppCompatButton implement
protected void onFinishInflate() {
super.onFinishInflate();
getRootView().setOnTouchListener(this);
getRootView().setOnLongClickListener(this);
}
@Override
public boolean onTouch(View view, MotionEvent event) {
super.onTouchEvent(event);
if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP) {
return handlePress(view.getId());
int action = (event.getAction() & MotionEvent.ACTION_MASK);
if (action == MotionEvent.ACTION_DOWN) {
return handlePress();
} else if (action == MotionEvent.ACTION_UP) {
preventRepeat();
if (!repeat) {
return handleRelease();
}
repeat = false;
}
return false;
}
protected boolean handlePress(int keyId) {
@Override
public boolean onLongClick(View view) {
hold = true;
// sometimes this gets called twice, so we debounce the call to the repeating function
repeatHandler.removeCallbacks(this::repeatOnLongPress);
repeatHandler.postDelayed(this::repeatOnLongPress, 1);
return true;
}
/**
* repeatOnLongPress
* Repeatedly calls "handleHold()" upon holding the respective SoftKey, to simulate physical keyboard behavior.
*/
private void repeatOnLongPress() {
if (tt9 == null) {
Logger.w(getClass().getCanonicalName(), "Traditional T9 handler is not set. Ignoring key press.");
hold = false;
return;
}
if (hold) {
repeat = true;
handleHold();
repeatHandler.removeCallbacks(this::repeatOnLongPress);
repeatHandler.postDelayed(this::repeatOnLongPress, tt9.getSettings().getSoftKeyRepeatDelay());
}
}
/**
* preventRepeat
* Prevents "handleHold()" from being called repeatedly when the SoftKey is being held.
*/
protected void preventRepeat() {
hold = false;
repeatHandler.removeCallbacks(this::repeatOnLongPress);
}
protected boolean handlePress() {
return false;
}
protected boolean handleHold() {
return false;
}
protected boolean handleRelease() {
if (tt9 == null) {
Logger.w(getClass().getCanonicalName(), "Traditional T9 handler is not set. Ignoring key press.");
return false;
}
int keyId = getId();
if (keyId == R.id.soft_key_add_word) return tt9.onKeyAddWord();
if (keyId == R.id.soft_key_input_mode) return tt9.onKeyNextInputMode();
if (keyId == R.id.soft_key_language) return tt9.onKeyNextLanguage();
@ -99,7 +165,7 @@ public class SoftKey extends androidx.appcompat.widget.AppCompatButton implement
/**
* render
* Sets the key label using "getKeyNameLabel()" and "getKeyFunctionLabel()" or if they both
* Sets the key label using "getTitle()" and "getSubtitle()" or if they both
* return NULL, the XML "text" attribute will be preserved.
*
* If there is only name label, it will be centered and at normal font size.
@ -107,19 +173,19 @@ public class SoftKey extends androidx.appcompat.widget.AppCompatButton implement
* have their font size adjusted to fit inside the key.
*/
public void render() {
String name = getTitle();
String func = getSubTitle();
String title = getTitle();
String subtitle = getSubTitle();
if (name == null) {
if (title == null) {
return;
} else if (func == null) {
setText(name);
} else if (subtitle == null) {
setText(title);
return;
}
SpannableStringBuilder sb = new SpannableStringBuilder(name);
SpannableStringBuilder sb = new SpannableStringBuilder(title);
sb.append('\n');
sb.append(func);
sb.append(subtitle);
sb.setSpan(new RelativeSizeSpan(COMPLEX_LABEL_TITLE_SIZE), 0, 2, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
sb.setSpan(new StyleSpan(Typeface.ITALIC), 0, 2, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);

View file

@ -26,13 +26,26 @@ public class SoftNumberKey extends SoftKey {
super(context, attrs, defStyleAttr);
}
protected boolean handlePress(int keyId) {
@Override
protected boolean handleHold() {
if (tt9 == null || tt9.getSettings().getInputMode() != InputMode.MODE_123 || getId() != R.id.soft_key_0) {
return super.handleHold();
}
preventRepeat();
int zeroCode = Key.numberToCode(0);
tt9.onKeyLongPress(zeroCode, new KeyEvent(KeyEvent.ACTION_DOWN, zeroCode));
return true;
}
@Override
protected boolean handleRelease() {
if (tt9 == null) {
Logger.w(getClass().getCanonicalName(), "Traditional T9 handler is not set. Ignoring key press.");
return false;
}
int keyCode = Key.numberToCode(getNumber(keyId));
int keyCode = Key.numberToCode(getNumber(getId()));
if (keyCode < 0) {
return false;
}
@ -43,6 +56,58 @@ public class SoftNumberKey extends SoftKey {
return true;
}
@Override
protected String getTitle() {
return String.valueOf(getNumber(getId()));
}
@Override
protected String getSubTitle() {
if (tt9 == null) {
return null;
}
int number = getNumber(getId());
if (number == 0) {
if (tt9.getSettings().getInputMode() == InputMode.MODE_123) {
return "+";
} else {
COMPLEX_LABEL_SUB_TITLE_SIZE = 1;
return "";
}
}
// no special labels in 123 mode
if (tt9.getSettings().getInputMode() == InputMode.MODE_123) {
return null;
}
// 1
if (number == 1) {
return ",:-)";
}
// 2-9
int textCase = tt9.getSettings().getTextCase();
Language language = LanguageCollection.getLanguage(tt9.getSettings().getInputLanguage());
if (language == null) {
Logger.d("SoftNumberKey.getLabel", "Cannot generate a label when the language is NULL.");
return "";
}
StringBuilder sb = new StringBuilder();
ArrayList<String> chars = language.getKeyCharacters(number, false);
for (int i = 0; i < 5 && i < chars.size(); i++) {
sb.append(
textCase == InputMode.CASE_UPPER ? chars.get(i).toUpperCase(language.getLocale()) : chars.get(i)
);
}
return sb.toString();
}
private int getNumber(int keyId) {
if (keyId == R.id.soft_key_0) return 0;
if (keyId == R.id.soft_key_1) return 1;
@ -57,44 +122,4 @@ public class SoftNumberKey extends SoftKey {
return -1;
}
@Override
protected String getTitle() {
return String.valueOf(getNumber(getId()));
}
@Override
protected String getSubTitle() {
if (tt9 == null || tt9.getSettings().getInputMode() == InputMode.MODE_123) {
return null;
}
int number = getNumber(getId());
int textCase = tt9.getSettings().getTextCase();
Language language = LanguageCollection.getLanguage(tt9.getSettings().getInputLanguage());
if (language == null) {
Logger.d("SoftNumberKey.getLabel", "Cannot generate a label when the language is NULL.");
return "";
}
if (number == 0) {
COMPLEX_LABEL_SUB_TITLE_SIZE = 1;
return "";
}
if (number == 1) {
return ",:-)";
}
StringBuilder sb = new StringBuilder();
ArrayList<String> chars = language.getKeyCharacters(number, false);
for (int i = 0; i < 5 && i < chars.size(); i++) {
sb.append(
textCase == InputMode.CASE_UPPER ? chars.get(i).toUpperCase(language.getLocale()) : chars.get(i)
);
}
return sb.toString();
}
}

View file

@ -21,12 +21,28 @@ public class SoftPunctuationKey extends SoftKey {
super(context, attrs, defStyleAttr);
}
protected boolean handlePress(int keyId) {
@Override
protected boolean handleHold() {
if (tt9 == null || tt9.getSettings().getInputMode() != InputMode.MODE_123) {
return super.handleHold();
}
preventRepeat();
int keyId = getId();
if (keyId == R.id.soft_key_punctuation_1) return tt9.onText(",");
if (keyId == R.id.soft_key_punctuation_2) return tt9.onText(".");
return false;
}
@Override
protected boolean handleRelease() {
if (tt9 == null) {
Logger.w(getClass().getCanonicalName(), "Traditional T9 handler is not set. Ignoring key press.");
return false;
}
int keyId = getId();
if (tt9.getSettings().getInputMode() == InputMode.MODE_123) {
if (keyId == R.id.soft_key_punctuation_1) return tt9.onOtherKey(KeyEvent.KEYCODE_STAR);
if (keyId == R.id.soft_key_punctuation_2) return tt9.onOtherKey(KeyEvent.KEYCODE_POUND);
@ -40,8 +56,11 @@ public class SoftPunctuationKey extends SoftKey {
@Override
protected String getTitle() {
int keyId = getId();
if (tt9 == null) {
return "PUNC";
}
int keyId = getId();
if (tt9.getSettings().getInputMode() == InputMode.MODE_123) {
if (keyId == R.id.soft_key_punctuation_1) return "";
if (keyId == R.id.soft_key_punctuation_2) return "#";
@ -52,4 +71,15 @@ public class SoftPunctuationKey extends SoftKey {
return "PUNC";
}
@Override
protected String getSubTitle() {
int keyId = getId();
if (tt9 != null && tt9.getSettings().getInputMode() == InputMode.MODE_123) {
if (keyId == R.id.soft_key_punctuation_1) return ",";
if (keyId == R.id.soft_key_punctuation_2) return ".";
}
return null;
}
}