diff --git a/README.md b/README.md
index add9c05aa..6e9e8fc09 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,9 @@ Now perfect for everyday use.
This application contains no ads, doesn't make any network requests and is Open Source.
+## Similar apps
+* [Calculator++](https://github.com/Bubu/android-calculatorpp) - Calculator with a similar UX, swipe to corners for advanced math symbols and operators. Works up to Android 13 but maybe unmaintained.
+
## Contributing
For instructions on building the application, see
diff --git a/check_layout.output b/check_layout.output
index 6ee6e3084..a8edbe51c 100644
--- a/check_layout.output
+++ b/check_layout.output
@@ -1,24 +1,27 @@
# res/xml/arab_alt.xml
Layout includes some ASCII punctuation but not all, missing: !, ", ', +, -, /, :, ;, <, =, >, ?, [, \, ], _, |, ~
-1 warnings
+Layout doesn't define some important keys, missing: f11_placeholder, f12_placeholder
+2 warnings
# res/xml/arab_pc_ckb.xml
Layout includes some ASCII punctuation but not all, missing: ", %, ', +, ,, ., :, ;, <, =, >, ?, `, |, ~
1 warnings
# res/xml/arab_pc_ir.xml
-Layout includes some ASCII punctuation but not all, missing: ", $, %, ', *, ,, /, ;, <, =, >, ?, [, \, ], ^, _, `, {, |, }, ~
-1 warnings
+Duplicate keys: (, )
+Layout includes some ASCII punctuation but not all, missing: ", %, ', ,, /, ;, <, =, >, ?, [, \, ], `, {, |, }
+2 warnings
# res/xml/arab_pc.xml
Layout includes some ASCII punctuation but not all, missing: !, ', +, ;, ?, \, |
1 warnings
# res/xml/beng_national.xml
Layout includes some ASCII punctuation but not all, missing: $
+Layout doesn't define some important keys, missing: f11_placeholder, f12_placeholder
Layout doesn't specify a script.
-2 warnings
+3 warnings
# res/xml/beng_provat.xml
Layout includes some ASCII punctuation but not all, missing: $, &, *, ., /, <, >, [, \, ], `, {, |, }
+Layout doesn't define some important keys, missing: f11_placeholder, f12_placeholder
Layout doesn't specify a script.
-2 warnings
-Not a layout file: res/xml/bottom_row.xml
+3 warnings
# res/xml/cyrl_jcuken_ru.xml
0 warnings
# res/xml/cyrl_jcuken_uk.xml
@@ -28,17 +31,16 @@ Layout includes some ASCII punctuation but not all, missing: ~
1 warnings
# res/xml/deva_alt.xml
Layout includes some ASCII punctuation but not all, missing: #, $, %, &, ', (, ), *, +, ., /, :, <, =, >, @, [, \, ], ^, _, `, {, |, }, ~
-1 warnings
+Layout doesn't define some important keys, missing: f11_placeholder, f12_placeholder
+2 warnings
# res/xml/deva_inscript.xml
+Duplicate keys: , ।
Layout includes some ASCII punctuation but not all, missing: ", $, ', ^, _, `, |
-1 warnings
-# res/xml/greekmath.xml
-Layout includes some ASCII punctuation but not all, missing: !, ", #, $, %, &, ', (, ), *, +, ,, -, /, :, ;, <, >, ?, @, [, \, ], _, `, {, |, }, ~
-Layout redefines the bottom row but some important keys are missing, missing: change_method, config, ctrl, switch_emoji, switch_second
-Layout doesn't specify a script.
+Layout doesn't define some important keys, missing: f11_placeholder, f12_placeholder
3 warnings
# res/xml/grek_qwerty.xml
-0 warnings
+Duplicate keys: ;
+1 warnings
# res/xml/hang_dubeolsik_kr.xml
0 warnings
# res/xml/hebr_1_il.xml
@@ -51,13 +53,16 @@ Layout includes some ASCII punctuation but not all, missing: (, ), <, >, [, ], {
0 warnings
# res/xml/latn_bone.xml
Layout includes some ASCII punctuation but not all, missing: $
-1 warnings
+Layout redefines the bottom row but some important keys are missing, missing: switch_backward
+2 warnings
# res/xml/latn_colemak.xml
0 warnings
# res/xml/latn_dvorak.xml
0 warnings
# res/xml/latn_neo2.xml
-0 warnings
+Duplicate keys: -
+Layout redefines the bottom row but some important keys are missing, missing: switch_forward
+2 warnings
# res/xml/latn_qwerty_br.xml
0 warnings
# res/xml/latn_qwerty_es.xml
@@ -73,9 +78,11 @@ Layout includes some ASCII punctuation but not all, missing: $
# res/xml/latn_qwerty_ro.xml
0 warnings
# res/xml/latn_qwerty_se.xml
-0 warnings
+Duplicate keys: !, ', ,, -, ., ?
+1 warnings
# res/xml/latn_qwerty_tr.xml
-0 warnings
+Layout doesn't define some important keys, missing: f11_placeholder, f12_placeholder
+1 warnings
# res/xml/latn_qwerty_us.xml
0 warnings
# res/xml/latn_qwerty_vi.xml
@@ -83,9 +90,11 @@ Layout includes some ASCII punctuation but not all, missing: \
1 warnings
# res/xml/latn_qwertz_cz_multifunctional.xml
Layout includes some ASCII punctuation but not all, missing: `
-1 warnings
+Layout doesn't define some important keys, missing: f11_placeholder, f12_placeholder
+2 warnings
# res/xml/latn_qwertz_cz.xml
-0 warnings
+Layout doesn't define some important keys, missing: f11_placeholder, f12_placeholder
+1 warnings
# res/xml/latn_qwertz_de.xml
0 warnings
# res/xml/latn_qwertz_fr_ch.xml
@@ -94,25 +103,7 @@ Layout includes some ASCII punctuation but not all, missing: `
0 warnings
# res/xml/latn_qwertz_sk.xml
Layout includes some ASCII punctuation but not all, missing: \, `
-1 warnings
+Layout doesn't define some important keys, missing: f11_placeholder, f12_placeholder
+2 warnings
# res/xml/latn_qwertz.xml
0 warnings
-Not a layout file: res/xml/method.xml
-Not a layout file: res/xml/number_row.xml
-# res/xml/numeric.xml
-Layout includes some ASCII punctuation but not all, missing: &, ?, @, `
-Layout redefines the bottom row but some important keys are missing, missing: change_method, config, switch_emoji, switch_numeric, switch_second
-Layout doesn't specify a script.
-3 warnings
-# res/xml/numpad.xml
-Layout includes some ASCII punctuation but not all, missing: !, ", #, $, %, &, ', (, ), ,, :, ;, <, >, ?, @, [, \, ], ^, _, `, {, |, }, ~
-Layout doesn't define some important keys, missing: backspace, delete
-Layout redefines the bottom row but some important keys are missing, missing: action, change_method, config, ctrl, down, enter, fn, left, right, space, switch_emoji, switch_numeric, switch_second, up
-Layout doesn't specify a script.
-4 warnings
-# res/xml/pin.xml
-Layout includes some ASCII punctuation but not all, missing: !, ", $, %, &, ', ;, <, =, >, ?, @, [, \, ], ^, _, `, {, |, }, ~
-Layout redefines the bottom row but some important keys are missing, missing: change_method, config, ctrl, fn, switch_emoji, switch_second
-Layout doesn't specify a script.
-3 warnings
-Not a layout file: res/xml/settings.xml
diff --git a/check_layout.py b/check_layout.py
index f0c1a3424..0741ffa0c 100644
--- a/check_layout.py
+++ b/check_layout.py
@@ -3,6 +3,11 @@
warning_count = 0
+KNOWN_NOT_LAYOUT = set([
+ "res/xml/number_row.xml", "res/xml/numpad.xml", "res/xml/pin.xml",
+ "res/xml/bottom_row.xml", "res/xml/settings.xml", "res/xml/method.xml",
+ "res/xml/greekmath.xml", "res/xml/numeric.xml" ])
+
def warn(msg):
global warning_count
print(msg)
@@ -31,27 +36,42 @@ def unexpected_keys(keys, symbols, msg):
def parse_layout(fname):
keys = set()
+ dup = set()
root = ET.parse(fname).getroot()
if root.tag != "keyboard":
return None
for row in root:
for key in row:
for attr in key.keys():
- keys.add(key.get(attr).removeprefix("\\"))
- return root, keys
+ if attr.startswith("key"):
+ k = key.get(attr).removeprefix("\\")
+ if k in keys: dup.add(k)
+ keys.add(k)
+ return root, keys, dup
def check_layout(layout):
- root, keys = layout
+ root, keys, dup = layout
+ if len(dup) > 0: warn("Duplicate keys: " + key_list_str(dup))
missing_some_of(keys, "~!@#$%^&*(){}`[]=\\-_;:/.,?<>'\"+|", "ASCII punctuation")
missing_some_of(keys, "0123456789", "digits")
- missing_some_of(keys, ["f11_placeholder", "f12_placeholder"])
- missing_some_of(keys, ["esc", "tab"])
- missing_required(keys, ["backspace", "delete"], "Layout doesn't define some important keys")
+ missing_required(keys,
+ ["esc", "tab", "backspace", "delete",
+ "f11_placeholder", "f12_placeholder"],
+ "Layout doesn't define some important keys")
+ unexpected_keys(keys,
+ ["copy", "paste", "cut", "selectAll", "shareText",
+ "pasteAsPlainText", "undo", "redo", "replaceText",
+ "textAssist", "autofill" ],
+ "Layout contains editing keys")
+ unexpected_keys(keys,
+ [ "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
+ "f10", "f11", "f12" ],
+ "Layout contains function keys")
bottom_row_keys = [
"ctrl", "fn", "switch_numeric", "change_method", "switch_emoji",
- "config", "switch_second", "enter", "action", "left", "up", "right",
- "down", "space"
+ "config", "switch_forward", "switch_backward", "enter", "action",
+ "left", "up", "right", "down", "space"
]
if root.get("bottom_row") == "false":
@@ -65,6 +85,8 @@ def check_layout(layout):
warn("Layout doesn't specify a script.")
for fname in sys.argv[1:]:
+ if fname in KNOWN_NOT_LAYOUT:
+ continue
layout = parse_layout(fname)
if layout == None:
print("Not a layout file: %s" % fname)
diff --git a/gen_layouts.py b/gen_layouts.py
index a8f13c86c..c2e6e8d87 100644
--- a/gen_layouts.py
+++ b/gen_layouts.py
@@ -54,10 +54,10 @@ def mk_array(tag, name, strings_items):
item.text = s
elem.append(item)
return elem
- none_item = [ ("none", "None") ]
+ system_item = [ ("system", "@string/pref_layout_e_system") ]
custom_item = [ ("custom", "@string/pref_layout_e_custom") ]
- values_items, entries_items = zip(*(none_item + layouts + custom_item)) # unzip
- ids_items = map(lambda s: "@xml/%s" % s if s not in ["none", "custom"] else "-1", values_items)
+ values_items, entries_items = zip(*(system_item + layouts + custom_item)) # unzip
+ ids_items = map(lambda s: "@xml/%s" % s if s not in ["system", "custom"] else "-1", values_items)
root = XML.Element("resources")
root.append(XML.Comment(text="DO NOT EDIT. This file is generated, see gen_layouts.py."))
root.append(mk_array("string-array", "pref_layout_values", values_items))
diff --git a/metadata/android/es-ES/full_description.txt b/metadata/android/es-ES/full_description.txt
new file mode 100644
index 000000000..f3eec1f30
--- /dev/null
+++ b/metadata/android/es-ES/full_description.txt
@@ -0,0 +1,6 @@
+La característica principal es que hay acceso a más caractéres deslizando hacia las esquinas de las teclas.
+
+Esta aplicación fue originalmente diseñada para programadores que usaran Termux.
+Ahora es perfecta para uso cotidiano.
+
+La misma no contiene ningún anuncio/publicidad, no realiza peticiones de red y es de Fuente Abierta.
diff --git a/metadata/android/es-ES/short_description.txt b/metadata/android/es-ES/short_description.txt
index 98969d19e..e9765d3ea 100644
--- a/metadata/android/es-ES/short_description.txt
+++ b/metadata/android/es-ES/short_description.txt
@@ -1 +1 @@
-Un teclado virtual ligero para desarrolladores.
+Un teclado virtual ligero para Android consciente de su privacidad.
diff --git a/res/layout/dialog_edit_text.xml b/res/layout/dialog_edit_text.xml
new file mode 100644
index 000000000..ad07947af
--- /dev/null
+++ b/res/layout/dialog_edit_text.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/res/layout/launcher_activity.xml b/res/layout/launcher_activity.xml
index dbd6b33dd..52064058f 100644
--- a/res/layout/launcher_activity.xml
+++ b/res/layout/launcher_activity.xml
@@ -2,7 +2,8 @@
-
+
+
diff --git a/res/layout/pref_layouts_add_btn.xml b/res/layout/pref_layouts_add_btn.xml
new file mode 100644
index 000000000..ab1b271c7
--- /dev/null
+++ b/res/layout/pref_layouts_add_btn.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/res/layout/pref_listgroup_add_btn.xml b/res/layout/pref_listgroup_add_btn.xml
new file mode 100644
index 000000000..bb555b51b
--- /dev/null
+++ b/res/layout/pref_listgroup_add_btn.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/res/layout/pref_listgroup_group.xml b/res/layout/pref_listgroup_group.xml
new file mode 100644
index 000000000..2b9db4bc5
--- /dev/null
+++ b/res/layout/pref_listgroup_group.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/res/layout/pref_listgroup_item_widget.xml b/res/layout/pref_listgroup_item_widget.xml
new file mode 100644
index 000000000..48e504eb9
--- /dev/null
+++ b/res/layout/pref_listgroup_item_widget.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 0cb90d1b0..2072e7a93 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -10,13 +10,12 @@
Upravit průhlednost pozadí klávesnice
Upravit průhlednost kláves
Upravit průhlednost stisknutých kláves
- Změnit rozvržení klávesnice
Dle nastavení systému
Vlastní rozvržení
- (Univerzální) Diakritická znaménka
- Zobrazovat znaménka pro všechny instalované systémové jazyky
- Zobrazovat znaménka pouze pro současně zvolený jazyk
- Skrýt (univerzální) diakritická znaménka
+ Přidat alternativní rozložení
+ Rozložení %1$d: %2$s
+
+ Vlastní rozvržení
Zobrazit NumPad
Nikdy
Pouze v režimu na šířku
@@ -24,9 +23,11 @@
Zobrazit řádek s čísly
Přidá řádek s čísly nad klávesnici, pokud je NumPad skrytý
Rozložení NumPadu
- Vyšší číslice jako první
- Nižší číslice jako první
+ Vyšší číslice jako první (horní řádek 789)
+ Nižší číslice jako první (horní řádek 123)
Přidat klávesy do klávesnice
+ Přidat vlastní klávesy
+ Výbrané klávesy k přidaní do klávesnice
Vedlejší rozvržení
Žádné
Psaní
@@ -43,6 +44,8 @@
Jak bude klávesa pro přepnutí klávesnice reagovat
Vibrace
Preference intenzity vibrací při stisku klávesy
+ Rozvržení zadávání PIN kódu
+ Při psaní čísel, datumů a telefonních čísel
Styl
Spodní odsazení
Výška klávesnice
@@ -64,9 +67,6 @@
Velmi dlouhá
Horizontální mezery mezi klávesami
Vertikální mezery mezi klávesami
- Pokročilé
- Vlastní rozvržení
- Více informací naleznete ve zdrojovém kódu. Tato možnost není určena pro běžné užití.
Deaktivovány
Dle systému
Silné
@@ -80,6 +80,25 @@
Odeslat
Aktivovat klávesnici
Tato aplikace je pouhou virtuální klávesnicí. Přejděte do systémového nastavení, kliknutím na tlačítko níže a aktivujte ji.
- Toto je volná, open-source aplikace. Její zdrojový kód, či hlášení chyb, naleznete na Githubu.
+ Toto je volná, open-source aplikace. Její zdrojový kód, či hlášení chyb, naleznete na Githubu.
Po aktivaci můžete klávesnici rovnou vyzkoušet zde:
+ Caps lock
+ Řecké a matematické symboly
+ Hlasové zadávání
+ Kopírovat
+ Vložit
+ Vyjmout
+ Označit vše
+ Sdílet text
+ Vložit jako prostý text
+ Zpět
+ Znovu
+ Nahradit
+ Asistovat
+ Předvyplnit
+ Indikátor řadové číslovky
+ Indikátor řadové číslovky
+ Horní index
+ Dolní index
+ Pokročilé
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 4cccd3a57..003f0472e 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -10,13 +10,12 @@
Deckkraft des Tastaturhintergrunds anpassen
Deckkraft der Tasten anpassen
Deckkraft gedrückter Tasten anpassen
- Tastaturlayout ändern
Systemeinstellung
Eigenes Layout
- Akzente
- Akzente für alle installierten Sprachen anzeigen
- Akzente nur für die gewählte Sprache anzeigen
- Akzente verbergen
+ Alternatives Layout hinzufügen
+ Layout %1$d: %2$s
+
+ Eigenes Layout
Ziffernblock anzeigen
Nie
Nur im Querformat
@@ -27,6 +26,8 @@
Hohe Ziffern zuerst
Niedrige Ziffern zuerst
Zusätzliche Zeichen zur Tastatur hinzufügen
+ Benutzerdefinierte Tasten hinzufügen
+ Tasten auswählen, die der Tastatur hinzugefügt werden sollen
Zweites Layout
Keines
Tippen
@@ -43,6 +44,8 @@
Verhalten der Tastaturumschalttaste
Vibration
Vibration bei Tastendruck ein-/ausschalten
+ PIN-Eingabe-Layout
+ Für die Nummern-, Datums- und Telefonnummern-Eingabe
Design
Unterer Abstand
Höhe der Tastatur
@@ -64,14 +67,11 @@
Sehr weit
Horizontaler Abstand zwischen den Tasten
Vertikaler Abstand zwischen den Tasten
- Erweitert
- Eigenes Layout
- Bitte Sourcecode ansehen. Diese Option ist nicht zur Verwendung vorgesehen.
-
-
-
-
-
+ Deaktiviert
+ System
+ Stark
+ Mittel
+ Schwach
Nächstes
Fertig
Los
@@ -80,6 +80,25 @@
Senden
Tastatur aktivieren
Diese App ist eine virtuelle Tastatur. Tippe auf den Button unten und aktivere Unexpected Keyboard in den Systemeinstellungen.
- Dies ist eine freie und quelloffene App. Du findest den Quellcode auf Github. Dort können auch Bugs gemeldet werden.
+ Dies ist eine freie und quelloffene App. Du findest den Quellcode auf Github. Dort können auch Bugs gemeldet werden.
Nach Aktivierung kannst du die Tastatur hier ausprobieren:
+ Feststelltaste
+ Griechische & mathematische Symbole
+ Spracheingabe
+ Kopieren
+ Einfügen
+ Ausschneiden
+ Alles auswählen
+ Text teilen
+ Unformatiert einfügen
+ Rückgängig
+ Wiederholen
+ Ersetzen
+ Assistieren
+ Automatische Vervollständigung
+ Ordinalzeichen
+ Ordinalzeichen
+ Hochgestellt
+ Tiefgestellt
+ Erweitert
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index b1908fd06..8f8703cd6 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -1,48 +1,51 @@
-
-
+ Unexpected Keyboard (debug)
+ Unexpected Keyboard
Ajustes de Unexpected Keyboard
-
-
+ En modo retrato
+ En modo paisaje
Formato
-
-
-
-
- Cambiar formato de teclado
+ Ajustar brillo de etiqueta
+ Ajustar opacidad del fondo del teclado
+ Ajustar opacidad de teclas
+ Ajustar opacidad de teclas apretadas
Ajustes del sistema
-
- Acentos
- Mostrar acentos para todos los lenguajes instalados
- Solo mostrar acentos para el lenguaje seleccionado
- Ocultar acentos
-
-
-
-
-
-
-
-
-
-
-
-
- Escribiendo
+ Formato personalizado
+
+
+
+ Formato personalizado
+ Mostrar pad numérico
+ Nunca
+ Solo en modo paisaje
+ Siempre
+ Mostrar fila númerica
+ Agrega una fila de numeros en la cima del teclado mientras el pad numérico esté oculto
+ Formato del pad numérico
+ Dígitos descendientes
+ Dígitos ascendientes
+ Agregar teclas
+ Agregar teclas personalizadas
+ Selecciona teclas para agregar al teclado
+ Formato secundario
+ Ninguno
+ Escritura
Distancia para deslizar
Distancia de caracteres en las esquinas de las letras (%s)
Tiempo de espera de repetición de tecla
Intervalo de repetición de tecla
-
-
-
-
-
-
-
+ Doble toque al Shift para bloquear las mayúsculas
+ Se puede bloquear cualquier modificador manteniéndolo apretado
+ Comportamiento
+ Capitalización automática
+ Apretar Shift al principio de una oración
+ Cambiar al último teclado usado
+ Comportamiento de la tecla para cambiar formatos
Vibración
Habilitar/deshabilitar vibración al presionar una tecla
+
+
Estilo
Margen del pie
Altura del teclado
@@ -54,32 +57,48 @@
Oscuro
Claro
Negro
-
-
-
- Muy corto
- Corto
+ Negro Alternativo
+ Blanco
+ ePaper
+ Muy corta
+ Corta
Normal
- Lejano
- Muy lejano
+ Lejana
+ Muy lejana
Espaciado horizontal entre las teclas
Espaciado vertical entre las teclas
-
-
-
-
-
-
-
-
+ Deshabilitada
+ Sistema
+ Fuerte
+ Media
+ Suave
Siguiente
Hecho
Ir
Anterior
Buscar
Enviar
-
-
-
-
+ Habilitar teclado
+ Esta aplicación es un teclado virtual. Apretar el botón de abajo te facilitará habilitarlo.
+ Esta es una aplicación gratuita, libre y de fuente abierta. EL código fuente se puede encontrar también para reportar errores en Github.
+ Tras habilitar, debajo se puede probar el teclado:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Avanzado
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 93d031011..7c58ca1f2 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -10,13 +10,12 @@
تنظیم کدر بودن پسزمینه صفحه کلید
تنظیم کدر بودن کلید
تنظیم کدر بودن کلید فشرده شده
- تغییر طرح صفحه کلید
تنظیمات سامانه
طرح صفارشی
- لهجهها
- نمایش لهجهها برای تمام زبانهی نصب شده
- فقط نمایش لهجهها برای زبانهای انتخاب شده
- پنهان کردن لهجهها
+
+
+
+ طرح شخصی
نمایش پد شمارهها
هرگز
فقط در حالت افقی
@@ -27,6 +26,8 @@
ابتدا اعداد بزرگ
ابتدا اعداد کوچک
افزودن کلیدها به صفحه کلید
+
+
طرح دوم
هیچ
درحال نوشتن
@@ -43,6 +44,8 @@
رفتار کلید تغییردهنده صفحه کلید
لرزش
فعال/غیرفعال کردن لرزش در زمان فشار دادن کلیدها
+
+
سبک
حاشیه پایین
ارتفاع صفحه کلید
@@ -64,9 +67,6 @@
بسیار دور
فاصله افقی بین کلیدها
فاصله عمودی بین کلیدها
- پیشرفته
- طرح شخصی
- کد منبع را ببینید. این گزینه قرار نیست استفاده شود.
@@ -80,6 +80,25 @@
ارسال
فعال کردن صفحه کلید
این برنامه یک صفحه کلید مجازی است. با کلیک روی گزینه زیر به تنظیمات سامانه بروید و صفحه کلید غیرمنتظره را فعال کنید.
- این یک برنامه آزاد و منبعباز است. شما میتوانید پیدا کنید کد منبع را و گزارش کنید باگها را در گیتهاب.
+ این یک برنامه متن باز و آزاد است. شما میتوانید کد منبع را در گیتهاب پیدا کرده و نیز باگها را گزارش کنید.
بعد از فعالسازی، صفحه کلید را اینجا امتحان کنید:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ پیشرفته
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 8985c19b3..429333565 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -10,13 +10,12 @@
Transparence du clavier
Transparence des touches
Transparence des touches pressées
- Disposition des touches
Paramètre système
Disposition personnalisée
- Accents
- Afficher les accents pour les langues installées
- Afficher les accents pour la langue sélectionnée
- Cacher les accents
+ Ajouter un clavier alternatif
+ Disposition %1$d: %2$s
+
+ Disposition personnalisée
Afficher le pavé numérique
Jamais
Seulement en mode paysage
@@ -27,6 +26,8 @@
Du plus haut au plus bas
Du plus bas au plus haut
Ajouter des touches au clavier
+ Ajouter des touches personnalisées
+ Sélectionner les touches à ajouter au clavier
Disposition secondaire
Aucune
Saisie
@@ -43,6 +44,8 @@
Comportement de la touche de changement de clavier
Vibreur
Vibration a chaque touche
+ Clavier PIN
+ Lors de la saisie de nombres, de dates et de numéros de téléphone
Style
Marge du bas
Hauteur du clavier
@@ -64,9 +67,6 @@
Très longue
Espacement horizontal entre les touches
Espacement vertical entre les touches
- Avancé
- Disposition personnalisée
- Cette option n\'est pas faite pour être utilisée.
Désactivé
Système
Fort
@@ -80,6 +80,25 @@
Envoyer
Activer le clavier
Cette application est un clavier virtuel. Activez-le dans les paramètres système en cliquant sur le bouton ci-dessous.
- Cette application est libre et open-source. Lisez le source code et reportez des problèmes sur Github.
+ Cette application est libre et open-source. Lisez le source code et reportez des problèmes sur Github.
Après l\'avoir activé, vous pouvez l\'essayer ici:
+ Verrouillage majuscules
+ Symboles mathématiques
+ Saisie vocale
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Avancé
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 893500c8b..1c7b96adf 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -10,13 +10,12 @@
- Cambia layout tastiera
Impostazioni di sistema
- Accenti
- Mostra accenti per tutte le lingue installate
- Mostra accenti solo per le lingue selezionate
- Nascondi accenti
+
+
+
+
@@ -27,6 +26,8 @@
+
+
Nessuno
Digitando
@@ -43,6 +44,8 @@
Vibrazione
Abilita/Disabilita Vibrazione alla pressione dei tasti
+
+
Stile
Margine inferiore
Altezza tastiera
@@ -64,9 +67,6 @@
Molto distante
Spazio orizzontale tra i tasti
Spazio verticale tra i tasti
-
-
-
@@ -80,6 +80,25 @@
Invia
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 7a9d001cb..e8e9f4a28 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -10,13 +10,12 @@
- 키보드 레이아웃 변경
시스템 세팅
- 악센트
- 설치된 모든 언어의 악센트 표시
- 선택한 언어의 악센트만 표시
- 모든 언어의 악센트 숨기기
+
+
+
+
@@ -27,6 +26,8 @@
+
+
타자
@@ -43,6 +44,8 @@
진동
키 누를 때 진동 키거/끄기
+
+
스타일
아래 넓이
키보드 높이
@@ -64,9 +67,6 @@
매우 넓음
키보드 양 옆 간격
키보드 세로 간격
-
-
-
@@ -80,6 +80,25 @@
보내기
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index aa8978865..b297df076 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -10,13 +10,12 @@
Pielāgot tastatūras fona necaurredzamību
Pielāgot taustiņu necaurredzamību
Pielāgot piespiesta taustiņa necaurredzamību
- Mainīt tastatūras izkārtojumu
Ierīces iestatījumi
Pielāgots izkārtojums
- Uzsvara zīmes
- Rādīt uzsvara zīmes visām uzstādītajām valodām
- Rādīt uzsvara zīmes tikai atlasītajām valodām
- Paslēpt uzsvara zīmes
+ Pievienot aizstājējizkārtojumu
+ Izkārtojums %1$d: %2$s
+
+ Pielāgots izkārtojums
Rādīt ciparnīcu
Nekad
Tikai guleniskajā skatā
@@ -27,6 +26,8 @@
Vispirms lielākie cipari
Vispirms mazākie cipari
Pievienot tastatūrai taustiņus
+ Pievienot pielāgotus taustiņus
+ Atlasīt taustiņus, ko pievienot tastatūrai
Otrējais izkārtojums
Neviens
Rakstīšana
@@ -43,6 +44,8 @@
Tastatūras pārslēgšanas taustiņa uzvedība
Trīcēšana
Iespējot/atspējot taustiņa piespiešanas trīcēšanu
+ Piespraust ievadīšanas izkārtojumu
+ Kad ievada skaitļus, datumus un tālruņa numurus
Izskata pielāgojumi
Apakšējā apmale
Tastatūras augstums
@@ -64,22 +67,40 @@
Ļoti tāls
Līmeniskais attālums starp taustiņiem
Stateniskais attālums starp taustiņiem
- Papildu
- Pielāgots izkārtojums
- Skatīt pirmkodu. Šī iespēja nav paredzēta izmantošanai.
-
-
-
-
-
+ Atspējota
+ Sistēmas
+ Spēcīga
+ Vidēja
+ Vāja
Nākamais
Darīts
Aiziet
Iepriekšējais
Meklēt
Sūtīt
-
-
-
-
+ Iespējot tastatūru
+ Šī lietotne ir virtuālā tastatūra.
+ Ar zemāk esošo pogu var atvērt sistēmas iestatījumus un iespējot Unexpected Keyboard.
+ Šī ir bezmaksas un atvērtā pirmkoda lietotne.
+ GitHub var atrast pirmkodu un ziņot par nepilnībām.
+ Pēc iespējošanas šeit var izmēģināt tastatūru:
+ Burtslēgs
+ Grieķu un matemātikas rakstzīmes
+ Rakstīšana ar balsi
+ Ievietot starpliktuvē
+ Ielīmēt
+ Izgriezt
+ Iezīmēt visu
+ Kopīgot tekstu
+ Ielīmēt kā vienkāršu tekstu
+ Atsaukt
+ Atatsaukt
+ Aizvietot
+ Palīgs
+ Automātiskā aizpilde
+ Kārtas rādītājs
+ Kārtas rādītājs
+ Augšraksts
+ Apakšraksts
+ Papildu
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 3309a7028..4aef205d6 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -10,13 +10,12 @@
Nieprzezroczystość tła klawiatury
Nieprzezroczystość klawisza
Nieprzezroczystość naciśniętego klawisza
- Zmień układ klawiatury
Systemowy
Własny układ
- Znaki diakrytyczne
- Pokaż znaki diakryt. dla wszystkich zainstalowanych języków
- Pokaż znaki diakryt. tylko dla wybranego języka
- Ukryj znaki diakrytyczne
+ Dodaj dodatkowy układ
+ Układ %1$d: %2$s
+
+ Własny układ
Pokaż klawiaturę numeryczną
Nigdy
Tylko w orientacji poziomej
@@ -27,6 +26,8 @@
Od największej cyfry
Od najmniejszej cyfry
Dodaj klawisze do klawiatury
+ Dodaj niestandardowe klawisze
+ Wybierz klawisze, które chcesz dodać do klawiatury
Drugi układ
Żaden
Pisanie
@@ -43,6 +44,8 @@
Działanie klawisza przełączającego klawiaturę
Wibracje
Wł./wył. wibrację przy naciśnięciu klawisza
+ Układ klawiatury PIN
+ Podczas wpisywania liczb, dat i numerów telefonu
Styl
Margines dolny
Wysokość klawiatury
@@ -64,9 +67,6 @@
Bardzo duża
Odległość pomiędzy klawiszami w poziomie
Odległość pomiędzy klawiszami w pionie
- Zaawansowane
- Własny układ
- Zobacz kod źródłowy. Ta opcja nie jest przeznaczona do użycia.
Wyłączone
Systemowe
Silne
@@ -80,6 +80,25 @@
Wyślij
Włącz klawiaturę
Ta aplikacja jest klawiaturą ekranową. Naciśnij poniższy przycisk, aby przejść do ustawień systemu i włącz Unexpected-Keyboard.
- Jest to darmowa aplikacja o otwartym kodzie źródłowym. Możesz zobaczyć kod źródłowy oraz zgłosić błedy na Githubie.
+ Jest to darmowa aplikacja o otwartym kodzie źródłowym. Możesz zobaczyć kod źródłowy oraz zgłosić błedy na Githubie.
Po jej włączeniu, możesz wypróbować klawiaturę tutaj:
+ Caps lock
+ Symbole greckie i matematyczne
+ Pisanie głosowe
+ Kopiuj
+ Wklej
+ Wytnij
+ Zaznacz wszystko
+ Udostępnij tekst
+ Wklej sam tekst
+ Cofnij
+ Ponów
+ Zamień
+ Asystent
+ Autouzupełnianie
+ Wskaźnik porządkowy (żeński)
+ Wskaźnik porządkowy (męski)
+ Indeks górny
+ Indeks dolny
+ Zaawansowane
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 8add41d4f..b5c2bbcc5 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -10,13 +10,12 @@
Ajustar opacidade do fundo do teclado
Ajustar opacidade das teclas
Ajustar opacidade das teclas pressionadas
- Mudar layout do teclado
Mesmo do sistema
Layout personalizado
- Acentos
- Mostrar acentos para todos os idiomas instalados
- Mostrar acentos só para o idioma selecionado
- Ocultar acentos
+ Adicione um layout alternativo
+ Layout %1$d: %2$s
+
+ Layout personalizado
Mostrar Teclado Numérico
Nunca
Somente no modo paisagem
@@ -27,6 +26,8 @@
Dígitos maiores primeiro
Dígitos menores primeiro
Adicionar teclas ao teclado
+ Adicionar teclas customizadas
+ Selecione teclas para serem adicionadas ao teclado
Layout secundário
Nenhum
Digitação
@@ -34,7 +35,7 @@
Distância até acionar os cantos das teclas (%s)
Tempo até repetir tecla
Intervalo de repetição de tecla
- Tecle duas vezes no shift para caixa alta
+ Tecle duas vezes no shift para travá-lo acionado
Ao invés de apertar e segurar por um tempo
Comportamento
Capitalização automática
@@ -43,6 +44,8 @@
Comportamento da tecla de troca de teclado
Vibração
Ativar/desativar vibração ao digitar
+ Layout PIN
+ Quando digitando números, datas ou números de telefone
Estilo
Margem inferior
Altura do teclado
@@ -64,14 +67,11 @@
Muito longo
Distância horizontal entre teclas
Distância vertical entre teclas
- Avançado
- Layout personalizado
- Veja o código-fonte. Esta opção não deve ser usada.
-
-
-
-
-
+ Desabilitado
+ Sistema
+ Intenso
+ Médio
+ Suave
Próximo
Pronto
Ir
@@ -80,6 +80,25 @@
Enviar
Ativar teclado
Este app é um teclado virtual. Vá para as configurações do sistema clicando no botão abaixo e ative o Teclado Unexpected.
- Este app é gratuito é de código aberto. Você pode consultar o código ou fazer sugestões em Github.
+ Este app é gratuito é de código aberto. Você pode consultar o código ou fazer sugestões em Github.
Após ativar, experimente aqui:
+ Caps lock
+ Grego & símbolos matemáticos
+ Digitação por voz
+ Copiar
+ Colar
+ Cortar
+ Selecionar tudo
+ Compartilhar texto
+ Colar texto não formatado
+ Desfazer
+ Refazer
+ Substituir
+ Assistente
+ Autopreenchimento
+ Indicador Ordinal
+ Indicador Ordinal
+ Sobrescrito
+ Subscrito
+ Avançado
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index be6857345..1de85fb56 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -10,13 +10,12 @@
Modifică opacitatea fundalului tastaturii
Modifică opacitatea tastelor
Modifică opacitatea tastei apăsate
- Schimbă aranjamentul tastaturii
Setări de Sistem
Aranjament personalizat
- Accente
- Arată accentele pentru toate limbile instalate
- Aratp accentele doar pentru limba selectată
- Ascunde accentele
+
+
+
+ Aranjament personalizat
Arată NumPad
Niciodată
Doar în mod panoramă
@@ -27,6 +26,8 @@
Mai întâi cifrele mari
Mai întâi cifrele mici
Adaugă taste pe tastatură
+
+
Aranjament secundar
Nimic
Tipărire
@@ -43,6 +44,8 @@
Comportamentul tastei pentru schimbarea tastaturii
Vibrație
Activați/dezactivați vibrația la apăsarea tastelor
+
+
Stil
Marginea de jos
Înălțimea tastaturii
@@ -64,9 +67,6 @@
Foarte depărtată
Distanța orizontală dintre taste
Distanța verticală dintre taste
- Setări avansate
- Aranjament personalizat
- Deschide codul sursă. Această opțiune nu e destinată spre folosință.
@@ -80,6 +80,25 @@
Trimite
Activează tastatura
Această aplicație este o tastatură virtuală. Accesați setările sistemului făcând clic pe butonul de mai jos și activați tastatura Unexpected.
- Aceasta este o aplicație gratuită și open source. Puteți găsi codul sursă sau raporta erori folosind link-ul Github.
+ Aceasta este o aplicație gratuită și open source. Puteți găsi codul sursă sau raporta erori folosind link-ul Github.
După activare, puteți să încercați tastatura aici:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Setări avansate
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 66e17d3fd..c3490f452 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -10,13 +10,12 @@
Изменить прозрачность фона
Изменить прозрачность клавиш
Изменить прозрачность нажатой клавиши
- Изменить раскладку клавиатуры
Системные настройки
Пользовательская раскладка
- Акцент
- Показывать акценты для всех установленных языков
- Показывать акценты только для выбранного языка
- Скрыть акценты
+
+
+
+ Пользовательская раскладка
Показывать NumPad
Никогда
Только в ландшафтном режиме
@@ -27,6 +26,8 @@
Старшие цифры сверху
Младшие цифры сверху
Добавить клавиши на клавиатуру
+
+
Дополнительная раскладка
Нет
Печать
@@ -43,6 +44,8 @@
Поведение клавиши переключения клавиатуры
Вибрация
Включение/выключение вибрации при нажатии клавиши
+
+
Стиль
Нижняя граница поля
Высота клавиатуры
@@ -64,9 +67,6 @@
Очень далеко
Горизонтальное расстояние между клавишами
Расстояние по вертикали между клавишами
- Расширенные настройки
- Пользовательская раскладка
- Откройте исходный код. Эта параметр не предназначен для использования.
@@ -80,6 +80,25 @@
Отправить
Включить клавиатуру
Данное приложение является виртуальной клавиатурой. Зайдите в настройки, нажав кнопку внизу и активируйте Unexpected-Keyboard.
- Это бесплатное приложение с открытым исходным кодом. Вы можете изучить код или сообщить об ошибках по ссылке Github.
+ Это бесплатное приложение с открытым исходным кодом. Вы можете изучить код или сообщить об ошибках по ссылке Github.
После активации вы можете попробовать клавиатуру прямо здесь:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Расширенные настройки
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 236f3685c..cf6133c2f 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -10,13 +10,12 @@
- Klavye Düzenini Değiştir
Sistem Ayarları
- Aksanlar
- Yüklü tüm dillerin aksanlarını göster
- Sadece seçili dilin aksanlarını göster
- Aksanları gizle
+
+
+
+
@@ -27,6 +26,8 @@
+
+
Hiçbiri
Yazma
@@ -43,6 +44,8 @@
Titreşim
Tuşa basıldığında titreşimi etkinleştir
+
+
Stil
Alt boşluk
Klavye yüksekliği
@@ -64,9 +67,6 @@
Çok uzun
Tuşlar arasındaki yatay boşluk
Tuşlar arasındaki dikey boşluk
-
-
-
@@ -80,6 +80,25 @@
Gönder
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index be2d51573..1580bf3d6 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -10,15 +10,12 @@
Tùy chỉnh độ trong suốt của bàn phím
Tùy chỉnh độ trong suốt của phím
Tùy chỉnh độ trong suốt của phím khi nhấn
- Thay đổi bố cục bàn phím
Hệ thống
Tùy chỉnh bố cục
- Dấu phụ
- Hiển thị cho các ngôn ngữ đã cài đặt
- Chỉ hiển thị cho các ngôn ngữ đã chọn
-
- Ẩn dấu phụ
-
+
+
+
+ Tùy chỉnh bố cục
Hiện NumPad
Không bao giờ
Chỉ trong chế độ phong cảnh
@@ -29,6 +26,8 @@
Số lớn nhất trước
Số nhỏ nhất trước
Thêm phím vào bàn phím
+
+
Bố cục phụ
Không
Gõ
@@ -45,6 +44,8 @@
Sự rung
Bật/tắt rung khi nhấn
+
+
Kiểu cách
Căn lề dưới
Chiều cao bàn phím
@@ -66,9 +67,6 @@
Rất xa
Khoảng cách giữa các phím theo chiều ngang
Khoảng cách giữa các phím theo chiều dọc
- Nâng cao
- Tùy chỉnh bố cục
- Hãy xem mã nguồn. Lựa chọn này không có mục đích sử dụng.
@@ -82,6 +80,25 @@
Gửi
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Nâng cao
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index c42a2375d..3a8f6af8f 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -10,13 +10,12 @@
调整键盘背景透明度
调整按键透明度
调整按下的按键的透明度
- 改变键盘布局
系统设置
自定义布局
- 声调
- 显示所有安装的语言的声调符号
- 只显示选择的语言的声调符号
- 隐藏声调符号
+
+
+
+ 自定义布局
显示数字小键盘
从不
只在横屏显示
@@ -27,6 +26,8 @@
大数字在上方
小数字在上方
选择要显示的按键
+
+
第二键盘布局
无
输入
@@ -43,6 +44,8 @@
切换键盘按钮的行为
振动
启用或者禁用按下按键时振动
+
+
样式
键盘下边距
键盘高度
@@ -64,9 +67,6 @@
非常长
按键的左右边距
按键的上下边距
- 高级设置
- 自定义布局
- 请查看源代码。这个选项不应该在正常情况下使用。
禁用
使用系统振动强度
强
@@ -80,6 +80,25 @@
发送
启用键盘
这是一个虚拟键盘软件。点击按钮进入系统设置,然后启用 Unexpected-Keyboard 即可使用。
- 这是一个免费且开源的软件。你可以在 Github 上找到源代码或者反馈 bug。
+ 这是一个免费且开源的软件。你可以在 Github 上找到源代码或者反馈 bug。
启用键盘后,可以在这里测试效果:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 高级设置
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 14a536d5a..2bbb9b611 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1,10 +1,5 @@
-
- - @string/pref_accents_e_all_installed
- - @string/pref_accents_e_selected
- - @string/pref_accents_e_none
-
- never
- landscape
@@ -23,11 +18,6 @@
- @string/pref_numpad_layout_e_high_first
- @string/pref_numpad_layout_e_low_first
-
- - 1
- - 2
- - 4
-
- @string/pref_theme_e_system
- @string/pref_theme_e_dark
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 693ef89d7..b012a7cc0 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -3,7 +3,4 @@
-
-
-
diff --git a/res/values/layouts.xml b/res/values/layouts.xml
index afaf0c3d7..73ae0d088 100644
--- a/res/values/layouts.xml
+++ b/res/values/layouts.xml
@@ -2,7 +2,7 @@
- - none
+ - system
- latn_qwerty_us
- latn_colemak
- latn_dvorak
@@ -44,13 +44,13 @@
- custom
- - None
+ - @string/pref_layout_e_system
- QWERTY (US)
- Colemak
- Dvorak
- Arabic Alt
- Arabic PC
- - Arabic (کوردی)
+ - Kurdish (کوردی)
- Persian PC
- বাংলা (জাতীয়)
- বাংলা (প্রভাত)
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 94eb47dfa..dbf258138 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -10,13 +10,12 @@
Adjust keyboard background opacity
Adjust key opacity
Adjust pressed key opacity
- Change keyboard layout
System settings
Custom layout
- Accents
- Show accents for all installed languages
- Only show accents for the selected language
- Hide accents
+ Add an alternate layout
+ Layout %1$d: %2$s
+ Remove layout
+ Custom layout
Show NumPad
Never
Only in landscape mode
@@ -27,6 +26,8 @@
High digits first
Low digits first
Add keys to the keyboard
+ Add custom keys
+ Select keys to add to the keyboard
Secondary layout
None
Typing
@@ -43,6 +44,8 @@
Behavior of the keyboard-switching key
Vibration
Enable/disable vibration on keypress
+ Pin entry layout
+ When typing numbers, dates and phone numbers
Style
Margin bottom
Keyboard height
@@ -64,9 +67,6 @@
Very far
Horizontal spacing between the keys
Vertical spacing between the keys
- Advanced
- Custom layout
- See the source code. This option is not meant to be used.
Disabled
System
Strong
@@ -80,6 +80,26 @@
Send
Enable keyboard
This application is a virtual keyboard. Go to the system settings by clicking on the button below and enable Unexpected-Keyboard.
- This is an free and open source application. You can find the source code or report bugs on Github.
+ This is an free and open source application. You can find the source code or report bugs on Github.
After enabling, you can try the keyboard here:
+ Caps lock
+ Greek & math symbols
+ Voice typing
+ Copy
+ Paste
+ Cut
+ Select all
+ Share text
+ Paste as plain text
+ Undo
+ Redo
+ Replace
+ Assist
+ Autofill
+ Ordinal Indicator
+ Ordinal Indicator
+ Superscript
+ Subscript
+
+ Advanced
diff --git a/res/values/values.xml b/res/values/values.xml
index c15118e5d..737e7db89 100644
--- a/res/values/values.xml
+++ b/res/values/values.xml
@@ -5,6 +5,7 @@
56dp
250dp
28dp
+ 28dp
true
false
diff --git a/res/xml/arab_pc.xml b/res/xml/arab_pc.xml
index 9fb9dad50..66a8fbd77 100644
--- a/res/xml/arab_pc.xml
+++ b/res/xml/arab_pc.xml
@@ -11,8 +11,8 @@
-
-
+
+
diff --git a/res/xml/arab_pc_ckb.xml b/res/xml/arab_pc_ckb.xml
index 53f09d94b..363e25fbe 100644
--- a/res/xml/arab_pc_ckb.xml
+++ b/res/xml/arab_pc_ckb.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/res/xml/arab_pc_ir.xml b/res/xml/arab_pc_ir.xml
index f28512391..35044aede 100644
--- a/res/xml/arab_pc_ir.xml
+++ b/res/xml/arab_pc_ir.xml
@@ -1,26 +1,25 @@
-
-
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
@@ -28,15 +27,15 @@
-
+
-
-
-
+
+
+
diff --git a/res/xml/bottom_row.xml b/res/xml/bottom_row.xml
index 56493dc34..ea7b8144c 100644
--- a/res/xml/bottom_row.xml
+++ b/res/xml/bottom_row.xml
@@ -2,7 +2,7 @@
-
-
-
+
+
+
diff --git a/res/xml/latn_azerty_fr.xml b/res/xml/latn_azerty_fr.xml
index e3cc1309a..cf8b185e6 100644
--- a/res/xml/latn_azerty_fr.xml
+++ b/res/xml/latn_azerty_fr.xml
@@ -29,7 +29,7 @@
-
+
diff --git a/res/xml/latn_bone.xml b/res/xml/latn_bone.xml
index ea3113113..9078f79a0 100644
--- a/res/xml/latn_bone.xml
+++ b/res/xml/latn_bone.xml
@@ -39,7 +39,7 @@
-
+
diff --git a/res/xml/latn_neo2.xml b/res/xml/latn_neo2.xml
index 939e1310f..f8904f1f7 100644
--- a/res/xml/latn_neo2.xml
+++ b/res/xml/latn_neo2.xml
@@ -42,7 +42,7 @@
-
+
diff --git a/res/xml/latn_qwerty_br.xml b/res/xml/latn_qwerty_br.xml
index d76c6e495..e4829aee3 100644
--- a/res/xml/latn_qwerty_br.xml
+++ b/res/xml/latn_qwerty_br.xml
@@ -15,7 +15,7 @@
-
+
@@ -28,7 +28,7 @@
-
+
diff --git a/res/xml/latn_qwerty_es.xml b/res/xml/latn_qwerty_es.xml
index 5f1fc24aa..cb3c2cc59 100644
--- a/res/xml/latn_qwerty_es.xml
+++ b/res/xml/latn_qwerty_es.xml
@@ -14,7 +14,7 @@
-
+
@@ -27,7 +27,7 @@
-
+
diff --git a/res/xml/latn_qwerty_hu.xml b/res/xml/latn_qwerty_hu.xml
index aee223c1a..1caf242a6 100644
--- a/res/xml/latn_qwerty_hu.xml
+++ b/res/xml/latn_qwerty_hu.xml
@@ -26,7 +26,7 @@
-
+
diff --git a/res/xml/latn_qwerty_lv.xml b/res/xml/latn_qwerty_lv.xml
index 1e82d8ed4..a373eb8d6 100644
--- a/res/xml/latn_qwerty_lv.xml
+++ b/res/xml/latn_qwerty_lv.xml
@@ -14,7 +14,7 @@
-
+
@@ -26,7 +26,7 @@
-
+
diff --git a/res/xml/latn_qwerty_no.xml b/res/xml/latn_qwerty_no.xml
index 9f38f0603..b86ea340b 100644
--- a/res/xml/latn_qwerty_no.xml
+++ b/res/xml/latn_qwerty_no.xml
@@ -14,7 +14,7 @@
-
+
@@ -26,7 +26,7 @@
-
+
diff --git a/res/xml/latn_qwerty_pl.xml b/res/xml/latn_qwerty_pl.xml
index c31ae76ff..9a5a3edf9 100644
--- a/res/xml/latn_qwerty_pl.xml
+++ b/res/xml/latn_qwerty_pl.xml
@@ -14,7 +14,7 @@
-
+
@@ -26,7 +26,7 @@
-
+
diff --git a/res/xml/latn_qwerty_ro.xml b/res/xml/latn_qwerty_ro.xml
index 1282d3679..fdc42326c 100644
--- a/res/xml/latn_qwerty_ro.xml
+++ b/res/xml/latn_qwerty_ro.xml
@@ -14,7 +14,7 @@
-
+
@@ -26,7 +26,7 @@
-
+
diff --git a/res/xml/latn_qwerty_se.xml b/res/xml/latn_qwerty_se.xml
index aab6bc669..bf3bb7d04 100644
--- a/res/xml/latn_qwerty_se.xml
+++ b/res/xml/latn_qwerty_se.xml
@@ -15,7 +15,7 @@
-
+
@@ -29,7 +29,7 @@
-
+
diff --git a/res/xml/latn_qwerty_tr.xml b/res/xml/latn_qwerty_tr.xml
index 2093db715..229a6d860 100644
--- a/res/xml/latn_qwerty_tr.xml
+++ b/res/xml/latn_qwerty_tr.xml
@@ -14,7 +14,7 @@
-
+
@@ -26,7 +26,7 @@
-
+
diff --git a/res/xml/latn_qwerty_us.xml b/res/xml/latn_qwerty_us.xml
index 916528329..0d394acef 100644
--- a/res/xml/latn_qwerty_us.xml
+++ b/res/xml/latn_qwerty_us.xml
@@ -35,7 +35,7 @@ See srcs/juloo.keyboard2/KeyValue.java for the keys that have a special meaning.
-
+
@@ -47,7 +47,7 @@ See srcs/juloo.keyboard2/KeyValue.java for the keys that have a special meaning.
-
+
diff --git a/res/xml/latn_qwerty_vi.xml b/res/xml/latn_qwerty_vi.xml
index 6af7bc7c5..fb7c19eab 100644
--- a/res/xml/latn_qwerty_vi.xml
+++ b/res/xml/latn_qwerty_vi.xml
@@ -15,7 +15,7 @@
-
+
@@ -27,7 +27,7 @@
-
+
diff --git a/res/xml/latn_qwertz.xml b/res/xml/latn_qwertz.xml
index 6ba19c65e..34929f502 100644
--- a/res/xml/latn_qwertz.xml
+++ b/res/xml/latn_qwertz.xml
@@ -26,7 +26,7 @@
-
+
diff --git a/res/xml/latn_qwertz_cz.xml b/res/xml/latn_qwertz_cz.xml
index 75f8a88e2..e3bbae942 100644
--- a/res/xml/latn_qwertz_cz.xml
+++ b/res/xml/latn_qwertz_cz.xml
@@ -14,7 +14,7 @@
-
+
@@ -26,7 +26,7 @@
-
+
diff --git a/res/xml/latn_qwertz_cz_multifunctional.xml b/res/xml/latn_qwertz_cz_multifunctional.xml
index 993941aab..9fc8dabc4 100644
--- a/res/xml/latn_qwertz_cz_multifunctional.xml
+++ b/res/xml/latn_qwertz_cz_multifunctional.xml
@@ -26,7 +26,7 @@
-
+
diff --git a/res/xml/latn_qwertz_de.xml b/res/xml/latn_qwertz_de.xml
index ff1ec11b7..122375bcf 100644
--- a/res/xml/latn_qwertz_de.xml
+++ b/res/xml/latn_qwertz_de.xml
@@ -30,7 +30,7 @@
-
+
diff --git a/res/xml/latn_qwertz_hu.xml b/res/xml/latn_qwertz_hu.xml
index a77aa1c33..61ebf24fb 100644
--- a/res/xml/latn_qwertz_hu.xml
+++ b/res/xml/latn_qwertz_hu.xml
@@ -26,7 +26,7 @@
-
+
diff --git a/res/xml/latn_qwertz_sk.xml b/res/xml/latn_qwertz_sk.xml
index f71a8256e..bb8f55314 100644
--- a/res/xml/latn_qwertz_sk.xml
+++ b/res/xml/latn_qwertz_sk.xml
@@ -14,7 +14,7 @@
-
+
@@ -27,7 +27,7 @@
-
+
diff --git a/res/xml/method.xml b/res/xml/method.xml
index f2fb92997..f60237721 100644
--- a/res/xml/method.xml
+++ b/res/xml/method.xml
@@ -4,33 +4,34 @@
-
-
+
+
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
+
-
-
-
-
+
+
+
+
diff --git a/res/xml/pin.xml b/res/xml/pin.xml
index 8456a727e..d3f684660 100644
--- a/res/xml/pin.xml
+++ b/res/xml/pin.xml
@@ -10,7 +10,7 @@
-
+
diff --git a/res/xml/settings.xml b/res/xml/settings.xml
index 322bf4d23..f6467d681 100644
--- a/res/xml/settings.xml
+++ b/res/xml/settings.xml
@@ -1,49 +1,15 @@
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
@@ -56,6 +22,7 @@
+
@@ -79,7 +46,4 @@
-
-
-
diff --git a/srcs/juloo.keyboard2/Config.java b/srcs/juloo.keyboard2/Config.java
index 2c48b3f66..fdc773026 100644
--- a/srcs/juloo.keyboard2/Config.java
+++ b/srcs/juloo.keyboard2/Config.java
@@ -3,11 +3,11 @@
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.os.Build;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.KeyEvent;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -25,9 +25,8 @@ final class Config
public final float sublabelTextSize;
// From preferences
- public KeyboardData layout; // Or 'null' for the system defaults
- public KeyboardData second_layout; // Or 'null' for none
- public KeyboardData custom_layout; // Might be 'null'
+ /** [null] represent the [system] layout. */
+ public List layouts;
public boolean show_numpad = false;
// From the 'numpad_layout' option, also apply to the numeric pane.
public boolean inverse_numpad = false;
@@ -48,20 +47,20 @@ final class Config
public int keyActivatedOpacity; // 0 - 255
public boolean double_tap_lock_shift;
public float characterSize; // Ratio
- public int accents; // Values are R.values.pref_accents_v_*
public int theme; // Values are R.style.*
public boolean autocapitalisation;
public boolean switch_input_immediate;
+ public boolean pin_entry_enabled;
// Dynamically set
public boolean shouldOfferSwitchingToNextInputMethod;
- public boolean shouldOfferSwitchingToSecond;
public boolean shouldOfferVoiceTyping;
public String actionLabel; // Might be 'null'
public int actionId; // Meaningful only when 'actionLabel' isn't 'null'
public boolean swapEnterActionKey; // Swap the "enter" and "action" keys
public ExtraKeys extra_keys_subtype;
public Set extra_keys_param;
+ public List extra_keys_custom;
public final IKeyEventHandler handler;
public boolean orientation_landscape = false;
@@ -78,7 +77,6 @@ private Config(SharedPreferences prefs, Resources res, IKeyEventHandler h)
refresh(res);
// initialized later
shouldOfferSwitchingToNextInputMethod = false;
- shouldOfferSwitchingToSecond = false;
shouldOfferVoiceTyping = false;
actionLabel = null;
actionId = 0;
@@ -114,9 +112,7 @@ public void refresh(Resources res)
{
keyboardHeightPercent = _prefs.getInt("keyboard_height", 35);
}
- layout = layout_of_string(res, _prefs.getString("layout", "none"));
- second_layout = tweak_secondary_layout(layout_of_string(res, _prefs.getString("second_layout", "none")));
- custom_layout = KeyboardData.load_string(_prefs.getString("custom_layout", ""));
+ layouts = LayoutsPreference.load_from_preferences(res, _prefs);
inverse_numpad = _prefs.getString("numpad_layout", "default").equals("low_first");
number_row = _prefs.getBoolean("number_row", false);
// The baseline for the swipe distance correspond to approximately the
@@ -150,11 +146,12 @@ public void refresh(Resources res)
characterSize =
_prefs.getFloat("character_size", 1.f)
* characterSizeScale;
- accents = Integer.valueOf(_prefs.getString("accents", "1"));
theme = getThemeId(res, _prefs.getString("theme", ""));
autocapitalisation = _prefs.getBoolean("autocapitalisation", true);
switch_input_immediate = _prefs.getBoolean("switch_input_immediate", false);
- extra_keys_param = ExtraKeyCheckBoxPreference.get_extra_keys(_prefs);
+ extra_keys_param = ExtraKeysPreference.get_extra_keys(_prefs);
+ extra_keys_custom = CustomExtraKeysPreference.get(_prefs);
+ pin_entry_enabled = _prefs.getBoolean("pin_entry_enabled", true);
}
KeyValue action_key()
@@ -170,6 +167,7 @@ KeyValue action_key()
* - Replace the action key to show the right label
* - Swap the enter and action keys
* - Add the optional numpad and number row
+ * - Add the extra keys
*/
public KeyboardData modify_layout(KeyboardData kw)
{
@@ -178,9 +176,17 @@ public KeyboardData modify_layout(KeyboardData kw)
// first iteration then automatically added.
final Set extra_keys = new HashSet();
final Set remove_keys = new HashSet();
- if (extra_keys_subtype != null)
- extra_keys_subtype.compute(extra_keys, kw.script);
extra_keys.addAll(extra_keys_param);
+ extra_keys.addAll(extra_keys_custom);
+ if (extra_keys_subtype != null)
+ {
+ Set present = new HashSet();
+ kw.getKeys(present);
+ present.addAll(extra_keys_param);
+ present.addAll(extra_keys_custom);
+ extra_keys_subtype.compute(extra_keys,
+ new ExtraKeys.Query(kw.script, present));
+ }
boolean number_row = this.number_row && !show_numpad;
if (number_row)
KeyboardData.number_row.getKeys(remove_keys);
@@ -208,8 +214,10 @@ public KeyValue apply(KeyValue key, boolean localized)
case ACTION:
return (swapEnterActionKey && action_key != null) ?
KeyValue.getKeyByName("enter") : action_key;
- case SWITCH_SECOND:
- return shouldOfferSwitchingToSecond ? key : null;
+ case SWITCH_FORWARD:
+ return (layouts.size() > 1) ? key : null;
+ case SWITCH_BACKWARD:
+ return (layouts.size() > 2) ? key : null;
case SWITCH_VOICE_TYPING:
return shouldOfferVoiceTyping ? key : null;
}
@@ -281,23 +289,6 @@ public KeyValue apply(KeyValue key, boolean localized)
});
}
- /** Modify a layout to turn it into a secondary layout by changing the
- "switch_second" key. */
- KeyboardData tweak_secondary_layout(KeyboardData layout)
- {
- if (layout == null)
- return null;
- return layout.mapKeys(new KeyboardData.MapKeyValues() {
- public KeyValue apply(KeyValue key, boolean localized)
- {
- if (key.getKind() == KeyValue.Kind.Event
- && key.getEvent() == KeyValue.Event.SWITCH_SECOND)
- return KeyValue.getKeyByName("switch_second_back");
- return key;
- }
- });
- }
-
private float get_dip_pref(DisplayMetrics dm, String pref_name, float def)
{
float value;
@@ -338,36 +329,6 @@ private int getThemeId(Resources res, String theme_name)
}
}
- /** Obtained from XML. */
- static List layout_ids_str = null;
- static TypedArray layout_ids_res = null;
-
- /** Might return [null] if the selected layout is "system", "custom" or if
- the name is not recognized. */
- public KeyboardData layout_of_string(Resources res, String name)
- {
- if (layout_ids_str == null)
- {
- layout_ids_str = Arrays.asList(res.getStringArray(R.array.pref_layout_values));
- layout_ids_res = res.obtainTypedArray(R.array.layout_ids);
- }
- int i = layout_ids_str.indexOf(name);
- if (i >= 0)
- {
- int id = layout_ids_res.getResourceId(i, 0);
- if (id > 0)
- return KeyboardData.load(res, id);
- // Fallthrough
- }
- switch (name)
- {
- case "custom": return custom_layout;
- case "system":
- case "none":
- default: return null;
- }
- }
-
char inverse_numpad_char(char c)
{
switch (c)
@@ -387,6 +348,7 @@ char inverse_numpad_char(char c)
public static void initGlobalConfig(SharedPreferences prefs, Resources res,
IKeyEventHandler handler)
{
+ migrate(prefs);
_globalConfig = new Config(prefs, res, handler);
}
@@ -399,4 +361,45 @@ public static interface IKeyEventHandler
{
public void key_up(KeyValue value, Pointers.Modifiers flags);
}
+
+ /** Config migrations. */
+
+ private static int CONFIG_VERSION = 1;
+
+ public static void migrate(SharedPreferences prefs)
+ {
+ int saved_version = prefs.getInt("version", 0);
+ Logs.debug_config_migration(saved_version, CONFIG_VERSION);
+ if (saved_version == CONFIG_VERSION)
+ return;
+ SharedPreferences.Editor e = prefs.edit();
+ e.putInt("version", CONFIG_VERSION);
+ // Migrations might run on an empty [prefs] for new installs, in this case
+ // they set the default values of complex options.
+ switch (saved_version) // Fallback switch
+ {
+ case 0:
+ // Primary, secondary and custom layout options are merged into the new
+ // Layouts option. This also sets the default value.
+ List l = new ArrayList();
+ l.add(migrate_layout(prefs.getString("layout", "system")));
+ String snd_layout = prefs.getString("second_layout", "none");
+ if (snd_layout != null && !snd_layout.equals("none"))
+ l.add(migrate_layout(snd_layout));
+ String custom_layout = prefs.getString("custom_layout", "");
+ if (custom_layout != null && !custom_layout.equals(""))
+ l.add(new LayoutsPreference.CustomLayout(custom_layout));
+ LayoutsPreference.save_to_preferences(e, l);
+ case 1:
+ default: break;
+ }
+ e.commit();
+ }
+
+ private static LayoutsPreference.Layout migrate_layout(String name)
+ {
+ if (name == null || name.equals("system"))
+ return new LayoutsPreference.SystemLayout();
+ return new LayoutsPreference.NamedLayout(name);
+ }
}
diff --git a/srcs/juloo.keyboard2/CustomExtraKeysPreference.java b/srcs/juloo.keyboard2/CustomExtraKeysPreference.java
new file mode 100644
index 000000000..b17ff8d98
--- /dev/null
+++ b/srcs/juloo.keyboard2/CustomExtraKeysPreference.java
@@ -0,0 +1,67 @@
+package juloo.keyboard2;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.preference.Preference;
+import android.preference.PreferenceCategory;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import java.util.ArrayList;
+import java.util.List;
+import org.json.JSONArray;
+import org.json.JSONException;
+
+/** Allows to enter custom keys to be added to the keyboard. This shows up at
+ the top of the "Add keys to the keyboard" option. */
+public class CustomExtraKeysPreference extends ListGroupPreference
+{
+ /** This pref stores a list of strings encoded as JSON. */
+ static final String KEY = "custom_extra_keys";
+ static final ListGroupPreference.Serializer SERIALIZER =
+ new ListGroupPreference.StringSerializer();
+
+ public CustomExtraKeysPreference(Context context, AttributeSet attrs)
+ {
+ super(context, attrs);
+ setKey(KEY);
+ }
+
+ public static List get(SharedPreferences prefs)
+ {
+ List kvs = new ArrayList();
+ List key_names = load_from_preferences(KEY, prefs, null, SERIALIZER);
+ if (key_names != null)
+ {
+ for (String key_name : key_names)
+ kvs.add(KeyValue.makeStringKey(key_name));
+ }
+ return kvs;
+ }
+
+ String label_of_value(String value, int i) { return value; }
+
+ @Override
+ void select(final SelectionCallback callback)
+ {
+ new AlertDialog.Builder(getContext())
+ .setView(R.layout.dialog_edit_text)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){
+ public void onClick(DialogInterface dialog, int which)
+ {
+ EditText input = (EditText)((AlertDialog)dialog).findViewById(R.id.text);
+ final String k = input.getText().toString();
+ if (!k.equals(""))
+ callback.select(k);
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null)
+ .show();
+ }
+
+ @Override
+ Serializer get_serializer() { return SERIALIZER; }
+}
diff --git a/srcs/juloo.keyboard2/ExtraKeyCheckBoxPreference.java b/srcs/juloo.keyboard2/ExtraKeyCheckBoxPreference.java
deleted file mode 100644
index 8f7471a8d..000000000
--- a/srcs/juloo.keyboard2/ExtraKeyCheckBoxPreference.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package juloo.keyboard2;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.content.SharedPreferences;
-import android.preference.CheckBoxPreference;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.TextView;
-import java.util.HashSet;
-import java.util.Set;
-
-public class ExtraKeyCheckBoxPreference extends CheckBoxPreference
-{
- public static String[] extra_keys = new String[]
- {
- "alt",
- "meta",
- "voice_typing",
- "accent_aigu",
- "accent_grave",
- "accent_double_aigu",
- "accent_dot_above",
- "accent_circonflexe",
- "accent_tilde",
- "accent_cedille",
- "accent_trema",
- "accent_ring",
- "accent_caron",
- "accent_macron",
- "accent_ogonek",
- "accent_breve",
- "accent_slash",
- "accent_bar",
- "accent_dot_below",
- "accent_hook_above",
- "accent_horn",
- "€",
- "ß",
- "£",
- "switch_greekmath",
- "capslock",
- "copy",
- "paste",
- "cut",
- "selectAll",
- "shareText",
- "pasteAsPlainText",
- "undo",
- "redo",
- "replaceText",
- "textAssist",
- "autofill",
- };
-
- public static boolean default_checked(String name)
- {
- switch (name)
- {
- case "voice_typing":
- return true;
- default:
- return false;
- }
- }
-
- boolean _key_font;
-
- public ExtraKeyCheckBoxPreference(Context context, AttributeSet attrs)
- {
- super(context, attrs);
- final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ExtraKeyCheckBoxPreference);
- int index = a.getInteger(R.styleable.ExtraKeyCheckBoxPreference_index, 0);
- a.recycle();
- String key_name = extra_keys[index];
- KeyValue kv = KeyValue.getKeyByName(key_name);
- String title = kv.getString();
- String descr = KeyValue.getKeyDescription(key_name);
- if (descr != null)
- title += " (" + descr + ")";
- setKey(pref_key_of_key_name(key_name));
- setDefaultValue(default_checked(key_name));
- setTitle(title);
- _key_font = kv.hasFlags(KeyValue.FLAG_KEY_FONT);
- }
-
- @Override
- protected void onBindView(View view)
- {
- super.onBindView(view);
- TextView title = (TextView)view.findViewById(android.R.id.title);
- title.setTypeface(_key_font ? Theme.getKeyFont(getContext()) : null);
- }
-
- static String pref_key_of_key_name(String key_name)
- {
- return "extra_key_" + key_name;
- }
-
- public static Set get_extra_keys(SharedPreferences prefs)
- {
- HashSet ks = new HashSet();
- for (String key_name : extra_keys)
- {
- if (prefs.getBoolean(pref_key_of_key_name(key_name), default_checked(key_name)))
- ks.add(KeyValue.getKeyByName(key_name));
- }
- return ks;
- }
-}
diff --git a/srcs/juloo.keyboard2/ExtraKeys.java b/srcs/juloo.keyboard2/ExtraKeys.java
index 22187c1d2..cfac3629d 100644
--- a/srcs/juloo.keyboard2/ExtraKeys.java
+++ b/srcs/juloo.keyboard2/ExtraKeys.java
@@ -1,6 +1,9 @@
package juloo.keyboard2;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -8,50 +11,118 @@
class ExtraKeys
{
- Map> _keys_per_script;
+ public static final ExtraKeys EMPTY = new ExtraKeys(Collections.EMPTY_LIST);
- public ExtraKeys()
+ Collection _ks;
+
+ public ExtraKeys(Collection ks)
+ {
+ _ks = ks;
+ }
+
+ /** Add the keys that should be added to the keyboard into [dst]. Keys
+ already added to [dst] might have an impact, see [ExtraKey.compute]. */
+ public void compute(Set dst, Query q)
+ {
+ for (ExtraKey k : _ks)
+ k.compute(dst, q);
+ }
+
+ public static ExtraKeys parse(String script, String str)
{
- _keys_per_script = new HashMap>();
+ Collection dst = new ArrayList();
+ String[] ks = str.split("\\|");
+ for (int i = 0; i < ks.length; i++)
+ dst.add(ExtraKey.parse(ks[i], script));
+ return new ExtraKeys(dst);
}
- public void add_keys_for_script(String script, List kvs)
+ /** Merge identical keys. This is required to decide whether to add
+ alternatives. Script is generalized (set to null) on any conflict. */
+ public static ExtraKeys merge(List kss)
{
- List ks = _keys_per_script.get(script);
- if (ks == null) ks = new ArrayList();
- ks.addAll(kvs);
- _keys_per_script.put(script, ks);
+ Map merged_keys = new HashMap();
+ for (ExtraKeys ks : kss)
+ for (ExtraKey k : ks._ks)
+ {
+ ExtraKey k2 = merged_keys.get(k.kv);
+ if (k2 != null)
+ k = k.merge_with(k2);
+ merged_keys.put(k.kv, k);
+ }
+ return new ExtraKeys(merged_keys.values());
}
- /** Add the keys that should be added to the keyboard into [dst]. [null] is
- a valid script. */
- public void compute(Set dst, String script)
+ final static class ExtraKey
{
- if (script == null)
+ /** The key to add. */
+ final KeyValue kv;
+ /** The key will be added to layouts of the same script. If null, might be
+ added to layouts of any script. */
+ final String script;
+ /** The key will not be added to layout that already contain all the
+ alternatives. */
+ final List alternatives;
+
+ ExtraKey(KeyValue kv_, String script_, List alts_)
{
- for (String sc : _keys_per_script.keySet())
- get_keys_of_script(dst, sc);
+ kv = kv_;
+ script = script_;
+ alternatives = alts_;
}
- else
+
+ /** Whether the key should be added to the keyboard. */
+ public void compute(Set dst, Query q)
{
- get_keys_of_script(dst, null);
- get_keys_of_script(dst, script);
+ // Add the alternative if it's the only one. The list of alternatives is
+ // enforced to be complete by the merging step. The same [kv] will not
+ // appear again in the list of extra keys with a different list of
+ // alternatives.
+ // Selecting the dead key in the "Add key to the keyboard" option would
+ // disable this behavior for a key.
+ boolean use_alternative = (alternatives.size() == 1 && !dst.contains(kv));
+ if
+ ((q.script == null || script == null || q.script.equals(script))
+ && (alternatives.size() == 0 || !q.present.containsAll(alternatives)))
+ dst.add(use_alternative ? alternatives.get(0) : kv);
}
- }
- void get_keys_of_script(Set dst, String script)
- {
- List ks = _keys_per_script.get(script);
- if (ks != null)
- dst.addAll(ks);
+ /** Return a new key from two. [kv] are expected to be equal. [script] is
+ generalized to [null] on any conflict. [alternatives] are concatenated.
+ */
+ public ExtraKey merge_with(ExtraKey k2)
+ {
+ String script_ =
+ (script != null && k2.script != null && script.equals(k2.script))
+ ? script : null;
+ List alts = new ArrayList(alternatives);
+ alts.addAll(k2.alternatives);
+ return new ExtraKey(kv, script_, alts);
+ }
+
+ /** Extra keys are of the form "key name" or "key name:alt 1:alt 2". */
+ public static ExtraKey parse(String str, String script)
+ {
+ String[] strs = str.split(":");
+ KeyValue kv = KeyValue.getKeyByName(strs[0]);
+ KeyValue[] alts = new KeyValue[strs.length-1];
+ for (int i = 1; i < strs.length; i++)
+ alts[i-1] = KeyValue.getKeyByName(strs[i]);
+ return new ExtraKey(kv, script, Arrays.asList(alts));
+ }
}
- public static List parse_extra_keys(String str)
+ public final static class Query
{
- List dst = new ArrayList();
- String[] ks = str.split("\\|");
- for (int i = 0; i < ks.length; i++)
- dst.add(KeyValue.getKeyByName(ks[i]));
- return dst;
+ /** Script of the current layout. Might be null. */
+ final String script;
+ /** Keys present on the layout. */
+ final Set present;
+
+ public Query(String script_, Set present_)
+ {
+ script = script_;
+ present = present_;
+ }
}
}
diff --git a/srcs/juloo.keyboard2/ExtraKeysPreference.java b/srcs/juloo.keyboard2/ExtraKeysPreference.java
new file mode 100644
index 000000000..ef9846cb7
--- /dev/null
+++ b/srcs/juloo.keyboard2/ExtraKeysPreference.java
@@ -0,0 +1,171 @@
+package juloo.keyboard2;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.preference.CheckBoxPreference;
+import android.preference.PreferenceCategory;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+import java.util.HashSet;
+import java.util.Set;
+
+/** This class implements the "extra keys" preference but also defines the
+ possible extra keys. */
+public class ExtraKeysPreference extends PreferenceCategory
+{
+ /** Array of the keys that can be selected. */
+ public static String[] extra_keys = new String[]
+ {
+ "alt",
+ "meta",
+ "voice_typing",
+ "accent_aigu",
+ "accent_grave",
+ "accent_double_aigu",
+ "accent_dot_above",
+ "accent_circonflexe",
+ "accent_tilde",
+ "accent_cedille",
+ "accent_trema",
+ "accent_ring",
+ "accent_caron",
+ "accent_macron",
+ "accent_ogonek",
+ "accent_breve",
+ "accent_slash",
+ "accent_bar",
+ "accent_dot_below",
+ "accent_hook_above",
+ "accent_horn",
+ "€",
+ "ß",
+ "£",
+ "§",
+ "†",
+ "ª",
+ "º",
+ "switch_greekmath",
+ "capslock",
+ "copy",
+ "paste",
+ "cut",
+ "selectAll",
+ "shareText",
+ "pasteAsPlainText",
+ "undo",
+ "redo",
+ "replaceText",
+ "textAssist",
+ "autofill",
+ "superscript",
+ "subscript",
+ };
+
+ /** Whether an extra key is enabled by default. */
+ public static boolean default_checked(String name)
+ {
+ switch (name)
+ {
+ case "voice_typing":
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /** Text that describe a key. Might be null. */
+ static String key_description(Resources res, String name)
+ {
+ int id = 0;
+ switch (name)
+ {
+ case "capslock": id = R.string.key_descr_capslock; break;
+ case "switch_greekmath": id = R.string.key_descr_switch_greekmath; break;
+ case "voice_typing": id = R.string.key_descr_voice_typing; break;
+ case "copy": id = R.string.key_descr_copy; break;
+ case "paste": id = R.string.key_descr_paste; break;
+ case "cut": id = R.string.key_descr_cut; break;
+ case "selectAll": id = R.string.key_descr_selectAll; break;
+ case "shareText": id = R.string.key_descr_shareText; break;
+ case "pasteAsPlainText": id = R.string.key_descr_pasteAsPlainText; break;
+ case "undo": id = R.string.key_descr_undo; break;
+ case "redo": id = R.string.key_descr_redo; break;
+ case "textAssist": id = R.string.key_descr_textAssist; break;
+ case "autofill": id = R.string.key_descr_autofill; break;
+ case "ª": id = R.string.key_descr_ª; break;
+ case "º": id = R.string.key_descr_º; break;
+ case "superscript": id = R.string.key_descr_superscript; break;
+ case "subscript": id = R.string.key_descr_subscript; break;
+ }
+ if (id == 0)
+ return null;
+ return res.getString(id);
+ }
+
+ /** Get the set of enabled extra keys. */
+ public static Set get_extra_keys(SharedPreferences prefs)
+ {
+ HashSet ks = new HashSet();
+ for (String key_name : extra_keys)
+ {
+ if (prefs.getBoolean(pref_key_of_key_name(key_name),
+ default_checked(key_name)))
+ ks.add(KeyValue.getKeyByName(key_name));
+ }
+ return ks;
+ }
+
+ boolean _attached = false; /** Whether it has already been attached. */
+
+ public ExtraKeysPreference(Context context, AttributeSet attrs)
+ {
+ super(context, attrs);
+ setOrderingAsAdded(true);
+ }
+
+ @Override
+ protected void onAttachedToActivity()
+ {
+ if (_attached)
+ return;
+ _attached = true;
+ for (String key_name : extra_keys)
+ addPreference(new ExtraKeyCheckBoxPreference(getContext(), key_name,
+ default_checked(key_name)));
+ }
+
+ public static String pref_key_of_key_name(String key_name)
+ {
+ return "extra_key_" + key_name;
+ }
+
+ static class ExtraKeyCheckBoxPreference extends CheckBoxPreference
+ {
+ boolean _key_font;
+
+ public ExtraKeyCheckBoxPreference(Context ctx, String key_name,
+ boolean default_checked)
+ {
+ super(ctx);
+ KeyValue kv = KeyValue.getKeyByName(key_name);
+ String title = kv.getString();
+ String descr = key_description(ctx.getResources(), key_name);
+ if (descr != null)
+ title += " (" + descr + ")";
+ setKey(pref_key_of_key_name(key_name));
+ setDefaultValue(default_checked);
+ setTitle(title);
+ _key_font = kv.hasFlags(KeyValue.FLAG_KEY_FONT);
+ }
+
+ @Override
+ protected void onBindView(View view)
+ {
+ super.onBindView(view);
+ TextView title = (TextView)view.findViewById(android.R.id.title);
+ title.setTypeface(_key_font ? Theme.getKeyFont(getContext()) : null);
+ }
+ }
+}
diff --git a/srcs/juloo.keyboard2/KeyModifier.java b/srcs/juloo.keyboard2/KeyModifier.java
index 86d41a091..eb831f156 100644
--- a/srcs/juloo.keyboard2/KeyModifier.java
+++ b/srcs/juloo.keyboard2/KeyModifier.java
@@ -238,7 +238,9 @@ private static String apply_fn_char(char c)
case '?': return "¿";
case '|': return "¦";
case '§': return "¶";
+ case '†': return "‡";
case '×': return "∙";
+ case ' ': return "nbsp";
// arrows
case '↖': return "⇖";
case '↑': return "⇑";
@@ -257,6 +259,7 @@ private static String apply_fn_char(char c)
case 'y': return "¥";
case 'c': return "¢";
case 'p': return "₱";
+ case 'h': return "₴";
case '€': case '£': return "removed"; // Avoid showing these twice
// alternating greek letters
case 'π': return "ϖ";
@@ -354,8 +357,28 @@ private static String apply_fn_char(char c)
case 'ं': return "ॕ";
case '़': return "ॎ";
case 'ऽ': return "ॽ";
- // other
- case ' ': return "nbsp";
+ // Persian numbers
+ case '۱': return "f1";
+ case '۲': return "f2";
+ case '۳': return "f3";
+ case '۴': return "f4";
+ case '۵': return "f5";
+ case '۶': return "f6";
+ case '۷': return "f7";
+ case '۸': return "f8";
+ case '۹': return "f9";
+ case '۰': return "f10";
+ // Arabic numbers
+ case '١': return "f1";
+ case '٢': return "f2";
+ case '٣': return "f3";
+ case '٤': return "f4";
+ case '٥': return "f5";
+ case '٦': return "f6";
+ case '٧': return "f7";
+ case '٨': return "f8";
+ case '٩': return "f9";
+ case '٠': return "f10";
default: return null;
}
}
@@ -706,13 +729,36 @@ public char apply(char c)
case '8': return '⁸';
case '9': return '⁹';
case '0': return '⁰';
- case 'i': return 'ⁱ';
case '+': return '⁺';
case '-': return '⁻';
case '=': return '⁼';
case '(': return '⁽';
case ')': return '⁾';
+ case 'a': return 'ᵃ';
+ case 'b': return 'ᵇ';
+ case 'c': return 'ᶜ';
+ case 'd': return 'ᵈ';
+ case 'e': return 'ᵉ';
+ case 'f': return 'ᶠ';
+ case 'g': return 'ᵍ';
+ case 'h': return 'ʰ';
+ case 'i': return 'ⁱ';
+ case 'j': return 'ʲ';
+ case 'k': return 'ᵏ';
+ case 'l': return 'ˡ';
+ case 'm': return 'ᵐ';
case 'n': return 'ⁿ';
+ case 'o': return 'ᵒ';
+ case 'p': return 'ᵖ';
+ case 'r': return 'ʳ';
+ case 's': return 'ˢ';
+ case 't': return 'ᵗ';
+ case 'u': return 'ᵘ';
+ case 'v': return 'ᵛ';
+ case 'w': return 'ʷ';
+ case 'x': return 'ˣ';
+ case 'y': return 'ʸ';
+ case 'z': return 'ᶻ';
default: return c;
}
}
@@ -739,10 +785,23 @@ public char apply(char c)
case '=': return '₌';
case '(': return '₍';
case ')': return '₎';
- case 'e': return 'ₑ';
case 'a': return 'ₐ';
- case 'x': return 'ₓ';
+ case 'e': return 'ₑ';
+ case 'h': return 'ₕ';
+ case 'i': return 'ᵢ';
+ case 'j': return 'ⱼ';
+ case 'k': return 'ₖ';
+ case 'l': return 'ₗ';
+ case 'm': return 'ₘ';
+ case 'n': return 'ₙ';
case 'o': return 'ₒ';
+ case 'p': return 'ₚ';
+ case 'r': return 'ᵣ';
+ case 's': return 'ₛ';
+ case 't': return 'ₜ';
+ case 'u': return 'ᵤ';
+ case 'v': return 'ᵥ';
+ case 'x': return 'ₓ';
default: return c;
}
}
diff --git a/srcs/juloo.keyboard2/KeyValue.java b/srcs/juloo.keyboard2/KeyValue.java
index ed80f8678..fe55b6d8d 100644
--- a/srcs/juloo.keyboard2/KeyValue.java
+++ b/srcs/juloo.keyboard2/KeyValue.java
@@ -15,8 +15,8 @@ public static enum Event
CHANGE_METHOD,
CHANGE_METHOD_PREV,
ACTION,
- SWITCH_SECOND,
- SWITCH_SECOND_BACK,
+ SWITCH_FORWARD,
+ SWITCH_BACKWARD,
SWITCH_GREEKMATH,
CAPS_LOCK,
SWITCH_VOICE_TYPING,
@@ -278,10 +278,20 @@ private static KeyValue keyeventKey(int symbol, int code, int flags)
return keyeventKey(String.valueOf((char)symbol), code, flags | FLAG_KEY_FONT);
}
- private static KeyValue editingKey(String symbol, Editing action)
+ private static KeyValue editingKey(String symbol, Editing action, int flags)
{
return new KeyValue(symbol, Kind.Editing, action.ordinal(),
- FLAG_SPECIAL | FLAG_SECONDARY | FLAG_SMALLER_FONT);
+ flags | FLAG_SPECIAL | FLAG_SECONDARY);
+ }
+
+ private static KeyValue editingKey(String symbol, Editing action)
+ {
+ return editingKey(symbol, action, FLAG_SMALLER_FONT);
+ }
+
+ private static KeyValue editingKey(int symbol, Editing action)
+ {
+ return editingKey(String.valueOf((char)symbol), action, FLAG_KEY_FONT);
}
/** A key that do nothing but has a unique ID. */
@@ -290,12 +300,13 @@ private static KeyValue placeholderKey(Placeholder id)
return new KeyValue("", Kind.Placeholder, id.ordinal(), 0);
}
- private static KeyValue fallbackMakeKey(String name)
+ /** Make a key that types a string. */
+ public static KeyValue makeStringKey(String str)
{
- if (name.length() == 1)
- return new KeyValue(name, Kind.Char, name.charAt(0), 0);
+ if (str.length() == 1)
+ return new KeyValue(str, Kind.Char, str.charAt(0), 0);
else
- return new KeyValue(name, Kind.String, 0, 0);
+ return new KeyValue(str, Kind.String, 0, FLAG_SMALLER_FONT);
}
public static KeyValue getKeyByName(String name)
@@ -305,33 +316,33 @@ public static KeyValue getKeyByName(String name)
/* These symbols have special meaning when in `res/xml` and are escaped in
standard layouts. The backslash is not stripped when parsed from the
custom layout option. */
- case "\\?": return fallbackMakeKey("?");
- case "\\#": return fallbackMakeKey("#");
- case "\\@": return fallbackMakeKey("@");
- case "\\\\": return fallbackMakeKey("\\");
+ case "\\?": return makeStringKey("?");
+ case "\\#": return makeStringKey("#");
+ case "\\@": return makeStringKey("@");
+ case "\\\\": return makeStringKey("\\");
- case "shift": return modifierKey(0x0A, Modifier.SHIFT, 0);
+ case "shift": return modifierKey(0xE00A, Modifier.SHIFT, 0);
case "ctrl": return modifierKey("Ctrl", Modifier.CTRL, 0);
case "alt": return modifierKey("Alt", Modifier.ALT, 0);
- case "accent_aigu": return diacritic(0x50, Modifier.AIGU);
- case "accent_caron": return diacritic(0x51, Modifier.CARON);
- case "accent_cedille": return diacritic(0x52, Modifier.CEDILLE);
- case "accent_circonflexe": return diacritic(0x53, Modifier.CIRCONFLEXE);
- case "accent_grave": return diacritic(0x54, Modifier.GRAVE);
- case "accent_macron": return diacritic(0x55, Modifier.MACRON);
- case "accent_ring": return diacritic(0x56, Modifier.RING);
- case "accent_tilde": return diacritic(0x57, Modifier.TILDE);
- case "accent_trema": return diacritic(0x58, Modifier.TREMA);
- case "accent_ogonek": return diacritic(0x59, Modifier.OGONEK);
- case "accent_dot_above": return diacritic(0x5A, Modifier.DOT_ABOVE);
- case "accent_double_aigu": return diacritic(0x5B, Modifier.DOUBLE_AIGU);
- case "accent_slash": return diacritic(0x5C, Modifier.SLASH);
- case "accent_arrow_right": return diacritic(0x5D, Modifier.ARROW_RIGHT);
- case "accent_breve": return diacritic(0x5E, Modifier.BREVE);
- case "accent_bar": return diacritic(0x5F, Modifier.BAR);
- case "accent_dot_below": return diacritic(0x60, Modifier.DOT_BELOW);
- case "accent_horn": return diacritic(0x61, Modifier.HORN);
- case "accent_hook_above": return diacritic(0x62, Modifier.HOOK_ABOVE);
+ case "accent_aigu": return diacritic(0xE050, Modifier.AIGU);
+ case "accent_caron": return diacritic(0xE051, Modifier.CARON);
+ case "accent_cedille": return diacritic(0xE052, Modifier.CEDILLE);
+ case "accent_circonflexe": return diacritic(0xE053, Modifier.CIRCONFLEXE);
+ case "accent_grave": return diacritic(0xE054, Modifier.GRAVE);
+ case "accent_macron": return diacritic(0xE055, Modifier.MACRON);
+ case "accent_ring": return diacritic(0xE056, Modifier.RING);
+ case "accent_tilde": return diacritic(0xE057, Modifier.TILDE);
+ case "accent_trema": return diacritic(0xE058, Modifier.TREMA);
+ case "accent_ogonek": return diacritic(0xE059, Modifier.OGONEK);
+ case "accent_dot_above": return diacritic(0xE05A, Modifier.DOT_ABOVE);
+ case "accent_double_aigu": return diacritic(0xE05B, Modifier.DOUBLE_AIGU);
+ case "accent_slash": return diacritic(0xE05C, Modifier.SLASH);
+ case "accent_arrow_right": return diacritic(0xE05D, Modifier.ARROW_RIGHT);
+ case "accent_breve": return diacritic(0xE05E, Modifier.BREVE);
+ case "accent_bar": return diacritic(0xE05F, Modifier.BAR);
+ case "accent_dot_below": return diacritic(0xE060, Modifier.DOT_BELOW);
+ case "accent_horn": return diacritic(0xE061, Modifier.HORN);
+ case "accent_hook_above": return diacritic(0xE062, Modifier.HOOK_ABOVE);
case "superscript": return modifierKey("Sup", Modifier.SUPERSCRIPT, 0);
case "subscript": return modifierKey("Sub", Modifier.SUBSCRIPT, 0);
case "ordinal": return modifierKey("Ord", Modifier.ORDINAL, 0);
@@ -340,32 +351,32 @@ public static KeyValue getKeyByName(String name)
case "fn": return modifierKey("Fn", Modifier.FN, 0);
case "meta": return modifierKey("Meta", Modifier.META, 0);
- case "config": return eventKey(0x04, Event.CONFIG, FLAG_SMALLER_FONT);
+ case "config": return eventKey(0xE004, Event.CONFIG, FLAG_SMALLER_FONT);
case "switch_text": return eventKey("ABC", Event.SWITCH_TEXT, FLAG_SMALLER_FONT);
case "switch_numeric": return eventKey("123+", Event.SWITCH_NUMERIC, FLAG_SMALLER_FONT);
- case "switch_emoji": return eventKey(0x01, Event.SWITCH_EMOJI, FLAG_SMALLER_FONT);
+ case "switch_emoji": return eventKey(0xE001, Event.SWITCH_EMOJI, FLAG_SMALLER_FONT);
case "switch_back_emoji": return eventKey("ABC", Event.SWITCH_BACK_EMOJI, 0);
- case "switch_second": return eventKey(0x13, Event.SWITCH_SECOND, FLAG_SMALLER_FONT);
- case "switch_second_back": return eventKey(0x14, Event.SWITCH_SECOND_BACK, FLAG_SMALLER_FONT);
+ case "switch_forward": return eventKey(0xE013, Event.SWITCH_FORWARD, FLAG_SMALLER_FONT);
+ case "switch_backward": return eventKey(0xE014, Event.SWITCH_BACKWARD, FLAG_SMALLER_FONT);
case "switch_greekmath": return eventKey("πλ∇¬", Event.SWITCH_GREEKMATH, FLAG_SMALLER_FONT);
- case "change_method": return eventKey(0x09, Event.CHANGE_METHOD, FLAG_SMALLER_FONT);
- case "change_method_prev": return eventKey(0x09, Event.CHANGE_METHOD_PREV, FLAG_SMALLER_FONT);
+ case "change_method": return eventKey(0xE009, Event.CHANGE_METHOD, FLAG_SMALLER_FONT);
+ case "change_method_prev": return eventKey(0xE009, Event.CHANGE_METHOD_PREV, FLAG_SMALLER_FONT);
case "action": return eventKey("Action", Event.ACTION, FLAG_SMALLER_FONT); // Will always be replaced
- case "capslock": return eventKey(0x12, Event.CAPS_LOCK, 0);
- case "voice_typing": return eventKey(0x15, Event.SWITCH_VOICE_TYPING, FLAG_SMALLER_FONT);
+ case "capslock": return eventKey(0xE012, Event.CAPS_LOCK, 0);
+ case "voice_typing": return eventKey(0xE015, Event.SWITCH_VOICE_TYPING, FLAG_SMALLER_FONT);
case "esc": return keyeventKey("Esc", KeyEvent.KEYCODE_ESCAPE, FLAG_SMALLER_FONT);
- case "enter": return keyeventKey(0x0E, KeyEvent.KEYCODE_ENTER, 0);
- case "up": return keyeventKey(0x05, KeyEvent.KEYCODE_DPAD_UP, 0);
- case "right": return keyeventKey(0x06, KeyEvent.KEYCODE_DPAD_RIGHT, 0);
- case "down": return keyeventKey(0x07, KeyEvent.KEYCODE_DPAD_DOWN, 0);
- case "left": return keyeventKey(0x08, KeyEvent.KEYCODE_DPAD_LEFT, 0);
- case "page_up": return keyeventKey(0x02, KeyEvent.KEYCODE_PAGE_UP, 0);
- case "page_down": return keyeventKey(0x03, KeyEvent.KEYCODE_PAGE_DOWN, 0);
- case "home": return keyeventKey(0x0B, KeyEvent.KEYCODE_MOVE_HOME, 0);
- case "end": return keyeventKey(0x0C, KeyEvent.KEYCODE_MOVE_END, 0);
- case "backspace": return keyeventKey(0x11, KeyEvent.KEYCODE_DEL, 0);
- case "delete": return keyeventKey(0x10, KeyEvent.KEYCODE_FORWARD_DEL, 0);
+ case "enter": return keyeventKey(0xE00E, KeyEvent.KEYCODE_ENTER, 0);
+ case "up": return keyeventKey(0xE005, KeyEvent.KEYCODE_DPAD_UP, 0);
+ case "right": return keyeventKey(0xE006, KeyEvent.KEYCODE_DPAD_RIGHT, 0);
+ case "down": return keyeventKey(0xE007, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ case "left": return keyeventKey(0xE008, KeyEvent.KEYCODE_DPAD_LEFT, 0);
+ case "page_up": return keyeventKey(0xE002, KeyEvent.KEYCODE_PAGE_UP, 0);
+ case "page_down": return keyeventKey(0xE003, KeyEvent.KEYCODE_PAGE_DOWN, 0);
+ case "home": return keyeventKey(0xE00B, KeyEvent.KEYCODE_MOVE_HOME, 0);
+ case "end": return keyeventKey(0xE00C, KeyEvent.KEYCODE_MOVE_END, 0);
+ case "backspace": return keyeventKey(0xE011, KeyEvent.KEYCODE_DEL, 0);
+ case "delete": return keyeventKey(0xE010, KeyEvent.KEYCODE_FORWARD_DEL, 0);
case "insert": return keyeventKey("Ins", KeyEvent.KEYCODE_INSERT, FLAG_SMALLER_FONT);
case "f1": return keyeventKey("F1", KeyEvent.KEYCODE_F1, 0);
case "f2": return keyeventKey("F2", KeyEvent.KEYCODE_F2, 0);
@@ -379,7 +390,7 @@ public static KeyValue getKeyByName(String name)
case "f10": return keyeventKey("F10", KeyEvent.KEYCODE_F10, 0);
case "f11": return keyeventKey("F11", KeyEvent.KEYCODE_F11, FLAG_SMALLER_FONT);
case "f12": return keyeventKey("F12", KeyEvent.KEYCODE_F12, FLAG_SMALLER_FONT);
- case "tab": return keyeventKey(0x0F, KeyEvent.KEYCODE_TAB, FLAG_SMALLER_FONT);
+ case "tab": return keyeventKey(0xE00F, KeyEvent.KEYCODE_TAB, FLAG_SMALLER_FONT);
case "\\t": return charKey("\\t", '\t', 0); // Send the tab character
case "space": return charKey("\r", ' ', FLAG_KEY_FONT | FLAG_SECONDARY);
@@ -432,41 +443,21 @@ public static KeyValue getKeyByName(String name)
case "zwj": return charKey("zwj", '\u200D', 0); // zero-width joiner (provides ligature)
case "zwnj": return charKey("zwnj", '\u200C', 0); // zero-width non joiner (prevents unintended ligature)
- case "copy": return editingKey("copy", Editing.COPY);
- case "paste": return editingKey("paste", Editing.PASTE);
- case "cut": return editingKey("cut", Editing.CUT);
- case "selectAll": return editingKey("s. all", Editing.SELECT_ALL);
- case "shareText": return editingKey("share", Editing.SHARE);
- case "pasteAsPlainText": return editingKey("", Editing.PASTE_PLAIN);
- case "undo": return editingKey("undo", Editing.UNDO);
- case "redo": return editingKey("redo", Editing.REDO);
- case "replaceText": return editingKey("repl.", Editing.REPLACE);
- case "textAssist": return editingKey("assist", Editing.ASSIST);
- case "autofill": return editingKey("auto.", Editing.AUTOFILL);
- default: return fallbackMakeKey(name);
+ case "copy": return editingKey(0xE030, Editing.COPY);
+ case "paste": return editingKey(0xE032, Editing.PASTE);
+ case "cut": return editingKey(0xE031, Editing.CUT);
+ case "selectAll": return editingKey(0xE033, Editing.SELECT_ALL);
+ case "shareText": return editingKey(0xE034, Editing.SHARE);
+ case "pasteAsPlainText": return editingKey(0xE035, Editing.PASTE_PLAIN);
+ case "undo": return editingKey(0xE036, Editing.UNDO);
+ case "redo": return editingKey(0xE037, Editing.REDO);
+ case "replaceText": return editingKey("repl", Editing.REPLACE);
+ case "textAssist": return editingKey(0xE038, Editing.ASSIST);
+ case "autofill": return editingKey("auto", Editing.AUTOFILL);
+ default: return makeStringKey(name);
}
}
- static final HashMap keys_descr = new HashMap();
-
- /* Some keys have a description attached. Return [null] if otherwise. */
- public static String getKeyDescription(String name)
- {
- return keys_descr.get(name);
- }
-
- static void addKeyDescr(String name, String descr)
- {
- keys_descr.put(name, descr);
- }
-
- static {
- /* Keys description is shown in the settings. */
- addKeyDescr("capslock", "Caps lock");
- addKeyDescr("switch_greekmath", "Greek & math symbols");
- addKeyDescr("voice_typing", "Voice typing");
- }
-
// Substitute for [assert], which has no effect on Android.
private static void check(boolean b)
{
diff --git a/srcs/juloo.keyboard2/Keyboard2.java b/srcs/juloo.keyboard2/Keyboard2.java
index 4b82c3330..924f87b74 100644
--- a/srcs/juloo.keyboard2/Keyboard2.java
+++ b/srcs/juloo.keyboard2/Keyboard2.java
@@ -18,6 +18,7 @@
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -26,13 +27,12 @@
public class Keyboard2 extends InputMethodService
implements SharedPreferences.OnSharedPreferenceChangeListener
{
- static private final String TAG = "Keyboard2";
-
private Keyboard2View _keyboardView;
private KeyEventHandler _keyeventhandler;
// If not 'null', the layout to use instead of [_currentTextLayout].
private KeyboardData _currentSpecialLayout;
- private Current_text_layout _currentTextLayout;
+ /** Current layout index in [Config.layouts]. */
+ private int _currentTextLayout;
// Layout associated with the currently selected locale. Not 'null'.
private KeyboardData _localeTextLayout;
private ViewGroup _emojiPane = null;
@@ -40,30 +40,36 @@ public class Keyboard2 extends InputMethodService
private Config _config;
- private boolean _debug_logs = false;
-
/** Layout currently visible. */
KeyboardData current_layout()
{
if (_currentSpecialLayout != null)
return _currentSpecialLayout;
- KeyboardData layout;
- if (_currentTextLayout == Current_text_layout.SECONDARY)
- layout = _config.second_layout;
- else if (_config.layout == null)
+ KeyboardData layout = null;
+ if (_currentTextLayout >= _config.layouts.size())
+ _currentTextLayout = 0;
+ if (_currentTextLayout < _config.layouts.size())
+ layout = _config.layouts.get(_currentTextLayout);
+ if (layout == null)
layout = _localeTextLayout;
- else
- layout = _config.layout;
return _config.modify_layout(layout);
}
- void setTextLayout(Current_text_layout layout)
+ void setTextLayout(int l)
{
- _currentTextLayout = layout;
+ if (l == _currentTextLayout)
+ return;
+ _currentTextLayout = l;
_currentSpecialLayout = null;
_keyboardView.setKeyboard(current_layout());
}
+ void incrTextLayout(int delta)
+ {
+ int s = _config.layouts.size();
+ setTextLayout((_currentTextLayout + delta + s) % s);
+ }
+
void setSpecialLayout(KeyboardData l)
{
_currentSpecialLayout = l;
@@ -75,19 +81,25 @@ KeyboardData loadLayout(int layout_id)
return KeyboardData.load(getResources(), layout_id);
}
+ /** Load a layout that contains a numpad (eg. the pin entry). */
+ KeyboardData loadNumpad(int layout_id)
+ {
+ return _config.modify_numpad(KeyboardData.load(getResources(), layout_id));
+ }
+
@Override
public void onCreate()
{
super.onCreate();
KeyboardData.init(getResources());
SharedPreferences prefs = DirectBootAwarePreferences.get_shared_preferences(this);
- prefs.registerOnSharedPreferenceChangeListener(this);
_keyeventhandler = new KeyEventHandler(getMainLooper(), this.new Receiver());
Config.initGlobalConfig(prefs, getResources(), _keyeventhandler);
+ prefs.registerOnSharedPreferenceChangeListener(this);
_config = Config.globalConfig();
_keyboardView = (Keyboard2View)inflate_view(R.layout.keyboard);
_keyboardView.reset();
- _debug_logs = getResources().getBoolean(R.bool.debug_logs);
+ Logs.set_debug_logs(getResources().getBoolean(R.bool.debug_logs));
}
private List getEnabledSubtypes(InputMethodManager imm)
@@ -99,34 +111,24 @@ private List getEnabledSubtypes(InputMethodManager imm)
return Arrays.asList();
}
- private void extra_keys_of_subtype(ExtraKeys dst, InputMethodSubtype subtype)
+ private ExtraKeys extra_keys_of_subtype(InputMethodSubtype subtype)
{
String extra_keys = subtype.getExtraValueOf("extra_keys");
String script = subtype.getExtraValueOf("script");
- if (extra_keys == null)
- return;
- dst.add_keys_for_script(script, ExtraKeys.parse_extra_keys(extra_keys));
+ if (extra_keys != null)
+ return ExtraKeys.parse(script, extra_keys);
+ return ExtraKeys.EMPTY;
}
private void refreshAccentsOption(InputMethodManager imm, InputMethodSubtype subtype)
{
- ExtraKeys extra_keys = new ExtraKeys();
List enabled_subtypes = getEnabledSubtypes(imm);
- switch (_config.accents)
- {
- // '3' was "all accents", now unused
- case 1: case 3:
- extra_keys_of_subtype(extra_keys, subtype);
- for (InputMethodSubtype s : enabled_subtypes)
- extra_keys_of_subtype(extra_keys, s);
- break;
- case 2:
- extra_keys_of_subtype(extra_keys, subtype);
- break;
- case 4: break;
- default: throw new IllegalArgumentException();
- }
- _config.extra_keys_subtype = extra_keys;
+ List extra_keys = new ArrayList();
+ // Gather extra keys from all enabled subtypes
+ extra_keys.add(extra_keys_of_subtype(subtype));
+ for (InputMethodSubtype s : enabled_subtypes)
+ extra_keys.add(extra_keys_of_subtype(s));
+ _config.extra_keys_subtype = ExtraKeys.merge(extra_keys);
if (enabled_subtypes.size() > 1)
_config.shouldOfferSwitchingToNextInputMethod = true;
}
@@ -153,22 +155,13 @@ private void refreshSubtypeImm()
{
String s = subtype.getExtraValueOf("default_layout");
if (s != null)
- default_layout = _config.layout_of_string(getResources(), s);
+ default_layout = LayoutsPreference.layout_of_string(getResources(), s);
refreshAccentsOption(imm, subtype);
}
}
if (default_layout == null)
- default_layout = KeyboardData.load(getResources(), R.xml.latn_qwerty_us);
+ default_layout = loadLayout(R.xml.latn_qwerty_us);
_localeTextLayout = default_layout;
- if (_config.second_layout == null)
- {
- _config.shouldOfferSwitchingToSecond = false;
- _currentTextLayout = Current_text_layout.PRIMARY;
- }
- else
- {
- _config.shouldOfferSwitchingToSecond = true;
- }
}
private String actionLabel_of_imeAction(int action)
@@ -239,30 +232,21 @@ SimpleEntry get_voice_typing_im(InputMethodManager i
return null;
}
- private void log_editor_info(EditorInfo info)
- {
- LogPrinter p = new LogPrinter(Log.DEBUG, TAG);
- info.dump(p, "");
- if (info.extras != null)
- Log.d(TAG, "extras: "+info.extras.toString());
- Log.d(TAG, "swapEnterActionKey: "+_config.swapEnterActionKey);
- Log.d(TAG, "actionLabel: "+_config.actionLabel);
- }
-
- private void refresh_special_layout(EditorInfo info)
+ private KeyboardData refresh_special_layout(EditorInfo info)
{
switch (info.inputType & InputType.TYPE_MASK_CLASS)
{
case InputType.TYPE_CLASS_NUMBER:
case InputType.TYPE_CLASS_PHONE:
case InputType.TYPE_CLASS_DATETIME:
- _currentSpecialLayout =
- _config.modify_numpad(KeyboardData.load(getResources(), R.xml.pin));
- break;
+ if (_config.pin_entry_enabled)
+ return loadNumpad(R.xml.pin);
+ else
+ return loadNumpad(R.xml.numeric);
default:
- _currentSpecialLayout = null;
break;
}
+ return null;
}
@Override
@@ -270,12 +254,11 @@ public void onStartInputView(EditorInfo info, boolean restarting)
{
refresh_config();
refresh_action_label(info);
- refresh_special_layout(info);
+ _currentSpecialLayout = refresh_special_layout(info);
_keyboardView.setKeyboard(current_layout());
_keyeventhandler.started(info);
setInputView(_keyboardView);
- if (_debug_logs)
- log_editor_info(info);
+ Logs.debug_startup_input_view(info, _config);
}
@Override
@@ -397,7 +380,7 @@ public void handle_event_key(KeyValue.Event ev)
break;
case SWITCH_NUMERIC:
- setSpecialLayout(_config.modify_numpad(loadLayout(R.xml.numeric)));
+ setSpecialLayout(loadNumpad(R.xml.numeric));
break;
case SWITCH_EMOJI:
@@ -427,17 +410,16 @@ public void handle_event_key(KeyValue.Event ev)
conn.performEditorAction(actionId);
break;
- case SWITCH_SECOND:
- if (_config.second_layout != null)
- setTextLayout(Current_text_layout.SECONDARY);
+ case SWITCH_FORWARD:
+ incrTextLayout(1);
break;
- case SWITCH_SECOND_BACK:
- setTextLayout(Current_text_layout.PRIMARY);
+ case SWITCH_BACKWARD:
+ incrTextLayout(-1);
break;
case SWITCH_GREEKMATH:
- setSpecialLayout(_config.modify_numpad(loadLayout(R.xml.greekmath)));
+ setSpecialLayout(loadNumpad(R.xml.greekmath));
break;
case CAPS_LOCK:
@@ -477,10 +459,4 @@ private View inflate_view(int layout)
{
return View.inflate(new ContextThemeWrapper(this, _config.theme), layout, null);
}
-
- private static enum Current_text_layout
- {
- PRIMARY,
- SECONDARY
- }
}
diff --git a/srcs/juloo.keyboard2/Keyboard2View.java b/srcs/juloo.keyboard2/Keyboard2View.java
index f4053f278..3f4a8950b 100644
--- a/srcs/juloo.keyboard2/Keyboard2View.java
+++ b/srcs/juloo.keyboard2/Keyboard2View.java
@@ -407,7 +407,12 @@ private void drawSubLabel(Canvas canvas, KeyValue kv, float x, float y,
x += keyW / 2f;
else
x += (a == Paint.Align.LEFT) ? subPadding : keyW - subPadding;
- canvas.drawText(kv.getString(), x, y, p);
+ String label = kv.getString();
+ int label_len = label.length();
+ // Limit the label of string keys to 3 characters
+ if (label_len > 3 && kv.getKind() == KeyValue.Kind.String)
+ label_len = 3;
+ canvas.drawText(label, 0, label_len, x, y, p);
}
private void drawIndication(Canvas canvas, String indication, float x,
diff --git a/srcs/juloo.keyboard2/LayoutListPreference.java b/srcs/juloo.keyboard2/LayoutListPreference.java
deleted file mode 100644
index 9e3072c71..000000000
--- a/srcs/juloo.keyboard2/LayoutListPreference.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package juloo.keyboard2;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.preference.ListPreference;
-import android.util.AttributeSet;
-
-public class LayoutListPreference extends ListPreference
-{
- public LayoutListPreference(Context context, AttributeSet attrs)
- {
- super(context, attrs);
- final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LayoutListPreference);
- String defaultString = a.getString(R.styleable.LayoutListPreference_defaultString);
- a.recycle();
- Resources res = context.getResources();
- String[] entries = res.getStringArray(R.array.pref_layout_entries);
- entries[0] = defaultString;
- setEntries(entries);
- setEntryValues(res.getStringArray(R.array.pref_layout_values));
- setSummary("%s");
- setDefaultValue("none");
- }
-}
diff --git a/srcs/juloo.keyboard2/LayoutsPreference.java b/srcs/juloo.keyboard2/LayoutsPreference.java
new file mode 100644
index 000000000..f15bad9d1
--- /dev/null
+++ b/srcs/juloo.keyboard2/LayoutsPreference.java
@@ -0,0 +1,266 @@
+package juloo.keyboard2;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class LayoutsPreference extends ListGroupPreference
+{
+ static final String KEY = "layouts";
+ static final List DEFAULT =
+ Collections.singletonList((Layout)new SystemLayout());
+ static final ListGroupPreference.Serializer SERIALIZER =
+ new Serializer();
+
+ /** Text displayed for each layout in the dialog list. */
+ String[] _layout_display_names;
+
+ public LayoutsPreference(Context ctx, AttributeSet attrs)
+ {
+ super(ctx, attrs);
+ setKey(KEY);
+ Resources res = ctx.getResources();
+ _layout_display_names = res.getStringArray(R.array.pref_layout_entries);
+ }
+
+ /** Obtained from [res/values/layouts.xml]. */
+ static List _unsafe_layout_ids_str = null;
+ static TypedArray _unsafe_layout_ids_res = null;
+
+ /** Layout internal names. Contains "system" and "custom". */
+ public static List get_layout_names(Resources res)
+ {
+ if (_unsafe_layout_ids_str == null)
+ _unsafe_layout_ids_str = Arrays.asList(
+ res.getStringArray(R.array.pref_layout_values));
+ return _unsafe_layout_ids_str;
+ }
+
+ /** Layout resource id for a layout name. [-1] if not found. */
+ public static int layout_id_of_name(Resources res, String name)
+ {
+ if (_unsafe_layout_ids_res == null)
+ _unsafe_layout_ids_res = res.obtainTypedArray(R.array.layout_ids);
+ int i = get_layout_names(res).indexOf(name);
+ if (i >= 0)
+ return _unsafe_layout_ids_res.getResourceId(i, 0);
+ return -1;
+ }
+
+ /** [null] for the "system" layout. */
+ public static List load_from_preferences(Resources res, SharedPreferences prefs)
+ {
+ List layouts = new ArrayList();
+ for (Layout l : load_from_preferences(KEY, prefs, DEFAULT, SERIALIZER))
+ {
+ if (l instanceof NamedLayout)
+ layouts.add(layout_of_string(res, ((NamedLayout)l).name));
+ else if (l instanceof CustomLayout)
+ layouts.add(KeyboardData.load_string(((CustomLayout)l).xml));
+ else // instanceof SystemLayout
+ layouts.add(null);
+ }
+ return layouts;
+ }
+
+ /** Does not call [prefs.commit()]. */
+ public static void save_to_preferences(SharedPreferences.Editor prefs, List items)
+ {
+ save_to_preferences(KEY, prefs, items, SERIALIZER);
+ }
+
+ public static KeyboardData layout_of_string(Resources res, String name)
+ {
+ int id = layout_id_of_name(res, name);
+ if (id > 0)
+ return KeyboardData.load(res, id);
+ // Might happen when the app is downgraded, return the system layout.
+ return null;
+ }
+
+ @Override
+ protected void onSetInitialValue(boolean restoreValue, Object defaultValue)
+ {
+ super.onSetInitialValue(restoreValue, defaultValue);
+ if (_values.size() == 0)
+ set_values(new ArrayList(DEFAULT), false);
+ }
+
+ String label_of_layout(Layout l)
+ {
+ if (l instanceof NamedLayout)
+ {
+ String lname = ((NamedLayout)l).name;
+ int value_i = get_layout_names(getContext().getResources()).indexOf(lname);
+ return value_i < 0 ? lname : _layout_display_names[value_i];
+ }
+ else if (l instanceof CustomLayout)
+ return getContext().getString(R.string.pref_layout_e_custom);
+ else // instanceof SystemLayout
+ return getContext().getString(R.string.pref_layout_e_system);
+ }
+
+ @Override
+ String label_of_value(Layout value, int i)
+ {
+ return getContext().getString(R.string.pref_layouts_item, i + 1,
+ label_of_layout(value));
+ }
+
+ @Override
+ AddButton on_attach_add_button(AddButton prev_btn)
+ {
+ if (prev_btn == null)
+ return new LayoutsAddButton(getContext());
+ return prev_btn;
+ }
+
+ @Override
+ boolean should_allow_remove_item(Layout value)
+ {
+ return (_values.size() > 1 && !(value instanceof CustomLayout));
+ }
+
+ @Override
+ ListGroupPreference.Serializer get_serializer() { return SERIALIZER; }
+
+ @Override
+ void select(final SelectionCallback callback)
+ {
+ ArrayAdapter layouts = new ArrayAdapter(getContext(), android.R.layout.simple_list_item_1, _layout_display_names);
+ new AlertDialog.Builder(getContext())
+ .setView(R.layout.dialog_edit_text)
+ .setAdapter(layouts, new DialogInterface.OnClickListener(){
+ public void onClick(DialogInterface _dialog, int which)
+ {
+ String name = get_layout_names(getContext().getResources()).get(which);
+ switch (name)
+ {
+ case "system":
+ callback.select(new SystemLayout());
+ break;
+ case "custom":
+ select_custom(callback, "");
+ break;
+ default:
+ callback.select(new NamedLayout(name));
+ break;
+ }
+ }
+ })
+ .show();
+ }
+
+ /** Dialog for specifying a custom layout. [initial_text] is the layout
+ description when modifying a layout. */
+ void select_custom(final SelectionCallback callback, String initial_text)
+ {
+ final EditText input = new EditText(getContext());
+ input.setText(initial_text);
+ AlertDialog.Builder dialog = new AlertDialog.Builder(getContext())
+ .setView(input)
+ .setTitle(R.string.pref_custom_layout_title)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){
+ public void onClick(DialogInterface _dialog, int _which)
+ {
+ callback.select(new CustomLayout(input.getText().toString()));
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null);
+ // Might be true when modifying an existing layout
+ if (callback.allow_remove() && _values.size() > 1)
+ dialog.setNeutralButton(R.string.pref_layouts_remove_custom, new DialogInterface.OnClickListener(){
+ public void onClick(DialogInterface _dialog, int _which)
+ {
+ callback.select(null);
+ }
+ });
+ dialog.show();
+ }
+
+ /** Called when modifying a layout. Custom layouts behave differently. */
+ @Override
+ void select(final SelectionCallback callback, Layout prev_layout)
+ {
+ if (prev_layout instanceof CustomLayout)
+ select_custom(callback, ((CustomLayout)prev_layout).xml);
+ else
+ select(callback);
+ }
+
+ class LayoutsAddButton extends AddButton
+ {
+ public LayoutsAddButton(Context ctx)
+ {
+ super(ctx);
+ setLayoutResource(R.layout.pref_layouts_add_btn);
+ }
+ }
+
+ /** A layout selected by the user. The only implementations are
+ [NamedLayout], [SystemLayout] and [CustomLayout]. */
+ interface Layout {}
+
+ static final class SystemLayout implements Layout
+ {
+ public SystemLayout() {}
+ }
+
+ /** The name of a layout defined in [res/xml]. */
+ static final class NamedLayout implements Layout
+ {
+ public final String name;
+ public NamedLayout(String n) { name = n; }
+ }
+
+ /** The XML description of a custom layout. */
+ static final class CustomLayout implements Layout
+ {
+ public final String xml;
+ public CustomLayout(String c) { xml = c; }
+ }
+
+ /** Named layouts are serialized to strings and custom layouts to JSON
+ objects with a [kind] field. */
+ static class Serializer implements ListGroupPreference.Serializer
+ {
+ public Layout load_item(Object obj) throws JSONException
+ {
+ if (obj instanceof String)
+ {
+ String name = (String)obj;
+ if (name.equals("system"))
+ return new SystemLayout();
+ return new NamedLayout(name);
+ }
+ JSONObject obj_ = (JSONObject)obj;
+ switch (obj_.getString("kind"))
+ {
+ case "custom": return new CustomLayout(obj_.getString("xml"));
+ case "system": default: return new SystemLayout();
+ }
+ }
+
+ public Object save_item(Layout v) throws JSONException
+ {
+ if (v instanceof NamedLayout)
+ return ((NamedLayout)v).name;
+ if (v instanceof CustomLayout)
+ return new JSONObject().put("kind", "custom")
+ .put("xml", ((CustomLayout)v).xml);
+ return new JSONObject().put("kind", "system");
+ }
+ }
+}
diff --git a/srcs/juloo.keyboard2/ListGroupPreference.java b/srcs/juloo.keyboard2/ListGroupPreference.java
new file mode 100644
index 000000000..075b38c3e
--- /dev/null
+++ b/srcs/juloo.keyboard2/ListGroupPreference.java
@@ -0,0 +1,293 @@
+package juloo.keyboard2;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.Preference;
+import android.preference.PreferenceGroup;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import java.util.ArrayList;
+import java.util.List;
+import org.json.JSONArray;
+import org.json.JSONException;
+
+/** A list of preferences where the users can add items to the end and modify
+ and remove items. Backed by a string list. Implement user selection in
+ [select()]. */
+public abstract class ListGroupPreference extends PreferenceGroup
+{
+ boolean _attached = false;
+ List _values;
+ /** The "add" button currently displayed. */
+ AddButton _add_button = null;
+
+ public ListGroupPreference(Context context, AttributeSet attrs)
+ {
+ super(context, attrs);
+ setOrderingAsAdded(true);
+ setLayoutResource(R.layout.pref_listgroup_group);
+ _values = new ArrayList();
+ }
+
+ /** Overrideable */
+
+ /** The label to display on the item for a given value. */
+ abstract String label_of_value(E value, int i);
+
+ /** Called every time the list changes and allows to change the "Add" button
+ appearance.
+ [prev_btn] is the previously attached button, might be null. */
+ AddButton on_attach_add_button(AddButton prev_btn)
+ {
+ if (prev_btn == null)
+ return new AddButton(getContext());
+ return prev_btn;
+ }
+
+ /** Called every time the list changes and allows to disable the "Remove"
+ buttons on every items. Might be used to enforce a minimum number of
+ items. */
+ boolean should_allow_remove_item(E _value)
+ {
+ return true;
+ }
+
+ /** Called when an item is added or modified. */
+ abstract void select(SelectionCallback callback);
+
+ /** Called when an item is modified. */
+ void select(SelectionCallback callback, E _old_value)
+ {
+ select(callback);
+ }
+
+ /** A separate class is used as the same serializer must be used in the
+ static context. See [Serializer] below. */
+ abstract Serializer get_serializer();
+
+ /** Load/save utils */
+
+ /** Read a value saved by preference from a [SharedPreferences] object.
+ [serializer] must be the same that is returned by [get_serializer()].
+ Returns [null] on error. */
+ static List load_from_preferences(String key,
+ SharedPreferences prefs, List def, Serializer serializer)
+ {
+ String s = prefs.getString(key, null);
+ return (s != null) ? load_from_string(s, serializer) : def;
+ }
+
+ /** Save items into the preferences. Does not call [prefs.commit()]. */
+ static void save_to_preferences(String key, SharedPreferences.Editor prefs, List items, Serializer serializer)
+ {
+ prefs.putString(key, save_to_string(items, serializer));
+ }
+
+ /** Decode a list of string previously encoded with [save_to_string]. Returns
+ [null] on error. */
+ static List load_from_string(String inp, Serializer serializer)
+ {
+ try
+ {
+ List l = new ArrayList();
+ JSONArray arr = new JSONArray(inp);
+ for (int i = 0; i < arr.length(); i++)
+ l.add(serializer.load_item(arr.get(i)));
+ return l;
+ }
+ catch (JSONException e)
+ {
+ Logs.exn("load_from_string", e);
+ return null;
+ }
+ }
+
+ /** Encode a list of string so it can be passed to
+ [Preference.persistString()]. Decode with [load_from_string]. */
+ static String save_to_string(List items, Serializer serializer)
+ {
+ List