Added computer numpad support
* support for the number keys * support for the arithmetic keys
This commit is contained in:
parent
b159e552e5
commit
008aea12e4
14 changed files with 203 additions and 136 deletions
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 *************/
|
||||
|
|
|
|||
135
src/io/github/sspanak/tt9/preferences/helpers/Hotkeys.java
Normal file
135
src/io/github/sspanak/tt9/preferences/helpers/Hotkeys.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue