2021-04-18 23:28:49 +02:00
|
|
|
|
package juloo.keyboard2;
|
|
|
|
|
|
|
|
|
|
import android.util.SparseArray;
|
|
|
|
|
import android.view.KeyCharacterMap;
|
2021-04-18 23:58:35 +02:00
|
|
|
|
import android.view.KeyEvent;
|
2021-04-18 23:28:49 +02:00
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
|
|
|
|
|
class KeyModifier
|
|
|
|
|
{
|
2022-03-19 16:27:57 +01:00
|
|
|
|
/** Cache key is KeyValue's name */
|
2021-04-18 23:28:49 +02:00
|
|
|
|
private static HashMap<String, SparseArray<KeyValue>> _cache =
|
|
|
|
|
new HashMap<String, SparseArray<KeyValue>>();
|
|
|
|
|
|
2022-03-19 16:27:57 +01:00
|
|
|
|
/** Represents a removed key, because a cache entry can't be [null]. */
|
|
|
|
|
private static final KeyValue removed_key = KeyValue.getKeyByName("removed");
|
|
|
|
|
|
|
|
|
|
/** Modify a key according to modifiers. */
|
2021-04-18 23:28:49 +02:00
|
|
|
|
public static KeyValue handleFlags(KeyValue k, int flags)
|
|
|
|
|
{
|
2022-03-19 16:27:57 +01:00
|
|
|
|
if (k == null)
|
|
|
|
|
return null;
|
2021-04-18 23:28:49 +02:00
|
|
|
|
SparseArray<KeyValue> ks = cacheEntry(k);
|
|
|
|
|
KeyValue r = ks.get(flags);
|
2022-03-19 16:27:57 +01:00
|
|
|
|
if (r == null) // Cold cache
|
|
|
|
|
{
|
|
|
|
|
r = k;
|
|
|
|
|
r = handleFn(r, flags);
|
2022-03-13 00:35:15 +01:00
|
|
|
|
r = handleShift(r, flags);
|
|
|
|
|
r = handleAccents(r, flags);
|
2022-03-19 16:27:57 +01:00
|
|
|
|
ks.put(flags, r);
|
|
|
|
|
}
|
|
|
|
|
return (r == removed_key) ? null : r;
|
2021-04-18 23:28:49 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-08 02:00:47 +02:00
|
|
|
|
private static KeyValue handleAccents(KeyValue k, int flags)
|
2021-04-18 23:28:49 +02:00
|
|
|
|
{
|
2021-05-08 02:00:47 +02:00
|
|
|
|
if (k.char_ == KeyValue.CHAR_NONE || (flags & KeyValue.FLAGS_ACCENTS) == 0)
|
|
|
|
|
return k;
|
|
|
|
|
char c = handleAccentChar(k.char_, flags);
|
|
|
|
|
if (c == 0 || c == k.char_)
|
|
|
|
|
return k;
|
|
|
|
|
return k.withCharAndSymbol(c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static KeyValue handleShift(KeyValue k, int flags)
|
|
|
|
|
{
|
|
|
|
|
if ((flags & KeyValue.FLAG_SHIFT) == 0)
|
|
|
|
|
return k;
|
2021-04-18 23:58:35 +02:00
|
|
|
|
char c = k.char_;
|
2021-05-08 02:00:47 +02:00
|
|
|
|
if (k.char_ != KeyValue.CHAR_NONE)
|
2021-04-18 23:28:49 +02:00
|
|
|
|
c = Character.toUpperCase(c);
|
2021-05-08 02:00:47 +02:00
|
|
|
|
if (c == k.char_) // More rules if toUpperCase() did nothing
|
|
|
|
|
switch (k.symbol)
|
|
|
|
|
{
|
|
|
|
|
case "→": c = '⇒'; break;
|
|
|
|
|
case "←": c = '⇐'; break;
|
2021-05-08 15:51:47 +02:00
|
|
|
|
case "<": c = '«'; break;
|
|
|
|
|
case ">": c = '»'; break;
|
|
|
|
|
case "“": c = '”'; break;
|
2021-05-08 02:00:47 +02:00
|
|
|
|
default: return k;
|
|
|
|
|
}
|
|
|
|
|
return k.withCharAndSymbol(c);
|
2021-04-18 23:28:49 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static char handleAccentChar(char c, int flags)
|
|
|
|
|
{
|
|
|
|
|
switch ((flags & KeyValue.FLAGS_ACCENTS))
|
|
|
|
|
{
|
2021-04-19 23:10:00 +02:00
|
|
|
|
case KeyValue.FLAG_ACCENT1:
|
|
|
|
|
return (char)KeyCharacterMap.getDeadChar('\u02CB', c);
|
|
|
|
|
case KeyValue.FLAG_ACCENT2:
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
case '`': return '´';
|
|
|
|
|
case '<': return '‘';
|
|
|
|
|
case '>': return '‘';
|
|
|
|
|
default: return (char)KeyCharacterMap.getDeadChar('\u00B4', c);
|
|
|
|
|
}
|
|
|
|
|
case KeyValue.FLAG_ACCENT3:
|
2022-01-01 19:00:27 +01:00
|
|
|
|
return (char)KeyCharacterMap.getDeadChar('\u02C6', c);
|
2021-05-08 02:00:47 +02:00
|
|
|
|
case KeyValue.FLAG_ACCENT4:
|
2021-05-08 02:03:23 +02:00
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
case '?': return '¿';
|
|
|
|
|
case '!': return '¡';
|
|
|
|
|
default: return (char)KeyCharacterMap.getDeadChar('\u02DC', c);
|
|
|
|
|
}
|
2021-05-08 02:00:47 +02:00
|
|
|
|
case KeyValue.FLAG_ACCENT5:
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
case 'u': return 'µ';
|
|
|
|
|
case '"': return '„';
|
2021-05-08 15:51:47 +02:00
|
|
|
|
case '\'': return '’';
|
2021-05-08 02:00:47 +02:00
|
|
|
|
case '-': return '¬';
|
|
|
|
|
case 'a': return 'æ';
|
|
|
|
|
case 'o': return 'œ';
|
|
|
|
|
default: return (char)KeyCharacterMap.getDeadChar('\u00B8', c);
|
|
|
|
|
}
|
|
|
|
|
case KeyValue.FLAG_ACCENT6:
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
case '-': return '÷';
|
|
|
|
|
default: return (char)KeyCharacterMap.getDeadChar('\u00A8', c);
|
|
|
|
|
}
|
2022-01-15 10:13:41 +01:00
|
|
|
|
case KeyValue.FLAG_ACCENT_CARON:
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
default: return (char)KeyCharacterMap.getDeadChar('\u02C7', c);
|
|
|
|
|
}
|
2021-12-11 17:05:49 +01:00
|
|
|
|
case KeyValue.FLAG_ACCENT_RING:
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
default: return (char)KeyCharacterMap.getDeadChar('\u02DA', c);
|
|
|
|
|
}
|
2022-01-15 10:13:41 +01:00
|
|
|
|
case KeyValue.FLAG_ACCENT_MACRON:
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
default: return (char)KeyCharacterMap.getDeadChar('\u00AF', c);
|
|
|
|
|
}
|
2022-02-17 12:29:46 +01:00
|
|
|
|
case KeyValue.FLAG_ACCENT_ORDINAL:
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
case 'a': return 'ª';
|
|
|
|
|
case 'o': return 'º';
|
|
|
|
|
case '1': return 'ª';
|
|
|
|
|
case '2': return 'º';
|
|
|
|
|
case '3': return 'ⁿ';
|
|
|
|
|
case '4': return 'ᵈ';
|
|
|
|
|
case '5': return 'ᵉ';
|
|
|
|
|
case '6': return 'ʳ';
|
|
|
|
|
case '7': return 'ˢ';
|
|
|
|
|
case '8': return 'ᵗ';
|
|
|
|
|
case '9': return 'ʰ';
|
2022-02-19 21:01:52 +01:00
|
|
|
|
case '*': return '°';
|
2022-02-17 12:29:46 +01:00
|
|
|
|
default: return c;
|
|
|
|
|
}
|
2021-05-08 02:00:47 +02:00
|
|
|
|
case KeyValue.FLAG_ACCENT_SUPERSCRIPT:
|
2021-04-19 23:10:00 +02:00
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
case '1': return '¹';
|
|
|
|
|
case '2': return '²';
|
|
|
|
|
case '3': return '³';
|
|
|
|
|
case '4': return '⁴';
|
|
|
|
|
case '5': return '⁵';
|
|
|
|
|
case '6': return '⁶';
|
|
|
|
|
case '7': return '⁷';
|
|
|
|
|
case '8': return '⁸';
|
|
|
|
|
case '9': return '⁹';
|
|
|
|
|
case '0': return '⁰';
|
2021-05-08 02:00:47 +02:00
|
|
|
|
case 'i': return 'ⁱ';
|
|
|
|
|
case '+': return '⁺';
|
|
|
|
|
case '-': return '⁻';
|
|
|
|
|
case '=': return '⁼';
|
|
|
|
|
case '(': return '⁽';
|
|
|
|
|
case ')': return '⁾';
|
|
|
|
|
case 'n': return 'ⁿ';
|
|
|
|
|
default: return c;
|
2021-04-19 23:10:00 +02:00
|
|
|
|
}
|
2021-05-08 02:00:47 +02:00
|
|
|
|
case KeyValue.FLAG_ACCENT_SUBSCRIPT:
|
2021-04-19 23:10:00 +02:00
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
case '1': return '₁';
|
|
|
|
|
case '2': return '₂';
|
|
|
|
|
case '3': return '₃';
|
|
|
|
|
case '4': return '₄';
|
|
|
|
|
case '5': return '₅';
|
|
|
|
|
case '6': return '₆';
|
|
|
|
|
case '7': return '₇';
|
|
|
|
|
case '8': return '₈';
|
|
|
|
|
case '9': return '₉';
|
|
|
|
|
case '0': return '₀';
|
2021-05-08 02:00:47 +02:00
|
|
|
|
case '+': return '₊';
|
|
|
|
|
case '-': return '₋';
|
|
|
|
|
case '=': return '₌';
|
|
|
|
|
case '(': return '₍';
|
|
|
|
|
case ')': return '₎';
|
|
|
|
|
case 'e': return 'ₑ';
|
|
|
|
|
case 'a': return 'ₐ';
|
|
|
|
|
case 'x': return 'ₓ';
|
|
|
|
|
case 'o': return 'ₒ';
|
|
|
|
|
default: return c;
|
2021-04-19 23:10:00 +02:00
|
|
|
|
}
|
2021-04-18 23:28:49 +02:00
|
|
|
|
default: return c; // Can't happen
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-18 23:58:35 +02:00
|
|
|
|
private static KeyValue handleFn(KeyValue k, int flags)
|
|
|
|
|
{
|
|
|
|
|
if ((flags & KeyValue.FLAG_FN) == 0)
|
2022-03-19 16:27:57 +01:00
|
|
|
|
{
|
|
|
|
|
switch (k.name)
|
|
|
|
|
{
|
|
|
|
|
// Remove some keys when Fn is *not* activated
|
|
|
|
|
case "f11_placeholder":
|
|
|
|
|
case "f12_placeholder": return removed_key;
|
|
|
|
|
default: return k;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-19 22:29:20 +02:00
|
|
|
|
String name;
|
|
|
|
|
switch (k.name)
|
2021-04-18 23:58:35 +02:00
|
|
|
|
{
|
2021-04-19 22:29:20 +02:00
|
|
|
|
case "1": name = "f1"; break;
|
|
|
|
|
case "2": name = "f2"; break;
|
|
|
|
|
case "3": name = "f3"; break;
|
|
|
|
|
case "4": name = "f4"; break;
|
|
|
|
|
case "5": name = "f5"; break;
|
|
|
|
|
case "6": name = "f6"; break;
|
|
|
|
|
case "7": name = "f7"; break;
|
|
|
|
|
case "8": name = "f8"; break;
|
|
|
|
|
case "9": name = "f9"; break;
|
|
|
|
|
case "0": name = "f10"; break;
|
2022-03-19 16:27:57 +01:00
|
|
|
|
case "f11_placeholder": name = "f11"; break;
|
|
|
|
|
case "f12_placeholder": name = "f12"; break;
|
2021-04-19 22:29:20 +02:00
|
|
|
|
case "up": name = "page_up"; break;
|
|
|
|
|
case "down": name = "page_down"; break;
|
|
|
|
|
case "left": name = "home"; break;
|
|
|
|
|
case "right": name = "end"; break;
|
2021-05-08 02:00:47 +02:00
|
|
|
|
case ">": name = "→"; break;
|
|
|
|
|
case "<": name = "←"; break;
|
2021-05-08 15:51:47 +02:00
|
|
|
|
case "\"": name = "“"; break;
|
|
|
|
|
case "-": name = "–"; break;
|
|
|
|
|
case "_": name = "—"; break;
|
2021-05-08 15:54:55 +02:00
|
|
|
|
case "esc": name = "insert"; break;
|
2021-12-05 20:16:01 +01:00
|
|
|
|
case "$": name = "€"; break;
|
|
|
|
|
case "#": name = "£"; break;
|
2022-01-01 19:00:27 +01:00
|
|
|
|
case "*": name = "°"; break;
|
2022-01-29 20:03:17 +01:00
|
|
|
|
case "tab": name = "\\t"; break;
|
2022-03-19 16:27:57 +01:00
|
|
|
|
case "€": case "£": return removed_key; // Avoid showing these twice
|
2021-05-08 02:00:47 +02:00
|
|
|
|
default: return k;
|
2021-04-18 23:58:35 +02:00
|
|
|
|
}
|
2021-04-19 22:29:20 +02:00
|
|
|
|
return KeyValue.getKeyByName(name);
|
2021-04-18 23:58:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-18 23:28:49 +02:00
|
|
|
|
/* Lookup the cache entry for a key. Create it needed. */
|
|
|
|
|
private static SparseArray<KeyValue> cacheEntry(KeyValue k)
|
|
|
|
|
{
|
|
|
|
|
SparseArray<KeyValue> ks = _cache.get(k.name);
|
|
|
|
|
if (ks == null)
|
|
|
|
|
{
|
|
|
|
|
ks = new SparseArray<KeyValue>();
|
|
|
|
|
_cache.put(k.name, ks);
|
|
|
|
|
}
|
|
|
|
|
return ks;
|
|
|
|
|
}
|
|
|
|
|
}
|