1
0
Fork 0

Added computer numpad support

* support for the number keys

* support for the arithmetic keys
This commit is contained in:
sspanak 2023-02-06 12:56:36 +02:00 committed by Dimo Karaivanov
parent b159e552e5
commit 008aea12e4
14 changed files with 203 additions and 136 deletions

View file

@ -194,18 +194,8 @@ abstract class KeyPadHandler extends InputMethodService {
return true;
}
switch (keyCode) {
case KeyEvent.KEYCODE_0:
case KeyEvent.KEYCODE_1:
case KeyEvent.KEYCODE_2:
case KeyEvent.KEYCODE_3:
case KeyEvent.KEYCODE_4:
case KeyEvent.KEYCODE_5:
case KeyEvent.KEYCODE_6:
case KeyEvent.KEYCODE_7:
case KeyEvent.KEYCODE_8:
case KeyEvent.KEYCODE_9:
return onNumber(Key.codeToNumber(keyCode), true, 0);
if (Key.isNumber(keyCode)) {
return onNumber(Key.codeToNumber(settings, keyCode), true, 0);
}
ignoreNextKeyUp = 0;
@ -250,7 +240,7 @@ abstract class KeyPadHandler extends InputMethodService {
}
if (keyCode == KeyEvent.KEYCODE_0) {
return onNumber(Key.codeToNumber(keyCode), false, numKeyRepeatCounter);
return onNumber(Key.codeToNumber(settings, keyCode), false, numKeyRepeatCounter);
}
// dialer fields are similar to pure numeric fields, but for user convenience, holding "0"
@ -267,21 +257,15 @@ abstract class KeyPadHandler extends InputMethodService {
return onOK();
}
if (Key.isNumber(keyCode)) {
return onNumber(Key.codeToNumber(settings, keyCode), false, numKeyRepeatCounter);
}
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP: return onUp();
case KeyEvent.KEYCODE_DPAD_DOWN: return onDown();
case KeyEvent.KEYCODE_DPAD_LEFT: return onLeft();
case KeyEvent.KEYCODE_DPAD_RIGHT: return onRight(keyRepeatCounter > 0);
case KeyEvent.KEYCODE_1:
case KeyEvent.KEYCODE_2:
case KeyEvent.KEYCODE_3:
case KeyEvent.KEYCODE_4:
case KeyEvent.KEYCODE_5:
case KeyEvent.KEYCODE_6:
case KeyEvent.KEYCODE_7:
case KeyEvent.KEYCODE_8:
case KeyEvent.KEYCODE_9:
return onNumber(Key.codeToNumber(keyCode), false, numKeyRepeatCounter);
case KeyEvent.KEYCODE_STAR: return onStar();
case KeyEvent.KEYCODE_POUND: return onPound();
}

View file

@ -6,7 +6,9 @@ import io.github.sspanak.tt9.preferences.SettingsStore;
public class Key {
public static boolean isNumber(int keyCode) {
return keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9;
return
(keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9)
|| (keyCode >= KeyEvent.KEYCODE_NUMPAD_0 && keyCode <= KeyEvent.KEYCODE_NUMPAD_9);
}
@ -27,28 +29,38 @@ public class Key {
}
public static int codeToNumber(int keyCode) {
public static int codeToNumber(SettingsStore settings, int keyCode) {
switch (keyCode) {
case KeyEvent.KEYCODE_0:
case KeyEvent.KEYCODE_NUMPAD_0:
return 0;
case KeyEvent.KEYCODE_1:
return 1;
case KeyEvent.KEYCODE_NUMPAD_1:
return settings.getUpsideDownKeys() ? 7 : 1;
case KeyEvent.KEYCODE_2:
return 2;
case KeyEvent.KEYCODE_NUMPAD_2:
return settings.getUpsideDownKeys() ? 8 : 2;
case KeyEvent.KEYCODE_3:
return 3;
case KeyEvent.KEYCODE_NUMPAD_3:
return settings.getUpsideDownKeys() ? 9 : 3;
case KeyEvent.KEYCODE_4:
case KeyEvent.KEYCODE_NUMPAD_4:
return 4;
case KeyEvent.KEYCODE_5:
case KeyEvent.KEYCODE_NUMPAD_5:
return 5;
case KeyEvent.KEYCODE_6:
case KeyEvent.KEYCODE_NUMPAD_6:
return 6;
case KeyEvent.KEYCODE_7:
return 7;
case KeyEvent.KEYCODE_NUMPAD_7:
return settings.getUpsideDownKeys() ? 1 : 7;
case KeyEvent.KEYCODE_8:
return 8;
case KeyEvent.KEYCODE_NUMPAD_8:
return settings.getUpsideDownKeys() ? 2 : 8;
case KeyEvent.KEYCODE_9:
return 9;
case KeyEvent.KEYCODE_NUMPAD_9:
return settings.getUpsideDownKeys() ? 3 : 9;
default:
return -1;
}

View file

@ -45,6 +45,7 @@ public class SettingsStore {
return true;
}
@SuppressWarnings("SameParameterValue")
private boolean isIntInList(int number, ArrayList<Integer> list, String logTag, String logMsg) {
if (!list.contains(number)) {
Logger.w(logTag, logMsg);
@ -209,6 +210,7 @@ public class SettingsStore {
public boolean getAutoSpace() { return prefs.getBoolean("auto_space", false); }
public boolean getAutoTextCase() { return prefs.getBoolean("auto_text_case", true); }
public String getDoubleZeroChar() { return prefs.getString("pref_double_zero_char", " "); }
public boolean getUpsideDownKeys() { return prefs.getBoolean("pref_upside_down_keys", false); }
/************* internal settings *************/

View file

@ -0,0 +1,135 @@
package io.github.sspanak.tt9.preferences.helpers;
import android.content.Context;
import android.content.res.Resources;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.ViewConfiguration;
import java.util.LinkedHashMap;
import java.util.Set;
import io.github.sspanak.tt9.R;
public class Hotkeys {
private final Context context;
private final Resources resources;
private final String holdKeyTranslation;
private final LinkedHashMap<String, String> KEYS = new LinkedHashMap<>();
public Hotkeys(Context context) {
this.context = context;
resources = context.getResources();
holdKeyTranslation = resources.getString(R.string.key_hold_key);
addNoKey();
generateList();
}
public String get(String key) {
return KEYS.get(key);
}
public Set<String> toSet() {
return KEYS.keySet();
}
/**
* addIfDeviceHasKey
* Add the key only if Android says the device has such keypad button or a permanent touch key.
*/
private void addIfDeviceHasKey(int code, String name, boolean allowHold) {
if (
(code == KeyEvent.KEYCODE_MENU && ViewConfiguration.get(context).hasPermanentMenuKey())
|| KeyCharacterMap.deviceHasKey(code)
) {
add(code, name, allowHold);
}
}
/**
* addIfDeviceHasKey
* Same as addIfDeviceHasKey, but accepts a Resource String as a key name.
*
*/
@SuppressWarnings("SameParameterValue")
private void addIfDeviceHasKey(int code, int nameResource, boolean allowHold) {
addIfDeviceHasKey(code, resources.getString(nameResource), allowHold);
}
/**
* add
* These key will be added as a selectable option, regardless if it exists or or not.
* No validation will be performed.
*/
private void add(int code, String name, boolean allowHold) {
KEYS.put(String.valueOf(code), name);
if (allowHold) {
KEYS.put(String.valueOf(-code), name + " " + holdKeyTranslation);
}
}
/**
* add
* Same as add(), but accepts a Resource String as a key name.
*/
@SuppressWarnings("SameParameterValue")
private void add(int code, int nameResource, boolean allowHold) {
add(code, resources.getString(nameResource), allowHold);
}
/**
* addNoKey
* This is the "--" option. The key code matches no key on the keypad.
*/
private void addNoKey() {
add(0, R.string.key_none, false);
}
/**
* generateList
* These keys will appears as options only if Android says the device has them.
*
* NOTE: Some TT9 functions do not support all keys. Here you just list all possible options.
* Actual validation and assigning happens in SectionKeymap.populate().
*
* NOTE 2: Holding is deliberately skipped for most of the keys.
* It's because handling holding requires short press event to be consumed in
* KeyPadHandler, as well.
*
* From user perspective, when holding is assigned to a function,
* short press will also stop performing its default system action, which may be confusing.
* And in order to avoid lengthy explanations in the documentation (that no one reads),
* the problem is avoided by simply not causing it.
*/
private void generateList() {
add(KeyEvent.KEYCODE_CALL, R.string.key_call, false);
addIfDeviceHasKey(KeyEvent.KEYCODE_BACK, R.string.key_back, false);
addIfDeviceHasKey(KeyEvent.KEYCODE_DEL, R.string.key_delete, false);
addIfDeviceHasKey(KeyEvent.KEYCODE_F1, "F1", true);
addIfDeviceHasKey(KeyEvent.KEYCODE_F2, "F2", true);
addIfDeviceHasKey(KeyEvent.KEYCODE_F3, "F3", true);
addIfDeviceHasKey(KeyEvent.KEYCODE_F4, "F4", true);
addIfDeviceHasKey(KeyEvent.KEYCODE_MENU, R.string.key_menu, false);
add(KeyEvent.KEYCODE_POUND, "#", true);
add(KeyEvent.KEYCODE_STAR, "", true);
addIfDeviceHasKey(KeyEvent.KEYCODE_NUMPAD_ADD, "Num +", true);
addIfDeviceHasKey(KeyEvent.KEYCODE_NUMPAD_SUBTRACT, "Num -", true);
addIfDeviceHasKey(KeyEvent.KEYCODE_NUMPAD_MULTIPLY, "Num *", true);
addIfDeviceHasKey(KeyEvent.KEYCODE_NUMPAD_DIVIDE, "Num /", true);
addIfDeviceHasKey(KeyEvent.KEYCODE_NUMPAD_DOT, "Num .", true);
}
}

View file

@ -1,21 +1,16 @@
package io.github.sspanak.tt9.preferences.items;
import android.content.Context;
import android.content.res.Resources;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.ViewConfiguration;
import androidx.preference.DropDownPreference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Objects;
import io.github.sspanak.tt9.Logger;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.helpers.Hotkeys;
public class SectionKeymap {
public static final String ITEM_ADD_WORD = "key_add_word";
@ -24,15 +19,15 @@ public class SectionKeymap {
public static final String ITEM_NEXT_LANGUAGE = "key_next_language";
public static final String ITEM_SHOW_SETTINGS = "key_show_settings";
private final LinkedHashMap<String, String> KEYS = new LinkedHashMap<>();
private final Hotkeys hotkeys;
private final Collection<DropDownPreference> items;
private final SettingsStore settings;
public SectionKeymap(Collection<DropDownPreference> dropDowns, Context context, SettingsStore settings) {
items = dropDowns;
hotkeys = new Hotkeys(context);
this.settings = settings;
generateKeyList(context);
}
@ -60,95 +55,7 @@ public class SectionKeymap {
}
/**
* generateKeyList
* Generates the key list to be used in each dropdown.
*
* NOTE: Some dropdowns do not support some keys,but filtering is performed
* in populate(), not here.
*
* NOTE 2: Holding is deliberately skipped for most of the keys. It's because
* when a function is assigned only to the "hold" state, the "short press" state
* also gets consumed in KeyPadHandler, effectively disabling the default function of the key.
* However, this may be confusing from user perspective, so in order to avoid lengthy
* explanations in the documentation (that no one reads), the problem is avoided by
* simply not causing it.
*
* So, if adding support for new keys, think twice whether to add the "hold" variant as well.
*/
private void generateKeyList(Context context) {
Resources resources = context.getResources();
KEYS.put(String.valueOf(0), resources.getString(R.string.key_none));
// BACK
if (KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK)) {
KEYS.put(String.valueOf(KeyEvent.KEYCODE_BACK), resources.getString(R.string.key_back));
}
// CALL
KEYS.put(String.valueOf(KeyEvent.KEYCODE_CALL), resources.getString(R.string.key_call));
// DELETE / BACKSPACE
if (KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_DEL)) {
KEYS.put(String.valueOf(KeyEvent.KEYCODE_DEL), resources.getString(R.string.key_delete));
}
// F1
if (KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_F1)) {
KEYS.put(String.valueOf(KeyEvent.KEYCODE_F1), resources.getString(R.string.key_f1));
KEYS.put(
String.valueOf(-KeyEvent.KEYCODE_F1),
resources.getString(R.string.key_f1) + " " + resources.getString(R.string.key_hold_key)
);
}
// F2
if (KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_F2)) {
KEYS.put(String.valueOf(KeyEvent.KEYCODE_F2), resources.getString(R.string.key_f2));
KEYS.put(
String.valueOf(-KeyEvent.KEYCODE_F2),
resources.getString(R.string.key_f2) + " " + resources.getString(R.string.key_hold_key)
);
}
// F3
if (KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_F3)) {
KEYS.put(String.valueOf(KeyEvent.KEYCODE_F3), resources.getString(R.string.key_f3));
KEYS.put(
String.valueOf(-KeyEvent.KEYCODE_F3),
resources.getString(R.string.key_f3) + " " + resources.getString(R.string.key_hold_key)
);
}
// F4
if (KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_F4)) {
KEYS.put(String.valueOf(KeyEvent.KEYCODE_F4), resources.getString(R.string.key_f4));
KEYS.put(
String.valueOf(-KeyEvent.KEYCODE_F4),
resources.getString(R.string.key_f4) + " " + resources.getString(R.string.key_hold_key)
);
}
// MENU
if (ViewConfiguration.get(context).hasPermanentMenuKey()) {
KEYS.put(String.valueOf(KeyEvent.KEYCODE_MENU), resources.getString(R.string.key_menu));
}
// #
KEYS.put(String.valueOf(KeyEvent.KEYCODE_POUND), resources.getString(R.string.key_pound));
KEYS.put(
String.valueOf(-KeyEvent.KEYCODE_POUND),
resources.getString(R.string.key_pound) + " " + resources.getString(R.string.key_hold_key)
);
// *
KEYS.put(String.valueOf(KeyEvent.KEYCODE_STAR), resources.getString(R.string.key_star));
KEYS.put(
String.valueOf(-KeyEvent.KEYCODE_STAR),
resources.getString(R.string.key_star) + " " + resources.getString(R.string.key_hold_key)
);
}
private void populateOtherItems(DropDownPreference itemToSkip) {
@ -169,7 +76,7 @@ public class SectionKeymap {
}
ArrayList<String> keys = new ArrayList<>();
for (String key : KEYS.keySet()) {
for (String key : hotkeys.toSet()) {
if (
validateKey(dropDown, String.valueOf(key))
// backspace works both when pressed short and long,
@ -185,7 +92,7 @@ public class SectionKeymap {
ArrayList<String> values = new ArrayList<>();
for (String key : keys) {
values.add(KEYS.get(key));
values.add(hotkeys.get(key));
}
dropDown.setEntries(values.toArray(new CharSequence[0]));
@ -222,7 +129,7 @@ public class SectionKeymap {
return;
}
dropDown.setSummary(KEYS.get(key));
dropDown.setSummary(hotkeys.get(key));
}