mirror of
https://github.com/Julow/Unexpected-Keyboard.git
synced 2025-08-19 16:25:58 +02:00
Compare commits
4 Commits
strwithsym
...
play-pause
Author | SHA1 | Date | |
---|---|---|---|
|
6d3dfd0c5a | ||
|
4d686a8836 | ||
|
b21bf3fffd | ||
|
7454389f48 |
11
build.gradle
11
build.gradle
@@ -2,10 +2,6 @@ plugins {
|
||||
id 'com.android.application' version '8.1.1'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation "junit:junit:4.13.2"
|
||||
}
|
||||
|
||||
android {
|
||||
namespace 'juloo.keyboard2'
|
||||
compileSdk 34
|
||||
@@ -25,10 +21,6 @@ android {
|
||||
res.srcDirs = ['res', 'build/generated-resources']
|
||||
assets.srcDirs = ['assets']
|
||||
}
|
||||
|
||||
test {
|
||||
java.srcDirs = ['test']
|
||||
}
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
@@ -92,6 +84,9 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
}
|
||||
|
||||
tasks.register('buildKeyboardFont') {
|
||||
println "\nBuilding assets/special_font.ttf"
|
||||
mkdir "$buildDir"
|
||||
|
@@ -64,7 +64,7 @@ Layout includes some ASCII punctuation but not all, missing: (, ), <, >, [, ], {
|
||||
# latn_bepo_fr
|
||||
0 warnings
|
||||
# latn_bone
|
||||
Layout includes some ASCII punctuation but not all, missing: $
|
||||
Layout doesn't define some important keys, missing: loc esc, loc tab
|
||||
Layout redefines the bottom row but some important keys are missing, missing: cursor_left, cursor_right, loc compose, loc end, loc home, loc page_down, loc page_up, loc switch_clipboard, loc switch_greekmath, loc voice_typing, switch_backward
|
||||
2 warnings
|
||||
# latn_colemak
|
||||
|
@@ -34,11 +34,19 @@ Here is a complete keyboard file with a single row containing an "a" key on the
|
||||
</keyboard>
|
||||
|
||||
## Keyboard metadata
|
||||
|
||||
The `<keyboard>`...`</keyboard>` pair follows the declaration tag and encloses the whole keyboard. The following properties may be used (The first two appear in the example above):
|
||||
|
||||
* `name`: The name of the keyboard. The name you specify will appear in the Settings menu. If not present, the layout will just appear as “Custom layout”.
|
||||
|
||||
* `script`: The (main) writing system that the keyboard supports. The possible values are `arabic`, `armenian`, `bengali`, `cyrillic`, `devanagari`, `gujarati`, `hangul`, `hebrew`, `latin`, `persian`, `shavian`, and `urdu`. It defaults to `latin`.
|
||||
|
||||
* `numpad_script`: The script to use for the numpad. This is useful for scripts where a different, non-ASCII set of numerals is used, like Devanagari and Arabic. It defaults to the same as `script`.
|
||||
* `bottom_row`: Whether or not to show the common bottom row. It accepts `true` or `false`, and defaults to `true`. If your custom layout defines the bottom row, then specify `bottom_row="false"` to disable the built-in bottom row.
|
||||
|
||||
* `bottom_row`: Whether or not to show the built-in bottom row. It accepts `true` or `false`, and defaults to `true`. If your custom layout defines the bottom row, then specify `bottom_row="false"` to disable the built-in bottom row.
|
||||
+ We recommend your layout use the built-in bottom row, because it is still evolving and your layout will incorporate innovations in future versions. However, to define your own, the current definition of the bottom row is in [bottom_row.xml](https://github.com/Julow/Unexpected-Keyboard/res/xml/bottom_row.xml). You can copypaste this XML into your custom layout as a starting point.
|
||||
+ Likewise, the current definition of the top (number) row is in [number_row.xml](https://github.com/Julow/Unexpected-Keyboard/res/xml/number_row.xml).
|
||||
|
||||
* `locale_extra_keys`: Whether Unexpected should add language-dependent extra keys from [method.xml](../res/xml/method.xml) to this layout. It accepts `true` or `false`, and defaults to `true`. To disable these automatic additions, specify `locale_extra_keys="false"`.
|
||||
|
||||
## Row
|
||||
|
@@ -119,7 +119,7 @@ Keys ending in `_placeholder` are normally hidden unless the Fn key is pressed.
|
||||
`ole`, `ole_placeholder`,
|
||||
`meteg`, `meteg_placeholder`
|
||||
|
||||
## Keyboard behavior keys
|
||||
## Unexpected Keyboard specific
|
||||
Value | Meaning
|
||||
:--------------------- | :------
|
||||
`config` | Gear icon; opens Unexpected Keyboard settings.
|
||||
@@ -148,28 +148,3 @@ These keys are known to do nothing.
|
||||
These keys are normally hidden unless the Fn modifier is activated.
|
||||
|
||||
`f11_placeholder` | `f12_placeholder`
|
||||
|
||||
## Complex keys
|
||||
|
||||
More complex keys are of this form:
|
||||
|
||||
```
|
||||
:<kind> <attributes>:<payload>
|
||||
```
|
||||
|
||||
Where `<kind>` is one of the kinds documented below and `<attributes>` is a
|
||||
space separated list of attributes. `<payload>` depends on the `<kind>`.
|
||||
|
||||
Attributes are:
|
||||
- `symbol='Sym'` is the symbol to be shown on the keyboard.
|
||||
- `flags='<flags>'` is a collection of flags that change the behavior of the key.
|
||||
`<flags>` is a coma separated list of:
|
||||
+ `dim`: Make the symbol dimmer.
|
||||
+ `small`: Make the symbol smaller.
|
||||
|
||||
### Kind `str`
|
||||
|
||||
Defines a key that outputs an arbitrary string. `<payload>` is a string wrapped
|
||||
in single-quotes (`'`), escaping of other single quotes is allowed with `\'`.
|
||||
|
||||
For example: `:str symbol='Sym':'Output string'`
|
||||
|
@@ -15,12 +15,13 @@ let
|
||||
|
||||
ANDROID_SDK_ROOT = "${android.androidsdk}/libexec/android-sdk";
|
||||
|
||||
gradle = pkgs.gradle.override { java = jdk; };
|
||||
# Without this option, aapt2 fails to run with a permissions error.
|
||||
gradle_wrapped = pkgs.runCommandLocal "gradle-wrapped" {
|
||||
nativeBuildInputs = with pkgs; [ makeBinaryWrapper ];
|
||||
} ''
|
||||
mkdir -p $out/bin
|
||||
ln -s ${pkgs.gradle}/bin/gradle $out/bin/gradle
|
||||
ln -s ${gradle}/bin/gradle $out/bin/gradle
|
||||
wrapProgram $out/bin/gradle \
|
||||
--add-flags "-Dorg.gradle.project.android.aapt2FromMavenOverride=${ANDROID_SDK_ROOT}/build-tools/${build_tools_version}/aapt2"
|
||||
'';
|
||||
|
@@ -210,7 +210,8 @@ public final class Config
|
||||
KeyValue action_key()
|
||||
{
|
||||
// Update the name to avoid caching in KeyModifier
|
||||
return (actionLabel == null) ? null : KeyValue.makeActionKey(actionLabel);
|
||||
return (actionLabel == null) ? null :
|
||||
KeyValue.getKeyByName("action").withSymbol(actionLabel);
|
||||
}
|
||||
|
||||
/** Update the layout according to the configuration.
|
||||
|
@@ -97,7 +97,6 @@ public final class KeyEventHandler
|
||||
_recv.set_compose_pending(true);
|
||||
break;
|
||||
case Cursor_move: move_cursor(key.getCursorMove()); break;
|
||||
case Complex: send_complex_key(key.getComplexKind(), key.getComplex()); break;
|
||||
}
|
||||
update_meta_state(old_mods);
|
||||
}
|
||||
@@ -216,16 +215,6 @@ public final class KeyEventHandler
|
||||
conn.performContextMenuAction(id);
|
||||
}
|
||||
|
||||
void send_complex_key(KeyValue.Complex.Kind kind, KeyValue.Complex val)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case StringWithSymbol:
|
||||
send_text(((KeyValue.Complex.StringWithSymbol)val).str);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
void handle_editing_key(KeyValue.Editing ev)
|
||||
{
|
||||
|
@@ -91,8 +91,7 @@ public final class KeyValue implements Comparable<KeyValue>
|
||||
{
|
||||
Char, String, Keyevent, Event, Compose_pending, Hangul_initial,
|
||||
Hangul_medial, Modifier, Editing, Placeholder,
|
||||
Cursor_move, // Value is encoded as a 16-bit integer.
|
||||
Complex, // [_payload] is a [KeyValue.Complex], value is [Complex.Kind].
|
||||
Cursor_move // Value is encoded as a 16-bit integer
|
||||
}
|
||||
|
||||
private static final int FLAGS_OFFSET = 19;
|
||||
@@ -130,13 +129,7 @@ public final class KeyValue implements Comparable<KeyValue>
|
||||
check((((Kind.values().length - 1) << KIND_OFFSET) & ~KIND_BITS) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* The symbol that is rendered on the keyboard as a [String].
|
||||
* Except for keys of kind:
|
||||
* - [String], this is also the string to output.
|
||||
* - [Complex], this is an instance of [KeyValue.Complex].
|
||||
*/
|
||||
private final Object _payload;
|
||||
private final String _symbol;
|
||||
|
||||
/** This field encodes three things: Kind, flags and value. */
|
||||
private final int _code;
|
||||
@@ -160,9 +153,7 @@ public final class KeyValue implements Comparable<KeyValue>
|
||||
When [getKind() == Kind.String], also the string to send. */
|
||||
public String getString()
|
||||
{
|
||||
if (getKind() == Kind.Complex)
|
||||
return ((Complex)_payload).getSymbol();
|
||||
return (String)_payload;
|
||||
return _symbol;
|
||||
}
|
||||
|
||||
/** Defined only when [getKind() == Kind.Char]. */
|
||||
@@ -220,32 +211,25 @@ public final class KeyValue implements Comparable<KeyValue>
|
||||
return (short)(_code & VALUE_BITS);
|
||||
}
|
||||
|
||||
/** Defined only when [getKind() == Kind.Complex]. */
|
||||
public Complex getComplex()
|
||||
{
|
||||
return (Complex)_payload;
|
||||
}
|
||||
|
||||
/** Defined only when [getKind() == Kind.Complex]. */
|
||||
public Complex.Kind getComplexKind()
|
||||
{
|
||||
return Complex.Kind.values()[(_code & VALUE_BITS)];
|
||||
}
|
||||
|
||||
/* Update the char and the symbol. */
|
||||
public KeyValue withChar(char c)
|
||||
{
|
||||
return new KeyValue(String.valueOf(c), Kind.Char, c, getFlags());
|
||||
}
|
||||
|
||||
public KeyValue withSymbol(String s)
|
||||
{
|
||||
return new KeyValue(s, (_code & KIND_BITS), (_code & VALUE_BITS), getFlags());
|
||||
}
|
||||
|
||||
public KeyValue withKeyevent(int code)
|
||||
{
|
||||
return new KeyValue(getString(), Kind.Keyevent, code, getFlags());
|
||||
return new KeyValue(_symbol, Kind.Keyevent, code, getFlags());
|
||||
}
|
||||
|
||||
public KeyValue withFlags(int f)
|
||||
{
|
||||
return new KeyValue(getString(), (_code & KIND_BITS), (_code & VALUE_BITS), f);
|
||||
return new KeyValue(_symbol, (_code & KIND_BITS), (_code & VALUE_BITS), f);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -263,9 +247,7 @@ public final class KeyValue implements Comparable<KeyValue>
|
||||
d = _code - snd._code;
|
||||
if (d != 0)
|
||||
return d;
|
||||
if (getKind() == Kind.Complex)
|
||||
return ((Complex)_payload).compareTo((Complex)snd._payload);
|
||||
return ((String)_payload).compareTo((String)snd._payload);
|
||||
return _symbol.compareTo(snd._symbol);
|
||||
}
|
||||
|
||||
/** Type-safe alternative to [equals]. */
|
||||
@@ -273,36 +255,24 @@ public final class KeyValue implements Comparable<KeyValue>
|
||||
{
|
||||
if (snd == null)
|
||||
return false;
|
||||
return _code == snd._code && _payload.equals(snd._payload);
|
||||
return _symbol.equals(snd._symbol) && _code == snd._code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return _payload.hashCode() + _code;
|
||||
return _symbol.hashCode() + _code;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
public KeyValue(String s, int kind, int value, int flags)
|
||||
{
|
||||
int value = _code & VALUE_BITS;
|
||||
return "[KeyValue " + getKind().toString() + "+" + getFlags() + "+" + value + " \"" + getString() + "\"]";
|
||||
}
|
||||
|
||||
private KeyValue(Object p, int kind, int value, int flags)
|
||||
{
|
||||
_payload = p;
|
||||
_symbol = s;
|
||||
_code = (kind & KIND_BITS) | (flags & FLAGS_BITS) | (value & VALUE_BITS);
|
||||
}
|
||||
|
||||
public KeyValue(Complex p, Complex.Kind value, int flags)
|
||||
public KeyValue(String s, Kind k, int v, int f)
|
||||
{
|
||||
this((Object)p, (Kind.Complex.ordinal() << KIND_OFFSET), value.ordinal(),
|
||||
flags);
|
||||
}
|
||||
|
||||
public KeyValue(String p, Kind k, int v, int f)
|
||||
{
|
||||
this(p, (k.ordinal() << KIND_OFFSET), v, f);
|
||||
this(s, (k.ordinal() << KIND_OFFSET), v, f);
|
||||
}
|
||||
|
||||
private static KeyValue charKey(String symbol, char c, int flags)
|
||||
@@ -427,11 +397,6 @@ public final class KeyValue implements Comparable<KeyValue>
|
||||
return KeyValue.makeCharKey((char)precomposed);
|
||||
}
|
||||
|
||||
public static KeyValue makeActionKey(String symbol)
|
||||
{
|
||||
return eventKey(symbol, Event.ACTION, FLAG_SMALLER_FONT);
|
||||
}
|
||||
|
||||
/** Make a key that types a string. A char key is returned for a string of
|
||||
length 1. */
|
||||
public static KeyValue makeStringKey(String str, int flags)
|
||||
@@ -442,36 +407,12 @@ public final class KeyValue implements Comparable<KeyValue>
|
||||
return new KeyValue(str, Kind.String, 0, flags | FLAG_SMALLER_FONT);
|
||||
}
|
||||
|
||||
public static KeyValue makeStringKeyWithSymbol(String str, String symbol, int flags)
|
||||
{
|
||||
return new KeyValue(new Complex.StringWithSymbol(str, symbol),
|
||||
Complex.Kind.StringWithSymbol, flags);
|
||||
}
|
||||
|
||||
/** Make a modifier key for passing to [KeyModifier]. */
|
||||
public static KeyValue makeInternalModifier(Modifier mod)
|
||||
{
|
||||
return new KeyValue("", Kind.Modifier, mod.ordinal(), 0);
|
||||
}
|
||||
|
||||
public static KeyValue parseKeyDefinition(String str)
|
||||
{
|
||||
if (str.length() < 2 || str.charAt(0) != ':')
|
||||
return makeStringKey(str);
|
||||
try
|
||||
{
|
||||
return KeyValueParser.parse(str);
|
||||
}
|
||||
catch (KeyValueParser.ParseError _e)
|
||||
{
|
||||
return makeStringKey(str);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a key by its name. If the given name doesn't correspond to a key
|
||||
* defined in this function, it is passed to [parseStringKey] as a fallback.
|
||||
*/
|
||||
public static KeyValue getKeyByName(String name)
|
||||
{
|
||||
switch (name)
|
||||
@@ -561,6 +502,7 @@ public final class KeyValue implements Comparable<KeyValue>
|
||||
case "f12": return keyeventKey("F12", KeyEvent.KEYCODE_F12, FLAG_SMALLER_FONT);
|
||||
case "tab": return keyeventKey(0xE00F, KeyEvent.KEYCODE_TAB, FLAG_SMALLER_FONT);
|
||||
case "menu": return keyeventKey("Menu", KeyEvent.KEYCODE_MENU, FLAG_SMALLER_FONT);
|
||||
case "playpause": return keyeventKey("Play", KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, FLAG_SMALLER_FONT);
|
||||
|
||||
/* Spaces */
|
||||
case "\\t": return charKey("\\t", '\t', 0); // Send the tab character
|
||||
@@ -658,8 +600,8 @@ public final class KeyValue implements Comparable<KeyValue>
|
||||
case "ㅍ": return makeHangulInitial("ㅍ", 17);
|
||||
case "ㅎ": return makeHangulInitial("ㅎ", 18);
|
||||
|
||||
/* The key is not one of the special ones. */
|
||||
default: return parseKeyDefinition(name);
|
||||
/* Fallback to a string key that types its name */
|
||||
default: return makeStringKey(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,49 +611,4 @@ public final class KeyValue implements Comparable<KeyValue>
|
||||
if (!b)
|
||||
throw new RuntimeException("Assertion failure");
|
||||
}
|
||||
|
||||
public static abstract class Complex
|
||||
{
|
||||
public abstract String getSymbol();
|
||||
|
||||
/** [compareTo] can assume that [snd] is an instance of the same class. */
|
||||
public abstract int compareTo(Complex snd);
|
||||
|
||||
public boolean equals(Object snd)
|
||||
{
|
||||
if (snd instanceof Complex)
|
||||
return compareTo((Complex)snd) == 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/** [hashCode] will be called on this class. */
|
||||
|
||||
/** The kind is stored in the [value] field of the key. */
|
||||
public static enum Kind
|
||||
{
|
||||
StringWithSymbol,
|
||||
}
|
||||
|
||||
public static final class StringWithSymbol extends Complex
|
||||
{
|
||||
public final String str;
|
||||
private final String _symbol;
|
||||
|
||||
public StringWithSymbol(String _str, String _sym)
|
||||
{
|
||||
str = _str;
|
||||
_symbol = _sym;
|
||||
}
|
||||
|
||||
public String getSymbol() { return _symbol; }
|
||||
|
||||
public int compareTo(Complex _snd)
|
||||
{
|
||||
StringWithSymbol snd = (StringWithSymbol)_snd;
|
||||
int d = str.compareTo(snd.str);
|
||||
if (d != 0) return d;
|
||||
return _symbol.compareTo(snd._symbol);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -1,150 +0,0 @@
|
||||
package juloo.keyboard2;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
Parse a key definition. The syntax for a key definition is:
|
||||
- [:(kind) (attributes):(payload)].
|
||||
- If [str] doesn't start with a [:] character, it is interpreted as an
|
||||
arbitrary string key.
|
||||
|
||||
[(kind)] specifies the kind of the key, it can be:
|
||||
- [str]: An arbitrary string key. The payload is the string to output when
|
||||
typed and is quoted by single quotes ([']). The payload can contain single
|
||||
quotes if they are escaped with a backslash ([\']).
|
||||
|
||||
The [(attributes)] part is a space-separated list of attributes, all optional,
|
||||
of the form: [attrname='attrvalue'].
|
||||
|
||||
Attributes can be:
|
||||
- [flags]: Add flags that change the behavior of the key.
|
||||
Value is a coma separated list of:
|
||||
- [dim]: Make the symbol dimmer on the keyboard.
|
||||
- [small]: Make the symbol smaller on the keyboard.
|
||||
- [symbol]: Specify the symbol that is rendered on the keyboard.
|
||||
It can contain single quotes if they are escaped: ([\']).
|
||||
|
||||
Examples:
|
||||
- [:str flags=dim,small symbol='MyKey':'My arbitrary string'].
|
||||
- [:str:'My arbitrary string'].
|
||||
|
||||
*/
|
||||
public final class KeyValueParser
|
||||
{
|
||||
static Pattern START_PAT;
|
||||
static Pattern ATTR_PAT;
|
||||
static Pattern QUOTED_PAT;
|
||||
static Pattern PAYLOAD_START_PAT;
|
||||
|
||||
static public KeyValue parse(String str) throws ParseError
|
||||
{
|
||||
String symbol = null;
|
||||
int flags = 0;
|
||||
init();
|
||||
// Kind
|
||||
Matcher m = START_PAT.matcher(str);
|
||||
if (!m.lookingAt())
|
||||
parseError("Expected kind, for example \":str ...\".", m);
|
||||
String kind = m.group(1);
|
||||
// Attributes
|
||||
while (true)
|
||||
{
|
||||
if (!match(m, ATTR_PAT))
|
||||
break;
|
||||
String attr_name = m.group(1);
|
||||
String attr_value = parseSingleQuotedString(m);
|
||||
switch (attr_name)
|
||||
{
|
||||
case "flags":
|
||||
flags = parseFlags(attr_value, m);
|
||||
break;
|
||||
case "symbol":
|
||||
symbol = attr_value;
|
||||
break;
|
||||
|
||||
default:
|
||||
parseError("Unknown attribute "+attr_name, m);
|
||||
}
|
||||
}
|
||||
// Payload
|
||||
if (!match(m, PAYLOAD_START_PAT))
|
||||
parseError("Unexpected character", m);
|
||||
switch (kind)
|
||||
{
|
||||
case "str":
|
||||
String payload = parseSingleQuotedString(m);
|
||||
if (symbol == null)
|
||||
return KeyValue.makeStringKey(payload, flags);
|
||||
return KeyValue.makeStringKeyWithSymbol(payload, symbol, flags);
|
||||
|
||||
default: break;
|
||||
}
|
||||
parseError("Unknown kind '"+kind+"'", m, 1);
|
||||
return null; // Unreachable
|
||||
}
|
||||
|
||||
static String parseSingleQuotedString(Matcher m) throws ParseError
|
||||
{
|
||||
if (!match(m, QUOTED_PAT))
|
||||
parseError("Expected quoted string", m);
|
||||
return m.group(1).replace("\\'", "'");
|
||||
}
|
||||
|
||||
static int parseFlags(String s, Matcher m) throws ParseError
|
||||
{
|
||||
int flags = 0;
|
||||
for (String f : s.split(","))
|
||||
{
|
||||
switch (f)
|
||||
{
|
||||
case "dim": flags |= KeyValue.FLAG_SECONDARY; break;
|
||||
case "small": flags |= KeyValue.FLAG_SMALLER_FONT; break;
|
||||
default: parseError("Unknown flag "+f, m);
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
static boolean match(Matcher m, Pattern pat)
|
||||
{
|
||||
try { m.region(m.end(), m.regionEnd()); } catch (Exception _e) {}
|
||||
m.usePattern(pat);
|
||||
return m.lookingAt();
|
||||
}
|
||||
|
||||
static void init()
|
||||
{
|
||||
if (START_PAT != null)
|
||||
return;
|
||||
START_PAT = Pattern.compile(":(\\w+)");
|
||||
ATTR_PAT = Pattern.compile("\\s*(\\w+)\\s*=");
|
||||
QUOTED_PAT = Pattern.compile("'(([^'\\\\]+|\\\\')*)'");
|
||||
PAYLOAD_START_PAT = Pattern.compile("\\s*:");
|
||||
}
|
||||
|
||||
static void parseError(String msg, Matcher m) throws ParseError
|
||||
{
|
||||
parseError(msg, m, m.regionStart());
|
||||
}
|
||||
|
||||
static void parseError(String msg, Matcher m, int i) throws ParseError
|
||||
{
|
||||
StringBuilder msg_ = new StringBuilder("Syntax error");
|
||||
try
|
||||
{
|
||||
char c = m.group(0).charAt(0);
|
||||
msg_.append(" at character '").append(c).append("'");
|
||||
} catch (IllegalStateException _e) {}
|
||||
msg_.append(" at position ");
|
||||
msg_.append(i);
|
||||
msg_.append(": ");
|
||||
msg_.append(msg);
|
||||
throw new ParseError(msg_.toString());
|
||||
}
|
||||
|
||||
public static class ParseError extends Exception
|
||||
{
|
||||
public ParseError(String msg) { super(msg); }
|
||||
};
|
||||
}
|
@@ -40,7 +40,7 @@ public class CustomExtraKeysPreference extends ListGroupPreference<String>
|
||||
if (key_names != null)
|
||||
{
|
||||
for (String key_name : key_names)
|
||||
kvs.put(KeyValue.parseKeyDefinition(key_name), KeyboardData.PreferredPos.DEFAULT);
|
||||
kvs.put(KeyValue.makeStringKey(key_name), KeyboardData.PreferredPos.DEFAULT);
|
||||
}
|
||||
return kvs;
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@
|
||||
<key key0="ه" key2="۸" key3="*"/>
|
||||
<key key0="خ" key2="۹" key3="(" key4=")"/>
|
||||
<key key0="ح" key2="۰"/>
|
||||
<key key0="ج" key2="چ"/>
|
||||
<key key0="ج"/>
|
||||
</row>
|
||||
<row>
|
||||
<key key0="ش" key2="loc tab"/>
|
||||
@@ -29,13 +29,13 @@
|
||||
<row>
|
||||
<key shift="0.5" key0="ظ"/>
|
||||
<key key0="ط"/>
|
||||
<key key0="ز" key2="«"/>
|
||||
<key key0="ر" key2="»"/>
|
||||
<key key0="ژ" key2="."/>
|
||||
<key key0="ز" key1="«" key2="»"/>
|
||||
<key key0="ر" key1="ژ" key2="."/>
|
||||
<key key0="ذ" key2=":"/>
|
||||
<key key0="د" key2="؛"/>
|
||||
<key key0="پ" key2="؟"/>
|
||||
<key key0="و"/>
|
||||
<key key0="چ"/>
|
||||
<key width="1.5" key0="backspace" key2="delete"/>
|
||||
</row>
|
||||
</keyboard>
|
||||
|
@@ -1,46 +1,72 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- https://neo-layout.org/Layouts/bone/ -->
|
||||
<keyboard name="Bone" bottom_row="false" script="latin">
|
||||
<!-- first row + characters from number row:
|
||||
jduaxphlmwß
|
||||
…_[]^!<>=&ſ
|
||||
°§ℓ»«$€„“”—
|
||||
›‹¢¥‚‘’
|
||||
-->
|
||||
<row>
|
||||
<key key0="j" key2="loc esc" key4="…"/>
|
||||
<key key0="d" key2="°" key4="_"/>
|
||||
<key key0="u" key2="§" key4="["/>
|
||||
<key key0="a" key4="]"/>
|
||||
<key key0="x" key4="^"/>
|
||||
<key key0="p" key3="!" key4="7"/>
|
||||
<key key0="h" key3="<" key4="8"/>
|
||||
<key key0="l" key1="ℓ" key3=">" key4="9"/>
|
||||
<key key0="m" key1="≠" key3="="/>
|
||||
<key key0="w" key3="&"/>
|
||||
<!--left side-->
|
||||
<key key0="j" key2="°" key4="…"/>
|
||||
<key key0="d" key2="§" key4="_"/>
|
||||
<key key0="u" key2="ℓ" key4="["/>
|
||||
<key key0="a" key2="»" key4="]" key1="›"/>
|
||||
<key key0="x" key2="«" key4="^" key1="‹"/>
|
||||
<!--middle-->
|
||||
<key key0="p" key7="¢" key8="!"/>
|
||||
<!--right side-->
|
||||
<key key0="h" key1="€" key3="<" key4="7" key2="¥"/>
|
||||
<key key0="l" key1="„" key3=">" key4="8" key2="‚"/>
|
||||
<key key0="m" key1="“" key3="=" key4="9" key2="‘"/>
|
||||
<key key0="w" key1="”" key3="&" key2="’"/>
|
||||
<key key0="ß" key1="—" key3="ſ"/>
|
||||
</row>
|
||||
<!--second row:
|
||||
ctieobnrsgq
|
||||
\/{}*?()-:@
|
||||
-->
|
||||
<row>
|
||||
<key key0="c" key2="loc tab" key4="\\"/>
|
||||
<key key0="t" key1="accent_circonflexe" key2="accent_caron" key4="/"/>
|
||||
<key key0="i" key1="accent_aigu" key2="accent_grave" key4="{"/>
|
||||
<key key0="e" key1="accent_cedille" key2="accent_ogonek" key4="}"/>
|
||||
<key key0="o" key1="accent_ring" key2="accent_dot_above" key4="*"/>
|
||||
<key key0="b" key2="accent_macron" key3="\?" key4="4"/>
|
||||
<key key0="n" key2="accent_tilde" key3="(" key4="5"/>
|
||||
<key key0="r" key2="accent_trema" key3=")" key4="6"/>
|
||||
<key key0="s" key2="accent_slash" key3="-"/>
|
||||
<key key0="g" key1="\@" key3=":"/>
|
||||
<!--left side-->
|
||||
<key key0="c" key4="\\"/>
|
||||
<key key0="t" key4="/"/>
|
||||
<key key0="i" key4="{"/>
|
||||
<key key0="e" key4="}"/>
|
||||
<key key0="o" key4="*"/>
|
||||
<!--middle-->
|
||||
<key key0="b" key8="\?"/>
|
||||
<!--right side-->
|
||||
<key key0="n" key3="(" key4="4"/>
|
||||
<key key0="r" key3=")" key4="5"/>
|
||||
<key key0="s" key3="-" key4="6"/>
|
||||
<key key0="g" key3=":"/>
|
||||
<key key0="q" key3="@"/>
|
||||
</row>
|
||||
<!--third row -> compressed to also fit shift and backspace:
|
||||
fvüäöyz,.k
|
||||
#$|~`+%"';
|
||||
-->
|
||||
<row>
|
||||
<key width="1.5" key0="shift" key4="\#" key2="loc capslock"/>
|
||||
<key key0="f" key4="|"/>
|
||||
<key key0="v" key4="~"/>
|
||||
<key key0="ß" key4="`"/>
|
||||
<key key0="y" key3="%" key4="1"/>
|
||||
<key key0="z" key1=""" key3="+" key4="2"/>
|
||||
<key key0="q" key1="'" key3="," key4="3"/>
|
||||
<key key0="k" key3="."/>
|
||||
<key width="1.5" key0="backspace" key1="delete" key3=";"/>
|
||||
<!--left side-->
|
||||
<key width="1.5" key0="shift" key4="\#"/>
|
||||
<key key0="f" key4="$"/>
|
||||
<key key0="v" key4="|"/>
|
||||
<key key0="ü" key4="~"/>
|
||||
<key key0="ä" key4="`"/>
|
||||
<!--right side-->
|
||||
<key key0="ö" key3="+"/>
|
||||
<key key0="y" key3="%" key4="1"/>
|
||||
<key key0="z" key3="," key1=""" key4="2"/>
|
||||
<key key0="k" key3="." key1="'" key4="3"/>
|
||||
<key width="1.5" key0="backspace" key3=";" key1="delete"/>
|
||||
</row>
|
||||
<!--bottom row-->
|
||||
<row height="0.95">
|
||||
<key width="1.8" key0="ctrl" key2="loc meta" key4="switch_numeric"/>
|
||||
<key width="1.2" key0="fn" key1="loc alt" key2="loc change_method" key3="switch_emoji" key4="config"/>
|
||||
<key width="4.0" key0="space" key7="switch_forward" key8="0"/>
|
||||
<key width="1.2" key7="up" key6="right" key5="left" key8="down"/>
|
||||
<key width="1.8" key0="enter" key3="action"/>
|
||||
<key width="1.8" key0="ctrl" key2="loc meta" key4="switch_numeric"/>
|
||||
<key width="1.2" key0="fn" key1="loc alt" key2="loc change_method" key3="switch_emoji" key4="config"/>
|
||||
<key width="5.0" key0="space" key7="switch_forward" key8="0"/>
|
||||
<key width="1.2" key5="left" key6="right" key7="up" key8="down"/>
|
||||
<key width="1.8" key0="enter" key3="action"/>
|
||||
</row>
|
||||
</keyboard>
|
||||
|
@@ -1,54 +0,0 @@
|
||||
package juloo.keyboard2;
|
||||
|
||||
import juloo.keyboard2.KeyValue;
|
||||
import juloo.keyboard2.KeyValueParser;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class KeyValueParserTest
|
||||
{
|
||||
public KeyValueParserTest() {}
|
||||
|
||||
@Test
|
||||
public void parse() throws Exception
|
||||
{
|
||||
Utils.parse(":str:'Foo'", KeyValue.makeStringKey("Foo"));
|
||||
Utils.parse(":str flags='dim':'Foo'", KeyValue.makeStringKey("Foo", KeyValue.FLAG_SECONDARY));
|
||||
Utils.parse(":str symbol='Symbol':'Foo'", KeyValue.makeStringKeyWithSymbol("Foo", "Symbol", 0));
|
||||
Utils.parse(":str symbol='Symbol' flags='dim':'Foo'", KeyValue.makeStringKeyWithSymbol("Foo", "Symbol", KeyValue.FLAG_SECONDARY));
|
||||
Utils.parse(":str flags='dim,small':'Foo'", KeyValue.makeStringKey("Foo", KeyValue.FLAG_SECONDARY | KeyValue.FLAG_SMALLER_FONT));
|
||||
Utils.parse(":str flags=',,':'Foo'", KeyValue.makeStringKey("Foo")); // Unintentional
|
||||
Utils.expect_error(":unknown:Foo"); // Unknown kind
|
||||
Utils.expect_error(":str:Foo"); // Unquoted string
|
||||
Utils.expect_error(":str flags:'Foo'"); // Malformed flags
|
||||
Utils.expect_error(":str flags=dim:'Foo'"); // Unquoted flags
|
||||
Utils.expect_error(":str unknown='foo':'Foo'"); // Unknown flags
|
||||
// Unterminated
|
||||
Utils.expect_error(":str");
|
||||
Utils.expect_error(":str ");
|
||||
Utils.expect_error(":str flags");
|
||||
Utils.expect_error(":str flags=");
|
||||
Utils.expect_error(":str flags='");
|
||||
Utils.expect_error(":str flags='' ");
|
||||
Utils.expect_error(":str flags='':");
|
||||
Utils.expect_error(":str flags='':'");
|
||||
}
|
||||
|
||||
/** JUnit removes these functions from stacktraces. */
|
||||
static class Utils
|
||||
{
|
||||
static void parse(String key_descr, KeyValue ref) throws Exception
|
||||
{
|
||||
assertEquals(ref, KeyValueParser.parse(key_descr));
|
||||
}
|
||||
|
||||
static void expect_error(String key_descr)
|
||||
{
|
||||
try
|
||||
{
|
||||
fail("Expected failure but got " + KeyValueParser.parse(key_descr));
|
||||
}
|
||||
catch (KeyValueParser.ParseError e) {}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
package juloo.keyboard2;
|
||||
|
||||
import juloo.keyboard2.KeyValue;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class KeyValueTest
|
||||
{
|
||||
public KeyValueTest() {}
|
||||
|
||||
@Test
|
||||
public void equals()
|
||||
{
|
||||
assertEquals(KeyValue.makeStringKeyWithSymbol("Foo", "Symbol", 0), KeyValue.makeStringKeyWithSymbol("Foo", "Symbol", 0));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user