abouttreesummaryrefslogcommitdiff
path: root/srcs
diff options
context:
space:
mode:
authorJules Aguillon2025-02-23 18:00:44 +0100
committerJules Aguillon2025-02-23 18:00:44 +0100
commitca25cc55f6bc2c7b3100da2f7bf18a078a23f55e (patch)
treee3e94c2fa073e44063b66d86f8be4789620714ad /srcs
parent68be82a4f92f47300b9960cf9cf65040c96f17ed (diff)
downloadunexpected-keyboard-ca25cc55f6bc2c7b3100da2f7bf18a078a23f55e.tar.gz
unexpected-keyboard-ca25cc55f6bc2c7b3100da2f7bf18a078a23f55e.zip
Apply compose sequences to String keys
This is mostly useful for characters that do not fit on a single 16-bit char. Shift sequences for ๐•จ๐•ฉ๐•—๐•˜๐•ค are added for illustration.
Diffstat (limited to 'srcs')
-rw-r--r--srcs/compose/shift.json11
-rw-r--r--srcs/juloo.keyboard2/ComposeKey.java42
-rw-r--r--srcs/juloo.keyboard2/ComposeKeyData.java14
-rw-r--r--srcs/juloo.keyboard2/KeyModifier.java60
-rw-r--r--srcs/juloo.keyboard2/LayoutModifier.java11
5 files changed, 82 insertions, 56 deletions
diff --git a/srcs/compose/shift.json b/srcs/compose/shift.json
index 8b87006..0a44829 100644
--- a/srcs/compose/shift.json
+++ b/srcs/compose/shift.json
@@ -125,5 +125,14 @@
"เฅข": "เฅฃ",
"เฅ’": "เฅ‘",
"เฅ…": "เฅฒ",
- "เฅ‰": "เค‘"
+ "เฅ‰": "เค‘",
+
+ // Mathematical symbols
+ "\uD835": {
+ "\uDD68": "๐•Ž", // ๐•จ โ†’ ๐•Ž
+ "\uDD69": "๐•", // ๐•ฉ โ†’ ๐•
+ "\uDD57": "๐”ฝ", // ๐•— โ†’ ๐”ฝ
+ "\uDD58": "๐”พ", // ๐•˜ โ†’ ๐”พ
+ "\uDD64": "๐•Š" // ๐•ค โ†’ ๐•Š
+ }
}
diff --git a/srcs/juloo.keyboard2/ComposeKey.java b/srcs/juloo.keyboard2/ComposeKey.java
index f2169b1..57b2a4e 100644
--- a/srcs/juloo.keyboard2/ComposeKey.java
+++ b/srcs/juloo.keyboard2/ComposeKey.java
@@ -4,31 +4,22 @@ import java.util.Arrays;
public final class ComposeKey
{
- /** Apply the pending compose sequence to [kv]. */
+ /** Apply the pending compose sequence to [kv]. Returns [null] if no sequence
+ matched. */
public static KeyValue apply(int state, KeyValue kv)
{
switch (kv.getKind())
{
case Char:
- KeyValue res = apply(state, kv.getChar());
- // Grey-out characters not part of any sequence.
- if (res == null)
- return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
- return res;
- /* Tapping compose again exits the pending sequence. */
- case Compose_pending:
- return KeyValue.getKeyByName("compose_cancel");
- /* These keys are not greyed. */
- case Event:
- case Modifier:
- return kv;
- /* Other keys cannot be part of sequences. */
- default:
- return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
+ return apply(state, kv.getChar());
+ case String:
+ return apply(state, kv.getString());
}
+ return null;
}
- /** Apply the pending compose sequence to char [c]. */
+ /** Apply the pending compose sequence to char [c]. Returns [null] if no
+ sequence matched. */
public static KeyValue apply(int prev, char c)
{
char[] states = ComposeKeyData.states;
@@ -51,6 +42,23 @@ public final class ComposeKey
return KeyValue.makeCharKey((char)next_header);
}
+ /** Apply each char of a string to a sequence. Returns [null] if no sequence
+ matched. */
+ public static KeyValue apply(int prev, String s)
+ {
+ int i = 0;
+ while (true)
+ {
+ KeyValue k = apply(prev, s.charAt(i));
+ i++;
+ if (k == null) return null;
+ if (i >= s.length()) return k;
+ if (k.getKind() != KeyValue.Kind.Compose_pending)
+ return null; // Found a final state before the end of [s].
+ prev = k.getPendingCompose();
+ }
+ }
+
/** The state machine is comprised of two arrays.
The [states] array represents the different states and the associated
diff --git a/srcs/juloo.keyboard2/ComposeKeyData.java b/srcs/juloo.keyboard2/ComposeKeyData.java
index 2c8b124..f84397a 100644
--- a/srcs/juloo.keyboard2/ComposeKeyData.java
+++ b/srcs/juloo.keyboard2/ComposeKeyData.java
@@ -118,9 +118,9 @@ public final class ComposeKeyData
"\u0963\u0965\u0971\uFFFF\u0bd0\uFFFF\u0bf2\uFFFF\u0bf0\uFFFF\u0bf1\uFFFF\u0bf3\u21d4\u21d5\u21d6\u21d7\u21d8\u21d9\u22c0\u22c1\u22c2\u22c3\u222e\u22b6\u044b\u0483\u00000123456789\u09e6\u09e7\u09e8\u09e9\u09ea\u09eb\u09ec\u09ed\u09ee\u09ef\u00000123456789\u0966\u0967\u0968\u0969\u096a\u096b\u096c\u096d\u096e\u096f\u000001" +
"23456789\u0ae6\u0ae7\u0ae8\u0ae9\u0aea\u0aeb\u0aec\u0aed\u0aee\u0aef\u00000123456789\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669\u00000123456789\u0ce6\u0ce7\u0ce8\u0ce9\u0cea\u0ceb\u0cec\u0ced\u0cee\u0cef\u00000123456789\u06f0" +
"\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9\u00000123456789\u0be6\u0be7\u0be8\u0be9\u0bea\u0beb\u0bec\u0bed\u0bee\u0bef\u0000\u00df\u0131\u01f0\u0237\u02b0\u02b2\u02b3\u02b7\u02e1\u0905\u0907\u0909\u090b\u090c\u090f\u0913\u0915\u0917\u091a\u091c\u091f\u0921\u0924\u0926\u0928\u092c\u092e\u0932\u0938\u0939\u093f\u0941\u0943\u0945\u0947\u0949\u094b\u0952\u0962\u0a85\u0a87" +
- "\u0a89\u0a8f\u0a93\u0a95\u0a97\u0a9a\u0a9c\u0a9f\u0aa1\u0aa4\u0aa6\u0aa8\u0aaa\u0aac\u0aae\u0ab2\u0ab8\u0ab9\u0abf\u0ac1\u0ac7\u0acb\u0bf9\u1d43\u1d47\u1d48\u1d49\u1d4d\u1d4f\u1d50\u1d52\u1d56\u1d57\u1d58\u1d5b\u1d60\u1d9c\u1da0\u1dbe\u1e97\u1e98\u1e99\u2071\u207f\u20b9\u2190\u2191\u2192\u2193\u2196\u2197\u2198\u2199\u2208\u220b\u2282\u2283\u2286\u2287\u2500\u2502\u250c\u2510\u2514\u2518\u251c\u2524\u252c\u2534\u253c\uFFFF\u004a" +
- "\u030c\uFFFF\u004a\u0307\u1d34\u1d36\u1d3f\u1d42\u1d38\u0906\u0908\u090a\u0910\u0914\u0916\u0918\u091b\u091d\u0920\u0922\u0925\u0927\u0923\u092d\u0902\u0933\u0936\u0903\u0940\u0942\u0948\u094c\u0951\u0a86\u0a88\u0a8a\u0a90\u0a94\u0a96\u0a98\u0a9b\u0a9d\u0aa0\u0aa2\u0aa5\u0aa7\u0aa3\u0aab\u0aad\u0a82\u0ab3\u0ab6\u0a83\u0ac0\u0ac2\u0ac8\u0acc\u1d2c\u1d2e\u1d30\u1d31\u1d33\u1d37\u1d39\u1d3c\u1d3e\u1d40\u1d41\u2c7d\u1db2\uFFFF\ua7f2" +
- "\uFFFF\ua7f3\u1d23\uFFFF\u0054\u0308\uFFFF\u0057\u030a\uFFFF\u0059\u030a\u1d35\u1d3a\u2550\u2551\u2554\u2557\u255a\u255d\u2560\u2563\u2566\u2569\u256c").toCharArray();
+ "\u0a89\u0a8f\u0a93\u0a95\u0a97\u0a9a\u0a9c\u0a9f\u0aa1\u0aa4\u0aa6\u0aa8\u0aaa\u0aac\u0aae\u0ab2\u0ab8\u0ab9\u0abf\u0ac1\u0ac7\u0acb\u0bf9\u1d43\u1d47\u1d48\u1d49\u1d4d\u1d4f\u1d50\u1d52\u1d56\u1d57\u1d58\u1d5b\u1d60\u1d9c\u1da0\u1dbe\u1e97\u1e98\u1e99\u2071\u207f\u20b9\u2190\u2191\u2192\u2193\u2196\u2197\u2198\u2199\u2208\u220b\u2282\u2283\u2286\u2287\u2500\u2502\u250c\u2510\u2514\u2518\u251c\u2524\u252c\u2534\u253c\ud835\uFFFF" +
+ "\u004a\u030c\uFFFF\u004a\u0307\u1d34\u1d36\u1d3f\u1d42\u1d38\u0906\u0908\u090a\u0910\u0914\u0916\u0918\u091b\u091d\u0920\u0922\u0925\u0927\u0923\u092d\u0902\u0933\u0936\u0903\u0940\u0942\u0948\u094c\u0951\u0a86\u0a88\u0a8a\u0a90\u0a94\u0a96\u0a98\u0a9b\u0a9d\u0aa0\u0aa2\u0aa5\u0aa7\u0aa3\u0aab\u0aad\u0a82\u0ab3\u0ab6\u0a83\u0ac0\u0ac2\u0ac8\u0acc\u1d2c\u1d2e\u1d30\u1d31\u1d33\u1d37\u1d39\u1d3c\u1d3e\u1d40\u1d41\u2c7d\u1db2\uFFFF" +
+ "\ua7f2\uFFFF\ua7f3\u1d23\uFFFF\u0054\u0308\uFFFF\u0057\u030a\uFFFF\u0059\u030a\u1d35\u1d3a\u2550\u2551\u2554\u2557\u255a\u255d\u2560\u2563\u2566\u2569\u256c\u0000\udd57\udd58\udd64\udd68\udd69\uFFFF\ud835\udd3d\uFFFF\ud835\udd3e\uFFFF\ud835\udd4a\uFFFF\ud835\udd4e\uFFFF\ud835\udd4f").toCharArray();
public static final char[] edges =
("\u0001\u0036\u0037\u0038\u0039\u003a\u003b\u003c\u003f\u0040\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u004a\u004b\u004c\u004d\u004e\u004f\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0059\u005a\u005b\\\u005d\u005e\u005f\u0060\u0061\u0062\u0063\u0064\u0067\u0068\u006b\u006e\u006f\u0072\u0075\u0078\u007b\u007e\u0081\u0001\u0001\u0001\u0001\u0001\u0003\u0000\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001" +
@@ -235,10 +235,10 @@ public final class ComposeKeyData
"\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0004\u0000\u0000\u0000\u0001\u0001\u0001\u0004\u0000\u0000\u0000\u0004\u0000\u0000\u0000\u0004\u0000\u0000\u0000\u0001\u0001\u0004\u0000\u0000\u0000\u0004\u0000\u0000\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001" +
"\u0001\u0001\u0001\u0002\u0000\u0002\u0000\u0002\u0000\u0002\u0000\u0002\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f16\u1f17\u1f18\u1f19\u1f1a\u1f1b\u1f1c\u1f1d\u1f1e\u1f1f\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f2b\u1f2c\u1f2d\u1f2e\u1f2f\u1f30\u1f31\u1f32\u1f33\u1f34\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f40\u1f41" +
"\u1f42\u1f43\u1f44\u1f45\u1f46\u1f47\u1f48\u1f49\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f55\u1f56\u1f57\u1f58\u1f59\u1f5a\u1f5b\u1f5c\u1f5d\u1f5e\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f6a\u1f6b\u1f6c\u1f6d\u1f6e\u1f6f\u1f70\u1f71\u1f72\u1f73\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f7f\u1f80\u1f81\u1f82\u1f83\u1f84\u1f85\u1f86\u1f87\u1f88\u0001" +
- "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f94\u1f95\u1f96\u1f97\u1f98\u1f99\u1f9a\u1f9b\u1f9c\u1f9d\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0070\u0f55\u0d0b\u200e\u2011\u2014\u2015\u2016\u2017\u2018\u2019\u201a\u201b\u1ebe\u1ebf\u201c\u201d\u201e\u201f\u2020\u2021\u2022\u2023\u2024\u2025\u2026\u2027\u2028\u2029\u202a\u202b\u202c\u202d\u1ee9\u1eb8\u202e\u1eb9\u202f\u2030\u1ef0\u2031\u2032" +
- "\u2033\u2034\u2035\u2036\u2037\u2038\u2039\u203a\u203b\u203c\u203d\u203e\u203f\u2040\u2041\u2042\u2043\u2044\u2045\u2046\u2047\u2048\u0f48\u2049\u204a\u204b\u204c\u204d\u204e\u204f\u2050\u2051\u2052\u2053\u2054\u2055\u2056\u2058\u205a\u205b\u205e\u2061\u2064\u2065\u0f48\u0e0d\u0e19\u0e0e\u0e1c\u1eff\u1f00\u1f01\u1f02\u1c43\u1c48\u1c9e\u1ca2\u1ca5\u1ca8\u2066\u2067\u2068\u2069\u206a\u206b\u206c\u206d\u206e\u206f\u2070\u0003\u0000" +
- "\u0000\u0003\u0000\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0002\u0000" +
- "\u0002\u0000\u0001\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001").toCharArray();
+ "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f94\u1f95\u1f96\u1f97\u1f98\u1f99\u1f9a\u1f9b\u1f9c\u1f9d\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0071\u0f55\u0d0b\u200f\u2012\u2015\u2016\u2017\u2018\u2019\u201a\u201b\u201c\u1ebe\u1ebf\u201d\u201e\u201f\u2020\u2021\u2022\u2023\u2024\u2025\u2026\u2027\u2028\u2029\u202a\u202b\u202c\u202d\u202e\u1ee9\u1eb8\u202f\u1eb9\u2030\u2031\u1ef0\u2032\u2033" +
+ "\u2034\u2035\u2036\u2037\u2038\u2039\u203a\u203b\u203c\u203d\u203e\u203f\u2040\u2041\u2042\u2043\u2044\u2045\u2046\u2047\u2048\u2049\u0f48\u204a\u204b\u204c\u204d\u204e\u204f\u2050\u2051\u2052\u2053\u2054\u2055\u2056\u2057\u2059\u205b\u205c\u205f\u2062\u2065\u2066\u0f48\u0e0d\u0e19\u0e0e\u0e1c\u1eff\u1f00\u1f01\u1f02\u1c43\u1c48\u1c9e\u1ca2\u1ca5\u1ca8\u2067\u2068\u2069\u206a\u206b\u206c\u206d\u206e\u206f\u2070\u2071\u2072\u0003" +
+ "\u0000\u0000\u0003\u0000\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0002" +
+ "\u0000\u0002\u0000\u0001\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0006\u2078\u207b\u207e\u2081\u2084\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000").toCharArray();
public static final int accent_aigu = 1;
public static final int accent_arrows = 130;
diff --git a/srcs/juloo.keyboard2/KeyModifier.java b/srcs/juloo.keyboard2/KeyModifier.java
index fcb0793..c9de407 100644
--- a/srcs/juloo.keyboard2/KeyModifier.java
+++ b/srcs/juloo.keyboard2/KeyModifier.java
@@ -36,7 +36,7 @@ public final class KeyModifier
case Modifier:
return modify(k, mod.getModifier());
case Compose_pending:
- return ComposeKey.apply(mod.getPendingCompose(), k);
+ return apply_compose_pending(mod.getPendingCompose(), k);
case Hangul_initial:
if (k.equals(mod)) // Allow typing the initial in letter form
return KeyValue.makeStringKey(k.getString(), KeyValue.FLAG_GREYED);
@@ -122,30 +122,44 @@ public final class KeyModifier
}
}
- /** Apply the given compose state or fallback to the dead_char. */
- private static KeyValue apply_compose_or_dead_char(KeyValue k, int state, char dead_char)
+ /** Keys that do not match any sequence are greyed. */
+ private static KeyValue apply_compose_pending(int state, KeyValue kv)
{
- switch (k.getKind())
+ switch (kv.getKind())
{
case Char:
- char c = k.getChar();
- KeyValue r = ComposeKey.apply(state, c);
- if (r != null)
- return r;
+ case String:
+ KeyValue res = ComposeKey.apply(state, kv);
+ // Grey-out characters not part of any sequence.
+ if (res == null)
+ return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
+ return res;
+ /* Tapping compose again exits the pending sequence. */
+ case Compose_pending:
+ return KeyValue.getKeyByName("compose_cancel");
+ /* These keys are not greyed. */
+ case Event:
+ case Modifier:
+ return kv;
+ /* Other keys cannot be part of sequences. */
+ default:
+ return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
}
+ }
+
+ /** Apply the given compose state or fallback to the dead_char. */
+ private static KeyValue apply_compose_or_dead_char(KeyValue k, int state, char dead_char)
+ {
+ KeyValue r = ComposeKey.apply(state, k);
+ if (r != null)
+ return r;
return apply_dead_char(k, dead_char);
}
private static KeyValue apply_compose(KeyValue k, int state)
{
- switch (k.getKind())
- {
- case Char:
- KeyValue r = ComposeKey.apply(state, k.getChar());
- if (r != null)
- return r;
- }
- return k;
+ KeyValue r = ComposeKey.apply(state, k);
+ return (r != null) ? r : k;
}
private static KeyValue apply_dead_char(KeyValue k, char dead_char)
@@ -179,18 +193,19 @@ public final class KeyModifier
if (mapped != null)
return mapped;
}
+ KeyValue r = ComposeKey.apply(ComposeKeyData.shift, k);
+ if (r != null)
+ return r;
switch (k.getKind())
{
case Char:
char kc = k.getChar();
- KeyValue r = ComposeKey.apply(ComposeKeyData.shift, kc);
- if (r != null)
- return r;
char c = Character.toUpperCase(kc);
return (kc == c) ? k : k.withChar(c);
case String:
- String s = Utils.capitalize_string(k.getString());
- return KeyValue.makeStringKey(s, k.getFlags());
+ String ks = k.getString();
+ String s = Utils.capitalize_string(ks);
+ return s.equals(ks) ? k : KeyValue.makeStringKey(s, k.getFlags());
default: return k;
}
}
@@ -207,7 +222,8 @@ public final class KeyModifier
switch (k.getKind())
{
case Char:
- KeyValue r = ComposeKey.apply(ComposeKeyData.fn, k.getChar());
+ case String:
+ KeyValue r = ComposeKey.apply(ComposeKeyData.fn, k);
return (r != null) ? r : k;
case Keyevent: name = apply_fn_keyevent(k.getKeyevent()); break;
case Event: name = apply_fn_event(k.getEvent()); break;
diff --git a/srcs/juloo.keyboard2/LayoutModifier.java b/srcs/juloo.keyboard2/LayoutModifier.java
index 830a50c..7be3fb6 100644
--- a/srcs/juloo.keyboard2/LayoutModifier.java
+++ b/srcs/juloo.keyboard2/LayoutModifier.java
@@ -138,15 +138,8 @@ public final class LayoutModifier
return new KeyboardData.MapKeyValues() {
public KeyValue apply(KeyValue key, boolean localized)
{
- switch (key.getKind())
- {
- case Char:
- KeyValue modified = ComposeKey.apply(map_digit, key.getChar());
- if (modified != null)
- return modified;
- break;
- }
- return key;
+ KeyValue modified = ComposeKey.apply(map_digit, key);
+ return (modified != null) ? modified : key;
}
};
}