diff options
| -rw-r--r-- | res/xml/qwerty.xml | 21 | ||||
| -rw-r--r-- | srcs/juloo.keyboard2/KeyValue.java | 9 | ||||
| -rw-r--r-- | srcs/juloo.keyboard2/Keyboard2View.java | 40 | ||||
| -rw-r--r-- | srcs/juloo.keyboard2/KeyboardData.java | 177 | ||||
| -rw-r--r-- | srcs/juloo.keyboard2/Pointers.java | 83 |
5 files changed, 166 insertions, 164 deletions
diff --git a/res/xml/qwerty.xml b/res/xml/qwerty.xml index 87b56f5..4f5245b 100644 --- a/res/xml/qwerty.xml +++ b/res/xml/qwerty.xml @@ -1,4 +1,25 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- This file defines the QWERTY layout. + +A layout is made of keys arranged into rows. Keys can be made bigger with the +'width' attribute and blank space can be added on the left of a key with the +'shift' attribute. + +'key0' assigns the symbol on the middle of the key. 'key1', 'key2', etc.. +assign symbols to the corners of a key, they are arranged like this: + + 1 7 2 + 5 0 6 + 3 8 4 + +Keys prefixed with 'loc ' are not visible on the keyboard. They are used to +specify a place for a key, if it needed to be added to the layout later. +(for example, by the "Add keys to keyboard" option) + +See bottom_row.xml for the definition of the bottom row and neo2.xml for a +layout that re-defines it. +See srcs/juloo.keyboard2/KeyValue.java for the keys that have a special meaning. +--> <keyboard> <row> <key key0="q" key2="1" key4="esc"/> diff --git a/srcs/juloo.keyboard2/KeyValue.java b/srcs/juloo.keyboard2/KeyValue.java index c4bd069..3e84ce8 100644 --- a/srcs/juloo.keyboard2/KeyValue.java +++ b/srcs/juloo.keyboard2/KeyValue.java @@ -202,7 +202,14 @@ final class KeyValue @Override public boolean equals(Object obj) { - KeyValue snd = (KeyValue)obj; + return sameKey((KeyValue)obj); + } + + /** Type-safe alternative to [equals]. */ + public boolean sameKey(KeyValue snd) + { + if (snd == null) + return false; return _symbol.equals(snd._symbol) && _code == snd._code; } diff --git a/srcs/juloo.keyboard2/Keyboard2View.java b/srcs/juloo.keyboard2/Keyboard2View.java index 3c642f0..0a75529 100644 --- a/srcs/juloo.keyboard2/Keyboard2View.java +++ b/srcs/juloo.keyboard2/Keyboard2View.java @@ -260,6 +260,19 @@ public class Keyboard2View extends View } } + /** Horizontal and vertical position of the 9 indexes. */ + static final Paint.Align[] LABEL_POSITION_H = new Paint.Align[]{ + Paint.Align.CENTER, Paint.Align.LEFT, Paint.Align.RIGHT, Paint.Align.LEFT, + Paint.Align.RIGHT, Paint.Align.LEFT, Paint.Align.RIGHT, + Paint.Align.CENTER, Paint.Align.CENTER + }; + + static final Vertical[] LABEL_POSITION_V = new Vertical[]{ + Vertical.CENTER, Vertical.TOP, Vertical.TOP, Vertical.BOTTOM, + Vertical.BOTTOM, Vertical.CENTER, Vertical.CENTER, Vertical.TOP, + Vertical.BOTTOM + }; + @Override protected void onDraw(Canvas canvas) { @@ -282,20 +295,12 @@ public class Keyboard2View extends View float keyW = _keyWidth * k.width - _config.keyHorizontalInterval; boolean isKeyDown = _pointers.isKeyDown(k); drawKeyFrame(canvas, x, y, keyW, keyH, isKeyDown); - drawLabel(canvas, k.key0, keyW / 2f + x, y, keyH, isKeyDown); - if (k.edgekeys) - { - drawSubLabel(canvas, k.key1, x, y, keyW, keyH, Paint.Align.CENTER, Vertical.TOP, isKeyDown); - drawSubLabel(canvas, k.key3, x, y, keyW, keyH, Paint.Align.LEFT, Vertical.CENTER, isKeyDown); - drawSubLabel(canvas, k.key2, x, y, keyW, keyH, Paint.Align.RIGHT, Vertical.CENTER, isKeyDown); - drawSubLabel(canvas, k.key4, x, y, keyW, keyH, Paint.Align.CENTER, Vertical.BOTTOM, isKeyDown); - } - else + if (k.keys[0] != null) + drawLabel(canvas, k.keys[0], keyW / 2f + x, y, keyH, isKeyDown); + for (int i = 1; i < 9; i++) { - drawSubLabel(canvas, k.key1, x, y, keyW, keyH, Paint.Align.LEFT, Vertical.TOP, isKeyDown); - drawSubLabel(canvas, k.key3, x, y, keyW, keyH, Paint.Align.LEFT, Vertical.BOTTOM, isKeyDown); - drawSubLabel(canvas, k.key2, x, y, keyW, keyH, Paint.Align.RIGHT, Vertical.TOP, isKeyDown); - drawSubLabel(canvas, k.key4, x, y, keyW, keyH, Paint.Align.RIGHT, Vertical.BOTTOM, isKeyDown); + if (k.keys[i] != null) + drawSubLabel(canvas, k.keys[i], x, y, keyW, keyH, i, isKeyDown); } if (k.indication != null) { @@ -367,8 +372,6 @@ public class Keyboard2View extends View private void drawLabel(Canvas canvas, KeyboardData.Corner k, float x, float y, float keyH, boolean isKeyDown) { - if (k == null) - return; KeyValue kv = KeyModifier.modify(k.kv, _mods); if (kv == null) return; @@ -381,11 +384,10 @@ public class Keyboard2View extends View } private void drawSubLabel(Canvas canvas, KeyboardData.Corner k, float x, - float y, float keyW, float keyH, Paint.Align a, Vertical v, - boolean isKeyDown) + float y, float keyW, float keyH, int sub_index, boolean isKeyDown) { - if (k == null) - return; + Paint.Align a = LABEL_POSITION_H[sub_index]; + Vertical v = LABEL_POSITION_V[sub_index]; KeyValue kv = KeyModifier.modify(k.kv, _mods); if (kv == null) return; diff --git a/srcs/juloo.keyboard2/KeyboardData.java b/srcs/juloo.keyboard2/KeyboardData.java index 1c5de76..aa215db 100644 --- a/srcs/juloo.keyboard2/KeyboardData.java +++ b/srcs/juloo.keyboard2/KeyboardData.java @@ -5,6 +5,7 @@ import android.content.res.XmlResourceParser; import android.util.Xml; import java.io.StringReader; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -278,50 +279,44 @@ class KeyboardData public static class Key { - /* - ** 1 2 - ** 0 - ** 3 4 + /** + * 1 7 2 + * 5 0 6 + * 3 8 4 */ - public final Corner key0; - public final Corner key1; - public final Corner key2; - public final Corner key3; - public final Corner key4; + public final Corner[] keys; /** Key width in relative unit. */ public final float width; /** Extra empty space on the left of the key. */ public final float shift; - /** Put keys 1 to 4 on the edges instead of the corners. */ - public final boolean edgekeys; /** Keys 2 and 3 are repeated as the finger moves laterally on the key. Used for the left and right arrow keys on the space bar. */ public final boolean slider; /** String printed on the keys. It has no other effect. */ public final String indication; - protected Key(Corner k0, Corner k1, Corner k2, Corner k3, Corner k4, float w, float s, boolean e, boolean sl, String i) + protected Key(Corner[] ks, float w, float s, boolean sl, String i) { - key0 = k0; - key1 = k1; - key2 = k2; - key3 = k3; - key4 = k4; + keys = ks; width = w; shift = s; - edgekeys = e; slider = sl; indication = i; } public static Key parse(XmlPullParser parser) throws Exception { - Corner k0 = Corner.parse_of_attr(parser, "key0"); - Corner k1 = Corner.parse_of_attr(parser, "key1"); - Corner k2 = Corner.parse_of_attr(parser, "key2"); - Corner k3 = Corner.parse_of_attr(parser, "key3"); - Corner k4 = Corner.parse_of_attr(parser, "key4"); + Corner[] ks = new Corner[9]; + ks[0] = Corner.parse_of_attr(parser, "key0"); + ks[1] = Corner.parse_of_attr(parser, "key1"); + ks[2] = Corner.parse_of_attr(parser, "key2"); + ks[3] = Corner.parse_of_attr(parser, "key3"); + ks[4] = Corner.parse_of_attr(parser, "key4"); + ks[5] = Corner.parse_of_attr(parser, "key5"); + ks[6] = Corner.parse_of_attr(parser, "key6"); + ks[7] = Corner.parse_of_attr(parser, "key7"); + ks[8] = Corner.parse_of_attr(parser, "key8"); float width = attribute_float(parser, "width", 1f); float shift = attribute_float(parser, "shift", 0.f); boolean edgekeys = attribute_bool(parser, "edgekeys", false); @@ -329,112 +324,86 @@ class KeyboardData String indication = parser.getAttributeValue(null, "indication"); while (parser.next() != XmlPullParser.END_TAG) continue ; - return new Key(k0, k1, k2, k3, k4, width, shift, edgekeys, slider, indication); + if (edgekeys) + ks = rearange_edgekeys(ks); + return new Key(ks, width, shift, slider, indication); } /** New key with the width multiplied by 's'. */ public Key scaleWidth(float s) { - return new Key(key0, key1, key2, key3, key4, width * s, shift, edgekeys, - slider, indication); + return new Key(keys, width * s, shift, slider, indication); } public void getKeys(Set<KeyValue> dst) { - getCorner(dst, key0); - getCorner(dst, key1); - getCorner(dst, key2); - getCorner(dst, key3); - getCorner(dst, key4); + for (int i = 0; i < keys.length; i++) + if (keys[i] != null) + dst.add(keys[i].kv); } - void getCorner(Set<KeyValue> dst, Corner k) { if (k != null) dst.add(k.kv); } - public KeyValue getKeyValue(int i) { - Corner c; - switch (i) - { - case 0: c = key0; break; - case 1: c = key1; break; - case 2: c = key2; break; - case 3: c = key3; break; - case 4: c = key4; break; - default: c = null; break; - } - return (c == null) ? null : c.kv; + if (keys[i] == null) + return null; + return keys[i].kv; } public Key withKeyValue(int i, KeyValue kv) { - Corner k0 = key0, k1 = key1, k2 = key2, k3 = key3, k4 = key4; - Corner k = Corner.of_kv(kv); - switch (i) - { - case 0: k0 = k; break; - case 1: k1 = k; break; - case 2: k2 = k; break; - case 3: k3 = k; break; - case 4: k4 = k; break; - } - return new Key(k0, k1, k2, k3, k4, width, shift, edgekeys, slider, - indication); + Corner[] ks = Arrays.copyOf(keys, keys.length); + ks[i] = Corner.of_kv(kv); + return new Key(ks, width, shift, slider, indication); } public Key withShift(float s) { - return new Key(key0, key1, key2, key3, key4, width, s, edgekeys, slider, - indication); + return new Key(keys, width, s, slider, indication); } - /** - * See Pointers.onTouchMove() for the represented direction. - */ - public KeyValue getAtDirection(int direction) + public boolean hasValue(KeyValue kv) { - Corner c = null; - if (edgekeys) - { - // \ 1 / - // \ / - // 3 0 2 - // / \ - // / 4 \ - switch (direction) - { - case 2: case 3: c = key1; break; - case 4: case 5: c = key2; break; - case 6: case 7: c = key4; break; - case 8: case 1: c = key3; break; - } - } - else - { - // 1 | 2 - // | - // --0-- - // | - // 3 | 4 - switch (direction) - { - case 1: case 2: c = key1; break; - case 3: case 4: c = key2; break; - case 5: case 6: c = key4; break; - case 7: case 8: c = key3; break; - } - } - return (c == null) ? null : c.kv; + for (int i = 0; i < keys.length; i++) + if (keys[i] != null && keys[i].kv.equals(kv)) + return true; + return false; } - public boolean hasValue(KeyValue kv) + public boolean hasValue(KeyValue kv, int i) { - return (hasValue(key0, kv) || hasValue(key1, kv) || hasValue(key2, kv) || - hasValue(key3, kv) || hasValue(key4, kv)); + if (keys[i] == null) + return false; + return kv.equals(keys[i].kv); } - private static boolean hasValue(Corner c, KeyValue kv) + /** Transform the key index for edgekeys. + * This option is no longer useful but is used by some layouts. + * 1 7 2 5 1 7 + * 5 0 6 → 3 0 2 + * 3 8 4 8 4 6 + */ + static Corner[] rearange_edgekeys(Corner[] ks) { - return (c != null && c.kv.equals(kv)); + Corner[] edge_ks = new Corner[ks.length]; + for (int i = 0; i < ks.length; i++) + edge_ks[edgekey_index(i)] = ks[i]; + return edge_ks; + } + + static int edgekey_index(int i) + { + switch (i) + { + case 5: return 1; + case 1: return 7; + case 7: return 2; + case 3: return 5; + case 2: return 6; + case 8: return 3; + case 4: return 8; + case 6: return 4; + default: return i; + } } } @@ -491,15 +460,15 @@ class KeyboardData public Key apply(Key k) { - return new Key(apply(k.key0), apply(k.key1), apply(k.key2), - apply(k.key3), apply(k.key4), k.width, k.shift, k.edgekeys, - k.slider, k.indication); + Corner[] ks = new Corner[k.keys.length]; + for (int i = 0; i < ks.length; i++) + if (k.keys[i] != null) + ks[i] = apply(k.keys[i]); + return new Key(ks, k.width, k.shift, k.slider, k.indication); } protected Corner apply(Corner c) { - if (c == null) - return null; KeyValue kv = apply(c.kv, c.localized); return (kv == null) ? null : new Corner(kv, c.localized); } diff --git a/srcs/juloo.keyboard2/Pointers.java b/srcs/juloo.keyboard2/Pointers.java index 51319ca..b9e4d07 100644 --- a/srcs/juloo.keyboard2/Pointers.java +++ b/srcs/juloo.keyboard2/Pointers.java @@ -167,32 +167,49 @@ public final class Pointers implements Handler.Callback // Don't take latched modifiers into account if an other key is pressed. // The other key already "own" the latched modifiers and will clear them. Modifiers mods = getModifiers(isOtherPointerDown()); - KeyValue value = handleKV(key.key0, mods); + KeyValue value = handleKV(key.keys[0], mods); Pointer ptr = new Pointer(pointerId, key, value, x, y, mods); _ptrs.add(ptr); startKeyRepeat(ptr); _handler.onPointerDown(false); } + static final int[] DIRECTION_TO_INDEX = new int[]{ + 7, 2, 2, 6, 6, 4, 4, 8, 8, 3, 3, 5, 5, 1, 1, 7 + }; + + /** + * [direction] is an int between [0] and [15] that represent 16 sections of a + * circle, clockwise, starting at the top. + */ + KeyValue getKeyAtDirection(KeyboardData.Key k, int direction) + { + int i = DIRECTION_TO_INDEX[direction]; + if (k.keys[i] == null) + return null; + return k.keys[i].kv; + } + /* - * Get the KeyValue at the given direction. In case of swipe (!= 0), get the - * nearest KeyValue that is not key0. + * Get the KeyValue at the given direction. In case of swipe (direction != + * null), get the nearest KeyValue that is not key0. * Take care of applying [_handler.onPointerSwipe] to the selected key, this * must be done at the same time to be sure to treat removed keys correctly. * Return [null] if no key could be found in the given direction or if the * selected key didn't change. */ - private KeyValue getKeyAtDirection(Pointer ptr, int direction) + private KeyValue getNearestKeyAtDirection(Pointer ptr, Integer direction) { - if (direction == 0) - return handleKV(ptr.key.key0, ptr.modifiers); + if (direction == null) + return handleKV(ptr.key.keys[0], ptr.modifiers); KeyValue k; - for (int i = 0; i > -3; i = (~i>>31) - i) + // [i] is [0, -1, 1, -2, 2, ...] + for (int i = 0; i > -4; i = (~i>>31) - i) { - int d = (direction + i + 8 - 1) % 8 + 1; + int d = (direction + i + 16 - 1) % 16; // Don't make the difference between a key that doesn't exist and a key // that is removed by [_handler]. Triggers side effects. - k = _handler.modifyKey(ptr.key.getAtDirection(d), ptr.modifiers); + k = _handler.modifyKey(getKeyAtDirection(ptr.key, d), ptr.modifiers); if (k != null) return k; } @@ -225,45 +242,32 @@ public final class Pointers implements Handler.Callback } float dist = Math.abs(dx) + Math.abs(dy); - int direction; + Integer direction; if (dist < _config.swipe_dist_px) { - direction = 0; + direction = null; } else { - // One of the 8 directions: - // |\2|3/| - // |1\|/4| - // |-----| - // |8/|\5| - // |/7|6\| - direction = 1; - if (dx > 0) direction += 2; - if (dx > Math.abs(dy) || (dx < 0 && dx > -Math.abs(dy))) direction += 1; - if (dy > 0) direction = 9 - direction; + // See [getKeyAtDirection()] for the meaning. The starting point on the + // circle is the top direction. + double a = Math.atan2(dy, dx); // between -pi and +pi, 0 is to the right + direction = ((int)(a * 16 / (Math.PI * 2)) + 21) % 16; } if (direction != ptr.selected_direction) { ptr.selected_direction = direction; - KeyValue newValue = getKeyAtDirection(ptr, direction); - if (newValue != null && (ptr.value == null || !newValue.equals(ptr.value))) + KeyValue newValue = getNearestKeyAtDirection(ptr, direction); + if (newValue != null && !newValue.equals(ptr.value)) { ptr.value = newValue; ptr.flags = newValue.getFlags(); - // Sliding mode is entered when key2 or key3 is down on a slider key. - if (ptr.key.slider) + // Sliding mode is entered when key5 or key6 is down on a slider key. + if (ptr.key.slider && + (ptr.key.hasValue(newValue, 5) || ptr.key.hasValue(newValue, 6))) { - switch (direction) - { - case 1: - case 8: - case 4: - case 5: - startSliding(ptr, dy); - break; - } + startSliding(ptr, dy); } _handler.onPointerDown(true); } @@ -419,9 +423,8 @@ public final class Pointers implements Handler.Callback int count = (int)(dx / _config.slide_step_px); if (count == ptr.sliding_count) return; - KeyValue newValue = handleKV( - (count < ptr.sliding_count) ? ptr.key.key3 : ptr.key.key2, - ptr.modifiers); + int key_index = (count < ptr.sliding_count) ? 5 : 6; + KeyValue newValue = handleKV(ptr.key.keys[key_index], ptr.modifiers); ptr.sliding_count = count; ptr.value = newValue; if (newValue != null) @@ -434,8 +437,8 @@ public final class Pointers implements Handler.Callback public int pointerId; /** The Key pressed by this Pointer */ public final KeyboardData.Key key; - /** Current direction. */ - public int selected_direction; + /** Current direction. [null] means not swiping. */ + public Integer selected_direction; /** Selected value with [modifiers] applied. */ public KeyValue value; public float downX; @@ -455,7 +458,7 @@ public final class Pointers implements Handler.Callback { pointerId = p; key = k; - selected_direction = 0; + selected_direction = null; value = v; downX = x; downY = y; |
