Code restructuring, miscellaneous fixes.
This commit is contained in:
+14
-5
@@ -21,12 +21,13 @@ isn't very reminiscent of a regular QWERTY keyboard which people are used to:
|
||||
other
|
||||
symbols from regular QWERTY keyboards.
|
||||
5. There is no extra alt-gr key to type in localized letters.
|
||||
6. In my opinion, it also lacks a control key, but that is unnecessary on smartphones, unless you
|
||||
6. The keyboard is too big for one hand typing.
|
||||
7. In my opinion, it also lacks a control key, but that is unnecessary on smartphones, unless you
|
||||
use the terminal or modify spreadsheets. However, providing appropriate UI elements for the
|
||||
actions
|
||||
possible on regular computers should be the responsibility of the application. Smartphones are
|
||||
simply different devices, with smaller screens and less space for complexity.
|
||||
7. Emojis.
|
||||
8. Emojis.
|
||||
|
||||
However, when designing a keyboard app for it one should already use all pre-existing quirks and
|
||||
decisions which materialized in the physical keyboard. For example, the alt key should be used for
|
||||
@@ -48,8 +49,10 @@ key is long pressed. A menu pops up, and as you hold the key the symbols are cyc
|
||||
5. Similar to regular visual keyboards on Android, a diacritic/alternate key is assigned to each key
|
||||
according to the language. Long pressing a key will allow you to cycle through available
|
||||
alternatives.
|
||||
6. I have no plans on adding a control key, as it is largely unnecessary on phones.
|
||||
7. I do not really use emojis, but I am aware that they are used by the majority of people. Most
|
||||
6. A toggleable UI that shows the left/right hand side keys, depending on a customizable setting for
|
||||
left handed people.
|
||||
7. I have no plans on adding a control key, as it is largely unnecessary on phones.
|
||||
8. I do not really use emojis, but I am aware that they are used by the majority of people. Most
|
||||
IM apps provide their own emoji list, so this isn't a priority. Designing a good UX for it is also
|
||||
hard on the Titan.
|
||||
|
||||
@@ -84,4 +87,10 @@ layout, which contains all characters used in Europe.
|
||||
## European
|
||||
German has the most speakers, therefore it's diacritics are the first in the list. Then French and
|
||||
Italian, which have similar diacritics. These come next. Afterwards, Spanish, then Polish, and the
|
||||
rest.
|
||||
rest.
|
||||
|
||||
## Cyrillic
|
||||
Regular JCUKEN layout, with additional characters for other non-Russian languages.
|
||||
|
||||
## Greek
|
||||
Works mostly like a regular Greek QWERTY keyboard.
|
||||
@@ -9,6 +9,7 @@ android {
|
||||
defaultConfig {
|
||||
applicationId "cfpi_fpsi.eu.titanboard"
|
||||
minSdk 19
|
||||
//noinspection OldTargetApi
|
||||
targetSdk 34
|
||||
versionCode 21
|
||||
versionName "0.2.1"
|
||||
|
||||
@@ -20,11 +20,7 @@
|
||||
package cfpi_fpsi.eu.titanboard;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.os.Build;
|
||||
import android.os.Vibrator;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
@@ -32,9 +28,6 @@ import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.ExtractedText;
|
||||
import android.view.inputmethod.ExtractedTextRequest;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
@@ -46,35 +39,29 @@ import java.util.Deque;
|
||||
// TODO: Implement device recognition and a keymap picking based on it.
|
||||
|
||||
public class InputMethod extends InputMethodService {
|
||||
private MetaKeyManager mMetaKeyManager;
|
||||
private ArrayList<String> mCurrentValues;
|
||||
private KeymapManager mKeymapManager;
|
||||
private Deque<String> mLanguageQueue = new ArrayDeque<>();
|
||||
private String mCurrentLanguage;
|
||||
private LinearLayout mInputView;
|
||||
private Vibrator mVibrator;
|
||||
SharedPreferences mPreferences;
|
||||
private final Deque<String> mLanguageQueue = new ArrayDeque<>();
|
||||
public MetaKeyManager mMetaKeyManager;
|
||||
public KeymapManager mKeymapManager;
|
||||
public String mCurrentLanguage;
|
||||
private int mKeyCounter = 0;
|
||||
private boolean mRegularKeyPressed = false;
|
||||
|
||||
private InputView mInputView;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
// Ideally, detect the device, but for now, load all available keymaps.
|
||||
mKeymapManager = new KeymapManager(getResources().getXml(R.xml.keymaps_titan));
|
||||
Collections.addAll(mLanguageQueue, mKeymapManager.getAvailableLanguages());
|
||||
mCurrentLanguage = mLanguageQueue.pop();
|
||||
mLanguageQueue.addLast(mCurrentLanguage);
|
||||
mVibrator = (Vibrator) getBaseContext().getSystemService(VIBRATOR_SERVICE);
|
||||
Vibrator mVibrator = (Vibrator) getBaseContext().getSystemService(VIBRATOR_SERVICE);
|
||||
mMetaKeyManager = new MetaKeyManager(mVibrator);
|
||||
mPreferences = getSharedPreferences(getString(R.string.preferences_key), Context.MODE_PRIVATE);
|
||||
mKeymapManager = new KeymapManager(getResources().getXml(R.xml.keymaps_titan));
|
||||
Collections.addAll(mLanguageQueue, mKeymapManager.getAvailableKeymaps());
|
||||
cycleLanguages();
|
||||
}
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
@Override
|
||||
public void onInitializeInterface() {
|
||||
mInputView = (LinearLayout) getLayoutInflater().inflate(R.layout.input, null);
|
||||
mInputView = (InputView) getLayoutInflater().inflate(R.layout.input, null);
|
||||
mInputView.updateStateText();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,8 +73,8 @@ public class InputMethod extends InputMethodService {
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
mMetaKeyManager.updateMetaStateDown(keyCode, event);
|
||||
updateMetaStateTextView();
|
||||
mMetaKeyManager.updateMetaStateDown(keyCode);
|
||||
mInputView.updateStateText();
|
||||
|
||||
InputConnection conn = getCurrentInputConnection();
|
||||
|
||||
@@ -96,7 +83,6 @@ public class InputMethod extends InputMethodService {
|
||||
}
|
||||
|
||||
switch (keyCode) {
|
||||
// If the keyboard is visible, hide it, otherwise, let the system handle the key.
|
||||
case KeyEvent.KEYCODE_BACK:
|
||||
if (isInputViewShown()) {
|
||||
requestHideSelf(0);
|
||||
@@ -108,10 +94,11 @@ public class InputMethod extends InputMethodService {
|
||||
mMetaKeyManager.adjustMetaStateAfterKeypress();
|
||||
return false;
|
||||
case KeyEvent.KEYCODE_SPACE:
|
||||
handleSpacebar(conn);
|
||||
conn.commitText(" ", 1);
|
||||
mMetaKeyManager.adjustMetaStateAfterKeypress();
|
||||
return true;
|
||||
default:
|
||||
mCurrentValues = getKeyValues(keyCode);
|
||||
ArrayList<String> mCurrentValues = getKeyValues(keyCode);
|
||||
|
||||
if (mCurrentValues == null) {
|
||||
return false;
|
||||
@@ -127,29 +114,23 @@ public class InputMethod extends InputMethodService {
|
||||
mKeyCounter = 0;
|
||||
}
|
||||
|
||||
updateSymbolsView(mCurrentValues, mKeyCounter);
|
||||
mInputView.updateSymbolsView(mCurrentValues, mKeyCounter);
|
||||
|
||||
ExtractedText text = conn.getExtractedText(new ExtractedTextRequest(), 0);
|
||||
|
||||
conn.setComposingRegion(text.selectionStart - 1, text.selectionStart);
|
||||
conn.setComposingText(mCurrentValues.get(mKeyCounter), 1);
|
||||
if (text != null) {
|
||||
conn.setComposingRegion(text.selectionStart - 1, text.selectionStart);
|
||||
conn.setComposingText(mCurrentValues.get(mKeyCounter), 1);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void handleSpacebar(InputConnection conn) {
|
||||
// If we press alt + space, we switch the language.
|
||||
if (mMetaKeyManager.getAlt().isActive()) {
|
||||
mCurrentLanguage = mLanguageQueue.pop();
|
||||
mLanguageQueue.addLast(mCurrentLanguage);
|
||||
updateMetaStateTextView();
|
||||
} else {
|
||||
conn.commitText(" ", 1);
|
||||
}
|
||||
|
||||
mMetaKeyManager.adjustMetaStateAfterKeypress();
|
||||
public void cycleLanguages() {
|
||||
mCurrentLanguage = mLanguageQueue.pop();
|
||||
mLanguageQueue.addLast(mCurrentLanguage);
|
||||
}
|
||||
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||
@@ -164,11 +145,11 @@ public class InputMethod extends InputMethodService {
|
||||
mMetaKeyManager.adjustMetaStateAfterKeypress();
|
||||
mKeyCounter = 0;
|
||||
mRegularKeyPressed = false;
|
||||
updateSymbolsView(null, 0);
|
||||
mInputView.updateSymbolsView(null, 0);
|
||||
}
|
||||
|
||||
mMetaKeyManager.updateMetaStateUp(keyCode, event);
|
||||
updateMetaStateTextView();
|
||||
mInputView.updateStateText();
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -181,13 +162,13 @@ public class InputMethod extends InputMethodService {
|
||||
@Override
|
||||
public void onStartInput(EditorInfo info, boolean restarting) {
|
||||
super.onStartInput(info, restarting);
|
||||
updateMetaStateTextView();
|
||||
mInputView.updateStateText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishInput() {
|
||||
mMetaKeyManager.resetMetaKeyState();
|
||||
updateMetaStateTextView();
|
||||
mInputView.updateStateText();
|
||||
}
|
||||
|
||||
private ArrayList<String> getKeyValues(int keyCode) {
|
||||
@@ -201,51 +182,4 @@ public class InputMethod extends InputMethodService {
|
||||
|
||||
return mKeymapManager.getKeyBase(mCurrentLanguage, keyCode);
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private void updateMetaStateTextView() {
|
||||
TextView shiftStateView = mInputView.findViewById(R.id.state_shift);
|
||||
TextView altStateView = mInputView.findViewById(R.id.state_alt);
|
||||
TextView languageStateView = mInputView.findViewById(R.id.state_language);
|
||||
|
||||
shiftStateView.setText(getStringForMetaKey(
|
||||
mMetaKeyManager.getShift(), "aa", "Aa", "AA"));
|
||||
altStateView.setText(getStringForMetaKey(
|
||||
mMetaKeyManager.getAlt(), "..", "#?", "#!"));
|
||||
languageStateView.setText(mKeymapManager.getShortLabel(mCurrentLanguage));
|
||||
}
|
||||
|
||||
private String getStringForMetaKey(MetaKeyManager.MetaKey key, String normal, String latched, String pressed) {
|
||||
if (key.isLatched()) {
|
||||
return latched;
|
||||
}
|
||||
|
||||
if (key.isLocked() || key.isPressed()) {
|
||||
return pressed;
|
||||
}
|
||||
|
||||
return normal;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public void updateSymbolsView(ArrayList<String> symbols, int index) {
|
||||
LinearLayout symbolsView = mInputView.findViewById(R.id.symbols);
|
||||
symbolsView.removeAllViews();
|
||||
if (symbols != null) {
|
||||
for (int i = 0; i < symbols.size(); ++i) {
|
||||
Button symbolButton;
|
||||
|
||||
if (i == index) {
|
||||
symbolButton = new Button(getBaseContext(), null, 0,
|
||||
R.style.KeyboardSymbolSelected);
|
||||
} else {
|
||||
symbolButton = new Button(getBaseContext(), null, 0,
|
||||
R.style.KeyboardSymbol);
|
||||
}
|
||||
|
||||
symbolButton.setText(symbols.get(i));
|
||||
symbolsView.addView(symbolButton);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* An input method for the Unihertz Titan/physical keyboard phones
|
||||
* Copyright (C) 2024 Emil Kosz
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package cfpi_fpsi.eu.titanboard;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class InputView extends RelativeLayout {
|
||||
private final InputMethod mInputMethod;
|
||||
private Button mStateButton;
|
||||
private LinearLayout mMultiList;
|
||||
|
||||
public InputView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs, 0);
|
||||
mInputMethod = (InputMethod) context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mMultiList = findViewById(R.id.multi_list);
|
||||
mStateButton = findViewById(R.id.input_state);
|
||||
mStateButton.setOnClickListener(button -> {
|
||||
mInputMethod.cycleLanguages();
|
||||
updateStateText();
|
||||
});
|
||||
}
|
||||
|
||||
public void updateStateText() {
|
||||
MetaKeyManager metaManager = mInputMethod.mMetaKeyManager;
|
||||
KeymapManager keymapManager = mInputMethod.mKeymapManager;
|
||||
String currentLanguage = mInputMethod.mCurrentLanguage;
|
||||
|
||||
if (metaManager.getAlt().isPressed() || metaManager.getAlt().isLocked()) {
|
||||
mStateButton.setText("#!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (metaManager.getAlt().isLatched()) {
|
||||
mStateButton.setText("#?");
|
||||
return;
|
||||
}
|
||||
|
||||
if (metaManager.getShift().isPressed() || metaManager.getShift().isLocked()) {
|
||||
mStateButton.setText(keymapManager.getKeymap(currentLanguage).getLockedCode());
|
||||
return;
|
||||
}
|
||||
|
||||
if (metaManager.getShift().isLatched()) {
|
||||
mStateButton.setText(keymapManager.getKeymap(currentLanguage).getLatchedCode());
|
||||
return;
|
||||
}
|
||||
|
||||
mStateButton.setText(keymapManager.getKeymap(currentLanguage).getCode());
|
||||
}
|
||||
|
||||
public void updateSymbolsView(ArrayList<String> symbols, int index) {
|
||||
for (int i = 0; i < mMultiList.getChildCount(); ++i) {
|
||||
TextView view = (TextView) mMultiList.getChildAt(i);
|
||||
view.setText("");
|
||||
}
|
||||
|
||||
if (symbols != null) {
|
||||
for (int i = 0; i < Math.min(mMultiList.getChildCount(), symbols.size()); ++i) {
|
||||
TextView view = (TextView) mMultiList.getChildAt(i);
|
||||
view.setText(symbols.get(i));
|
||||
if (i == index) {
|
||||
view.setTextAppearance(getContext(), R.style.InputViewSymbolSelected);
|
||||
} else {
|
||||
view.setTextAppearance(getContext(), R.style.InputViewSymbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,24 +19,20 @@
|
||||
|
||||
package cfpi_fpsi.eu.titanboard;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class KeymapManager {
|
||||
// Yeah... I know this is a little wacky.
|
||||
private final HashMap<String, Keymap> mKeymaps = new HashMap<>();
|
||||
|
||||
public KeymapManager(XmlPullParser parser) {
|
||||
Keymap keymap = null;
|
||||
int code = 0;
|
||||
String lang = null, shortLabel = null, label = null;
|
||||
String label = null, name = null, latchedName = null, lockedName = null;
|
||||
Key key = null;
|
||||
|
||||
try {
|
||||
@@ -46,26 +42,26 @@ public class KeymapManager {
|
||||
// We encounter a new keymap.
|
||||
if (type == XmlPullParser.START_TAG && parser.getName().equals("keymap")) {
|
||||
keymap = new Keymap();
|
||||
lang = null;
|
||||
shortLabel = null;
|
||||
label = null;
|
||||
for (int i = 0; i < parser.getAttributeCount(); ++i) {
|
||||
switch (parser.getAttributeName(i)) {
|
||||
case "lang":
|
||||
lang = parser.getAttributeValue(i);
|
||||
break;
|
||||
case "short-label":
|
||||
shortLabel = parser.getAttributeValue(i);
|
||||
break;
|
||||
case "label":
|
||||
label = parser.getAttributeValue(i);
|
||||
break;
|
||||
case "name":
|
||||
name = parser.getAttributeValue(i);
|
||||
break;
|
||||
case "latched-name":
|
||||
latchedName = parser.getAttributeValue(i);
|
||||
break;
|
||||
case "locked-name":
|
||||
lockedName = parser.getAttributeValue(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (type == XmlPullParser.END_TAG && parser.getName().equals("keymap")) {
|
||||
keymap.mShortLabel = shortLabel;
|
||||
keymap.mLabel = label;
|
||||
mKeymaps.put(lang, keymap);
|
||||
} else if (type == XmlPullParser.END_TAG && parser.getName().equals("keymap")
|
||||
&& keymap != null) {
|
||||
keymap.setStrings(label, name, latchedName, lockedName);
|
||||
mKeymaps.put(label, keymap);
|
||||
}
|
||||
|
||||
// We got a new key.
|
||||
@@ -76,33 +72,32 @@ public class KeymapManager {
|
||||
code = Integer.parseInt(parser.getAttributeValue(i));
|
||||
}
|
||||
}
|
||||
} else if (type == XmlPullParser.END_TAG && parser.getName().equals("key")) {
|
||||
Log.d("STATE", "+++ Keycode: " + code);
|
||||
Log.d("STATE", key.toString());
|
||||
} else if (type == XmlPullParser.END_TAG && parser.getName().equals("key")
|
||||
&& keymap != null) {
|
||||
keymap.put(code, key);
|
||||
}
|
||||
|
||||
// We encountered a base value.
|
||||
if (type == XmlPullParser.START_TAG && parser.getName().equals("base")) {
|
||||
for (int i = 0; i < parser.getAttributeCount(); ++i) {
|
||||
if (parser.getAttributeName(i).startsWith("value")) {
|
||||
key.mBase.add(parser.getAttributeValue(i));
|
||||
if (parser.getAttributeName(i).startsWith("value") && key != null) {
|
||||
key.getBase().add(parser.getAttributeValue(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
// We encountered a shift value.
|
||||
if (type == XmlPullParser.START_TAG && parser.getName().equals("shift")) {
|
||||
for (int i = 0; i < parser.getAttributeCount(); ++i) {
|
||||
if (parser.getAttributeName(i).startsWith("value")) {
|
||||
key.mShift.add(parser.getAttributeValue(i));
|
||||
if (parser.getAttributeName(i).startsWith("value") && key != null) {
|
||||
key.getShift().add(parser.getAttributeValue(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
// We encountered an alt value.
|
||||
if (type == XmlPullParser.START_TAG && parser.getName().equals("alt")) {
|
||||
for (int i = 0; i < parser.getAttributeCount(); ++i) {
|
||||
if (parser.getAttributeName(i).startsWith("value")) {
|
||||
key.mAlt.add(parser.getAttributeValue(i));
|
||||
if (parser.getAttributeName(i).startsWith("value") && key != null) {
|
||||
key.getAlt().add(parser.getAttributeValue(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,92 +109,80 @@ public class KeymapManager {
|
||||
}
|
||||
}
|
||||
|
||||
public String[] getAvailableLanguages() {
|
||||
public String[] getAvailableKeymaps() {
|
||||
return mKeymaps.keySet().toArray(new String[0]);
|
||||
}
|
||||
|
||||
public String getShortLabel(String lang) {
|
||||
Keymap keymap = mKeymaps.get(lang);
|
||||
if (keymap != null) {
|
||||
return keymap.mShortLabel;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
public Keymap getKeymap(String lang) {
|
||||
return mKeymaps.get(lang);
|
||||
}
|
||||
|
||||
public ArrayList<String> getKeyBase(String lang, int keyCode) {
|
||||
Key key = getKey(lang, keyCode);
|
||||
if (key != null) {
|
||||
return key.mBase;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return getKey(lang, keyCode) != null ? getKey(lang, keyCode).getBase() : null;
|
||||
}
|
||||
|
||||
public ArrayList<String> getKeyShift(String lang, int keyCode) {
|
||||
Key key = getKey(lang, keyCode);
|
||||
if (key != null) {
|
||||
return key.mShift;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return getKey(lang, keyCode) != null ? getKey(lang, keyCode).getShift() : null;
|
||||
}
|
||||
|
||||
public ArrayList<String> getKeyAlt(String lang, int keyCode) {
|
||||
Key key = getKey(lang, keyCode);
|
||||
if (key != null) {
|
||||
return key.mAlt;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return getKey(lang, keyCode) != null ? getKey(lang, keyCode).getAlt() : null;
|
||||
}
|
||||
|
||||
public Key getKey(String lang, int keyCode) {
|
||||
Keymap keymap = mKeymaps.get(lang);
|
||||
if (keymap != null) {
|
||||
Key key = keymap.get(keyCode);
|
||||
if (key != null) {
|
||||
return key;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return keymap.get(keyCode);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Keymap extends HashMap<Integer, Key> {
|
||||
public String mShortLabel;
|
||||
public String mLabel;
|
||||
public static class Keymap extends HashMap<Integer, Key> {
|
||||
private String mLabel; // The full name of the keymap.
|
||||
private String mCode; // A two-letter code for when the keyboard is lowercase.
|
||||
private String mLatchedCode; // Above, but when the keyboard is shift latched.
|
||||
private String mLockedCode; // Above, but when the shift is locked/pressed.
|
||||
|
||||
public String getCode() {
|
||||
return mCode;
|
||||
}
|
||||
|
||||
public String getLatchedCode() {
|
||||
return mLatchedCode;
|
||||
}
|
||||
|
||||
public String getLockedCode() {
|
||||
return mLockedCode;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return mLabel;
|
||||
}
|
||||
|
||||
public void setStrings(String label, String code, String latched, String locked) {
|
||||
mLabel = label;
|
||||
mCode = code;
|
||||
mLatchedCode = latched;
|
||||
mLockedCode = locked;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Key {
|
||||
public ArrayList<String> mBase = new ArrayList<>();
|
||||
public ArrayList<String> mShift = new ArrayList<>();
|
||||
public ArrayList<String> mAlt = new ArrayList<>();
|
||||
private final ArrayList<String> mBase = new ArrayList<>();
|
||||
private final ArrayList<String> mShift = new ArrayList<>();
|
||||
private final ArrayList<String> mAlt = new ArrayList<>();
|
||||
|
||||
public String toString() {
|
||||
StringBuilder output = new StringBuilder();
|
||||
public ArrayList<String> getBase() {
|
||||
return mBase;
|
||||
}
|
||||
|
||||
output.append("\n=== Base: ");
|
||||
for (String value : mBase) {
|
||||
output.append(value);
|
||||
output.append(",");
|
||||
}
|
||||
public ArrayList<String> getShift() {
|
||||
return mShift;
|
||||
}
|
||||
|
||||
output.append("\n=== Shift: ");
|
||||
for (String value : mShift) {
|
||||
output.append(value);
|
||||
output.append(",");
|
||||
}
|
||||
|
||||
output.append("\n=== Alt: ");
|
||||
for (String value : mAlt) {
|
||||
output.append(value);
|
||||
output.append(",");
|
||||
}
|
||||
|
||||
return output.toString();
|
||||
public ArrayList<String> getAlt() {
|
||||
return mAlt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,31 +23,31 @@ import android.os.Vibrator;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
public class MetaKeyManager {
|
||||
public MetaKey mShift = new MetaKey();
|
||||
public MetaKey mAlt = new MetaKey();
|
||||
public final MetaKey mShift = new MetaKey();
|
||||
public final MetaKey mAlt = new MetaKey();
|
||||
|
||||
private Vibrator mVibrator;
|
||||
private final Vibrator mVibrator;
|
||||
|
||||
public MetaKeyManager(Vibrator vibrator) {
|
||||
mVibrator = vibrator;
|
||||
}
|
||||
|
||||
public void updateMetaStateDown(int keyCode, KeyEvent event) {
|
||||
public void updateMetaStateDown(int keyCode) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_ALT_LEFT:
|
||||
case KeyEvent.KEYCODE_ALT_RIGHT:
|
||||
updateMetaKeyDown(mAlt, event);
|
||||
updateMetaKeyDown(mAlt);
|
||||
break;
|
||||
case KeyEvent.KEYCODE_SHIFT_LEFT:
|
||||
case KeyEvent.KEYCODE_SHIFT_RIGHT:
|
||||
updateMetaKeyDown(mShift, event);
|
||||
updateMetaKeyDown(mShift);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void updateMetaKeyDown(MetaKey key, KeyEvent event) {
|
||||
void updateMetaKeyDown(MetaKey key) {
|
||||
// Perhaps this function should be renamed to something...
|
||||
key.setUsed(false);
|
||||
key.setPressed(true);
|
||||
|
||||
@@ -23,12 +23,9 @@ import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.widget.RadioGroup;
|
||||
import android.widget.SeekBar;
|
||||
|
||||
public class PreferencesActivity extends Activity {
|
||||
SharedPreferences mPreferences;
|
||||
SharedPreferences.Editor mPrefEditor;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -37,6 +34,5 @@ public class PreferencesActivity extends Activity {
|
||||
|
||||
mPreferences = getBaseContext().getSharedPreferences(getString(R.string.preferences_key),
|
||||
Context.MODE_PRIVATE);
|
||||
mPrefEditor = mPreferences.edit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ An input method for the Unihertz Titan/physical keyboard phones
|
||||
~ Copyright (C) 2024 Emil Kosz
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
~
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||
<item android:state_pressed="false">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#333" />
|
||||
<corners android:radius="8dp" />
|
||||
</shape>
|
||||
</item>
|
||||
<item android:state_pressed="true">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#555" />
|
||||
<corners android:radius="8dp" />
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
||||
@@ -1,51 +1,71 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="@style/KeyboardBackground"
|
||||
<cfpi_fpsi.eu.titanboard.InputView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
style="@style/InputViewBackground"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:orientation="vertical">
|
||||
android:layout_gravity="bottom">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/candidates"
|
||||
<HorizontalScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="visible">
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignTop="@id/input_state"
|
||||
android:layout_alignBottom="@id/input_state"
|
||||
android:layout_toStartOf="@id/input_state">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/state_shift"
|
||||
style="@style/KeyboardState"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="aa"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/state_alt"
|
||||
style="@style/KeyboardState"
|
||||
android:layout_height="wrap_content"
|
||||
android:text=".."
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="0px"
|
||||
<LinearLayout
|
||||
android:id="@+id/multi_list"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1">
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/symbols"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal" />
|
||||
</HorizontalScrollView>
|
||||
<TextView
|
||||
style="@style/InputViewSymbol"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/state_language"
|
||||
style="@style/KeyboardState"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="PL" />
|
||||
<TextView
|
||||
style="@style/InputViewSymbol"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
style="@style/InputViewSymbol"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
style="@style/InputViewSymbol"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
style="@style/InputViewSymbol"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
style="@style/InputViewSymbol"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
style="@style/InputViewSymbol"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
style="@style/InputViewSymbol"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
style="@style/InputViewSymbol"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
style="@style/InputViewSymbol"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
</HorizontalScrollView>
|
||||
|
||||
<Button
|
||||
android:id="@+id/input_state"
|
||||
style="@style/InputViewButton"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="@string/inputview_default_state" />
|
||||
|
||||
</cfpi_fpsi.eu.titanboard.InputView>
|
||||
@@ -1,22 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" >
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/longclick_speed_label"
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/header1"
|
||||
style="@style/PreferencesHeader"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Long click speed:" />
|
||||
android:text="@string/preferences_functions" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/longClickLabel"
|
||||
style="@style/PreferencesLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/header1"
|
||||
android:text="@string/preferences_long_click_speed" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/longclick_speed"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
android:id="@+id/longClickValue"
|
||||
style="@style/PreferencesSlider"
|
||||
android:layout_below="@id/longClickLabel" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/switch1"
|
||||
style="@style/PreferencesSwitch"
|
||||
android:layout_below="@id/longClickValue"
|
||||
android:text="@string/preferences_auto_caps" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/switch2"
|
||||
style="@style/PreferencesSwitch"
|
||||
android:layout_below="@id/switch1"
|
||||
android:text="@string/preferences_auto_period" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/switch3"
|
||||
style="@style/PreferencesSwitch"
|
||||
android:layout_below="@id/switch2"
|
||||
android:text="@string/preferences_auto_correct" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
style="@style/PreferencesHeader"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Languages:" />
|
||||
</LinearLayout>
|
||||
android:layout_below="@id/switch3"
|
||||
android:text="@string/preferences_languages" />
|
||||
</RelativeLayout>
|
||||
@@ -1,37 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<style name="KeyboardBackground">
|
||||
|
||||
<style name="InputViewBackground">
|
||||
<item name="android:background">#222</item>
|
||||
<item name="android:padding">2dp</item>
|
||||
<item name="android:padding">8dp</item>
|
||||
</style>
|
||||
|
||||
<style name="KeyboardDivider">
|
||||
<item name="android:layout_height">3dp</item>
|
||||
<item name="android:layout_marginTop">4dp</item>
|
||||
<item name="android:layout_marginBottom">2dp</item>
|
||||
<item name="android:background">#444</item>
|
||||
</style>
|
||||
|
||||
<style name="KeyboardState">
|
||||
<style name="InputViewButton">
|
||||
<item name="android:background">@drawable/button</item>
|
||||
<item name="android:textColor">#AAA</item>
|
||||
<item name="android:textSize">18sp</item>
|
||||
<item name="android:textAlignment">center</item>
|
||||
<item name="android:typeface">monospace</item>
|
||||
<item name="android:layout_width">40dp</item>
|
||||
<item name="android:layout_gravity">center</item>
|
||||
<item name="android:gravity">center_vertical</item>
|
||||
<item name="android:layout_width">48dp</item>
|
||||
<item name="android:layout_height">48dp</item>
|
||||
<item name="android:clickable">true</item>
|
||||
</style>
|
||||
|
||||
<style name="KeyboardStateLocked" parent="KeyboardState">
|
||||
<style name="InputViewSymbol">
|
||||
<item name="android:textColor">#AAA</item>
|
||||
<item name="android:textSize">18sp</item>
|
||||
<item name="android:textAlignment">center</item>
|
||||
<item name="android:layout_width">32dp</item>
|
||||
<item name="android:layout_height">48dp</item>
|
||||
<item name="android:layout_marginStart">8dp</item>
|
||||
<item name="android:layout_weight">0</item>
|
||||
<item name="android:layout_gravity">center_vertical</item>
|
||||
</style>
|
||||
|
||||
<style name="InputViewSymbolSelected" parent="InputViewSymbol">
|
||||
<item name="android:textColor">#DDD</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
</style>
|
||||
|
||||
<style name="KeyboardSymbol">
|
||||
<item name="android:background">#333</item>
|
||||
<item name="android:textColor">#FFF</item>
|
||||
<style name="PreferencesHeader">
|
||||
<item name="android:textSize">18sp</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
<item name="android:textColor">#AD1457</item>
|
||||
<item name="android:layout_margin">8dp</item>
|
||||
</style>
|
||||
|
||||
<style name="KeyboardSymbolSelected" parent="KeyboardSymbol">
|
||||
<item name="android:background">#444</item>
|
||||
<style name="PreferencesLabel">
|
||||
<item name="android:textColor">#000</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:layout_margin">8dp</item>
|
||||
</style>
|
||||
|
||||
<style name="PreferencesSwitch">
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:layout_margin">8dp</item>
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">48dp</item>
|
||||
</style>
|
||||
|
||||
<style name="PreferencesSlider">
|
||||
<item name="android:layout_margin">8dp</item>
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">48dp</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -2,6 +2,14 @@
|
||||
<string name="app_name">Titanboard</string>
|
||||
<string name="ime_label">Titanboard</string>
|
||||
|
||||
<string name="inputview_default_state">\?\?</string>
|
||||
|
||||
<string name="preferences_label">Titanboard preferences</string>
|
||||
<string name="preferences_functions">Functions</string>
|
||||
<string name="preferences_languages">Languages</string>
|
||||
<string name="preferences_long_click_speed">Long click speed</string>
|
||||
<string name="preferences_auto_caps">Automatic capitalization</string>
|
||||
<string name="preferences_auto_period">Automatic periods</string>
|
||||
<string name="preferences_auto_correct">Autocorrect</string>
|
||||
<string name="preferences_key">cfpi_fpsi.eu.titanboard.prefs</string>
|
||||
</resources>
|
||||
@@ -22,9 +22,10 @@
|
||||
<!-- Checked with German, French, Italian, Spanish, Polish, Romanian, Dutch, Serbo-Croatian,
|
||||
Turkish, Hungarian, Swedish, Czech, Portuguese, Catalan, Serbian, Albanian. -->
|
||||
<keymap
|
||||
name="eu"
|
||||
label="European"
|
||||
lang="eu_EU"
|
||||
short-label="EU">
|
||||
latched-name="Eu"
|
||||
locked-name="EU">
|
||||
<!-- Checked. -->
|
||||
<key code="29"> <!-- A -->
|
||||
<base value="a" />
|
||||
@@ -77,10 +78,10 @@
|
||||
<shift value="Đ" />
|
||||
<shift value="Ď" />
|
||||
<alt value=""" />
|
||||
<alt value="„"/>
|
||||
<alt value="”"/>
|
||||
<alt value="«"/>
|
||||
<alt value="»"/>
|
||||
<alt value="„" />
|
||||
<alt value="”" />
|
||||
<alt value="«" />
|
||||
<alt value="»" />
|
||||
</key>
|
||||
<!-- Checked -->
|
||||
<key code="33"> <!-- E -->
|
||||
@@ -122,6 +123,7 @@
|
||||
<base value="h" />
|
||||
<shift value="H" />
|
||||
<alt value="#" />
|
||||
<alt value="€" />
|
||||
<alt value="$" />
|
||||
</key>
|
||||
<!-- Checked -->
|
||||
@@ -213,7 +215,7 @@
|
||||
<base value="q" />
|
||||
<shift value="Q" />
|
||||
<alt value=":" />
|
||||
<alt value=";"/>
|
||||
<alt value=";" />
|
||||
</key>
|
||||
<!-- Checked -->
|
||||
<key code="46"> <!-- R -->
|
||||
@@ -279,6 +281,7 @@
|
||||
<base value="v" />
|
||||
<shift value="V" />
|
||||
<alt value="." />
|
||||
<alt value="…" />
|
||||
</key>
|
||||
<!-- Checked -->
|
||||
<key code="51"> <!-- W -->
|
||||
@@ -293,6 +296,7 @@
|
||||
<base value="x" />
|
||||
<shift value="X" />
|
||||
<alt value="?" />
|
||||
<alt value="¿" />
|
||||
</key>
|
||||
<!-- Checked -->
|
||||
<key code="53"> <!-- Y -->
|
||||
@@ -318,6 +322,185 @@
|
||||
<shift value="Ź" />
|
||||
<shift value="Ž" />
|
||||
<alt value="!" />
|
||||
<alt value="¡" />
|
||||
</key>
|
||||
</keymap>
|
||||
<!-- Cyrillic phonetic -->
|
||||
<!-- https://en.wikipedia.org/wiki/Phonetic_keyboard_layout#Russian_Phonetic_Keyboard_2.0 -->
|
||||
<keymap
|
||||
name="цp"
|
||||
label="Phonetic Cyrillic"
|
||||
latched-name="Цp"
|
||||
locked-name="ЦP">
|
||||
<key code="29"> <!-- A -->
|
||||
<base value="а" />
|
||||
<shift value="A" />
|
||||
<alt value="@" />
|
||||
</key>
|
||||
<key code="30"> <!-- B -->
|
||||
<base value="б" />
|
||||
<shift value="Б" />
|
||||
<alt value="7" />
|
||||
</key>
|
||||
<key code="31"> <!-- C -->
|
||||
<base value="ч" />
|
||||
<base value="ц" />
|
||||
<shift value="Ч" />
|
||||
<shift value="Ц" />
|
||||
<alt value="," />
|
||||
<alt value="&" />
|
||||
</key>
|
||||
<key code="32"> <!-- D -->
|
||||
<base value="д" />
|
||||
<shift value="Д" />
|
||||
<alt value=""" />
|
||||
<alt value="„" />
|
||||
<alt value="”" />
|
||||
<alt value="«" />
|
||||
<alt value="»" />
|
||||
</key>
|
||||
<key code="33"> <!-- E -->
|
||||
<base value="e" />
|
||||
<base value="ё" />
|
||||
<shift value="E" />
|
||||
<shift value="Ё" />
|
||||
<alt value="_" />
|
||||
<alt value="~" />
|
||||
</key>
|
||||
<key code="34"> <!-- F -->
|
||||
<base value="ф" />
|
||||
<shift value="Ф" />
|
||||
<alt value="+" />
|
||||
<alt value="=" />
|
||||
</key>
|
||||
<key code="35"> <!-- G -->
|
||||
<base value="г" />
|
||||
<shift value="Г" />
|
||||
<alt value="*" />
|
||||
<alt value="^" />
|
||||
</key>
|
||||
<key code="36"> <!-- H -->
|
||||
<base value="ш" />
|
||||
<base value="щ" />
|
||||
<shift value="Ш" />
|
||||
<shift value="Щ" />
|
||||
<alt value="#" />
|
||||
<alt value="€" />
|
||||
<alt value="$" />
|
||||
</key>
|
||||
<key code="37"> <!-- I -->
|
||||
<base value="и" />
|
||||
<base value="й" />
|
||||
<shift value="И" />
|
||||
<shift value="Й" />
|
||||
<alt value="2" />
|
||||
</key>
|
||||
<key code="38"> <!-- J -->
|
||||
<base value="ж" />
|
||||
<shift value="Ж" />
|
||||
<alt value="4" />
|
||||
</key>
|
||||
<key code="39"> <!-- K -->
|
||||
<base value="к" />
|
||||
<shift value="К" />
|
||||
<alt value="5" />
|
||||
</key>
|
||||
<key code="40"> <!-- L -->
|
||||
<base value="л" />
|
||||
<base value="э" />
|
||||
<shift value="Л" />
|
||||
<shift value="Э" />
|
||||
<alt value="6" />
|
||||
</key>
|
||||
<key code="41"> <!-- M -->
|
||||
<base value="м" />
|
||||
<shift value="М" />
|
||||
<alt value="9" />
|
||||
</key>
|
||||
<key code="42"> <!-- N -->
|
||||
<base value="н" />
|
||||
<shift value="Н" />
|
||||
<alt value="8" />
|
||||
</key>
|
||||
<key code="43"> <!-- O -->
|
||||
<base value="о" />
|
||||
<shift value="О" />
|
||||
<alt value="3" />
|
||||
</key>
|
||||
<key code="44"> <!-- P -->
|
||||
<base value="п" />
|
||||
<shift value="П" />
|
||||
<alt value="0" />
|
||||
</key>
|
||||
<key code="45"> <!-- Q -->
|
||||
<base value="ю" />
|
||||
<shift value="Ю" />
|
||||
<alt value=":" />
|
||||
<alt value=";" />
|
||||
</key>
|
||||
<key code="46"> <!-- R -->
|
||||
<base value="р" />
|
||||
<shift value="Р" />
|
||||
<alt value="-" />
|
||||
<alt value="–" />
|
||||
<alt value="—" />
|
||||
</key>
|
||||
<key code="47"> <!-- S -->
|
||||
<base value="с" />
|
||||
<shift value="С" />
|
||||
<alt value="'" />
|
||||
<alt value="‚" />
|
||||
<alt value="’" />
|
||||
</key>
|
||||
<key code="48"> <!-- T -->
|
||||
<base value="т" />
|
||||
<shift value="Т" />
|
||||
<alt value="(" />
|
||||
<alt value="<" />
|
||||
<alt value="[" />
|
||||
<alt value="{" />
|
||||
</key>
|
||||
<key code="49"> <!-- U -->
|
||||
<base value="у" />
|
||||
<shift value="У" />
|
||||
<alt value="1" />
|
||||
</key>
|
||||
<key code="50"> <!-- V -->
|
||||
<base value="в" />
|
||||
<shift value="В" />
|
||||
<alt value="." />
|
||||
<alt value="…" />
|
||||
</key>
|
||||
<key code="51"> <!-- W -->
|
||||
<base value="ы" />
|
||||
<base value="ь" />
|
||||
<shift value="Ы" />
|
||||
<shift value="Ь" />
|
||||
<alt value="/" />
|
||||
<alt value="\\" />
|
||||
<alt value="|" />
|
||||
</key>
|
||||
<key code="52"> <!-- X -->
|
||||
<base value="х" />
|
||||
<base value="ъ" />
|
||||
<shift value="Х" />
|
||||
<shift value="Ъ" />
|
||||
<alt value="?" />
|
||||
<alt value="¿" />
|
||||
</key>
|
||||
<key code="53"> <!-- Y -->
|
||||
<base value="я" />
|
||||
<shift value="Я" />
|
||||
<alt value=")" />
|
||||
<alt value=">" />
|
||||
<alt value="]" />
|
||||
<alt value="}" />
|
||||
</key>
|
||||
<key code="54"> <!-- Z -->
|
||||
<base value="з" />
|
||||
<shift value="З" />
|
||||
<alt value="!" />
|
||||
<alt value="¡" />
|
||||
</key>
|
||||
</keymap>
|
||||
</device-keymap-list>
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<input-method xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:settingsActivity="cfpi_fpsi.eu.titanboard.PreferencesActivity"
|
||||
android:supportsSwitchingToNextInputMethod="false ">
|
||||
android:supportsSwitchingToNextInputMethod="false">
|
||||
<subtype
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:isAsciiCapable="true"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
[versions]
|
||||
#noinspection AndroidGradlePluginVersion
|
||||
agp = "8.4.1"
|
||||
|
||||
[libraries]
|
||||
|
||||
Reference in New Issue
Block a user