multi-press protection hack
This commit is contained in:
parent
6b95c6b9d1
commit
81d71abe39
18 changed files with 158 additions and 20 deletions
|
|
@ -6,6 +6,8 @@ import android.view.View;
|
|||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.ime.helpers.Key;
|
||||
import io.github.sspanak.tt9.preferences.SettingsStore;
|
||||
|
|
@ -14,6 +16,9 @@ import io.github.sspanak.tt9.preferences.SettingsStore;
|
|||
abstract class KeyPadHandler extends InputMethodService {
|
||||
protected SettingsStore settings;
|
||||
|
||||
// debounce handling
|
||||
private final HashMap<Integer, Long> lastKeyTime = new HashMap<>();
|
||||
|
||||
// temporal key handling
|
||||
private boolean isBackspaceHandled = false;
|
||||
|
||||
|
|
@ -112,6 +117,10 @@ abstract class KeyPadHandler extends InputMethodService {
|
|||
*/
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (debounceKey(keyCode, event)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (shouldBeOff()) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -187,6 +196,10 @@ abstract class KeyPadHandler extends InputMethodService {
|
|||
*/
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||
if (debounceKey(keyCode, event)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (shouldBeOff()) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -273,6 +286,26 @@ abstract class KeyPadHandler extends InputMethodService {
|
|||
}
|
||||
|
||||
|
||||
private boolean debounceKey(int keyCode, KeyEvent event) {
|
||||
if (settings.getKeyPadDebounceTime() <= 0 || event.isLongPress()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
Long lastTime = lastKeyTime.get(keyCode);
|
||||
|
||||
if (lastTime != null && now - lastTime < settings.getKeyPadDebounceTime()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
lastKeyTime.put(keyCode, now);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// hardware key handlers
|
||||
abstract protected boolean onBack();
|
||||
abstract public boolean onBackspace();
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ public class SettingsStore {
|
|||
|
||||
/************* typing settings *************/
|
||||
|
||||
public int getAbcAutoAcceptTimeout() { return prefs.getBoolean("abc_auto_accept", true) ? 800 : -1; }
|
||||
public int getAbcAutoAcceptTimeout() { return prefs.getBoolean("abc_auto_accept", true) ? 800 + getKeyPadDebounceTime() : -1; }
|
||||
public boolean getAutoSpace() { return prefs.getBoolean("auto_space", true); }
|
||||
public boolean getAutoTextCase() { return prefs.getBoolean("auto_text_case", true); }
|
||||
public String getDoubleZeroChar() {
|
||||
|
|
@ -275,7 +275,6 @@ public class SettingsStore {
|
|||
public final static int DICTIONARY_IMPORT_BATCH_SIZE = 5000; // words
|
||||
public final static int DICTIONARY_IMPORT_PROGRESS_UPDATE_TIME = 250; // ms
|
||||
public final static int DICTIONARY_MISSING_WARNING_INTERVAL = 30000; // ms
|
||||
public final static int PREFERENCES_CLICK_DEBOUNCE_TIME = 250; // ms
|
||||
public final static byte SLOW_QUERY_TIME = 50; // ms
|
||||
public final static int SOFT_KEY_REPEAT_DELAY = 40; // ms
|
||||
public final static float SOFT_KEY_COMPLEX_LABEL_TITLE_SIZE = 0.55f;
|
||||
|
|
@ -304,4 +303,20 @@ public class SettingsStore {
|
|||
public boolean getGoogleChatHack() {
|
||||
return prefs.getBoolean("pref_hack_google_chat", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protection against faulty devices, that sometimes send two (or more) click events
|
||||
* per a single key press, which absolutely undesirable side effects.
|
||||
* There were reports about this on <a href="https://github.com/sspanak/tt9/issues/117">Kyocera KYF31</a>
|
||||
* and on <a href="https://github.com/sspanak/tt9/issues/399">CAT S22</a>.
|
||||
*/
|
||||
public final static int PREFERENCES_CLICK_DEBOUNCE_TIME = 250; // ms
|
||||
|
||||
public int getKeyPadDebounceTime() {
|
||||
try {
|
||||
return Integer.parseInt(prefs.getString("pref_key_pad_debounce_time", "0"));
|
||||
} catch (NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,16 +57,6 @@ abstract public class ItemClickable {
|
|||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* debounceClick
|
||||
* Protection against faulty devices, that sometimes send two (or more) click events
|
||||
* per a single key press.
|
||||
*
|
||||
* My smashed Qin F21 Pro+ occasionally does this, if I press the keys hard.
|
||||
* There were reports the same happens on Kyocera KYF31, causing absolutely undesirable side effects.
|
||||
* See: <a href="https://github.com/sspanak/tt9/issues/117">...</a>
|
||||
*/
|
||||
protected boolean debounceClick(Preference p) {
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - lastClickTime < SettingsStore.PREFERENCES_CLICK_DEBOUNCE_TIME) {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,20 @@ public class ItemDropDown {
|
|||
item.setEntries(this.values.values().toArray(new CharSequence[0]));
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
if (item != null) {
|
||||
item.setEnabled(false);
|
||||
item.setOnPreferenceChangeListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void enable() {
|
||||
if (item != null) {
|
||||
item.setEnabled(true);
|
||||
enableClickHandler();
|
||||
}
|
||||
}
|
||||
|
||||
public ItemDropDown enableClickHandler() {
|
||||
if (item == null) {
|
||||
Logger.w("SectionKeymap.populateItem", "Cannot set a click listener a NULL item. Ignoring.");
|
||||
|
|
@ -63,7 +77,7 @@ public class ItemDropDown {
|
|||
public void preview() {
|
||||
try {
|
||||
setPreview(values.get(Integer.parseInt(item.getValue())));
|
||||
} catch (NumberFormatException e) {
|
||||
} catch (Exception e) {
|
||||
setPreview("");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
package io.github.sspanak.tt9.preferences.items;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.preference.DropDownPreference;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import io.github.sspanak.tt9.R;
|
||||
|
||||
public class ItemKeyPadDebounceTime extends ItemDropDown {
|
||||
public static final String NAME = "pref_key_pad_debounce_time";
|
||||
|
||||
private final Context context;
|
||||
|
||||
public ItemKeyPadDebounceTime(Context context, DropDownPreference item) {
|
||||
super(item);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public ItemDropDown populate() {
|
||||
LinkedHashMap<Integer, String> dropDownOptions = new LinkedHashMap<>();
|
||||
dropDownOptions.put(0, context.getString(R.string.pref_hack_key_pad_debounce_off));
|
||||
|
||||
int[] values = new int[] { 33, 50, 100, 150, 250, 350 };
|
||||
for (int value : values) {
|
||||
dropDownOptions.put(value, value + " ms");
|
||||
}
|
||||
super.populate(dropDownOptions);
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import androidx.preference.Preference;
|
|||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.ime.helpers.SystemSettings;
|
||||
import io.github.sspanak.tt9.preferences.PreferencesActivity;
|
||||
import io.github.sspanak.tt9.preferences.items.ItemKeyPadDebounceTime;
|
||||
import io.github.sspanak.tt9.preferences.items.ItemSelectGlobalKeyboard;
|
||||
import io.github.sspanak.tt9.preferences.items.ItemSetDefaultGlobalKeyboard;
|
||||
|
||||
|
|
@ -17,18 +18,18 @@ public class SetupScreen extends BaseScreenFragment {
|
|||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
createKeyboardSection();
|
||||
boolean isTT9On = SystemSettings.isTT9Enabled(activity);
|
||||
createKeyboardSection(isTT9On);
|
||||
createHacksSection(isTT9On);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
createKeyboardSection();
|
||||
onCreate();
|
||||
}
|
||||
|
||||
private void createKeyboardSection() {
|
||||
boolean isTT9On = SystemSettings.isTT9Enabled(activity);
|
||||
|
||||
private void createKeyboardSection(boolean isTT9On) {
|
||||
Preference statusItem = findPreference("global_tt9_status");
|
||||
if (statusItem != null) {
|
||||
statusItem.setSummary(
|
||||
|
|
@ -43,4 +44,29 @@ public class SetupScreen extends BaseScreenFragment {
|
|||
new ItemSetDefaultGlobalKeyboard(defaultKeyboardItem, activity).enableClickHandler();
|
||||
}
|
||||
}
|
||||
|
||||
private void createHacksSection(boolean isTT9On) {
|
||||
Preference altScrolling = findPreference("pref_alternative_suggestion_scrolling");
|
||||
if (altScrolling != null) {
|
||||
altScrolling.setEnabled(isTT9On);
|
||||
}
|
||||
|
||||
Preference hackGoogleChat = findPreference("pref_hack_google_chat");
|
||||
if (hackGoogleChat != null) {
|
||||
hackGoogleChat.setEnabled(isTT9On);
|
||||
}
|
||||
|
||||
Preference hackFBMessenger = findPreference("pref_hack_fb_messenger");
|
||||
if (hackFBMessenger != null) {
|
||||
hackFBMessenger.setEnabled(isTT9On);
|
||||
}
|
||||
|
||||
ItemKeyPadDebounceTime item = new ItemKeyPadDebounceTime(activity, findPreference(ItemKeyPadDebounceTime.NAME));
|
||||
item.populate().preview();
|
||||
if (isTT9On) {
|
||||
item.enable();
|
||||
} else {
|
||||
item.disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,4 +82,6 @@
|
|||
<string name="pref_dark_theme_no">Не</string>
|
||||
<string name="pref_dark_theme_auto">Автоматично</string>
|
||||
<string name="add_word_confirm">Да се добави ли „%1$s“ към %2$s?</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">Защита от многократно натискане</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">Изключена</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -34,4 +34,6 @@
|
|||
<string name="donate_summary">Wenn Ihnen %1$s gefällt, könnten Sie die Entwicklung auf %2$s unterstützen.</string>
|
||||
<string name="pref_hack_fb_messenger">Mit \"OK\" in Facebook Messenger senden</string>
|
||||
<string name="pref_hack_google_chat">Nachrichten mit \"OK\" in Google Chat senden</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">Mehrfacher Pressschutz</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">Aus</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -78,4 +78,6 @@
|
|||
<string name="donate_summary">Si te gusta %1$s, podrías apoyar su desarrollo en: %2$s.</string>
|
||||
<string name="pref_hack_fb_messenger">Enviar con «OK» en Facebook Messenger</string>
|
||||
<string name="pref_hack_google_chat">Enviar mensajes con «OK» en Google Chat</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">Protección con múltiples clics</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">Apagado</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -76,4 +76,6 @@
|
|||
<string name="add_word_confirm">Ajouter mot « %1$s » à %2$s?</string>
|
||||
<string name="donate_title">Donner</string>
|
||||
<string name="donate_summary">Si vous aimez %1$s vous pouvez soutenir son développement à : %2$s</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">Protection multi-presse</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">Désactivée</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -43,5 +43,7 @@
|
|||
<string name="donate_summary">Se ti piace %1$s, potresti supportarne lo sviluppo su: %2$s.</string>
|
||||
<string name="pref_hack_fb_messenger">Inviare con \"OK\" su Facebook Messenger</string>
|
||||
<string name="pref_hack_google_chat">Inviare messaggi con \"OK\" su Google Chat</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">Protezione multi-pressione</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">Spento</string>
|
||||
</resources>
|
||||
|
||||
|
|
|
|||
|
|
@ -71,4 +71,6 @@
|
|||
<string name="donate_summary">אם אתה אוהב את %1$s, תוכל לתמוך בפיתוח שלו בכתובת: %2$s</string>
|
||||
<string name="pref_hack_fb_messenger">שלח עם \"OK\" ב-Facebook Messenger.</string>
|
||||
<string name="pref_hack_google_chat">שלח הודעות עם \"OK\" ב-Google Chat</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">הגנה מרובה לחיצות</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">כבוי</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -34,4 +34,6 @@
|
|||
<string name="donate_summary">Als je %1$s leuk vindt, zou je de ontwikkeling kunnen ondersteunen op: %2$s.</string>
|
||||
<string name="pref_hack_fb_messenger">Verstuur met \"OK\" in Facebook Messenger</string>
|
||||
<string name="pref_hack_google_chat">Stuur berichten met \"OK\" in Google Chat</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">Bescherming tegen meervoudig persen</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">Uit</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -67,4 +67,6 @@
|
|||
<string name="donate_summary">Se você gosta de %1$s, você poderia apoiar o seu desenvolvimento em: %2$s.</string>
|
||||
<string name="pref_hack_fb_messenger">Enviar com \"OK\" no Facebook Messenger</string>
|
||||
<string name="pref_hack_google_chat">Enviar mensagens com \"OK\" no Google Chat</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">Proteção multiclique</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">Desligado</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -82,4 +82,6 @@
|
|||
<string name="donate_title">Поддержать</string>
|
||||
<string name="donate_summary">Если вам нравится %1$s, вы можете поддержать его разработку по: %2$s.</string>
|
||||
<string name="pref_hack_google_chat">Отправка сообщения с «ОК» в Google Chat</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">Защита от многократного нажатия</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">Выключена</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -82,4 +82,6 @@
|
|||
<string name="donate_title">Підтримуйте</string>
|
||||
<string name="donate_summary">Якщо вам подобається %1$s, ви можете підтримати його розробку за: %2$s.</string>
|
||||
<string name="pref_hack_google_chat">Надсилати повідомлення з «ОК» до Google Chat</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">Захист від багаторазового натискання</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">Вимкнено</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@
|
|||
<string name="pref_double_zero_char">Character for Double 0-key Press</string>
|
||||
<string name="pref_hack_google_chat">Send messages with \"OK\" in Google Chat</string>
|
||||
<string name="pref_hack_fb_messenger">Send with \"OK\" in Facebook Messenger</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">Multi-Press Protection</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">Off</string>
|
||||
<string name="pref_show_soft_function_keys">Show On-Screen Keys</string>
|
||||
<string name="pref_show_soft_numpad">Show On-Screen Numpad</string>
|
||||
<string name="pref_show_soft_numpad_summary" translatable="false">(BETA)</string>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
app:layout="@layout/pref_text"
|
||||
app:orderingFromXml="true">
|
||||
<Preference
|
||||
|
|
@ -37,5 +36,11 @@
|
|||
app:layout="@layout/pref_switch"
|
||||
app:title="@string/pref_hack_fb_messenger"/>
|
||||
|
||||
<DropDownPreference
|
||||
app:iconSpaceReserved="false"
|
||||
app:key="pref_key_pad_debounce_time"
|
||||
app:layout="@layout/pref_dropdown"
|
||||
app:title="@string/pref_hack_key_pad_debounce_time" />
|
||||
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue