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.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import io.github.sspanak.tt9.Logger; import io.github.sspanak.tt9.Logger;
import io.github.sspanak.tt9.preferences.SettingsStore;
public class SoftBackspaceKey extends SoftKey { public class SoftBackspaceKey extends SoftKey {
private SettingsStore settings;
long lastBackspaceCall = 0;
public SoftBackspaceKey(Context context) { public SoftBackspaceKey(Context context) {
super(context); super(context);
@ -24,52 +19,23 @@ public class SoftBackspaceKey extends SoftKey {
super(context, attrs, defStyleAttr); super(context, attrs, defStyleAttr);
} }
private SettingsStore getSettings() { @Override
if (settings == null) { final protected boolean handlePress() {
settings = new SettingsStore(getContext()); return handleHold();
}
return settings;
} }
@Override @Override
final public boolean onTouch(View view, MotionEvent event) { final protected boolean handleHold() {
if (tt9 == null) { if (tt9 == null) {
Logger.w(getClass().getCanonicalName(), "Traditional T9 handler is not set. Ignoring key press."); Logger.w(getClass().getCanonicalName(), "Traditional T9 handler is not set. Ignoring key press.");
return false; return false;
} }
int action = event.getAction() & MotionEvent.ACTION_MASK; return tt9.onBackspace();
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;
} }
@Override @Override
final protected boolean handlePress(int b) { final protected boolean handleRelease() {
return tt9.onBackspace(); return false;
} }
} }

View file

@ -2,6 +2,8 @@ package io.github.sspanak.tt9.ui.main.keys;
import android.content.Context; import android.content.Context;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.os.Handler;
import android.os.Looper;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.text.Spanned; import android.text.Spanned;
import android.text.style.RelativeSizeSpan; 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.R;
import io.github.sspanak.tt9.ime.TraditionalT9; 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 TraditionalT9 tt9;
protected float COMPLEX_LABEL_TITLE_SIZE = 0.55f; protected float COMPLEX_LABEL_TITLE_SIZE = 0.55f;
protected float COMPLEX_LABEL_SUB_TITLE_SIZE = 0.8f; 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) { public SoftKey(Context context) {
super(context); super(context);
} }
@ -33,6 +41,7 @@ public class SoftKey extends androidx.appcompat.widget.AppCompatButton implement
super(context, attrs, defStyleAttr); super(context, attrs, defStyleAttr);
} }
public void setTT9(TraditionalT9 tt9) { public void setTT9(TraditionalT9 tt9) {
this.tt9 = tt9; this.tt9 = tt9;
} }
@ -50,25 +59,82 @@ public class SoftKey extends androidx.appcompat.widget.AppCompatButton implement
protected void onFinishInflate() { protected void onFinishInflate() {
super.onFinishInflate(); super.onFinishInflate();
getRootView().setOnTouchListener(this); getRootView().setOnTouchListener(this);
getRootView().setOnLongClickListener(this);
} }
@Override @Override
public boolean onTouch(View view, MotionEvent event) { public boolean onTouch(View view, MotionEvent event) {
super.onTouchEvent(event); super.onTouchEvent(event);
if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP) { int action = (event.getAction() & MotionEvent.ACTION_MASK);
return handlePress(view.getId());
if (action == MotionEvent.ACTION_DOWN) {
return handlePress();
} else if (action == MotionEvent.ACTION_UP) {
preventRepeat();
if (!repeat) {
return handleRelease();
}
repeat = false;
} }
return 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) { if (tt9 == null) {
Logger.w(getClass().getCanonicalName(), "Traditional T9 handler is not set. Ignoring key press."); Logger.w(getClass().getCanonicalName(), "Traditional T9 handler is not set. Ignoring key press.");
return false; return false;
} }
int keyId = getId();
if (keyId == R.id.soft_key_add_word) return tt9.onKeyAddWord(); 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_input_mode) return tt9.onKeyNextInputMode();
if (keyId == R.id.soft_key_language) return tt9.onKeyNextLanguage(); if (keyId == R.id.soft_key_language) return tt9.onKeyNextLanguage();
@ -99,7 +165,7 @@ public class SoftKey extends androidx.appcompat.widget.AppCompatButton implement
/** /**
* render * 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. * return NULL, the XML "text" attribute will be preserved.
* *
* If there is only name label, it will be centered and at normal font size. * 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. * have their font size adjusted to fit inside the key.
*/ */
public void render() { public void render() {
String name = getTitle(); String title = getTitle();
String func = getSubTitle(); String subtitle = getSubTitle();
if (name == null) { if (title == null) {
return; return;
} else if (func == null) { } else if (subtitle == null) {
setText(name); setText(title);
return; return;
} }
SpannableStringBuilder sb = new SpannableStringBuilder(name); SpannableStringBuilder sb = new SpannableStringBuilder(title);
sb.append('\n'); 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 RelativeSizeSpan(COMPLEX_LABEL_TITLE_SIZE), 0, 2, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
sb.setSpan(new StyleSpan(Typeface.ITALIC), 0, 2, Spanned.SPAN_EXCLUSIVE_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); 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) { if (tt9 == null) {
Logger.w(getClass().getCanonicalName(), "Traditional T9 handler is not set. Ignoring key press."); Logger.w(getClass().getCanonicalName(), "Traditional T9 handler is not set. Ignoring key press.");
return false; return false;
} }
int keyCode = Key.numberToCode(getNumber(keyId)); int keyCode = Key.numberToCode(getNumber(getId()));
if (keyCode < 0) { if (keyCode < 0) {
return false; return false;
} }
@ -43,6 +56,58 @@ public class SoftNumberKey extends SoftKey {
return true; 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) { private int getNumber(int keyId) {
if (keyId == R.id.soft_key_0) return 0; if (keyId == R.id.soft_key_0) return 0;
if (keyId == R.id.soft_key_1) return 1; if (keyId == R.id.soft_key_1) return 1;
@ -57,44 +122,4 @@ public class SoftNumberKey extends SoftKey {
return -1; 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); 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) { if (tt9 == null) {
Logger.w(getClass().getCanonicalName(), "Traditional T9 handler is not set. Ignoring key press."); Logger.w(getClass().getCanonicalName(), "Traditional T9 handler is not set. Ignoring key press.");
return false; return false;
} }
int keyId = getId();
if (tt9.getSettings().getInputMode() == InputMode.MODE_123) { 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_1) return tt9.onOtherKey(KeyEvent.KEYCODE_STAR);
if (keyId == R.id.soft_key_punctuation_2) return tt9.onOtherKey(KeyEvent.KEYCODE_POUND); if (keyId == R.id.soft_key_punctuation_2) return tt9.onOtherKey(KeyEvent.KEYCODE_POUND);
@ -40,8 +56,11 @@ public class SoftPunctuationKey extends SoftKey {
@Override @Override
protected String getTitle() { protected String getTitle() {
int keyId = getId(); if (tt9 == null) {
return "PUNC";
}
int keyId = getId();
if (tt9.getSettings().getInputMode() == InputMode.MODE_123) { if (tt9.getSettings().getInputMode() == InputMode.MODE_123) {
if (keyId == R.id.soft_key_punctuation_1) return ""; if (keyId == R.id.soft_key_punctuation_1) return "";
if (keyId == R.id.soft_key_punctuation_2) return "#"; if (keyId == R.id.soft_key_punctuation_2) return "#";
@ -52,4 +71,15 @@ public class SoftPunctuationKey extends SoftKey {
return "PUNC"; 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;
}
} }