Code restructuring, miscellaneous fixes.

This commit is contained in:
2024-10-20 18:25:19 +02:00
parent e98639dc9d
commit bf695b19e0
15 changed files with 592 additions and 274 deletions
+14 -5
View File
@@ -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.
+1
View File
@@ -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();
}
}
+33
View File
@@ -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>
+60 -40
View File
@@ -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>
+40 -12
View File
@@ -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>
+43 -19
View File
@@ -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>
+8
View File
@@ -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>
+190 -7
View File
@@ -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="&quot;" />
<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="&amp;" />
</key>
<key code="32"> <!-- D -->
<base value="д" />
<shift value="Д" />
<alt value="&quot;" />
<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="&apos;" />
<alt value="‚" />
<alt value="’" />
</key>
<key code="48"> <!-- T -->
<base value="т" />
<shift value="Т" />
<alt value="(" />
<alt value="&lt;" />
<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="&gt;" />
<alt value="]" />
<alt value="}" />
</key>
<key code="54"> <!-- Z -->
<base value="з" />
<shift value="З" />
<alt value="!" />
<alt value="¡" />
</key>
</keymap>
</device-keymap-list>
+1 -1
View File
@@ -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
View File
@@ -1,4 +1,5 @@
[versions]
#noinspection AndroidGradlePluginVersion
agp = "8.4.1"
[libraries]