Several changes. UI revamp, added a UX document explaining the choices, misc. bugfixes, double click to toggle meta key.

This commit is contained in:
2024-10-16 17:25:41 +02:00
parent c7c4c58e85
commit e40dab3342
13 changed files with 410 additions and 291 deletions
+98
View File
@@ -0,0 +1,98 @@
# Titanboard user experience
Keyboards are an integral part of the functioning of any computer, including the smartphone. Care
should then be taken to design keyboards to be as intuitive, easy to use, and unobstructed as
possible.
The Unihertz Titan already has a physical keyboard. It's poorly designed in many aspects. Mainly, it
isn't very reminiscent of a regular QWERTY keyboard which people are used to:
1. The worst part is arguably the shift and alt keys being at the top of the keyboard, instead of on
the bottom.
2. The spacebar key is on the same row as the bottom QWERTY alphabet keys.
3. The numerical keys, which are some of the most commonly used keys in phones (passwords, PIN
codes)
and in regular language are right below the alt key, which makes typing them very awkward. One
could
also argue that the numpad is in a "reversed" layout, but this is consistent with the usual
layout
found on phones.
4. It lacks some commonly used symbols: ';', '&', '=', '<', '>', '$'. Other than that, it lacks some
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
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.
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
the alternate characters printed on the keyboard, the shift key should give us uppercase characters
and so on.
# Solutions
Here are my solutions for the above listed problems:
1. This is solvable with shift/alt latching. This makes it so when you press these keys once, the
next key pressed will be either uppercased or the alternate key visible on the physical button.
Additionally, the shift and alt key can be toggled by double-clicking in a fast succession,
similar
to regular visual keyboards on Android.
2. This is unfortunately unsolvable with software.
3. See 1., latching the keys solves this issue.
4. This requires a visual keyboard, the UI of which is discussed later. Why does this require a
visual keyboard, and not some alternate "symbol" mode, perhaps accessible with some keyboard
shortcuts? That would make the learning curve of the keyboard higher, and it would be less
intuitive. One should make sure not to complicate the physical keyboard any more than it already
is,
and use all of its idiosyncrasies but add no more.
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 print it. Ideally, there should also be a
popup
menu allowing for several characters under one key. Cycling through the keys would use the
shift/alt
keys (so that no matter what key you use, the other hand can cycle through) and selecting it
would
happen on release of the key.
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
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.
Taking into account typing ergonomics and pre-existing UX choices of other keyboard designers, this
input method should make typing on the Unihertz Titan a pleasant experience. Other than fixing the
fundamental issues, the keyboard should also:
1. Provide a way of managing the clipboard, or at the very least pasting things with an UI element.
This is to make the usage intuitive and not introduce any additional keys such as a ctrl key.
2. Autocorrect, language switching, auto caps and periods.
3. Some minimal customization, but just enough not to overwhelm the user.
For the Unihertz Titan Pocket/Slim, the sym key will be used as the alt+gr key, providing diacritics
and such. This is because in the official documentation and implementation the alt key is designed
for the alternate keys printed on the buttons.
# User interface
Google recommends that visual keyboards should not occupy more than half of the screen estate.
However, most phones have long, vertical screens, which means essentially that the keyboard will
be a square, and so will the remaining view. On the Titan, the screen is already square, so the
remaining space will be proportionally much smaller. Therefore, the keyboard should occupy very
minimal screen estate, as to allow the user to see the application they are interacting with.
For this reason, I make sure the keyboard occupies 20–25 % screen estate. This is enough for a
symbol bar and a suggestions bar, as well as some additional buttons such as language change or
settings.
Both the symbol bar and suggestions bar are scrollable. The suggestions being scrollable is a
feature on some visual keyboards already, however, I have come to the decision to make this for the
symbol bar as well. An expandable menu would make the keyboard occupy half, or more of the screen.
A scrollable bar is more intuitive and can hold an indefinite amount of characters, possibly also
user-defined.
A simple divider between the suggestion and symbol bar is added to avoid accidental clicks.
+2 -1
View File
@@ -11,7 +11,7 @@ android {
minSdk 19
targetSdk 34
versionCode 1
versionName "1.0"
versionName "0.1"
}
buildTypes {
@@ -28,3 +28,4 @@ android {
}
+12 -2
View File
@@ -3,26 +3,36 @@
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:icon="@drawable/icon"
android:label="@string/app_name"
android:supportsRtl="true"
tools:targetApi="31">
<service
android:name="TitanboardIME"
android:name=".IME"
android:directBootAware="true"
android:exported="false"
android:icon="@drawable/icon"
android:label="@string/ime_label"
android:permission="android.permission.BIND_INPUT_METHOD">
<intent-filter>
<action android:name="android.view.InputMethod" />
</intent-filter>
<meta-data
android:name="android.view.im"
android:resource="@xml/method" />
</service>
<activity
android:name=".PreferencesActivity"
android:exported="true"
android:label="@string/preferences_label">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
</application>
</manifest>
@@ -1,19 +1,42 @@
/*
* 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.annotation.SuppressLint;
import android.inputmethodservice.InputMethodService;
import android.os.Build;
import android.os.Vibrator;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
public class TitanboardIME extends InputMethodService {
private final MetaKeyManager mMetaKeyManager = new MetaKeyManager();
public class IME extends InputMethodService {
private MetaKeyManager mMetaKeyManager;
private Keymap mKeymap;
private LinearLayout mInputView;
private Vibrator mVibrator;
@Override
public void onCreate() {
@@ -23,6 +46,8 @@ public class TitanboardIME extends InputMethodService {
// Unihertz phones: the Pocket and the Slim. However, as I don't have them, it'll be guesswork.
// Sym key support is already implemented.
mKeymap = new Keymap(getResources().getXml(R.xml.keymap_titan));
mVibrator = (Vibrator) getBaseContext().getSystemService(VIBRATOR_SERVICE);
mMetaKeyManager = new MetaKeyManager(mVibrator);
}
@SuppressLint("InflateParams")
@@ -50,17 +75,20 @@ public class TitanboardIME extends InputMethodService {
}
switch (keyCode) {
// The back key behaviour is handled by the IMS already.
// If the keyboard is visible, hide it, otherwise, let the system handle the key.
case KeyEvent.KEYCODE_BACK:
if (isInputViewShown()) {
requestHideSelf(0);
return true;
}
return false;
// If it's the Enter key, we let the application do it's job.
case KeyEvent.KEYCODE_ENTER:
return false;
// If it's the backspace key, we remove one character.
case KeyEvent.KEYCODE_DEL:
conn.deleteSurroundingText(1, 0);
mMetaKeyManager.adjustMetaStateAfterKeypress();
if (conn.getSelectedText(0) == null) {
conn.deleteSurroundingText(1, 0);
return true;
}
return false;
case KeyEvent.KEYCODE_SPACE:
conn.commitText(" ", 1);
@@ -68,18 +96,19 @@ public class TitanboardIME extends InputMethodService {
return true;
default:
String key = getKey(keyCode);
if (key != null) {
conn.commitText(getKey(keyCode), 1);
mMetaKeyManager.adjustMetaStateAfterKeypress();
return true;
} else {
if (key == null) {
return false;
}
conn.commitText(getKey(keyCode), 1);
mMetaKeyManager.adjustMetaStateAfterKeypress();
return true;
}
}
public boolean onKeyUp(int keyCode, KeyEvent event) {
mMetaKeyManager.updateMetaStateUp(keyCode);
mMetaKeyManager.updateMetaStateUp(keyCode, event);
updateMetaStateTextView();
return false;
}
@@ -93,9 +122,6 @@ public class TitanboardIME extends InputMethodService {
public void onFinishInput() {
mMetaKeyManager.resetMetaKeyState();
updateMetaStateTextView();
mInputView.findViewById(R.id.extra_view).setVisibility(View.GONE);
Button key = mInputView.findViewById(R.id.expand_button);
key.setText("▲");
}
private String getKey(int keyCode) {
@@ -144,20 +170,9 @@ public class TitanboardIME extends InputMethodService {
}
}
/** @noinspection unused*/
public void onInputViewExtraKeyClick(View v) {
int visibility = mInputView.findViewById(R.id.extra_view).getVisibility();
Button key = (Button) v;
if (visibility == View.VISIBLE) {
mInputView.findViewById(R.id.extra_view).setVisibility(View.GONE);
key.setText("▲");
} else {
mInputView.findViewById(R.id.extra_view).setVisibility(View.VISIBLE);
key.setText("▼");
}
}
/** @noinspection unused*/
/**
* @noinspection unused
*/
public void onInputViewKeyClick(View v) {
Button key = (Button) v;
InputConnection conn = getCurrentInputConnection();
@@ -1,3 +1,22 @@
/*
* 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 org.xmlpull.v1.XmlPullParser;
@@ -1,62 +1,93 @@
/*
* 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.os.Vibrator;
import android.view.KeyEvent;
public class MetaKeyManager {
private static final int mRepeatCount = 5;
private MetaKey mMetaKeyPressed = MetaKey.NONE;
private MetaKey mMetaKeyLatched = MetaKey.NONE;
private MetaKey mMetaKeyLocked = MetaKey.NONE;
private boolean mMetaKeyUsed = false;
private long mKeyUpTime;
private Vibrator mVibrator;
public MetaKeyManager(Vibrator vibrator) {
mVibrator = vibrator;
}
public void updateMetaStateDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_ALT_LEFT:
case KeyEvent.KEYCODE_ALT_RIGHT:
updateMetaKeyDown(MetaKey.ALT, event.getRepeatCount());
updateMetaKeyDown(MetaKey.ALT, event);
break;
case KeyEvent.KEYCODE_SHIFT_LEFT:
case KeyEvent.KEYCODE_SHIFT_RIGHT:
updateMetaKeyDown(MetaKey.SHIFT, event.getRepeatCount());
updateMetaKeyDown(MetaKey.SHIFT, event);
break;
case KeyEvent.KEYCODE_SYM:
updateMetaKeyDown(MetaKey.SYM, event.getRepeatCount());
updateMetaKeyDown(MetaKey.SYM, event);
break;
default:
break;
}
}
void updateMetaKeyDown(MetaKey key, int repeatCount) {
void updateMetaKeyDown(MetaKey key, KeyEvent event) {
// Perhaps this function should be renamed to something...
mMetaKeyUsed = false;
mMetaKeyPressed = key;
mMetaKeyLatched = mMetaKeyLocked != MetaKey.NONE ? mMetaKeyLocked : mMetaKeyLatched;
mMetaKeyLocked = repeatCount > mRepeatCount ? key : MetaKey.NONE;
mMetaKeyLocked = MetaKey.NONE;
}
public void updateMetaStateUp(int keyCode) {
public void updateMetaStateUp(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_ALT_LEFT:
case KeyEvent.KEYCODE_ALT_RIGHT:
updateMetaKeyUp(MetaKey.ALT);
updateMetaKeyUp(MetaKey.ALT, event);
break;
case KeyEvent.KEYCODE_SHIFT_LEFT:
case KeyEvent.KEYCODE_SHIFT_RIGHT:
updateMetaKeyUp(MetaKey.SHIFT);
updateMetaKeyUp(MetaKey.SHIFT, event);
break;
case KeyEvent.KEYCODE_SYM:
updateMetaKeyUp(MetaKey.SYM);
updateMetaKeyUp(MetaKey.SYM, event);
break;
default:
break;
}
}
public void updateMetaKeyUp(MetaKey key) {
public void updateMetaKeyUp(MetaKey key, KeyEvent event) {
if (event.getEventTime() - mKeyUpTime < 400 && mMetaKeyLatched == key) {
mMetaKeyLocked = key;
mVibrator.vibrate(30);
}
mKeyUpTime = event.getEventTime();
mMetaKeyPressed = MetaKey.NONE;
if (mMetaKeyLatched == MetaKey.NONE && mMetaKeyLocked == MetaKey.NONE
&& !mMetaKeyUsed) {
if (mMetaKeyLatched == MetaKey.NONE && mMetaKeyLocked == MetaKey.NONE && !mMetaKeyUsed) {
mMetaKeyLatched = key;
} else {
mMetaKeyLatched = MetaKey.NONE;
@@ -67,7 +98,9 @@ public class MetaKeyManager {
if (mMetaKeyLatched != MetaKey.NONE) {
mMetaKeyLatched = MetaKey.NONE;
mMetaKeyUsed = false;
} else if (mMetaKeyPressed != MetaKey.NONE) {
}
if (mMetaKeyPressed != MetaKey.NONE) {
mMetaKeyUsed = true;
}
}
@@ -79,6 +112,11 @@ public class MetaKeyManager {
mMetaKeyUsed = false;
}
public void setMetaKeyLatched(MetaKey key) {
resetMetaKeyState();
mMetaKeyLatched = key;
}
public MetaKey getMetaKeyPressed() {
return mMetaKeyPressed;
}
@@ -0,0 +1,31 @@
/*
* 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.app.Activity;
import android.os.Bundle;
public class PreferencesActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.preferences);
}
}
+4 -2
View File
@@ -2,8 +2,10 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false">
<shape>
<solid android:color="#333" />
<stroke android:width="1dp" android:color="#222" />
<gradient android:angle="-45"
android:startColor="#333"
android:endColor="#222"/>
<stroke android:width="1dp" android:color="#333" />
</shape>
</item>
<item android:state_pressed="true">
+90 -227
View File
@@ -14,264 +14,127 @@
android:orientation="horizontal"
android:visibility="visible">
<Button
android:id="@+id/suggestion_1"
style="@style/KeyboardCandidate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
<Button
android:id="@+id/suggestion_2"
style="@style/KeyboardCandidate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
<Button
android:id="@+id/suggestion_3"
style="@style/KeyboardCandidate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
<TextView
android:id="@+id/state"
style="@style/KeyboardState"
android:layout_width="10dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="aa"
android:typeface="normal"
tools:ignore="HardcodedText" />
</LinearLayout>
<LinearLayout
android:id="@+id/extra_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
<View
style="@style/KeyboardDivider"
android:layout_width="match_parent" />
<LinearLayout
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
android:layout_weight="1">
<Button
style="@style/KeyboardKey"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="–"
tools:ignore="HardcodedText" />
android:orientation="horizontal" />
</HorizontalScrollView>
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="—"
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="`"
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="~"
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="{"
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="}"
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="\\"
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="π"
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="≤"
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="≥"
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="^"
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="["
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="]"
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="|"
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
<View
style="@style/KeyboardDivider"
android:layout_width="match_parent" />
<LinearLayout
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
android:layout_height="match_parent">
<Button
style="@style/KeyboardKey"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="&lt;"
tools:ignore="HardcodedText" />
android:orientation="horizontal">
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="&gt;"
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_height="wrap_content"
android:text="&lt;" />
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="="
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_height="wrap_content"
android:text="&gt;" />
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="$"
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_height="wrap_content"
android:text="^" />
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="%"
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_height="wrap_content"
android:text="~" />
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text=";"
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_height="wrap_content"
android:text="\\" />
<Button
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="&amp;"
tools:ignore="HardcodedText" />
<Button
style="@style/KeyboardKey"
android:layout_height="wrap_content"
android:text="=" />
<!--suppress AndroidMissingOnClickHandler -->
<Button
android:id="@+id/expand_button"
style="@style/KeyboardKey"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:onClick="onInputViewExtraKeyClick"
android:text="▲ "
tools:ignore="HardcodedText,OnClick" />
<Button
style="@style/KeyboardKey"
android:layout_height="wrap_content"
android:text="&amp;" />
<Button
style="@style/KeyboardKey"
android:layout_height="wrap_content"
android:text=";" />
<Button
style="@style/KeyboardKey"
android:layout_height="wrap_content"
android:text="|" />
<Button
style="@style/KeyboardKey"
android:layout_height="wrap_content"
android:text="[" />
<Button
style="@style/KeyboardKey"
android:layout_height="wrap_content"
android:text="]" />
<Button
style="@style/KeyboardKey"
android:layout_height="wrap_content"
android:text="{" />
<Button
style="@style/KeyboardKey"
android:layout_height="wrap_content"
android:text="}" />
<Button
style="@style/KeyboardKey"
android:layout_height="wrap_content"
android:text="←" />
<Button
style="@style/KeyboardKey"
android:layout_height="wrap_content"
android:text="↑" />
<Button
style="@style/KeyboardKey"
android:layout_height="wrap_content"
android:text="↓" />
<Button
style="@style/KeyboardKey"
android:layout_height="wrap_content"
android:text="→" />
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
</LinearLayout>
+34
View File
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<CheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Automatic capitalization" />
<CheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Automatic periods" />
<CheckBox
android:id="@+id/checkBox3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Autocorrect" />
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Time between clicks to detect double click" />
<SeekBar
android:id="@+id/seekBar3"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
+1
View File
@@ -1,4 +1,5 @@
<resources>
<string name="app_name">Titanboard</string>
<string name="ime_label">Titanboard</string>
<string name="preferences_label">Preferences</string>
</resources>
+4 -6
View File
@@ -18,8 +18,7 @@
<item name="android:textSize">18sp</item>
<item name="android:textAlignment">center</item>
<item name="android:typeface">monospace</item>
<item name="android:layout_weight">1</item>
<item name="android:width">0px</item>
<item name="android:layout_width">72dp</item>
</style>
<style name="KeyboardStateLocked" parent="KeyboardState">
@@ -31,8 +30,7 @@
<item name="android:textColor">#FFF</item>
<item name="android:textSize">18sp</item>
<item name="android:layout_marginTop">2dp</item>
<item name="android:layout_weight">2.33</item>
<item name="android:width">0px</item>
<item name="android:layout_width">wrap_content</item>
</style>
<style name="KeyboardKey">
@@ -40,8 +38,8 @@
<item name="android:textColor">#FFF</item>
<item name="android:textSize">18sp</item>
<item name="android:layout_marginTop">2dp</item>
<item name="android:layout_weight">1</item>
<item name="android:layout_marginBottom">2dp</item>
<item name="android:onClick">onInputViewKeyClick</item>
<item name="android:width">0px</item>
<item name="android:layout_width">72dp</item>
</style>
</resources>
+18 -9
View File
@@ -3,7 +3,8 @@
<key
code="29"
value="a"
valueAlt="@" />
valueAlt="@"
valueSym="ą" />
<key
code="30"
value="b"
@@ -11,7 +12,8 @@
<key
code="31"
value="c"
valueAlt="," />
valueAlt=","
valueSym="ć" />
<key
code="32"
value="d"
@@ -19,7 +21,8 @@
<key
code="33"
value="e"
valueAlt="_" />
valueAlt="_"
valueSym="ę" />
<key
code="34"
value="f"
@@ -47,7 +50,8 @@
<key
code="40"
value="l"
valueAlt="6" />
valueAlt="6"
valueSym="ł" />
<key
code="41"
value="m"
@@ -55,11 +59,13 @@
<key
code="42"
value="n"
valueAlt="8" />
valueAlt="8"
valueSym="ń" />
<key
code="43"
value="o"
valueAlt="3" />
valueAlt="3"
valueSym="ó" />
<key
code="44"
value="p"
@@ -75,7 +81,8 @@
<key
code="47"
value="s"
valueAlt="&apos;" />
valueAlt="&apos;"
valueSym="ś" />
<key
code="48"
value="t"
@@ -95,7 +102,8 @@
<key
code="52"
value="x"
valueAlt="?" />
valueAlt="?"
valueSym="ź" />
<key
code="53"
value="y"
@@ -103,5 +111,6 @@
<key
code="54"
value="z"
valueAlt="!" />
valueAlt="!"
valueSym="ż" />
</keymap>