Compare commits

..

9 Commits

Author SHA1 Message Date
Jules Aguillon
87da258c5b Fix margin calculation on Android 14
Some checks failed
Make Apk CI / Build-Apk (push) Has been cancelled
Check translations / check-translations (push) Has been cancelled
Check layouts / check_layout.output (push) Has been cancelled
Check layouts / Generated files (push) Has been cancelled
2024-12-26 18:10:02 +01:00
Jules Aguillon
dd99579a90 Comment 2024-12-26 17:42:57 +01:00
Jules Aguillon
cc3d2591a7 Simpler fix for the launcher activity 2024-12-26 17:36:25 +01:00
Jules Aguillon
ede983aef7 Implement for the settings activity 2024-12-26 17:25:30 +01:00
Jules Aguillon
d396af9240 Implement edge-to-edge for the launcher activity 2024-12-26 17:11:17 +01:00
Jules Aguillon
185ddcec60 Account for buttons in the gesture-navigation bar
Some checks are pending
Check layouts / check_layout.output (push) Waiting to run
Check layouts / Generated files (push) Waiting to run
Check translations / check-translations (push) Waiting to run
Make Apk CI / Build-Apk (push) Waiting to run
The back and IME switching buttons that appear in the navigation bar are
not accounted by WindowInsets and would overlap with the keyboard.
2024-12-26 13:41:06 +01:00
Jules Aguillon
f13af579c1 Allow keyboard to draw behind navigation bars 2024-12-26 13:37:05 +01:00
Jules Aguillon
da957d534b Keyboard doesn't draw behind button-navigation bars in landscape mode 2024-12-26 12:32:35 +01:00
Jules Aguillon
139ff760e0 Proper support for Android 15 edge-to-edge
The keyboard background now extends under the system bars and display
cutout but the keys do not.

This does not yet handle the gesture navigation bar changing height when
the IME dismiss and switch buttons are added.
2024-12-24 17:13:16 +01:00
133 changed files with 3401 additions and 4751 deletions

View File

@@ -13,7 +13,7 @@ jobs:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@v4 uses: actions/checkout@v4
- run: python3 gen_layouts.py - run: python3 gen_layouts.py
- name: "Run 'python3 gen_layouts.py' to update generated files" - name: "Check that the generated 'layouts.xml' is uptodate, otherwise run 'python3 gen_layouts.py'"
run: git diff --exit-code run: git diff --exit-code
check-layouts: check-layouts:
name: check_layout.output name: check_layout.output
@@ -22,5 +22,5 @@ jobs:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@v4 uses: actions/checkout@v4
- run: python3 check_layout.py - run: python3 check_layout.py
- name: "Fix your layout accordingly or run 'python3 check_layout.py' to promote the warnings" - name: "Check that the generated 'check_layout.output' is uptodate, otherwise run 'python3 check_layout.py'"
run: git diff --exit-code run: git diff --exit-code

1
.gitignore vendored
View File

@@ -10,4 +10,3 @@
/build /build
# Directory _build is not used anymore # Directory _build is not used anymore
/_build /_build
/release

Binary file not shown.

View File

@@ -12,10 +12,10 @@ android {
defaultConfig { defaultConfig {
applicationId "juloo.keyboard2" applicationId "juloo.keyboard2"
minSdk 21 minSdk 11
targetSdkVersion 35 targetSdkVersion 35
versionCode 46 versionCode 44
versionName "1.30.3" versionName "1.30.1"
} }
sourceSets { sourceSets {
@@ -134,8 +134,12 @@ tasks.register('genLayoutsList') {
tasks.register('checkKeyboardLayouts') { tasks.register('checkKeyboardLayouts') {
println "\nChecking layouts" println "\nChecking layouts"
exec { exec {
def layouts = new File(projectDir, "srcs/layouts").listFiles().findAll {
it.name.endsWith(".xml")
}
workingDir = projectDir workingDir = projectDir
commandLine("python", "check_layout.py") commandLine("python", "check_layout.py", *layouts)
standardOutput = new FileOutputStream("${projectDir}/check_layout.output")
} }
} }

View File

@@ -1,36 +1,185 @@
arab_alt: Layout includes some ASCII punctuation but not all, missing: !, ", ', +, -, /, :, ;, <, =, >, ?, [, \, ], _, |, ~ # arab_alt
arab_hamvaj_tly: Layout includes some ASCII punctuation but not all, missing: ", %, ', ,, /, ;, <, =, >, ?, [, \, ], _, `, {, |, } Layout includes some ASCII punctuation but not all, missing: !, ", ', +, -, /, :, ;, <, =, >, ?, [, \, ], _, |, ~
arab_pc: Layout includes some ASCII punctuation but not all, missing: !, ', +, ;, ?, \, | 1 warnings
arab_pc_ckb: Layout includes some ASCII punctuation but not all, missing: ", %, ', +, ,, ;, <, =, >, ?, `, |, ~ # arab_hamvaj_tly
arab_pc_ckb_fa: Layout includes some ASCII punctuation but not all, missing: ", #, $, %, &, ', ,, /, ;, ?, @, \, ^, `, |, ~ Layout includes some ASCII punctuation but not all, missing: ", %, ', ,, /, ;, <, =, >, ?, [, \, ], _, `, {, |, }
arab_pc_hindu: Layout includes some ASCII punctuation but not all, missing: !, ', +, ;, ?, \, | Layout doesn't define some important keys, missing: loc esc
arab_pc_ir: Layout includes some ASCII punctuation but not all, missing: ", %, ', ,, /, ;, <, =, >, ?, [, \, ], `, {, |, } 2 warnings
beng_national: Layout includes some ASCII punctuation but not all, missing: $ # arab_pc
beng_provat: Layout includes some ASCII punctuation but not all, missing: $, &, *, ., /, <, >, [, \, ], `, {, |, } Layout includes some ASCII punctuation but not all, missing: !, ', +, ;, ?, \, |
cyrl_yaverti: Layout includes some ASCII punctuation but not all, missing: ~ 1 warnings
cyrl_yqukeng_tj: These keys are now added automatically, unexpected: f11_placeholder, f12_placeholder # arab_pc_ckb
cyrl_yxukeng_os: Layout includes some ASCII punctuation but not all, missing: ", #, $, &, ', @, [, ], ~ Layout includes some ASCII punctuation but not all, missing: ", %, ', +, ,, ;, <, =, >, ?, `, |, ~
cyrl_yxukeng_os: These keys are now added automatically, unexpected: f11_placeholder, f12_placeholder 1 warnings
deva_alt: Layout includes some ASCII punctuation but not all, missing: #, $, %, &, ', (, ), *, +, ., /, :, <, =, >, [, \, ], ^, _, `, {, |, }, ~ # arab_pc_ckb_fa
deva_alt: Layout doesn't define some important keys, missing: delete Layout includes some ASCII punctuation but not all, missing: ", #, $, %, &, ', ,, /, ;, ?, @, \, ^, `, |, ~
deva_inscript: Duplicate keys: । Layout doesn't define some important keys, missing: loc esc, loc tab
deva_inscript: Layout includes some ASCII punctuation but not all, missing: ", $, ', ^, _, `, | 2 warnings
deva_phonetic_in: Duplicate keys: ट # arab_pc_hindu
grek_qwerty: Duplicate keys: ; Layout includes some ASCII punctuation but not all, missing: !, ', +, ;, ?, \, |
guj_phonetic_in: Duplicate keys: ટ, ડ 1 warnings
hebr_1_il: Layout includes some ASCII punctuation but not all, missing: (, ), <, >, [, ], {, } # arab_pc_ir
hebr_2_il: Layout includes some ASCII punctuation but not all, missing: (, ), <, >, [, ], {, } Layout includes some ASCII punctuation but not all, missing: ", %, ', ,, /, ;, <, =, >, ?, [, \, ], `, {, |, }
kann_kannada: Layout includes some ASCII punctuation but not all, missing: #, $, %, (, ), *, +, /, <, =, >, [, \, ], ^, `, {, |, }, ~ 1 warnings
latn_bepo_fr: Missing important key, missing: loc capslock # armenian_ph_am
latn_bone: Missing important key, missing: loc capslock 0 warnings
latn_colemak: Some keys contain whitespaces, unexpected: ́ # beng_national
latn_dvorak: Missing important key, missing: loc capslock Layout includes some ASCII punctuation but not all, missing: $
latn_neo2: Layout redefines the bottom row but some important keys are missing, missing: loc switch_clipboard 1 warnings
latn_qwerty_se: Duplicate keys: !, ', ,, -, ., ? # beng_provat
latn_qwerty_tly: Duplicate keys: a, c, j, q Layout includes some ASCII punctuation but not all, missing: $, &, *, ., /, <, >, [, \, ], `, {, |, }
latn_qwerty_tly: Missing programming keys, missing: loc esc, loc tab 1 warnings
latn_qwertz_cz_multifunctional: Layout includes some ASCII punctuation but not all, missing: ` # cyrl_jcuken_kk
latn_qwertz_sk: Layout includes some ASCII punctuation but not all, missing: ` 0 warnings
urdu_phonetic_ur: Duplicate keys: # cyrl_jcuken_ru
urdu_phonetic_ur: Layout includes some ASCII punctuation but not all, missing: <, >, ?, `, |, ~ 0 warnings
urdu_phonetic_ur: Some keys contain whitespaces, unexpected: # cyrl_jcuken_uk
0 warnings
# cyrl_lynyertz_sr
0 warnings
# cyrl_ueishsht
0 warnings
# cyrl_yaverti
Layout includes some ASCII punctuation but not all, missing: ~
1 warnings
# cyrl_yqukeng_tj
Layout doesn't define some important keys, missing: loc esc, loc tab
These keys are now added automatically, unexpected: f11_placeholder, f12_placeholder
2 warnings
# cyrl_yxukeng_os
Layout includes some ASCII punctuation but not all, missing: ", #, $, &, ', @, [, ], ~
Layout doesn't define some important keys, missing: loc esc, loc tab
These keys are now added automatically, unexpected: f11_placeholder, f12_placeholder
3 warnings
# deva_alt
Layout includes some ASCII punctuation but not all, missing: #, $, %, &, ', (, ), +, ., /, :, <, =, >, [, \, ], ^, _, `, {, |, }, ~
Layout doesn't define some important keys, missing: loc esc, loc tab
2 warnings
# deva_inscript
Duplicate keys: ।
Layout includes some ASCII punctuation but not all, missing: ", $, ', ^, _, `, |
2 warnings
# deva_phonetic_in
Duplicate keys: ट
1 warnings
# georgian_mes
0 warnings
# georgian_qwerty
0 warnings
# grek_qwerty
Duplicate keys: ;
1 warnings
# guj_phonetic_in
Duplicate keys: ટ, ડ
1 warnings
# hang_dubeolsik_kr
Layout doesn't define some important keys, missing: loc esc, loc tab
1 warnings
# hebr_1_il
Layout includes some ASCII punctuation but not all, missing: (, ), <, >, [, ], {, }
1 warnings
# hebr_2_il
Layout includes some ASCII punctuation but not all, missing: (, ), <, >, [, ], {, }
1 warnings
# kann_kannada
Layout includes some ASCII punctuation but not all, missing: #, $, %, (, ), *, +, /, <, =, >, [, \, ], ^, `, {, |, }, ~
Layout doesn't define some important keys, missing: loc esc, loc tab
2 warnings
# latn_azerty_be
0 warnings
# latn_azerty_fr
0 warnings
# latn_bepo_fr
0 warnings
# latn_bone
Layout doesn't define some important keys, missing: loc esc, loc tab
Layout redefines the bottom row but some important keys are missing, missing: cursor_left, cursor_right, loc compose, loc end, loc home, loc page_down, loc page_up, loc switch_clipboard, loc switch_greekmath, loc voice_typing, switch_backward
2 warnings
# latn_colemak
Some keys contain whitespaces, unexpected: ́
1 warnings
# latn_dvorak
0 warnings
# latn_neo2
Layout redefines the bottom row but some important keys are missing, missing: loc switch_clipboard
1 warnings
# latn_qwerty_br
0 warnings
# latn_qwerty_cy
0 warnings
# latn_qwerty_cz
0 warnings
# latn_qwerty_da
0 warnings
# latn_qwerty_es
0 warnings
# latn_qwerty_et
0 warnings
# latn_qwerty_ga
0 warnings
# latn_qwerty_gb
0 warnings
# latn_qwerty_haw
0 warnings
# latn_qwerty_hu
0 warnings
# latn_qwerty_jp
0 warnings
# latn_qwerty_kk
0 warnings
# latn_qwerty_lv
0 warnings
# latn_qwerty_no
0 warnings
# latn_qwerty_pl
0 warnings
# latn_qwerty_ro
0 warnings
# latn_qwerty_se
Duplicate keys: !, ', ,, -, ., ?
1 warnings
# latn_qwerty_sk
0 warnings
# latn_qwerty_sr
0 warnings
# latn_qwerty_tly
Duplicate keys: a, c, j, q
Layout doesn't define some important keys, missing: loc esc, loc tab
2 warnings
# latn_qwerty_tr
0 warnings
# latn_qwerty_us
0 warnings
# latn_qwerty_vi
0 warnings
# latn_qwertz
0 warnings
# latn_qwertz_cz
0 warnings
# latn_qwertz_cz_diacritics
0 warnings
# latn_qwertz_cz_multifunctional
Layout includes some ASCII punctuation but not all, missing: `
1 warnings
# latn_qwertz_de
0 warnings
# latn_qwertz_fr_ch
0 warnings
# latn_qwertz_hu
0 warnings
# latn_qwertz_sk
Layout includes some ASCII punctuation but not all, missing: `
1 warnings
# latn_qwertz_sq
0 warnings
# latn_workman_us
0 warnings
# shaw_imperial_en
0 warnings
# tamil_default
0 warnings
# urdu_phonetic_ur
Duplicate keys:
Layout includes some ASCII punctuation but not all, missing: <, >, ?, `, |, ~
Some keys contain whitespaces, unexpected:
3 warnings

View File

@@ -1,8 +1,7 @@
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
import sys, os, glob import sys, os
layout_file_name = 0 warning_count = 0
warnings = []
KNOWN_NOT_LAYOUT = set([ KNOWN_NOT_LAYOUT = set([
"number_row", "numpad", "pin", "number_row", "numpad", "pin",
@@ -16,8 +15,9 @@ KEY_ATTRIBUTES = set([
]) ])
def warn(msg): def warn(msg):
global warnings global warning_count
warnings.append("%s: %s" % (layout_file_name, msg)) print(msg)
warning_count += 1
def key_list_str(keys): def key_list_str(keys):
return ", ".join(sorted(list(keys))) return ", ".join(sorted(list(keys)))
@@ -73,7 +73,9 @@ def check_layout(layout):
if len(dup) > 0: warn("Duplicate keys: " + key_list_str(dup)) if len(dup) > 0: warn("Duplicate keys: " + key_list_str(dup))
missing_some_of(keys, "~!@#$%^&*(){}`[]=\\-_;:/.,?<>'\"+|", "ASCII punctuation") missing_some_of(keys, "~!@#$%^&*(){}`[]=\\-_;:/.,?<>'\"+|", "ASCII punctuation")
missing_some_of(keys, "0123456789", "digits") missing_some_of(keys, "0123456789", "digits")
missing_required(keys, ["backspace", "delete"], "Layout doesn't define some important keys") missing_required(keys,
["loc esc", "loc tab", "backspace", "delete"],
"Layout doesn't define some important keys")
unexpected_keys(keys, unexpected_keys(keys,
["copy", "paste", "cut", "selectAll", "shareText", ["copy", "paste", "cut", "selectAll", "shareText",
"pasteAsPlainText", "undo", "redo" ], "pasteAsPlainText", "undo", "redo" ],
@@ -87,10 +89,6 @@ def check_layout(layout):
unexpected_keys(keys, filter(lambda k: k.strip()!=k, keys), "Some keys contain whitespaces") unexpected_keys(keys, filter(lambda k: k.strip()!=k, keys), "Some keys contain whitespaces")
unexpected_keys(keys, ["f11_placeholder", "f12_placeholder"], "These keys are now added automatically") unexpected_keys(keys, ["f11_placeholder", "f12_placeholder"], "These keys are now added automatically")
if root.get("script", "latin") == "latin":
missing_required(keys, ["shift", "loc capslock"], "Missing important key")
missing_required(keys, ["loc esc", "loc tab"], "Missing programming keys")
_, bottom_row_keys, _ = parse_row("res/xml/bottom_row.xml") _, bottom_row_keys, _ = parse_row("res/xml/bottom_row.xml")
if root.get("bottom_row") == "false": if root.get("bottom_row") == "false":
@@ -103,17 +101,15 @@ def check_layout(layout):
if root.get("script") == None: if root.get("script") == None:
warn("Layout doesn't specify a script.") warn("Layout doesn't specify a script.")
for fname in sorted(glob.glob("srcs/layouts/*.xml")): for fname in sorted(sys.argv[1:]):
layout_id, _ = os.path.splitext(os.path.basename(fname)) layout_id, _ = os.path.splitext(os.path.basename(fname))
if layout_id in KNOWN_NOT_LAYOUT: if layout_id in KNOWN_NOT_LAYOUT:
continue continue
layout_file_name = layout_id
layout = parse_layout(fname) layout = parse_layout(fname)
if layout == None: if layout == None:
warn("Not a layout file") print("Not a layout file: %s" % layout_id)
else: else:
print("# %s" % layout_id)
warning_count = 0
check_layout(layout) check_layout(layout)
print("%d warnings" % warning_count)
with open("check_layout.output", "w") as out:
for w in warnings:
print(w, file=out)

View File

@@ -47,8 +47,6 @@ The `<keyboard>`...`</keyboard>` pair follows the declaration tag and encloses t
+ We recommend your layout use the built-in bottom row, because it is still evolving and your layout will incorporate innovations in future versions. However, to define your own, the current definition of the bottom row is in [bottom_row.xml](https://github.com/Julow/Unexpected-Keyboard/res/xml/bottom_row.xml). You can copypaste this XML into your custom layout as a starting point. + We recommend your layout use the built-in bottom row, because it is still evolving and your layout will incorporate innovations in future versions. However, to define your own, the current definition of the bottom row is in [bottom_row.xml](https://github.com/Julow/Unexpected-Keyboard/res/xml/bottom_row.xml). You can copypaste this XML into your custom layout as a starting point.
+ Likewise, the current definition of the top (number) row is in [number_row.xml](https://github.com/Julow/Unexpected-Keyboard/res/xml/number_row.xml). + Likewise, the current definition of the top (number) row is in [number_row.xml](https://github.com/Julow/Unexpected-Keyboard/res/xml/number_row.xml).
* `embedded_number_row`: Whether the layout has an embedded number row, and thus the "Show number row" setting shouldn't add another one. It accepts `true` or `false`, and defaults to `false`.
* `locale_extra_keys`: Whether Unexpected should add language-dependent extra keys from [method.xml](../res/xml/method.xml) to this layout. It accepts `true` or `false`, and defaults to `true`. To disable these automatic additions, specify `locale_extra_keys="false"`. * `locale_extra_keys`: Whether Unexpected should add language-dependent extra keys from [method.xml](../res/xml/method.xml) to this layout. It accepts `true` or `false`, and defaults to `true`. To disable these automatic additions, specify `locale_extra_keys="false"`.
## Row ## Row
@@ -95,6 +93,7 @@ The following optional properties define the effects of swipes:
You can define a swipe only once with either compass-point or numeric notation. Unexpected Keyboard automatically puts a small legend in that direction from the center of the key. You can define a swipe only once with either compass-point or numeric notation. Unexpected Keyboard automatically puts a small legend in that direction from the center of the key.
* `slider`: If `slider="true"`, and the key also has `w` and `e` properties, then the key tracks horizontal finger motion precisely and sends the `w` and `e` keystrokes repeatedly. In built-in layouts, this makes the space bar send left and right characters as the user slides on the space bar.
* `anticircle`: The key value to send when doing an anti-clockwise gesture on the key. * `anticircle`: The key value to send when doing an anti-clockwise gesture on the key.
### Layout ### Layout

View File

@@ -1,74 +1,43 @@
# Key values # Key values
A key value defines what a key on the keyboard does when pressed or swiped. This is an exhaustive list of special values accepted for the `key0` through `key8` or `nw` through `se` attributes on a key.
Key values appear in the following places: Any string that does not exactly match these will be printed verbatim.
A key can output multiple characters, but cannot combine multiple built-in key values.
- In custom layouts, they are the value of: the `c` attribute, the compass-point attributes `nw` ... `se`, and the old-style `key0` ... `key8` attributes. ## Escape codes
- Internally, they are used in the definition of the "Add keys to the keyboard" setting. Value | Escape code for
Key values can be any of the following:
- The name of a special key. A complete list of valid special keys follows.
- An arbitrary sequence of characters not containing `:`.
This results in a key that writes the specified characters.
- The syntax `legend:key_def`.
`legend` is the visible legend on the keyboard. It cannot contain `:`.
`key_def` can be:
+ The name of a special key, as listed below.
+ `'string'` An arbitrary string that can contain `:`. `'` can be added to the string as `` \' ``.
+ `keyevent:keycode` An Android keycode. They are listed as `KEYCODE_...` in [KeyEvent](https://developer.android.com/reference/android/view/KeyEvent#summary).
Examples:
+ `⏯:keyevent:85` A play/pause key (which has no effect in most apps).
+ `my@:'my.email@domain.com'` A key that sends an arbitrary string
- A macro, `legend:key_def1,key_def2,...`.
This results in a key with legend `legend` that behaves as if the sequence of `key_def` had been pressed in order.
Examples:
+ `CA:ctrl,a,ctrl,c` A key with legend CA that sends the sequence `ctrl+a`, `ctrl+c`.
+ `Cd:ctrl,backspace` A key with legend Cd that sends the shortcut `ctrl+backspace`.
### Escape codes
When defining a key value, several characters have special effects. If you want a character not to have its usual effect but to be taken literally, you should "escape" it in the usual way for XML:
To get this character... | ...you can type
:---- | :------ :---- | :------
A literal newline character, which is different from `enter` and `action` in certain apps. | `\n` `\?` | `?`
A literal tab character, which is different from `tab` in certain apps. | `\t` `\#` | `#`
`\` | `\\` `\@` | `@`
`&` | `&amp;` `\n` | Literal newline character. This is different from `enter` and `action` in certain apps.
`<` | `&lt;` `\t` | Literal tab character. This is different from `tab` in certain apps.
`>` | `&gt;` `\\` | `\`
`"` | `&quot;`
The characters `?`, `#`, and `@` do not need to be escaped when writing custom layouts. Internally, they can be escaped by prepending backslash (by typing `\?`, `\#`, and `\@`). XML escape codes also work, including:
The characters `,` and `:` can be escaped in a key value, using single quotes. For example, this macro defines a key with legend `http` that sends a string containing `:`: `<key c="http:home,'https://'" />` For simplicity, `,` and `:` cannot be escaped in the key legend. Value | Escape code for
:------- | :------
`&amp;` | `&`
`&lt;` | `<`
`&gt;` | `>`
`&quot;` | `"`
## Modifiers ## Modifiers
System modifiers are sent to the app, which can take app-specific action. System modifiers are sent to the app, which is free to do whatever they want in response.
The other modifiers only exist within the keyboard.
Value | Meaning Value | Meaning
:---------- | :------ :---------- | :------
`shift` | System modifier. `shift` | System modifier.
`ctrl` | System modifier. `ctrl` | System modifier.
`alt` | System modifier. `alt` | System modifier.
`meta` | System modifier. Equivalent to the Windows key. `meta` | System modifier. Equivalent to the Windows key.
`fn` | Activates Fn mode, which assigns letters and symbols to special characters. e.g. `fn` `!` = `¡`
`compose` | Compose key. Enables composing characters using Linux-like shortcuts; e.g. `Compose` `A` `single quote` types `Á` (A with acute accent).
`capslock` | Actives and locks Shift
The other modifiers take effect only within the keyboard. ## Special keys
Value | Meaning
:---------- | :------
`fn` | Activates Fn mode, which assigns letters and symbols to special characters. Example: `fn` `!` = `¡`
`compose` | Compose key. Enables composing characters using Linux-like shortcuts. Example: `Compose` `A` `'` types `Á` (A with acute accent).
`capslock` | Activates and locks Shift.
## App function keys
These keys are sent to apps, which are free to ignore them. The keyboard does not perform editing in response to these keys. These keys are sent to apps, which are free to ignore them. The keyboard does not perform editing in response to these keys.
`esc`, `enter`, `esc`, `enter`,
@@ -84,17 +53,6 @@ These keys are sent to apps, which are free to ignore them. The keyboard does no
`selectAll`, `pasteAsPlainText`, `selectAll`, `pasteAsPlainText`,
`undo`, `redo` `undo`, `redo`
## Keyboard editing actions
In contrast, these keys perform editing on the text without sending anything to the app.
Value | Meaning
:-------------------- | :------
`cursor_left` | Moves the cursor to the left with the slider gesture.
`cursor_right` | Moves the cursor to the right with the slider gesture.
`cursor_up` | Moves the cursor up with the slider gesture. Warning: this might make the cursor leave the text box.
`cursor_down` | Moves the cursor down with the slider gesture. Warning: this might make the cursor leave the text box.
`delete_word` | Delete the word to the left of the cursor.
`forward_delete_word` | Delete the word to the right of the cursor.
## Whitespace ## Whitespace
Value | Meaning Value | Meaning
:------ | :------ :------ | :------
@@ -104,6 +62,13 @@ Value | Meaning
`zwj` | Zero-width joiner. `zwj` | Zero-width joiner.
`zwnj` | Zero-width non-joiner. `zwnj` | Zero-width non-joiner.
## Keyboard editing actions
These keys perform editing on the text without sending keys that the app can interpret differently or ignore.
Value | Meaning
:----------------- | :------
`cursor_left` | Moves the cursor position to the left directly, without sending a `left` key event.
`cursor_right` | Moves the cursor position to the right directly, without sending a `right` key event.
## Other modifiers and diacritics ## Other modifiers and diacritics
Value | Meaning Value | Meaning
:------------------- | :------ :------------------- | :------
@@ -185,3 +150,50 @@ These keys are known to do nothing.
These keys are normally hidden unless the Fn modifier is activated. These keys are normally hidden unless the Fn modifier is activated.
`f11_placeholder` | `f12_placeholder` `f11_placeholder` | `f12_placeholder`
## Complex keys
More complex keys are of this form:
```
:<kind> <attributes>:<payload>
```
Where `<kind>` is one of the kinds documented below and `<attributes>` is a
space separated list of attributes. `<payload>` depends on the `<kind>`.
Attributes are:
- `symbol='Sym'` specifies the symbol to be shown on the keyboard.
- `flags='<flags>'` changes the behavior of the key.
`<flags>` is a coma separated list of:
+ `dim`: Make the symbol dimmer.
+ `small`: Make the symbol smaller.
### Kind `str`
Defines a key that outputs an arbitrary string. `<payload>` is a string wrapped
in single-quotes (`'`), escaping of other single quotes is allowed with `\'`.
For example:
- `:str:'Arbitrary string with a \' inside'`
- `:str symbol='Symbol':'Output string'`
### Kind `char`
Defines a key that outputs a single character. `<payload>` is the character to
output, unquoted.
This kind of key can be used to define a character key with a different symbol
on it. `char` keys can be modified by `ctrl` and other modifiers, unlike `str`
keys.
For example:
- `:char symbol='љ':q`, which is used to implement `ctrl` shortcuts in cyrillic
layouts.
### Kind `keyevent`
Defines a key that sends an Android [key event](https://developer.android.com/reference/android/view/KeyEvent).
`<payload>` is the key event number.
For example:
- `:keyevent symbol='⏯' flags='small':85`

View File

@@ -1 +0,0 @@
Bug fixes

View File

@@ -1 +0,0 @@
Bug fixes

View File

@@ -122,17 +122,8 @@ Tato aplikace neobsahuje žádné reklamy, nevyužívá připojení k síti a je
<string name="key_descr_end">End</string> <string name="key_descr_end">End</string>
<string name="key_descr_clipboard">Správce schránky</string> <string name="key_descr_clipboard">Správce schránky</string>
<!-- <string name="key_descr_combining">Combining diacritic</string> --> <!-- <string name="key_descr_combining">Combining diacritic</string> -->
<!-- <string name="key_descr_dead_key">Dead key</string> -->
<!-- <string name="key_descr_zwj">Zero width joiner</string> -->
<!-- <string name="key_descr_zwnj">Zero width non-joiner</string> -->
<!-- <string name="key_descr_nbsp">Non-breaking space</string> -->
<!-- <string name="key_descr_nnbsp">Narrow non-breaking space</string> -->
<!-- <string name="key_descr_delete_word">Delete a word</string> -->
<!-- <string name="key_descr_forward_delete_word">Delete a word on the right</string> -->
<!-- <string name="key_descr_gesture">Gesture</string> -->
<string name="clipboard_history_heading">Nedávno kopírovaný text</string> <string name="clipboard_history_heading">Nedávno kopírovaný text</string>
<string name="clipboard_pin_heading">Připnout</string> <string name="clipboard_pin_heading">Připnout</string>
<string name="clipboard_remove_confirm">Odebrat ze schránky?</string> <string name="clipboard_remove_confirm">Odebrat ze schránky?</string>
<string name="clipboard_remove_confirmed">Ano</string> <string name="clipboard_remove_confirmed">Ano</string>
<!-- <string name="toast_no_voice_input">No voice typing app installed</string> -->
</resources> </resources>

View File

@@ -122,17 +122,8 @@ Diese App enthält keine Werbung, benötigt keinen Netzwerkzugriff und ist quell
<string name="key_descr_end">Ende</string> <string name="key_descr_end">Ende</string>
<string name="key_descr_clipboard">Clipboard-Manager</string> <string name="key_descr_clipboard">Clipboard-Manager</string>
<!-- <string name="key_descr_combining">Combining diacritic</string> --> <!-- <string name="key_descr_combining">Combining diacritic</string> -->
<!-- <string name="key_descr_dead_key">Dead key</string> -->
<!-- <string name="key_descr_zwj">Zero width joiner</string> -->
<!-- <string name="key_descr_zwnj">Zero width non-joiner</string> -->
<!-- <string name="key_descr_nbsp">Non-breaking space</string> -->
<!-- <string name="key_descr_nnbsp">Narrow non-breaking space</string> -->
<!-- <string name="key_descr_delete_word">Delete a word</string> -->
<!-- <string name="key_descr_forward_delete_word">Delete a word on the right</string> -->
<!-- <string name="key_descr_gesture">Gesture</string> -->
<string name="clipboard_history_heading">Zuletzt kopierter Text</string> <string name="clipboard_history_heading">Zuletzt kopierter Text</string>
<string name="clipboard_pin_heading">Angeheftet</string> <string name="clipboard_pin_heading">Angeheftet</string>
<string name="clipboard_remove_confirm">Aus der Zwischenablage entfernen?</string> <string name="clipboard_remove_confirm">Aus der Zwischenablage entfernen?</string>
<string name="clipboard_remove_confirmed">Ja</string> <string name="clipboard_remove_confirmed">Ja</string>
<!-- <string name="toast_no_voice_input">No voice typing app installed</string> -->
</resources> </resources>

View File

@@ -122,17 +122,8 @@ La misma no contiene ningún anuncio/publicidad, no realiza peticiones de red y
<string name="key_descr_end">Fin</string> <string name="key_descr_end">Fin</string>
<string name="key_descr_clipboard">Arreglar portapapeles</string> <string name="key_descr_clipboard">Arreglar portapapeles</string>
<!-- <string name="key_descr_combining">Combining diacritic</string> --> <!-- <string name="key_descr_combining">Combining diacritic</string> -->
<!-- <string name="key_descr_dead_key">Dead key</string> -->
<!-- <string name="key_descr_zwj">Zero width joiner</string> -->
<!-- <string name="key_descr_zwnj">Zero width non-joiner</string> -->
<!-- <string name="key_descr_nbsp">Non-breaking space</string> -->
<!-- <string name="key_descr_nnbsp">Narrow non-breaking space</string> -->
<!-- <string name="key_descr_delete_word">Delete a word</string> -->
<!-- <string name="key_descr_forward_delete_word">Delete a word on the right</string> -->
<!-- <string name="key_descr_gesture">Gesture</string> -->
<string name="clipboard_history_heading">Textos recién copiados</string> <string name="clipboard_history_heading">Textos recién copiados</string>
<string name="clipboard_pin_heading">Pegado</string> <string name="clipboard_pin_heading">Pegado</string>
<string name="clipboard_remove_confirm">¿Sacar este portapapeles?</string> <string name="clipboard_remove_confirm">¿Sacar este portapapeles?</string>
<string name="clipboard_remove_confirmed"></string> <string name="clipboard_remove_confirmed"></string>
<!-- <string name="toast_no_voice_input">No voice typing app installed</string> -->
</resources> </resources>

View File

@@ -122,17 +122,8 @@ This application contains no ads, doesn't make any network requests and is Open
<!-- <string name="key_descr_end">End</string> --> <!-- <string name="key_descr_end">End</string> -->
<!-- <string name="key_descr_clipboard">Clipboard manager</string> --> <!-- <string name="key_descr_clipboard">Clipboard manager</string> -->
<!-- <string name="key_descr_combining">Combining diacritic</string> --> <!-- <string name="key_descr_combining">Combining diacritic</string> -->
<!-- <string name="key_descr_dead_key">Dead key</string> -->
<!-- <string name="key_descr_zwj">Zero width joiner</string> -->
<!-- <string name="key_descr_zwnj">Zero width non-joiner</string> -->
<!-- <string name="key_descr_nbsp">Non-breaking space</string> -->
<!-- <string name="key_descr_nnbsp">Narrow non-breaking space</string> -->
<!-- <string name="key_descr_delete_word">Delete a word</string> -->
<!-- <string name="key_descr_forward_delete_word">Delete a word on the right</string> -->
<!-- <string name="key_descr_gesture">Gesture</string> -->
<!-- <string name="clipboard_history_heading">Recently copied text</string> --> <!-- <string name="clipboard_history_heading">Recently copied text</string> -->
<!-- <string name="clipboard_pin_heading">Pinned</string> --> <!-- <string name="clipboard_pin_heading">Pinned</string> -->
<!-- <string name="clipboard_remove_confirm">Remove this clipboard?</string> --> <!-- <string name="clipboard_remove_confirm">Remove this clipboard?</string> -->
<!-- <string name="clipboard_remove_confirmed">Yes</string> --> <!-- <string name="clipboard_remove_confirmed">Yes</string> -->
<!-- <string name="toast_no_voice_input">No voice typing app installed</string> -->
</resources> </resources>

View File

@@ -122,17 +122,8 @@ Cette application ne contient pas de publicité, n'accède pas au réseau et est
<string name="key_descr_end">Fin</string> <string name="key_descr_end">Fin</string>
<string name="key_descr_clipboard">Presse-papiers</string> <string name="key_descr_clipboard">Presse-papiers</string>
<!-- <string name="key_descr_combining">Combining diacritic</string> --> <!-- <string name="key_descr_combining">Combining diacritic</string> -->
<!-- <string name="key_descr_dead_key">Dead key</string> -->
<!-- <string name="key_descr_zwj">Zero width joiner</string> -->
<!-- <string name="key_descr_zwnj">Zero width non-joiner</string> -->
<!-- <string name="key_descr_nbsp">Non-breaking space</string> -->
<!-- <string name="key_descr_nnbsp">Narrow non-breaking space</string> -->
<!-- <string name="key_descr_delete_word">Delete a word</string> -->
<!-- <string name="key_descr_forward_delete_word">Delete a word on the right</string> -->
<!-- <string name="key_descr_gesture">Gesture</string> -->
<string name="clipboard_history_heading">Texte récemment copié</string> <string name="clipboard_history_heading">Texte récemment copié</string>
<string name="clipboard_pin_heading">Épinglé</string> <string name="clipboard_pin_heading">Épinglé</string>
<string name="clipboard_remove_confirm">Supprimer ce presse-papiers ?</string> <string name="clipboard_remove_confirm">Supprimer ce presse-papiers ?</string>
<string name="clipboard_remove_confirmed">Oui</string> <string name="clipboard_remove_confirmed">Oui</string>
<!-- <string name="toast_no_voice_input">No voice typing app installed</string> -->
</resources> </resources>

View File

@@ -122,17 +122,8 @@ This application contains no ads, doesn't make any network requests and is Open
<!-- <string name="key_descr_end">End</string> --> <!-- <string name="key_descr_end">End</string> -->
<!-- <string name="key_descr_clipboard">Clipboard manager</string> --> <!-- <string name="key_descr_clipboard">Clipboard manager</string> -->
<!-- <string name="key_descr_combining">Combining diacritic</string> --> <!-- <string name="key_descr_combining">Combining diacritic</string> -->
<!-- <string name="key_descr_dead_key">Dead key</string> -->
<!-- <string name="key_descr_zwj">Zero width joiner</string> -->
<!-- <string name="key_descr_zwnj">Zero width non-joiner</string> -->
<!-- <string name="key_descr_nbsp">Non-breaking space</string> -->
<!-- <string name="key_descr_nnbsp">Narrow non-breaking space</string> -->
<!-- <string name="key_descr_delete_word">Delete a word</string> -->
<!-- <string name="key_descr_forward_delete_word">Delete a word on the right</string> -->
<!-- <string name="key_descr_gesture">Gesture</string> -->
<!-- <string name="clipboard_history_heading">Recently copied text</string> --> <!-- <string name="clipboard_history_heading">Recently copied text</string> -->
<!-- <string name="clipboard_pin_heading">Pinned</string> --> <!-- <string name="clipboard_pin_heading">Pinned</string> -->
<!-- <string name="clipboard_remove_confirm">Remove this clipboard?</string> --> <!-- <string name="clipboard_remove_confirm">Remove this clipboard?</string> -->
<!-- <string name="clipboard_remove_confirmed">Yes</string> --> <!-- <string name="clipboard_remove_confirmed">Yes</string> -->
<!-- <string name="toast_no_voice_input">No voice typing app installed</string> -->
</resources> </resources>

View File

@@ -123,17 +123,8 @@ PCキーボードでの半角入力を再現しています。日本語入力、
<string name="key_descr_end">End</string> <string name="key_descr_end">End</string>
<string name="key_descr_clipboard">クリップボード</string> <string name="key_descr_clipboard">クリップボード</string>
<!-- <string name="key_descr_combining">Combining diacritic</string> --> <!-- <string name="key_descr_combining">Combining diacritic</string> -->
<!-- <string name="key_descr_dead_key">Dead key</string> -->
<!-- <string name="key_descr_zwj">Zero width joiner</string> -->
<!-- <string name="key_descr_zwnj">Zero width non-joiner</string> -->
<!-- <string name="key_descr_nbsp">Non-breaking space</string> -->
<!-- <string name="key_descr_nnbsp">Narrow non-breaking space</string> -->
<!-- <string name="key_descr_delete_word">Delete a word</string> -->
<!-- <string name="key_descr_forward_delete_word">Delete a word on the right</string> -->
<!-- <string name="key_descr_gesture">Gesture</string> -->
<string name="clipboard_history_heading">最近コピーしたテキスト</string> <string name="clipboard_history_heading">最近コピーしたテキスト</string>
<string name="clipboard_pin_heading">お気に入り</string> <string name="clipboard_pin_heading">お気に入り</string>
<string name="clipboard_remove_confirm">クリップボードから削除しますか?</string> <string name="clipboard_remove_confirm">クリップボードから削除しますか?</string>
<string name="clipboard_remove_confirmed">はい</string> <string name="clipboard_remove_confirmed">はい</string>
<!-- <string name="toast_no_voice_input">No voice typing app installed</string> -->
</resources> </resources>

View File

@@ -122,17 +122,8 @@
<string name="key_descr_end">종료</string> <string name="key_descr_end">종료</string>
<string name="key_descr_clipboard">클립보드 관리자</string> <string name="key_descr_clipboard">클립보드 관리자</string>
<!-- <string name="key_descr_combining">Combining diacritic</string> --> <!-- <string name="key_descr_combining">Combining diacritic</string> -->
<!-- <string name="key_descr_dead_key">Dead key</string> -->
<!-- <string name="key_descr_zwj">Zero width joiner</string> -->
<!-- <string name="key_descr_zwnj">Zero width non-joiner</string> -->
<!-- <string name="key_descr_nbsp">Non-breaking space</string> -->
<!-- <string name="key_descr_nnbsp">Narrow non-breaking space</string> -->
<!-- <string name="key_descr_delete_word">Delete a word</string> -->
<!-- <string name="key_descr_forward_delete_word">Delete a word on the right</string> -->
<!-- <string name="key_descr_gesture">Gesture</string> -->
<string name="clipboard_history_heading">최근에 복사한 텍스트</string> <string name="clipboard_history_heading">최근에 복사한 텍스트</string>
<string name="clipboard_pin_heading">고정</string> <string name="clipboard_pin_heading">고정</string>
<string name="clipboard_remove_confirm">이 클립보드를 제거하시겠습니까?</string> <string name="clipboard_remove_confirm">이 클립보드를 제거하시겠습니까?</string>
<string name="clipboard_remove_confirmed"></string> <string name="clipboard_remove_confirmed"></string>
<!-- <string name="toast_no_voice_input">No voice typing app installed</string> -->
</resources> </resources>

View File

@@ -38,7 +38,7 @@ Tagad lieliski piemērota izmantošanai ikdienā.
<string name="pref_category_typing">Rakstīšana</string> <string name="pref_category_typing">Rakstīšana</string>
<string name="pref_swipe_dist_title">Pavilkšanas attālums</string> <string name="pref_swipe_dist_title">Pavilkšanas attālums</string>
<string name="pref_swipe_dist_summary">Taustiņu stūros esošo rakstzīmju attālums (%s)</string> <string name="pref_swipe_dist_summary">Taustiņu stūros esošo rakstzīmju attālums (%s)</string>
<string name="pref_long_timeout_title">Ilgas piespiešanas noildze</string> <string name="pref_long_timeout_title">Ilgas piepiešanas noildze</string>
<string name="pref_long_interval_title">Taustiņa atkārtošanās aizture</string> <string name="pref_long_interval_title">Taustiņa atkārtošanās aizture</string>
<string name="pref_keyrepeat_enabled">Taustiņa atkārtošanās ar ilgu piespiešanu</string> <string name="pref_keyrepeat_enabled">Taustiņa atkārtošanās ar ilgu piespiešanu</string>
<string name="pref_lock_double_tap_title">Divkāršs piesitiens burtslēgam</string> <string name="pref_lock_double_tap_title">Divkāršs piesitiens burtslēgam</string>
@@ -124,17 +124,8 @@ Tagad lieliski piemērota izmantošanai ikdienā.
<string name="key_descr_end">Beigas</string> <string name="key_descr_end">Beigas</string>
<string name="key_descr_clipboard">Starpliktuves pārvaldnieks</string> <string name="key_descr_clipboard">Starpliktuves pārvaldnieks</string>
<!-- <string name="key_descr_combining">Combining diacritic</string> --> <!-- <string name="key_descr_combining">Combining diacritic</string> -->
<!-- <string name="key_descr_dead_key">Dead key</string> -->
<!-- <string name="key_descr_zwj">Zero width joiner</string> -->
<!-- <string name="key_descr_zwnj">Zero width non-joiner</string> -->
<!-- <string name="key_descr_nbsp">Non-breaking space</string> -->
<!-- <string name="key_descr_nnbsp">Narrow non-breaking space</string> -->
<!-- <string name="key_descr_delete_word">Delete a word</string> -->
<!-- <string name="key_descr_forward_delete_word">Delete a word on the right</string> -->
<!-- <string name="key_descr_gesture">Gesture</string> -->
<string name="clipboard_history_heading">Nesen starpliktuvē ievietots teksts</string> <string name="clipboard_history_heading">Nesen starpliktuvē ievietots teksts</string>
<string name="clipboard_pin_heading">Piesprausts</string> <string name="clipboard_pin_heading">Piesprausts</string>
<string name="clipboard_remove_confirm">Noņemt šo starpliktuves vienumu?</string> <string name="clipboard_remove_confirm">Noņemt šo starpliktuves vienumu?</string>
<string name="clipboard_remove_confirmed"></string> <string name="clipboard_remove_confirmed"></string>
<!-- <string name="toast_no_voice_input">No voice typing app installed</string> -->
</resources> </resources>

View File

@@ -122,17 +122,8 @@ Aplikacja nie zawiera reklam, nie żąda dostępu do internetu, a jej kod źród
<string name="key_descr_end">End</string> <string name="key_descr_end">End</string>
<string name="key_descr_clipboard">Zarządzanie schowkiem</string> <string name="key_descr_clipboard">Zarządzanie schowkiem</string>
<!-- <string name="key_descr_combining">Combining diacritic</string> --> <!-- <string name="key_descr_combining">Combining diacritic</string> -->
<!-- <string name="key_descr_dead_key">Dead key</string> -->
<!-- <string name="key_descr_zwj">Zero width joiner</string> -->
<!-- <string name="key_descr_zwnj">Zero width non-joiner</string> -->
<!-- <string name="key_descr_nbsp">Non-breaking space</string> -->
<!-- <string name="key_descr_nnbsp">Narrow non-breaking space</string> -->
<!-- <string name="key_descr_delete_word">Delete a word</string> -->
<!-- <string name="key_descr_forward_delete_word">Delete a word on the right</string> -->
<!-- <string name="key_descr_gesture">Gesture</string> -->
<string name="clipboard_history_heading">Ostatnio skopiowane elementy</string> <string name="clipboard_history_heading">Ostatnio skopiowane elementy</string>
<string name="clipboard_pin_heading">Przypięte</string> <string name="clipboard_pin_heading">Przypięte</string>
<string name="clipboard_remove_confirm">Usunąć ten element ze schowka?</string> <string name="clipboard_remove_confirm">Usunąć ten element ze schowka?</string>
<string name="clipboard_remove_confirmed">Tak</string> <string name="clipboard_remove_confirmed">Tak</string>
<!-- <string name="toast_no_voice_input">No voice typing app installed</string> -->
</resources> </resources>

View File

@@ -122,17 +122,8 @@ Este aplicativo não contém anúncios, não faz nenhuma solicitação de rede e
<string name="key_descr_end">End</string> <string name="key_descr_end">End</string>
<string name="key_descr_clipboard">Área de transferência</string> <string name="key_descr_clipboard">Área de transferência</string>
<string name="key_descr_combining">Combinação de diacríticos</string> <string name="key_descr_combining">Combinação de diacríticos</string>
<!-- <string name="key_descr_dead_key">Dead key</string> -->
<!-- <string name="key_descr_zwj">Zero width joiner</string> -->
<!-- <string name="key_descr_zwnj">Zero width non-joiner</string> -->
<!-- <string name="key_descr_nbsp">Non-breaking space</string> -->
<!-- <string name="key_descr_nnbsp">Narrow non-breaking space</string> -->
<!-- <string name="key_descr_delete_word">Delete a word</string> -->
<!-- <string name="key_descr_forward_delete_word">Delete a word on the right</string> -->
<!-- <string name="key_descr_gesture">Gesture</string> -->
<string name="clipboard_history_heading">Textos recém copiados</string> <string name="clipboard_history_heading">Textos recém copiados</string>
<string name="clipboard_pin_heading">Fixados</string> <string name="clipboard_pin_heading">Fixados</string>
<string name="clipboard_remove_confirm">Remover esta cópia?</string> <string name="clipboard_remove_confirm">Remover esta cópia?</string>
<string name="clipboard_remove_confirmed">Sim</string> <string name="clipboard_remove_confirmed">Sim</string>
<!-- <string name="toast_no_voice_input">No voice typing app installed</string> -->
</resources> </resources>

View File

@@ -122,17 +122,8 @@ Această aplicație nu conține publicitate, nu folosește rețeaua deloc și e
<!-- <string name="key_descr_end">End</string> --> <!-- <string name="key_descr_end">End</string> -->
<!-- <string name="key_descr_clipboard">Clipboard manager</string> --> <!-- <string name="key_descr_clipboard">Clipboard manager</string> -->
<!-- <string name="key_descr_combining">Combining diacritic</string> --> <!-- <string name="key_descr_combining">Combining diacritic</string> -->
<!-- <string name="key_descr_dead_key">Dead key</string> -->
<!-- <string name="key_descr_zwj">Zero width joiner</string> -->
<!-- <string name="key_descr_zwnj">Zero width non-joiner</string> -->
<!-- <string name="key_descr_nbsp">Non-breaking space</string> -->
<!-- <string name="key_descr_nnbsp">Narrow non-breaking space</string> -->
<!-- <string name="key_descr_delete_word">Delete a word</string> -->
<!-- <string name="key_descr_forward_delete_word">Delete a word on the right</string> -->
<!-- <string name="key_descr_gesture">Gesture</string> -->
<!-- <string name="clipboard_history_heading">Recently copied text</string> --> <!-- <string name="clipboard_history_heading">Recently copied text</string> -->
<!-- <string name="clipboard_pin_heading">Pinned</string> --> <!-- <string name="clipboard_pin_heading">Pinned</string> -->
<!-- <string name="clipboard_remove_confirm">Remove this clipboard?</string> --> <!-- <string name="clipboard_remove_confirm">Remove this clipboard?</string> -->
<!-- <string name="clipboard_remove_confirmed">Yes</string> --> <!-- <string name="clipboard_remove_confirmed">Yes</string> -->
<!-- <string name="toast_no_voice_input">No voice typing app installed</string> -->
</resources> </resources>

View File

@@ -71,7 +71,7 @@
<string name="pref_theme_e_monet">Моне (системная)</string> <string name="pref_theme_e_monet">Моне (системная)</string>
<string name="pref_theme_e_monetlight">Моне (светлая)</string> <string name="pref_theme_e_monetlight">Моне (светлая)</string>
<string name="pref_theme_e_monetdark">Моне (темная)</string> <string name="pref_theme_e_monetdark">Моне (темная)</string>
<string name="pref_theme_e_rosepine">Розовая сосна</string> <!-- <string name="pref_theme_e_rosepine">Rosé Pine</string> -->
<string name="pref_swipe_dist_e_very_short">Очень короткая</string> <string name="pref_swipe_dist_e_very_short">Очень короткая</string>
<string name="pref_swipe_dist_e_short">Короткая</string> <string name="pref_swipe_dist_e_short">Короткая</string>
<string name="pref_swipe_dist_e_default">Обычная</string> <string name="pref_swipe_dist_e_default">Обычная</string>
@@ -122,17 +122,8 @@
<string name="key_descr_end">End</string> <string name="key_descr_end">End</string>
<string name="key_descr_clipboard">Менеджер буфера обмена</string> <string name="key_descr_clipboard">Менеджер буфера обмена</string>
<string name="key_descr_combining">Сочетание диакритических знаков</string> <string name="key_descr_combining">Сочетание диакритических знаков</string>
<!-- <string name="key_descr_dead_key">Dead key</string> -->
<string name="key_descr_zwj">Соединитель нулевой ширины</string>
<string name="key_descr_zwnj">Разделитель нулевой ширины</string>
<string name="key_descr_nbsp">Неразрывный пробел</string>
<string name="key_descr_nnbsp">Узкий неразрывный пробел</string>
<!-- <string name="key_descr_delete_word">Delete a word</string> -->
<!-- <string name="key_descr_forward_delete_word">Delete a word on the right</string> -->
<!-- <string name="key_descr_gesture">Gesture</string> -->
<string name="clipboard_history_heading">Недавно скопированный текст</string> <string name="clipboard_history_heading">Недавно скопированный текст</string>
<string name="clipboard_pin_heading">Закреплено</string> <string name="clipboard_pin_heading">Закреплено</string>
<string name="clipboard_remove_confirm">Удалить этот буфер обмена?</string> <string name="clipboard_remove_confirm">Удалить этот буфер обмена?</string>
<string name="clipboard_remove_confirmed">Да</string> <string name="clipboard_remove_confirmed">Да</string>
<!-- <string name="toast_no_voice_input">No voice typing app installed</string> -->
</resources> </resources>

View File

@@ -122,17 +122,8 @@ Bu uygulama açık kaynaklıdır. Reklam içermez ve internete bağlanmaz."</str
<string name="key_descr_end">SON(Sağ yön tuşu)</string> <string name="key_descr_end">SON(Sağ yön tuşu)</string>
<string name="key_descr_clipboard">Pano</string> <string name="key_descr_clipboard">Pano</string>
<!-- <string name="key_descr_combining">Combining diacritic</string> --> <!-- <string name="key_descr_combining">Combining diacritic</string> -->
<!-- <string name="key_descr_dead_key">Dead key</string> -->
<!-- <string name="key_descr_zwj">Zero width joiner</string> -->
<!-- <string name="key_descr_zwnj">Zero width non-joiner</string> -->
<!-- <string name="key_descr_nbsp">Non-breaking space</string> -->
<!-- <string name="key_descr_nnbsp">Narrow non-breaking space</string> -->
<!-- <string name="key_descr_delete_word">Delete a word</string> -->
<!-- <string name="key_descr_forward_delete_word">Delete a word on the right</string> -->
<!-- <string name="key_descr_gesture">Gesture</string> -->
<string name="clipboard_history_heading">Son kopyalanan metin</string> <string name="clipboard_history_heading">Son kopyalanan metin</string>
<string name="clipboard_pin_heading">Sabitlendi</string> <string name="clipboard_pin_heading">Sabitlendi</string>
<string name="clipboard_remove_confirm">Bu sabitlemeyi sil</string> <string name="clipboard_remove_confirm">Bu sabitlemeyi sil</string>
<string name="clipboard_remove_confirmed">Evet</string> <string name="clipboard_remove_confirmed">Evet</string>
<!-- <string name="toast_no_voice_input">No voice typing app installed</string> -->
</resources> </resources>

View File

@@ -71,7 +71,7 @@
<string name="pref_theme_e_monet">Моне (Системна)</string> <string name="pref_theme_e_monet">Моне (Системна)</string>
<string name="pref_theme_e_monetlight">Моне (Світла)</string> <string name="pref_theme_e_monetlight">Моне (Світла)</string>
<string name="pref_theme_e_monetdark">Моне (Темна)</string> <string name="pref_theme_e_monetdark">Моне (Темна)</string>
<string name="pref_theme_e_rosepine">Рожева сосна</string> <!-- <string name="pref_theme_e_rosepine">Rosé Pine</string> -->
<string name="pref_swipe_dist_e_very_short">Дуже коротка</string> <string name="pref_swipe_dist_e_very_short">Дуже коротка</string>
<string name="pref_swipe_dist_e_short">Коротка</string> <string name="pref_swipe_dist_e_short">Коротка</string>
<string name="pref_swipe_dist_e_default">Звичайна</string> <string name="pref_swipe_dist_e_default">Звичайна</string>
@@ -122,17 +122,8 @@
<string name="key_descr_end">End</string> <string name="key_descr_end">End</string>
<string name="key_descr_clipboard">Менеджер буфера обміну</string> <string name="key_descr_clipboard">Менеджер буфера обміну</string>
<string name="key_descr_combining">Комбінування діакритики</string> <string name="key_descr_combining">Комбінування діакритики</string>
<string name="key_descr_dead_key">Мертва клавіша</string>
<string name="key_descr_zwj">З\'єднувач нульової ширини</string>
<string name="key_descr_zwnj">Разділювач нульової ширини</string>
<string name="key_descr_nbsp">Нерозривний пробіл</string>
<string name="key_descr_nnbsp">Вузький нерозривний пробіл</string>
<!-- <string name="key_descr_delete_word">Delete a word</string> -->
<!-- <string name="key_descr_forward_delete_word">Delete a word on the right</string> -->
<!-- <string name="key_descr_gesture">Gesture</string> -->
<string name="clipboard_history_heading">Нещодавно скопійований текст</string> <string name="clipboard_history_heading">Нещодавно скопійований текст</string>
<string name="clipboard_pin_heading">Закріплено</string> <string name="clipboard_pin_heading">Закріплено</string>
<string name="clipboard_remove_confirm">Видалити цей буфер обміну?</string> <string name="clipboard_remove_confirm">Видалити цей буфер обміну?</string>
<string name="clipboard_remove_confirmed">Так</string> <string name="clipboard_remove_confirmed">Так</string>
<!-- <string name="toast_no_voice_input">No voice typing app installed</string> -->
</resources> </resources>

View File

@@ -122,17 +122,8 @@ Bây giờ đã hoàn hảo cho việc sử dụng hàng ngày.
<!-- <string name="key_descr_end">End</string> --> <!-- <string name="key_descr_end">End</string> -->
<!-- <string name="key_descr_clipboard">Clipboard manager</string> --> <!-- <string name="key_descr_clipboard">Clipboard manager</string> -->
<!-- <string name="key_descr_combining">Combining diacritic</string> --> <!-- <string name="key_descr_combining">Combining diacritic</string> -->
<!-- <string name="key_descr_dead_key">Dead key</string> -->
<!-- <string name="key_descr_zwj">Zero width joiner</string> -->
<!-- <string name="key_descr_zwnj">Zero width non-joiner</string> -->
<!-- <string name="key_descr_nbsp">Non-breaking space</string> -->
<!-- <string name="key_descr_nnbsp">Narrow non-breaking space</string> -->
<!-- <string name="key_descr_delete_word">Delete a word</string> -->
<!-- <string name="key_descr_forward_delete_word">Delete a word on the right</string> -->
<!-- <string name="key_descr_gesture">Gesture</string> -->
<!-- <string name="clipboard_history_heading">Recently copied text</string> --> <!-- <string name="clipboard_history_heading">Recently copied text</string> -->
<!-- <string name="clipboard_pin_heading">Pinned</string> --> <!-- <string name="clipboard_pin_heading">Pinned</string> -->
<!-- <string name="clipboard_remove_confirm">Remove this clipboard?</string> --> <!-- <string name="clipboard_remove_confirm">Remove this clipboard?</string> -->
<!-- <string name="clipboard_remove_confirmed">Yes</string> --> <!-- <string name="clipboard_remove_confirmed">Yes</string> -->
<!-- <string name="toast_no_voice_input">No voice typing app installed</string> -->
</resources> </resources>

View File

@@ -122,17 +122,8 @@
<string name="key_descr_end">End</string> <string name="key_descr_end">End</string>
<!-- <string name="key_descr_clipboard">Clipboard manager</string> --> <!-- <string name="key_descr_clipboard">Clipboard manager</string> -->
<!-- <string name="key_descr_combining">Combining diacritic</string> --> <!-- <string name="key_descr_combining">Combining diacritic</string> -->
<!-- <string name="key_descr_dead_key">Dead key</string> -->
<!-- <string name="key_descr_zwj">Zero width joiner</string> -->
<!-- <string name="key_descr_zwnj">Zero width non-joiner</string> -->
<!-- <string name="key_descr_nbsp">Non-breaking space</string> -->
<!-- <string name="key_descr_nnbsp">Narrow non-breaking space</string> -->
<!-- <string name="key_descr_delete_word">Delete a word</string> -->
<!-- <string name="key_descr_forward_delete_word">Delete a word on the right</string> -->
<!-- <string name="key_descr_gesture">Gesture</string> -->
<!-- <string name="clipboard_history_heading">Recently copied text</string> --> <!-- <string name="clipboard_history_heading">Recently copied text</string> -->
<!-- <string name="clipboard_pin_heading">Pinned</string> --> <!-- <string name="clipboard_pin_heading">Pinned</string> -->
<!-- <string name="clipboard_remove_confirm">Remove this clipboard?</string> --> <!-- <string name="clipboard_remove_confirm">Remove this clipboard?</string> -->
<!-- <string name="clipboard_remove_confirmed">Yes</string> --> <!-- <string name="clipboard_remove_confirmed">Yes</string> -->
<!-- <string name="toast_no_voice_input">No voice typing app installed</string> -->
</resources> </resources>

View File

@@ -16,7 +16,6 @@
<item>armenian_ph_am</item> <item>armenian_ph_am</item>
<item>beng_national</item> <item>beng_national</item>
<item>beng_provat</item> <item>beng_provat</item>
<item>cyrl_fcuzhen_mn</item>
<item>cyrl_jcuken_kk</item> <item>cyrl_jcuken_kk</item>
<item>cyrl_jcuken_ru</item> <item>cyrl_jcuken_ru</item>
<item>cyrl_jcuken_uk</item> <item>cyrl_jcuken_uk</item>
@@ -41,9 +40,6 @@
<item>latn_bepo_fr</item> <item>latn_bepo_fr</item>
<item>latn_bone</item> <item>latn_bone</item>
<item>latn_neo2</item> <item>latn_neo2</item>
<item>latn_qwerty_apl</item>
<item>latn_qwerty_az</item>
<item>latn_qwerty_bqn</item>
<item>latn_qwerty_br</item> <item>latn_qwerty_br</item>
<item>latn_qwerty_cy</item> <item>latn_qwerty_cy</item>
<item>latn_qwerty_cz</item> <item>latn_qwerty_cz</item>
@@ -56,9 +52,7 @@
<item>latn_qwerty_hu</item> <item>latn_qwerty_hu</item>
<item>latn_qwerty_jp</item> <item>latn_qwerty_jp</item>
<item>latn_qwerty_kk</item> <item>latn_qwerty_kk</item>
<item>latn_qwerty_lt</item>
<item>latn_qwerty_lv</item> <item>latn_qwerty_lv</item>
<item>latn_qwerty_mt</item>
<item>latn_qwerty_no</item> <item>latn_qwerty_no</item>
<item>latn_qwerty_pl</item> <item>latn_qwerty_pl</item>
<item>latn_qwerty_ro</item> <item>latn_qwerty_ro</item>
@@ -67,7 +61,6 @@
<item>latn_qwerty_sr</item> <item>latn_qwerty_sr</item>
<item>latn_qwerty_tly</item> <item>latn_qwerty_tly</item>
<item>latn_qwerty_tr</item> <item>latn_qwerty_tr</item>
<item>latn_qwerty_uz</item>
<item>latn_qwerty_vi</item> <item>latn_qwerty_vi</item>
<item>latn_qwertz</item> <item>latn_qwertz</item>
<item>latn_qwertz_cz</item> <item>latn_qwertz_cz</item>
@@ -99,7 +92,6 @@
<item>Armenian</item> <item>Armenian</item>
<item>বাংলা (জাতীয়)</item> <item>বাংলা (জাতীয়)</item>
<item>বাংলা (প্রভাত)</item> <item>বাংলা (প্রভাত)</item>
<item>ФЦУЖЭН (Монгол)</item>
<item>ЙЦУКЕН (Қазақша)</item> <item>ЙЦУКЕН (Қазақша)</item>
<item>ЙЦУКЕН (Русский)</item> <item>ЙЦУКЕН (Русский)</item>
<item>ЙЦУКЕН (Українська)</item> <item>ЙЦУКЕН (Українська)</item>
@@ -118,15 +110,12 @@
<item>두벌식 (Korean)</item> <item>두벌식 (Korean)</item>
<item>Hebrew 1</item> <item>Hebrew 1</item>
<item>Hebrew 2</item> <item>Hebrew 2</item>
<item>ಕನ್ನಡ - Kannada</item> <item>ಕನ್ನಡ</item>
<item>AZERTY (Belgian)</item> <item>AZERTY (Belgian)</item>
<item>AZERTY (Français)</item> <item>AZERTY (Français)</item>
<item>BEPO (Français)</item> <item>BEPO (Français)</item>
<item>Bone</item> <item>Bone</item>
<item>Neo 2</item> <item>Neo 2</item>
<item>QWERTY (APL)</item>
<item>QWERTY (Azərbaycanca)</item>
<item>QWERTY (BQN)</item>
<item>QWERTY (Brasileiro)</item> <item>QWERTY (Brasileiro)</item>
<item>QWERTY (Welsh)</item> <item>QWERTY (Welsh)</item>
<item>QWERTY (Czech)</item> <item>QWERTY (Czech)</item>
@@ -139,9 +128,7 @@
<item>QWERTY (Magyar)</item> <item>QWERTY (Magyar)</item>
<item>QWERTY (Japan)</item> <item>QWERTY (Japan)</item>
<item>QWERTY (Qazaqşa)</item> <item>QWERTY (Qazaqşa)</item>
<item>QWERTY (Lietuviškai)</item>
<item>QWERTY (Latvian)</item> <item>QWERTY (Latvian)</item>
<item>QWERTY (Malti)</item>
<item>QWERTY (Norwegian)</item> <item>QWERTY (Norwegian)</item>
<item>QWERTY (Polski)</item> <item>QWERTY (Polski)</item>
<item>QWERTY (Română)</item> <item>QWERTY (Română)</item>
@@ -150,7 +137,6 @@
<item>QWERTY (Srpski, latinica)</item> <item>QWERTY (Srpski, latinica)</item>
<item>QWERTY (Talysh New Latin)</item> <item>QWERTY (Talysh New Latin)</item>
<item>QWERTY (Türkçe)</item> <item>QWERTY (Türkçe)</item>
<item>QWERTY (Oʻzbekcha)</item>
<item>QWERTY (Vietnamese)</item> <item>QWERTY (Vietnamese)</item>
<item>QWERTZ</item> <item>QWERTZ</item>
<item>QWERTZ (Czech)</item> <item>QWERTZ (Czech)</item>
@@ -182,7 +168,6 @@
<item>@xml/armenian_ph_am</item> <item>@xml/armenian_ph_am</item>
<item>@xml/beng_national</item> <item>@xml/beng_national</item>
<item>@xml/beng_provat</item> <item>@xml/beng_provat</item>
<item>@xml/cyrl_fcuzhen_mn</item>
<item>@xml/cyrl_jcuken_kk</item> <item>@xml/cyrl_jcuken_kk</item>
<item>@xml/cyrl_jcuken_ru</item> <item>@xml/cyrl_jcuken_ru</item>
<item>@xml/cyrl_jcuken_uk</item> <item>@xml/cyrl_jcuken_uk</item>
@@ -207,9 +192,6 @@
<item>@xml/latn_bepo_fr</item> <item>@xml/latn_bepo_fr</item>
<item>@xml/latn_bone</item> <item>@xml/latn_bone</item>
<item>@xml/latn_neo2</item> <item>@xml/latn_neo2</item>
<item>@xml/latn_qwerty_apl</item>
<item>@xml/latn_qwerty_az</item>
<item>@xml/latn_qwerty_bqn</item>
<item>@xml/latn_qwerty_br</item> <item>@xml/latn_qwerty_br</item>
<item>@xml/latn_qwerty_cy</item> <item>@xml/latn_qwerty_cy</item>
<item>@xml/latn_qwerty_cz</item> <item>@xml/latn_qwerty_cz</item>
@@ -222,9 +204,7 @@
<item>@xml/latn_qwerty_hu</item> <item>@xml/latn_qwerty_hu</item>
<item>@xml/latn_qwerty_jp</item> <item>@xml/latn_qwerty_jp</item>
<item>@xml/latn_qwerty_kk</item> <item>@xml/latn_qwerty_kk</item>
<item>@xml/latn_qwerty_lt</item>
<item>@xml/latn_qwerty_lv</item> <item>@xml/latn_qwerty_lv</item>
<item>@xml/latn_qwerty_mt</item>
<item>@xml/latn_qwerty_no</item> <item>@xml/latn_qwerty_no</item>
<item>@xml/latn_qwerty_pl</item> <item>@xml/latn_qwerty_pl</item>
<item>@xml/latn_qwerty_ro</item> <item>@xml/latn_qwerty_ro</item>
@@ -233,7 +213,6 @@
<item>@xml/latn_qwerty_sr</item> <item>@xml/latn_qwerty_sr</item>
<item>@xml/latn_qwerty_tly</item> <item>@xml/latn_qwerty_tly</item>
<item>@xml/latn_qwerty_tr</item> <item>@xml/latn_qwerty_tr</item>
<item>@xml/latn_qwerty_uz</item>
<item>@xml/latn_qwerty_vi</item> <item>@xml/latn_qwerty_vi</item>
<item>@xml/latn_qwertz</item> <item>@xml/latn_qwertz</item>
<item>@xml/latn_qwertz_cz</item> <item>@xml/latn_qwertz_cz</item>

View File

@@ -122,17 +122,8 @@ This application contains no ads, doesn't make any network requests and is Open
<string name="key_descr_end">End</string> <string name="key_descr_end">End</string>
<string name="key_descr_clipboard">Clipboard manager</string> <string name="key_descr_clipboard">Clipboard manager</string>
<string name="key_descr_combining">Combining diacritic</string> <string name="key_descr_combining">Combining diacritic</string>
<string name="key_descr_dead_key">Dead key</string>
<string name="key_descr_zwj">Zero width joiner</string>
<string name="key_descr_zwnj">Zero width non-joiner</string>
<string name="key_descr_nbsp">Non-breaking space</string>
<string name="key_descr_nnbsp">Narrow non-breaking space</string>
<string name="key_descr_delete_word">Delete a word</string>
<string name="key_descr_forward_delete_word">Delete a word on the right</string>
<string name="key_descr_gesture">Gesture</string>
<string name="clipboard_history_heading">Recently copied text</string> <string name="clipboard_history_heading">Recently copied text</string>
<string name="clipboard_pin_heading">Pinned</string> <string name="clipboard_pin_heading">Pinned</string>
<string name="clipboard_remove_confirm">Remove this clipboard?</string> <string name="clipboard_remove_confirm">Remove this clipboard?</string>
<string name="clipboard_remove_confirmed">Yes</string> <string name="clipboard_remove_confirmed">Yes</string>
<string name="toast_no_voice_input">No voice typing app installed</string>
</resources> </resources>

View File

@@ -2,7 +2,7 @@
<row height="0.95"> <row height="0.95">
<key width="1.7" key0="ctrl" key1="loc switch_greekmath" key2="loc meta" key3="loc switch_clipboard" key4="switch_numeric"/> <key width="1.7" key0="ctrl" key1="loc switch_greekmath" key2="loc meta" key3="loc switch_clipboard" key4="switch_numeric"/>
<key width="1.1" key0="fn" key1="loc alt" key2="loc change_method" key3="switch_emoji" key4="config"/> <key width="1.1" key0="fn" key1="loc alt" key2="loc change_method" key3="switch_emoji" key4="config"/>
<key width="4.4" key0="space" key7="switch_forward" key8="switch_backward" key5="cursor_left" key6="cursor_right"/> <key width="4.4" key0="space" key7="switch_forward" key8="switch_backward" key5="cursor_left" key6="cursor_right" slider="true"/>
<key width="1.1" key0="loc compose" key7="up" key6="right" key5="left" key8="down" key1="loc home" key2="loc page_up" key3="loc end" key4="loc page_down"/> <key width="1.1" key0="loc compose" key7="up" key6="right" key5="left" key8="down" key1="loc home" key2="loc page_up" key3="loc end" key4="loc page_down"/>
<key width="1.7" key0="enter" key1="loc voice_typing" key2="action"/> <key width="1.7" key0="enter" key1="loc voice_typing" key2="action"/>
</row> </row>

View File

@@ -3,7 +3,7 @@
<keyboard bottom_row="false"> <keyboard bottom_row="false">
<row height="0.95"> <row height="0.95">
<key key0="switch_back_clipboard"/> <key key0="switch_back_clipboard"/>
<key width="3" key0="space" key5="cursor_left" key6="cursor_right"/> <key width="3" key0="space" key5="cursor_left" key6="cursor_right" slider="true"/>
<key key0="backspace" key2="delete"/> <key key0="backspace" key2="delete"/>
<key key0="enter" key2="action"/> <key key0="enter" key2="action"/>
</row> </row>

View File

@@ -3,7 +3,7 @@
<keyboard bottom_row="false"> <keyboard bottom_row="false">
<row height="0.95"> <row height="0.95">
<key key0="switch_back_emoji"/> <key key0="switch_back_emoji"/>
<key width="3" key0="space" key5="cursor_left" key6="cursor_right"/> <key width="3" key0="space" key5="cursor_left" key6="cursor_right" slider="true"/>
<key key0="backspace" key2="delete"/> <key key0="backspace" key2="delete"/>
<key key0="enter" key2="action"/> <key key0="enter" key2="action"/>
</row> </row>

View File

@@ -17,7 +17,7 @@
<key key0="σ" key3="←" key4="∂"/> <key key0="σ" key3="←" key4="∂"/>
<key key0="δ" key3="↓" key4="∫"/> <key key0="δ" key3="↓" key4="∫"/>
<key key0="φ" key3="→" key4="∃"/> <key key0="φ" key3="→" key4="∃"/>
<key key0="γ" key3="∋" key4="∈"/> <key key0="γ" key4="∈"/>
<key key0="η" key1="⊕" key4="4"/> <key key0="η" key1="⊕" key4="4"/>
<key key0="ξ" key1="⊖" key3="" key4="5"/> <key key0="ξ" key1="⊖" key3="" key4="5"/>
<key key0="κ" key1="⊙" key3="" key4="6"/> <key key0="κ" key1="⊙" key3="" key4="6"/>

View File

@@ -6,7 +6,6 @@
<subtype android:label="%s" android:languageTag="ar" android:imeSubtypeLocale="ar" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=arabic,default_layout=arab_pc_hindu"/> <subtype android:label="%s" android:languageTag="ar" android:imeSubtypeLocale="ar" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=arabic,default_layout=arab_pc_hindu"/>
<subtype android:label="%s" android:languageTag="ar" android:imeSubtypeLocale="ar_TN" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=arabic,default_layout=arab_pc"/> <subtype android:label="%s" android:languageTag="ar" android:imeSubtypeLocale="ar_TN" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=arabic,default_layout=arab_pc"/>
<subtype android:label="%s" android:languageTag="ay" android:imeSubtypeLocale="ay_AM" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=armenian,default_layout=armenian_ph_am"/> <subtype android:label="%s" android:languageTag="ay" android:imeSubtypeLocale="ay_AM" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=armenian,default_layout=armenian_ph_am"/>
<subtype android:label="%s" android:languageTag="az" android:imeSubtypeLocale="az_AZ" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_az,extra_keys=accent_trema:ü:ö@w|accent_cedille:ç:ş@s|ğ@g|ı@k|ə@l"/>
<subtype android:label="%s" android:languageTag="be" android:imeSubtypeLocale="be_BY" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=cyrillic,default_layout=cyrl_jcuken_ru,extra_keys=ґ|є|і|ї|ў"/> <subtype android:label="%s" android:languageTag="be" android:imeSubtypeLocale="be_BY" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=cyrillic,default_layout=cyrl_jcuken_ru,extra_keys=ґ|є|і|ї|ў"/>
<subtype android:label="%s" android:languageTag="bg" android:imeSubtypeLocale="bg_BG" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=cyrillic,default_layout=cyrl_ueishsht,extra_keys=€"/> <subtype android:label="%s" android:languageTag="bg" android:imeSubtypeLocale="bg_BG" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=cyrillic,default_layout=cyrl_ueishsht,extra_keys=€"/>
<subtype android:label="%s" android:languageTag="bn" android:imeSubtypeLocale="bn_BD" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_us,extra_keys=৳"/> <subtype android:label="%s" android:languageTag="bn" android:imeSubtypeLocale="bn_BD" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_us,extra_keys=৳"/>
@@ -22,7 +21,6 @@
<subtype android:label="%s" android:languageTag="en-IN" android:imeSubtypeLocale="en_IN" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_us"/> <subtype android:label="%s" android:languageTag="en-IN" android:imeSubtypeLocale="en_IN" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_us"/>
<subtype android:label="%s" android:languageTag="en-US" android:imeSubtypeLocale="en_US" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_us"/> <subtype android:label="%s" android:languageTag="en-US" android:imeSubtypeLocale="en_US" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_us"/>
<subtype android:label="%s" android:languageTag="es" android:imeSubtypeLocale="es_ES" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_es,extra_keys=accent_aigu:á:é:í:ó:ú@d|accent_tilde:ñ@n|accent_grave@f|accent_trema@u|€"/> <subtype android:label="%s" android:languageTag="es" android:imeSubtypeLocale="es_ES" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_es,extra_keys=accent_aigu:á:é:í:ó:ú@d|accent_tilde:ñ@n|accent_grave@f|accent_trema@u|€"/>
<subtype android:label="%s" android:languageTag="et" android:imeSubtypeLocale="et_EE" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_et,extra_keys=accent_trema:ä:ö:ü@u|accent_tilde:õ@o|accent_caron:š:ž@s|€"/>
<subtype android:label="%s" android:languageTag="fa" android:imeSubtypeLocale="fa_IR" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="default_layout=arab_pc_ir"/> <subtype android:label="%s" android:languageTag="fa" android:imeSubtypeLocale="fa_IR" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="default_layout=arab_pc_ir"/>
<subtype android:label="%s" android:languageTag="fr-BE" android:imeSubtypeLocale="fr_BE" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_azerty_be,extra_keys=accent_grave:è@f|accent_aigu:á:é:í:ó:ú:ý:j́@d|accent_circonflexe:ê@f|accent_cedille:ç@c|accent_trema@u|€"/> <subtype android:label="%s" android:languageTag="fr-BE" android:imeSubtypeLocale="fr_BE" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_azerty_be,extra_keys=accent_grave:è@f|accent_aigu:á:é:í:ó:ú:ý:j́@d|accent_circonflexe:ê@f|accent_cedille:ç@c|accent_trema@u|€"/>
<subtype android:label="%s" android:languageTag="fr-CA" android:imeSubtypeLocale="fr_CA" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_azerty_fr,extra_keys=accent_grave:à:è:ù@f|accent_aigu:é@d|accent_circonflexe:â:ê:ô@f|accent_cedille:ç@c|accent_trema:ë:ï:ü:ÿ@u"/> <subtype android:label="%s" android:languageTag="fr-CA" android:imeSubtypeLocale="fr_CA" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_azerty_fr,extra_keys=accent_grave:à:è:ù@f|accent_aigu:é@d|accent_circonflexe:â:ê:ô@f|accent_cedille:ç@c|accent_trema:ë:ï:ü:ÿ@u"/>
@@ -35,15 +33,14 @@
<subtype android:label="%s" android:languageTag="hu" android:imeSubtypeLocale="hu_HU" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwertz_hu,extra_keys=accent_aigu:á:é:í:ó:ú@d|accent_trema:ö:ü@u|accent_ogonek@s|accent_double_aigu:ő:ű@k|€"/> <subtype android:label="%s" android:languageTag="hu" android:imeSubtypeLocale="hu_HU" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwertz_hu,extra_keys=accent_aigu:á:é:í:ó:ú@d|accent_trema:ö:ü@u|accent_ogonek@s|accent_double_aigu:ő:ű@k|€"/>
<subtype android:label="%s" android:languageTag="is" android:imeSubtypeLocale="is_IS" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_us,extra_keys=ð|þ|æ|accent_trema:ö@o|accent_aigu:á:é:í:ó:ú:ý@d"/> <subtype android:label="%s" android:languageTag="is" android:imeSubtypeLocale="is_IS" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_us,extra_keys=ð|þ|æ|accent_trema:ö@o|accent_aigu:á:é:í:ó:ú:ý@d"/>
<subtype android:label="%s" android:languageTag="it" android:imeSubtypeLocale="it_IT" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_us,extra_keys=accent_grave:à:è:ì:ò:ù@f|accent_aigu:é:ó@d|accent_circonflexe:î@f|€|ə"/> <subtype android:label="%s" android:languageTag="it" android:imeSubtypeLocale="it_IT" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_us,extra_keys=accent_grave:à:è:ì:ò:ù@f|accent_aigu:é:ó@d|accent_circonflexe:î@f|€|ə"/>
<subtype android:label="%s" android:languageTag="ja" android:imeSubtypeLocale="ja_JP" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_jp"/>
<subtype android:label="%s" android:languageTag="ka-GE" android:imeSubtypeLocale="ka_GE" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=georgian_mes"/> <subtype android:label="%s" android:languageTag="ka-GE" android:imeSubtypeLocale="ka_GE" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=georgian_mes"/>
<subtype android:label="%s" android:languageTag="kk" android:imeSubtypeLocale="kk_KZ" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=cyrl_jcuken_kk"/> <subtype android:label="%s" android:languageTag="kk" android:imeSubtypeLocale="kk_KZ" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=cyrl_jcuken_kk"/>
<subtype android:label="%s" android:languageTag="kn" android:imeSubtypeLocale="kn_IN" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=kannada,default_layout=kann_kannada"/> <subtype android:label="%s" android:languageTag="kn" android:imeSubtypeLocale="kn_IN" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=kannada,default_layout=kann_kannada"/>
<subtype android:label="%s" android:languageTag="ko" android:imeSubtypeLocale="ko_KR" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=hangul,default_layout=latn_qwerty_us"/> <subtype android:label="%s" android:languageTag="ko" android:imeSubtypeLocale="ko_KR" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=hangul,default_layout=latn_qwerty_us"/>
<subtype android:label="%s" android:languageTag="lt" android:imeSubtypeLocale="lt_LT" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_lt,extra_keys=accent_ogonek:ą:ę:į:ų@s|accent_caron:č:š:ž@f|accent_dot_above:ė@s|accent_macron:ū@o|€"/> <subtype android:label="%s" android:languageTag="lt" android:imeSubtypeLocale="lt_LT" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_us,extra_keys=accent_ogonek:ą:ę:į:ų@s|accent_caron:č:š:ž@f|accent_dot_above:ė@s|accent_macron:ū@o|€"/>
<subtype android:label="%s" android:languageTag="lv" android:imeSubtypeLocale="lv_LV" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_lv,extra_keys=accent_macron:ā:ē:ī:ū@o|accent_caron:č:š:ž@f|accent_ogonek:ķ:ļ:ņ@s|accent_cedille:ģ@c|€"/> <subtype android:label="%s" android:languageTag="lv" android:imeSubtypeLocale="lv_LV" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_lv,extra_keys=accent_macron:ā:ē:ī:ū@o|accent_caron:č:š:ž@f|accent_ogonek:ķ:ļ:ņ@s|accent_cedille:ģ@c|€"/>
<subtype android:label="%s" android:languageTag="mn" android:imeSubtypeLocale="mn_MN" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=cyrillic,default_layout=cyrl_fcuzhen_mn,extra_keys=ү|ө"/>
<subtype android:label="%s" android:languageTag="mr" android:imeSubtypeLocale="mr_IN" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=devanagari,default_layout=deva_inscript,extra_keys=₹"/> <subtype android:label="%s" android:languageTag="mr" android:imeSubtypeLocale="mr_IN" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=devanagari,default_layout=deva_inscript,extra_keys=₹"/>
<subtype android:label="%s" android:languageTag="mt" android:imeSubtypeLocale="mt_MT" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_mt,extra_keys=accent_grave:à:è:ì:ò:ù|accent_dot_above:ċ:ż:ġ|ħ"/>
<subtype android:label="%s" android:languageTag="ne" android:imeSubtypeLocale="ne_NE" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=devanagari,default_layout=deva_inscript,extra_keys=₹"/> <subtype android:label="%s" android:languageTag="ne" android:imeSubtypeLocale="ne_NE" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=devanagari,default_layout=deva_inscript,extra_keys=₹"/>
<subtype android:label="%s" android:languageTag="nl-BE" android:imeSubtypeLocale="nl_BE" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_azerty_be,extra_keys=accent_grave:è@f|accent_aigu:á:é:í:ó:ú:ý:j́@d|accent_circonflexe:ê@f|accent_cedille:ç@c|accent_trema@u|€"/> <subtype android:label="%s" android:languageTag="nl-BE" android:imeSubtypeLocale="nl_BE" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_azerty_be,extra_keys=accent_grave:è@f|accent_aigu:á:é:í:ó:ú:ý:j́@d|accent_circonflexe:ê@f|accent_cedille:ç@c|accent_trema@u|€"/>
<subtype android:label="%s" android:languageTag="no" android:imeSubtypeLocale="no_NO" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_us,extra_keys=€|æ@a|å@a|ø@o|accent_aigu:é:ó@d|accent_grave:è:ò:ù@f|accent_circonflexe:ê:ô@f"/> <subtype android:label="%s" android:languageTag="no" android:imeSubtypeLocale="no_NO" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_us,extra_keys=€|æ@a|å@a|ø@o|accent_aigu:é:ó@d|accent_grave:è:ò:ù@f|accent_circonflexe:ê:ô@f"/>
@@ -60,6 +57,5 @@
<subtype android:label="%s" android:languageTag="tly" android:imeSubtypeLocale="tly_IR" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="default_layout=arab_hamvaj_tly"/> <subtype android:label="%s" android:languageTag="tly" android:imeSubtypeLocale="tly_IR" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="default_layout=arab_hamvaj_tly"/>
<subtype android:label="%s" android:languageTag="tr" android:imeSubtypeLocale="tr_TR" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_tr,extra_keys=accent_cedille:ç:ş@c|accent_trema:ö:ü@u|accent_circonflexe:â:î:û@f|₺|ı|ğ"/> <subtype android:label="%s" android:languageTag="tr" android:imeSubtypeLocale="tr_TR" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_tr,extra_keys=accent_cedille:ç:ş@c|accent_trema:ö:ü@u|accent_circonflexe:â:î:û@f|₺|ı|ğ"/>
<subtype android:label="%s" android:languageTag="uk" android:imeSubtypeLocale="uk_UA" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=cyrillic,default_layout=cyrl_jcuken_uk,extra_keys=ґ|є|і|ї|₴"/> <subtype android:label="%s" android:languageTag="uk" android:imeSubtypeLocale="uk_UA" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=cyrillic,default_layout=cyrl_jcuken_uk,extra_keys=ґ|є|і|ї|₴"/>
<subtype android:label="%s" android:languageTag="uz" android:imeSubtypeLocale="uz_UZ" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_uz,extra_keys=ʻ|ʼ"/>
<subtype android:label="%s" android:languageTag="vi" android:imeSubtypeLocale="vi_VN" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_vi"/> <subtype android:label="%s" android:languageTag="vi" android:imeSubtypeLocale="vi_VN" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_vi"/>
</input-method> </input-method>

View File

@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<row height="0.75"> <row height="0.75">
<key key0="1" se="!"/> <key key0="1"/>
<key key0="2" se="@"/> <key key0="2"/>
<key key0="3" se="#"/> <key key0="3"/>
<key key0="4" se="$"/> <key key0="4"/>
<key key0="5" se="%"/> <key key0="5"/>
<key key0="6" sw="^"/> <key key0="6"/>
<key key0="7" sw="&amp;"/> <key key0="7"/>
<key key0="8" sw="*"/> <key key0="8"/>
<key key0="9" sw="("/> <key key0="9"/>
<key key0="0" sw=")"/> <key key0="0"/>
</row> </row>

View File

@@ -10,7 +10,7 @@
<key shift="1.0" key0="4" indication="GHI"/> <key shift="1.0" key0="4" indication="GHI"/>
<key key0="5" indication="JKL"/> <key key0="5" indication="JKL"/>
<key key0="6" indication="MNO"/> <key key0="6" indication="MNO"/>
<key key0="(" key1="paste" key2="=" key3=":" key4="-"/> <key key0="(" key2="=" key3=":" key4="-"/>
</row> </row>
<row> <row>
<key shift="1.0" key0="7" indication="PQRS"/> <key shift="1.0" key0="7" indication="PQRS"/>

View File

@@ -11,36 +11,8 @@ let
buildToolsVersions = [ build_tools_version ]; buildToolsVersions = [ build_tools_version ];
platformVersions = [ "34" ]; platformVersions = [ "34" ];
abiVersions = [ "armeabi-v7a" ]; abiVersions = [ "armeabi-v7a" ];
inherit repoJson;
}; };
# Ensure we have the needed system images
repoJson = pkgs.fetchurl {
url =
"https://raw.githubusercontent.com/NixOS/nixpkgs/ebc7402410a3ce2d25622137c190d4ab83945c10/pkgs/development/mobile/androidenv/repo.json";
hash = "sha256-4/0FMyxM+7d66qfhlY3A10RIe6j6VrW8DIilH2eQyzc=";
};
emulators = let
mk_emulator = { platformVersion, device ? "pixel_6", abiVersion ? "x86_64", systemImageType ? "default" }:
pkgs.androidenv.emulateApp rec {
name = "emulator_api${platformVersion}";
inherit platformVersion abiVersion systemImageType;
androidAvdFlags = "--device ${device}";
sdkExtraArgs = { inherit repoJson; };
};
# Allow to install several emulators in the same environment
link_emulator = version_name: args: {
name = "bin/emulate_android_${version_name}";
path = "${mk_emulator args}/bin/run-test-emulator";
};
in pkgs.linkFarm "emulator" [
(link_emulator "5" { platformVersion = "21"; })
# (link_emulator "14" { platformVersion = "34"; })
# There's no 'default' image for Android 15
(link_emulator "15" { platformVersion = "35"; systemImageType = "google_apis"; })
];
ANDROID_SDK_ROOT = "${android.androidsdk}/libexec/android-sdk"; ANDROID_SDK_ROOT = "${android.androidsdk}/libexec/android-sdk";
gradle = pkgs.gradle.override { java = jdk; }; gradle = pkgs.gradle.override { java = jdk; };
@@ -55,14 +27,8 @@ let
''; '';
in pkgs.mkShell { in pkgs.mkShell {
buildInputs = [ buildInputs =
pkgs.findutils [ pkgs.findutils pkgs.fontforge jdk android.androidsdk gradle_wrapped ];
pkgs.fontforge
jdk
android.androidsdk
gradle_wrapped
emulators
];
JAVA_HOME = jdk.home; JAVA_HOME = jdk.home;
inherit ANDROID_SDK_ROOT; inherit ANDROID_SDK_ROOT;
} }

View File

@@ -78,6 +78,7 @@
"": "", "": "",
"∩": "⋂", "∩": "⋂",
"∃": "∄", "∃": "∄",
"∈": "∉",
"∫": "∮", "∫": "∮",
"Π": "∏", "Π": "∏",
"Σ": "∑", "Σ": "∑",
@@ -88,16 +89,6 @@
"⊃": "⊇", "⊃": "⊇",
"±": "∓", "±": "∓",
// APL
"": "⍶",
"⍵": "⍹",
"⋄": "⌺",
"⍝": "⍧",
"∆": "⍙",
"∇": "⍢",
"": "⍡",
"⎕": "⍞",
// hebrew niqqud // hebrew niqqud
"ק": "qamats", // kamatz "ק": "qamats", // kamatz
"ר": "hataf_qamats", // reduced kamatz "ר": "hataf_qamats", // reduced kamatz
@@ -257,12 +248,5 @@
"ۆ": "combining_arabic_v", "ۆ": "combining_arabic_v",
"س": "ـ", "س": "ـ",
"ف": "ڤ", "ف": "ڤ",
"ن": "ں", "ن": "ں"
// Tamil
"ய": ":௰",
"ஒ": ":ௐ",
"ள": ":௱",
"ச": ":௲",
"வ": ":௳"
} }

View File

@@ -18,13 +18,6 @@
"┐": "╗", "┐": "╗",
"─": "═", "─": "═",
"│": "║", "│": "║",
"∈": "∉",
"∋": "∌",
"⊂": "⊄",
"⊃": "⊅",
"⊆": "⊈",
"⊇": "⊉",
// superscript // superscript
"ᵃ": "ᴬ", "ᵃ": "ᴬ",
"ᵇ": "ᴮ", "ᵇ": "ᴮ",
@@ -49,22 +42,18 @@
"ʷ": "ᵂ", "ʷ": "ᵂ",
"ᶾ": "ᴣ", "ᶾ": "ᴣ",
"ᵠ": "ᶲ", "ᵠ": "ᶲ",
// german eszett has an uppercase, but because it is uncommon, java doesn't know about it // german eszett has an uppercase, but because it is uncommon, java doesn't know about it
"ß": "ẞ", "ß": "ẞ",
// these characters don't have a preapplied uppercase version, so we use combining characters // these characters don't have a preapplied uppercase version, so we use combining characters
"ẗ": "T\u0308", "ẗ": "T\u0308",
"ẘ": "W\u030A", "ẘ": "W\u030A",
"ẙ": "Y\u030A", "ẙ": "Y\u030A",
"ǰ": "J\u030C", "ǰ": "J\u030C",
"ȷ": "J\u0307", "ȷ": "J\u0307",
// In Turkish, upper case of 'iı' is 'İI' but Java's toUpperCase will // In Turkish, upper case of 'iı' is 'İI' but Java's toUpperCase will
// return 'II'. To make 'İ' accessible, make it the shift of 'ı'. This // return 'II'. To make 'İ' accessible, make it the shift of 'ı'. This
// has the inconvenient of swapping i and ı on the keyboard. // has the inconvenient of swapping i and ı on the keyboard.
"ı": "İ", "ı": "İ",
"₹": "₨", "₹": "₨",
// Gujarati alternate characters // Gujarati alternate characters
"અ": "આ", "અ": "આ",
@@ -91,9 +80,13 @@
"લ": "ળ", "લ": "ળ",
"સ": "શ", "સ": "શ",
"હ": "", "હ": "",
// Tamil alternate characters // Tamil alternate characters
"௹": "₨", "௹": "₨",
"ய": ":௰",
"ஒ": ":ௐ",
"ள": ":௱",
"ச": ":௲",
"வ": ":௳",
// Modern Hindi and Sanskrit // Modern Hindi and Sanskrit
"अ": "आ", "अ": "आ",
@@ -125,14 +118,5 @@
"ॢ": "ॣ", "ॢ": "ॣ",
"॒": "॑", "॒": "॑",
"ॅ": "ॲ", "ॅ": "ॲ",
"ॉ": "ऑ", "ॉ": "ऑ"
// Mathematical symbols
"\uD835": {
"\uDD68": "𝕎", // 𝕨𝕎
"\uDD69": "𝕏", // 𝕩𝕏
"\uDD57": "𝔽", // 𝕗𝔽
"\uDD58": "𝔾", // 𝕘𝔾
"\uDD64": "𝕊" // 𝕤𝕊
}
} }

View File

@@ -1,6 +1,7 @@
package juloo.keyboard2; package juloo.keyboard2;
import android.os.Handler; import android.os.Handler;
import android.os.Looper;
import android.text.InputType; import android.text.InputType;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
@@ -26,9 +27,9 @@ public final class Autocapitalisation
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES |
InputType.TYPE_TEXT_FLAG_CAP_WORDS; InputType.TYPE_TEXT_FLAG_CAP_WORDS;
public Autocapitalisation(Handler h, Callback cb) public Autocapitalisation(Looper looper, Callback cb)
{ {
_handler = h; _handler = new Handler(looper);
_callback = cb; _callback = cb;
} }
@@ -87,24 +88,6 @@ public final class Autocapitalisation
callback_now(true); callback_now(true);
} }
/** Pause auto capitalisation until [unpause()] is called. */
public boolean pause()
{
boolean was_enabled = _enabled;
stop();
_enabled = false;
return was_enabled;
}
/** Continue auto capitalisation after [pause()] was called. Argument is the
output of [pause()]. */
public void unpause(boolean was_enabled)
{
_enabled = was_enabled;
_should_update_caps_mode = true;
callback_now(true);
}
public static interface Callback public static interface Callback
{ {
public void update_shift_state(boolean should_enable, boolean should_disable); public void update_shift_state(boolean should_enable, boolean should_disable);

View File

@@ -4,22 +4,29 @@ import java.util.Arrays;
public final class ComposeKey public final class ComposeKey
{ {
/** Apply the pending compose sequence to [kv]. Returns [null] if no sequence /** Apply the pending compose sequence to [kv]. */
matched. */
public static KeyValue apply(int state, KeyValue kv) public static KeyValue apply(int state, KeyValue kv)
{ {
switch (kv.getKind()) switch (kv.getKind())
{ {
case Char: case Char:
return apply(state, kv.getChar()); KeyValue res = apply(state, kv.getChar());
case String: // Grey-out characters not part of any sequence.
return apply(state, kv.getString()); if (res == null)
return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
return res;
/* These keys are not greyed. */
case Event:
case Modifier:
case Compose_pending:
return kv;
/* Other keys cannot be part of sequences. */
default:
return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
} }
return null;
} }
/** Apply the pending compose sequence to char [c]. Returns [null] if no /** Apply the pending compose sequence to char [c]. */
sequence matched. */
public static KeyValue apply(int prev, char c) public static KeyValue apply(int prev, char c)
{ {
char[] states = ComposeKeyData.states; char[] states = ComposeKeyData.states;
@@ -42,25 +49,6 @@ public final class ComposeKey
return KeyValue.makeCharKey((char)next_header); return KeyValue.makeCharKey((char)next_header);
} }
/** Apply each char of a string to a sequence. Returns [null] if no sequence
matched. */
public static KeyValue apply(int prev, String s)
{
final int len = s.length();
int i = 0;
if (len == 0) return null;
while (true)
{
KeyValue k = apply(prev, s.charAt(i));
i++;
if (k == null) return null;
if (i >= len) return k;
if (k.getKind() != KeyValue.Kind.Compose_pending)
return null; // Found a final state before the end of [s].
prev = k.getPendingCompose();
}
}
/** The state machine is comprised of two arrays. /** The state machine is comprised of two arrays.
The [states] array represents the different states and the associated The [states] array represents the different states and the associated

View File

@@ -110,17 +110,17 @@ public final class ComposeKeyData
"/\u22ac\u0000\u00a8\u00af\u2218\u22a5\u2336\u0000_\u2218\u22a4\u0000/\u22ad\u0000/\u22ae\u0000/\u22af\u0000/\u22ea\u0000/\u22eb\u0000/\u22ec\u0000/\u22ed\u0000_\u2395\u233a\u0000_\u0000_\u0000_\u0000'/:<=>?\\\u00f7\u2190\u2191\u2192\u2193\u2206\u2207\u2218\u2227\u2228\u2260\u22c4\u25cb\u233c\u0000*-.\\_" + "/\u22ac\u0000\u00a8\u00af\u2218\u22a5\u2336\u0000_\u2218\u22a4\u0000/\u22ad\u0000/\u22ae\u0000/\u22af\u0000/\u22ea\u0000/\u22eb\u0000/\u22ec\u0000/\u22ed\u0000_\u2395\u233a\u0000_\u0000_\u0000_\u0000'/:<=>?\\\u00f7\u2190\u2191\u2192\u2193\u2206\u2207\u2218\u2227\u2228\u2260\u22c4\u25cb\u233c\u0000*-.\\_" +
"|\u00a8\u2218\u2395\u0000/\u2adc\u0000 !\"%'()*,-.0123456789:<=>?[]^_abcehlopruyz{|}\u00a3\u00a7\u00b1\u00d7\u0398\u03a0\u03a3\u03b2\u03b3\u03b5\u03b8\u03ba\u03c0\u03c1\u03c3\u03c5\u03c6\u0430\u0435" + "|\u00a8\u2218\u2395\u0000/\u2adc\u0000 !\"%'()*,-.0123456789:<=>?[]^_abcehlopruyz{|}\u00a3\u00a7\u00b1\u00d7\u0398\u03a0\u03a3\u03b2\u03b3\u03b5\u03b8\u03ba\u03c0\u03c1\u03c3\u03c5\u03c6\u0430\u0435" +
"\u0437\u0438\u0439\u043b\u043c\u043d\u043e\u0441\u0443\u0447\u0448\u044a\u044b\u044c\u044d\u044f\u0456\u0458\u045f\u0461\u0481\u0487\u049b\u04b7\u04c8\u0513\u05d1\u05d3\u05d5\u05d6\u05d7\u05dd\u05e1\u05e3\u05e4\u05e6\u05e7\u05e8\u05e9\u0625\u0626\u0627\u0628\u0629\u062b\u062d\u0631\u0632\u0633\u0635\u0637\u0639\u063a\u063d\u0641\u0642\u0643\u0644\u0646\u0647\u064a\u064f\u0650\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668" + "\u0437\u0438\u0439\u043b\u043c\u043d\u043e\u0441\u0443\u0447\u0448\u044a\u044b\u044c\u044d\u044f\u0456\u0458\u045f\u0461\u0481\u0487\u049b\u04b7\u04c8\u0513\u05d1\u05d3\u05d5\u05d6\u05d7\u05dd\u05e1\u05e3\u05e4\u05e6\u05e7\u05e8\u05e9\u0625\u0626\u0627\u0628\u0629\u062b\u062d\u0631\u0632\u0633\u0635\u0637\u0639\u063a\u063d\u0641\u0642\u0643\u0644\u0646\u0647\u064a\u064f\u0650\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668" +
"\u0669\u06a1\u06a9\u06c6\u06c9\u06cc\u06ce\u06f0\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9\u0901\u0902\u0905\u0906\u0907\u0908\u0909\u090a\u090b\u090c\u090f\u0910\u0913\u0914\u0915\u0916\u0917\u0918\u091a\u091b\u091c\u091d\u091f\u0921\u0922\u0923\u0925\u0926\u0928\u092a\u092b\u092c\u092f\u0930\u0933\u0935\u0936\u0937\u093c\u093d\u093e\u093f\u0940\u0941\u0943\u0947\u0948\u094b\u094c\u0953\u0956\u0962\u0964\u0970\u0b92" + "\u0669\u06a1\u06a9\u06c6\u06c9\u06cc\u06ce\u06f0\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9\u0901\u0902\u0905\u0906\u0907\u0908\u0909\u090a\u090b\u090c\u090f\u0910\u0913\u0914\u0915\u0916\u0917\u0918\u091a\u091b\u091c\u091d\u091f\u0921\u0922\u0923\u0925\u0926\u0928\u092a\u092b\u092c\u092f\u0930\u0933\u0935\u0936\u0937\u093c\u093d\u093e\u093f\u0940\u0941\u0943\u0947\u0948\u094b\u094c\u0953\u0956\u0962\u0964\u0970\u2020" +
"\u0b9a\u0baf\u0bb3\u0bb5\u2020\u20ac\u20b9\u2190\u2191\u2192\u2193\u2194\u2195\u2196\u2197\u2198\u2199\u2203\u2206\u2207\u2227\u2228\u2229\u222a\u222b\u2282\u2283\u22a4\u22b7\u22c4\u235d\u2375\u237a\u2395\ua649\ua651\ua67d\uFFFF\u006e\u0062\u0073\u0070\uFFFF\u0066\u0031\u0030\uFFFF\u0066\u0031\uFFFF\u0066\u0032\uFFFF\u0066\u0033\uFFFF\u0066\u0034\uFFFF\u0066\u0035\uFFFF\u0066\u0036\uFFFF\u0066\u0037\uFFFF\u0066\u0038\uFFFF\u0066" + "\u20ac\u20b9\u2190\u2191\u2192\u2193\u2194\u2195\u2196\u2197\u2198\u2199\u2203\u2208\u2227\u2228\u2229\u222a\u222b\u2282\u2283\u22b7\ua649\ua651\ua67d\uFFFF\u006e\u0062\u0073\u0070\uFFFF\u0066\u0031\u0030\uFFFF\u0066\u0031\uFFFF\u0066\u0032\uFFFF\u0066\u0033\uFFFF\u0066\u0034\uFFFF\u0066\u0035\uFFFF\u0066\u0036\uFFFF\u0066\u0037\uFFFF\u0066\u0038\uFFFF\u0066\u0039\uFFFF\u007a\u0077\u006e\u006a\u20b1\u20b4\u20bf\uFFFF\u0072\u0065" +
"\u0039\uFFFF\u007a\u0077\u006e\u006a\u20b1\u20b4\u20bf\uFFFF\u0072\u0065\u006d\u006f\u0076\u0065\u0064\u2213\u2219\u03f4\u220f\u2211\u03d0\u0263\u03f5\u03d1\u03f0\u03d6\u03f1\u03c2\u03d2\u03d5\u0465\uFFFF\ua641\u0456\u0458\u046b\u0467\u047b\u0455\uFFFF\ua64b\u044c\uFFFF\ua651\u044a\u0454\u0438\uFFFF\ua66f\uFFFF\u0068\u0061\u0074\u0061\u0066\u005f\u0073\u0065\u0067\u006f\u006c\uFFFF\u0064\u0061\u0067\u0065\u0073\u0068\uFFFF\u0068" + "\u006d\u006f\u0076\u0065\u0064\u2213\u2219\u03f4\u220f\u2211\u03d0\u0263\u03f5\u03d1\u03f0\u03d6\u03f1\u03c2\u03d2\u03d5\u0465\uFFFF\ua641\u0456\u0458\u046b\u0467\u047b\u0455\uFFFF\ua64b\u044c\uFFFF\ua651\u044a\u0454\u0438\uFFFF\ua66f\uFFFF\u0068\u0061\u0074\u0061\u0066\u005f\u0073\u0065\u0067\u006f\u006c\uFFFF\u0064\u0061\u0067\u0065\u0073\u0068\uFFFF\u0068\u006f\u006c\u0061\u006d\uFFFF\u0071\u0075\u0062\u0075\u0074\u0073\uFFFF" +
"\u006f\u006c\u0061\u006d\uFFFF\u0071\u0075\u0062\u0075\u0074\u0073\uFFFF\u0068\u0069\u0072\u0069\u0071\uFFFF\u0072\u0061\u0066\u0065\uFFFF\u0073\u0065\u0067\u006f\u006c\uFFFF\u0068\u0061\u0074\u0061\u0066\u005f\u0070\u0061\u0074\u0061\u0068\uFFFF\u0070\u0061\u0074\u0061\u0068\uFFFF\u0074\u0073\u0065\u0072\u0065\uFFFF\u0071\u0061\u006d\u0061\u0074\u0073\uFFFF\u0068\u0061\u0074\u0061\u0066\u005f\u0071\u0061\u006d\u0061\u0074\u0073" + "\u0068\u0069\u0072\u0069\u0071\uFFFF\u0072\u0061\u0066\u0065\uFFFF\u0073\u0065\u0067\u006f\u006c\uFFFF\u0068\u0061\u0074\u0061\u0066\u005f\u0070\u0061\u0074\u0061\u0068\uFFFF\u0070\u0061\u0074\u0061\u0068\uFFFF\u0074\u0073\u0065\u0072\u0065\uFFFF\u0071\u0061\u006d\u0061\u0074\u0073\uFFFF\u0068\u0061\u0074\u0061\u0066\u005f\u0071\u0061\u006d\u0061\u0074\u0073\uFFFF\u0073\u0068\u0065\u0076\u0061\u066e\u067e\u06c1\u0698\u0640\u0636" +
"\uFFFF\u0073\u0068\u0065\u0076\u0061\u066e\u067e\u06c1\u0698\u0640\u0636\u0638\u0621\u06a4\u063a\u06a9\u06ba\u06be\u06cc\u0643\u064a\u0900\u0955\u0972\u0911\u0973\u0974\u0976\u0977\u0960\u0961\u090d\u090e\u0912\u0975\u097b\u097c\uFFFF\u0936\u094d\u091a\u0979\u0978\u097e\uFFFF\u0924\u094d\u0930\uFFFF\u0926\u094d\u0930\uFFFF\u092a\u094d\u0930\u097f\u097a\uFFFF\u0936\u094d\u0930\uFFFF\u0915\u094d\u0937\u094e\u097d\u0949\u093a\u093b" + "\u0638\u0621\u06a4\u063a\u06a9\u06ba\u06be\u06cc\u0643\u064a\u0900\u0955\u0972\u0911\u0973\u0974\u0976\u0977\u0960\u0961\u090d\u090e\u0912\u0975\u097b\u097c\uFFFF\u0936\u094d\u091a\u0979\u0978\u097e\uFFFF\u0924\u094d\u0930\uFFFF\u0926\u094d\u0930\uFFFF\u092a\u094d\u0930\u097f\u097a\uFFFF\u0936\u094d\u0930\uFFFF\u0915\u094d\u0937\u094e\u097d\u0949\u093a\u093b\u0904\u0944\u0945\u0946\u094a\u094f\u0954\u0957\u0963\u0965\u0971\u21d4" +
"\u0904\u0944\u0945\u0946\u094a\u094f\u0954\u0957\u0963\u0965\u0971\uFFFF\u0bd0\uFFFF\u0bf2\uFFFF\u0bf0\uFFFF\u0bf1\uFFFF\u0bf3\u21d4\u21d5\u21d6\u21d7\u21d8\u21d9\u22c0\u22c1\u22c2\u22c3\u222e\u22b6\u044b\u0483\u00000123456789\u09e6\u09e7\u09e8\u09e9\u09ea\u09eb\u09ec\u09ed\u09ee\u09ef\u00000123456789\u0966\u0967\u0968\u0969\u096a" + "\u21d5\u21d6\u21d7\u21d8\u21d9\u22c0\u22c1\u22c2\u22c3\u222e\u22b6\u044b\u0483\u00000123456789\u09e6\u09e7\u09e8\u09e9\u09ea\u09eb\u09ec\u09ed\u09ee\u09ef\u00000123456789\u0966\u0967\u0968\u0969\u096a\u096b\u096c\u096d\u096e\u096f\u00000123456789\u0ae6\u0ae7\u0ae8\u0ae9\u0aea\u0aeb" +
"\u096b\u096c\u096d\u096e\u096f\u00000123456789\u0ae6\u0ae7\u0ae8\u0ae9\u0aea\u0aeb\u0aec\u0aed\u0aee\u0aef\u00000123456789\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669\u00000123456789\u0ce6\u0ce7\u0ce8\u0ce9\u0cea\u0ceb\u0cec\u0ced\u0cee\u0cef\u0000012" + "\u0aec\u0aed\u0aee\u0aef\u00000123456789\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669\u00000123456789\u0ce6\u0ce7\u0ce8\u0ce9\u0cea\u0ceb\u0cec\u0ced\u0cee\u0cef\u00000123456789\u06f0\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9\u00000123" +
"3456789\u06f0\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9\u00000123456789\u0be6\u0be7\u0be8\u0be9\u0bea\u0beb\u0bec\u0bed\u0bee\u0bef\u0000\u00df\u0131\u01f0\u0237\u02b0\u02b2\u02b3\u02b7\u02e1\u0905\u0907\u0909\u090b\u090c\u090f\u0913\u0915\u0917\u091a\u091c\u091f\u0921\u0924\u0926\u0928\u092c\u092e\u0932\u0938\u0939\u093f\u0941\u0943" + "456789\u0be6\u0be7\u0be8\u0be9\u0bea\u0beb\u0bec\u0bed\u0bee\u0bef\u0000\u00df\u0131\u01f0\u0237\u02b0\u02b2\u02b3\u02b7\u02e1\u0905\u0907\u0909\u090b\u090c\u090f\u0913\u0915\u0917\u091a\u091c\u091f\u0921\u0924\u0926\u0928\u092c\u092e\u0932\u0938\u0939\u093f\u0941\u0943\u0945\u0947\u0949\u094b\u0952\u0962\u0a85\u0a87\u0a89\u0a8f\u0a93\u0a95\u0a97\u0a9a\u0a9c\u0a9f\u0aa1\u0aa4\u0aa6\u0aa8\u0aaa\u0aac" +
"\u0945\u0947\u0949\u094b\u0952\u0962\u0a85\u0a87\u0a89\u0a8f\u0a93\u0a95\u0a97\u0a9a\u0a9c\u0a9f\u0aa1\u0aa4\u0aa6\u0aa8\u0aaa\u0aac\u0aae\u0ab2\u0ab8\u0ab9\u0abf\u0ac1\u0ac7\u0acb\u0bf9\u1d43\u1d47\u1d48\u1d49\u1d4d\u1d4f\u1d50\u1d52\u1d56\u1d57\u1d58\u1d5b\u1d60\u1d9c\u1da0\u1dbe\u1e97\u1e98\u1e99\u2071\u207f\u20b9\u2190\u2191\u2192\u2193\u2196\u2197\u2198\u2199\u2208\u220b\u2282\u2283\u2286\u2287\u2500\u2502\u250c\u2510\u2514" + "\u0aae\u0ab2\u0ab8\u0ab9\u0abf\u0ac1\u0ac7\u0acb\u0b92\u0b9a\u0baf\u0bb3\u0bb5\u0bf9\u1d43\u1d47\u1d48\u1d49\u1d4d\u1d4f\u1d50\u1d52\u1d56\u1d57\u1d58\u1d5b\u1d60\u1d9c\u1da0\u1dbe\u1e97\u1e98\u1e99\u2071\u207f\u20b9\u2190\u2191\u2192\u2193\u2196\u2197\u2198\u2199\u2500\u2502\u250c\u2510\u2514\u2518\u251c\u2524\u252c\u2534\u253c\uFFFF\u004a\u030c\uFFFF\u004a\u0307\u1d34\u1d36\u1d3f\u1d42\u1d38\u0906\u0908\u090a\u0910\u0914\u0916" +
"\u2518\u251c\u2524\u252c\u2534\u253c\ud835\uFFFF\u004a\u030c\uFFFF\u004a\u0307\u1d34\u1d36\u1d3f\u1d42\u1d38\u0906\u0908\u090a\u0910\u0914\u0916\u0918\u091b\u091d\u0920\u0922\u0925\u0927\u0923\u092d\u0902\u0933\u0936\u0903\u0940\u0942\u0948\u094c\u0951\u0a86\u0a88\u0a8a\u0a90\u0a94\u0a96\u0a98\u0a9b\u0a9d\u0aa0\u0aa2\u0aa5\u0aa7\u0aa3\u0aab\u0aad\u0a82\u0ab3\u0ab6\u0a83\u0ac0\u0ac2\u0ac8\u0acc\u1d2c\u1d2e\u1d30\u1d31\u1d33\u1d37" + "\u0918\u091b\u091d\u0920\u0922\u0925\u0927\u0923\u092d\u0902\u0933\u0936\u0903\u0940\u0942\u0948\u094c\u0951\u0a86\u0a88\u0a8a\u0a90\u0a94\u0a96\u0a98\u0a9b\u0a9d\u0aa0\u0aa2\u0aa5\u0aa7\u0aa3\u0aab\u0aad\u0a82\u0ab3\u0ab6\u0a83\u0ac0\u0ac2\u0ac8\u0acc\uFFFF\u0bd0\uFFFF\u0bf2\uFFFF\u0bf0\uFFFF\u0bf1\uFFFF\u0bf3\u1d2c\u1d2e\u1d30\u1d31\u1d33\u1d37\u1d39\u1d3c\u1d3e\u1d40\u1d41\u2c7d\u1db2\uFFFF\ua7f2\uFFFF\ua7f3\u1d23\uFFFF\u0054" +
"\u1d39\u1d3c\u1d3e\u1d40\u1d41\u2c7d\u1db2\uFFFF\ua7f2\uFFFF\ua7f3\u1d23\uFFFF\u0054\u0308\uFFFF\u0057\u030a\uFFFF\u0059\u030a\u1d35\u1d3a\u2550\u2551\u2554\u2557\u255a\u255d\u2560\u2563\u2566\u2569\u256c\u0000\udd57\udd58\udd64\udd68\udd69\uFFFF\ud835\udd3d\uFFFF\ud835\udd3e\uFFFF\ud835\udd4a\uFFFF\ud835\udd4e\uFFFF\ud835\udd4f").toCharArray(); "\u0308\uFFFF\u0057\u030a\uFFFF\u0059\u030a\u1d35\u1d3a\u2550\u2551\u2554\u2557\u255a\u255d\u2560\u2563\u2566\u2569\u256c").toCharArray();
public static final char[] edges = public static final char[] edges =
("\u0001\u0036\u0037\u0038\u0039\u003a\u003b\u003c\u003f\u0040\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u004a\u004b\u004c\u004d\u004e\u004f\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0059\u005a\u005b\\\u005d\u005e\u005f\u0060\u0061\u0062\u0063\u0064\u0067\u0068\u006b\u006e\u006f\u0072\u0075\u0078\u007b\u007e\u0081\u0001\u0001\u0001\u0001\u0001\u0003\u0000\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001" + ("\u0001\u0036\u0037\u0038\u0039\u003a\u003b\u003c\u003f\u0040\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u004a\u004b\u004c\u004d\u004e\u004f\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0059\u005a\u005b\\\u005d\u005e\u005f\u0060\u0061\u0062\u0063\u0064\u0067\u0068\u006b\u006e\u006f\u0072\u0075\u0078\u007b\u007e\u0081\u0001\u0001\u0001\u0001\u0001\u0003\u0000\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001" +
@@ -226,19 +226,19 @@ public final class ComposeKeyData
"\u1c22\u0001\u0001\u0003\u1387\u1c26\u0001\u0003\u0cab\u1c2a\u0001\u0003\u1388\u1c2e\u0001\u0003\u0cac\u1c32\u0001\u0002\u1c35\u0001\u0004\u111c\u1389\u1c3a\u0001\u0005\u138a\u1407\u04f5\u1c40\u0001\u0002\u1c43\u0001\u0002\u111d\u0002\u1c48\u0001\u0008\u111e\u04e4\u1c51\u1c52\u1c53\u1c54\u1c55\u0001\u0001\u0001\u0001\u0001\u0002\u1c58\u0001\u0002\u1c5b\u0001\u0004\u1408\u0de1\u1c60\u0001\u0004\u1409\u0de1\u1c65\u0001\u0002\u1c51" + "\u1c22\u0001\u0001\u0003\u1387\u1c26\u0001\u0003\u0cab\u1c2a\u0001\u0003\u1388\u1c2e\u0001\u0003\u0cac\u1c32\u0001\u0002\u1c35\u0001\u0004\u111c\u1389\u1c3a\u0001\u0005\u138a\u1407\u04f5\u1c40\u0001\u0002\u1c43\u0001\u0002\u111d\u0002\u1c48\u0001\u0008\u111e\u04e4\u1c51\u1c52\u1c53\u1c54\u1c55\u0001\u0001\u0001\u0001\u0001\u0002\u1c58\u0001\u0002\u1c5b\u0001\u0004\u1408\u0de1\u1c60\u0001\u0004\u1409\u0de1\u1c65\u0001\u0002\u1c51" +
"\u0002\u138b\u0002\u1c6c\u0001\u0002\u1c6f\u0001\u0002\u1c72\u0001\u0002\u1c75\u0001\u0003\u111f\u1c79\u0001\u0002\u111f\u0002\u1c7e\u0001\u0002\u1c81\u0001\u0002\u1c84\u0001\u0002\u1c87\u0001\u0002\u1c8a\u0001\u0002\u1c8d\u0001\u0002\u1c90\u0001\u0002\u1c93\u0001\u0002\u1c96\u0001\u0002\u1c99\u0001\u0004\u1c9e\u1120\u138c\u0001\u0003\u1ca2\u1121\u0001\u0002\u1ca5\u0001\u0002\u1ca8\u0001\u0002\u1cab\u0001\u0002\u1cae\u0001\u0002" + "\u0002\u138b\u0002\u1c6c\u0001\u0002\u1c6f\u0001\u0002\u1c72\u0001\u0002\u1c75\u0001\u0003\u111f\u1c79\u0001\u0002\u111f\u0002\u1c7e\u0001\u0002\u1c81\u0001\u0002\u1c84\u0001\u0002\u1c87\u0001\u0002\u1c8a\u0001\u0002\u1c8d\u0001\u0002\u1c90\u0001\u0002\u1c93\u0001\u0002\u1c96\u0001\u0002\u1c99\u0001\u0004\u1c9e\u1120\u138c\u0001\u0003\u1ca2\u1121\u0001\u0002\u1ca5\u0001\u0002\u1ca8\u0001\u0002\u1cab\u0001\u0002\u1cae\u0001\u0002" +
"\u1cb1\u0001\u0005\u1423\u1473\u1c52\u1cb7\u0001\u0004\u1122\u1c53\u1cb7\u0002\u1cbe\u0001\u0002\u1cc1\u0001\u0002\u1cc4\u0001\u0002\u1cc7\u0001\u0002\u1cca\u0001\u0002\u1ccd\u0001\u0002\u1cd0\u0001\u0003\u1123\u1cd4\u0001\u0002\u1124\u0002\u1125\u0002\u1126\u0016\u083b\u0d65\u0da7\u0deb\u0e1e\u0e3d\u0e7c\u0fe8\u1550\u1c26\u1c2a\u1c2e\u1c32\u1c3a\u1c40\u1c54\u1c60\u1c65\u1c79\u1cd4\u1cf1\u0001\n\u0c23\u0cad\u0d23\u0fe9\u1127" + "\u1cb1\u0001\u0005\u1423\u1473\u1c52\u1cb7\u0001\u0004\u1122\u1c53\u1cb7\u0002\u1cbe\u0001\u0002\u1cc1\u0001\u0002\u1cc4\u0001\u0002\u1cc7\u0001\u0002\u1cca\u0001\u0002\u1ccd\u0001\u0002\u1cd0\u0001\u0003\u1123\u1cd4\u0001\u0002\u1124\u0002\u1125\u0002\u1126\u0016\u083b\u0d65\u0da7\u0deb\u0e1e\u0e3d\u0e7c\u0fe8\u1550\u1c26\u1c2a\u1c2e\u1c32\u1c3a\u1c40\u1c54\u1c60\u1c65\u1c79\u1cd4\u1cf1\u0001\n\u0c23\u0cad\u0d23\u0fe9\u1127" +
"\u138d\u1424\u1c55\u1cf1\u0002\u1cfe\u0001\u00f6\u1df5\u066c\u06cc\u0706\u07ce\u06cd\u06ce\u0351\u0cfd\u0c95\u0cfe\u1dfa\u1dfe\u1e01\u1e04\u1e07\u1e0a\u1e0d\u1e10\u1e13\u1e16\u1e19\u0ddf\u1401\u0e36\u0e66\u07d3\u07d4\u0c59\u0c94\u1222\u1e1e\u0d58\u0e0f\u1e1f\u0ca6\u12fa\u0e13\u0e14\u0d5a\u0e18\u1e20\u0d00\u0688\u0d02\u1e21\u0f3a\u1e29\u1e2a\u1e2b\u1e2c\u1e2d\u1e2e\u1e2f\u1e30\u1e31\u1e32\u1e33\u1e34\u1e35\u1e36\u1e37\u162d\u1e38" + "\u138d\u1424\u1c55\u1cf1\u0002\u1cfe\u0001\u00ea\u1de9\u066c\u06cc\u0706\u07ce\u06cd\u06ce\u0351\u0cfd\u0c95\u0cfe\u1dee\u1df2\u1df5\u1df8\u1dfb\u1dfe\u1e01\u1e04\u1e07\u1e0a\u1e0d\u0ddf\u1401\u0e36\u0e66\u07d3\u07d4\u0c59\u0c94\u1222\u1e12\u0d58\u0e0f\u1e13\u0ca6\u12fa\u0e13\u0e14\u0d5a\u0e18\u1e14\u0d00\u0688\u0d02\u1e15\u0f3a\u1e1d\u1e1e\u1e1f\u1e20\u1e21\u1e22\u1e23\u1e24\u1e25\u1e26\u1e27\u1e28\u1e29\u1e2a\u1e2b\u162d\u1e2c" +
"\u1e39\u1e3b\u1e3c\u0d1f\u1e3d\u1e3e\u1e3f\u1e40\u1e41\u16ef\u16ea\u1e43\u1e44\u1e46\u1e47\u179e\u1e48\u0fb7\u0d22\u1640\u0d1e\u1e49\u1665\u166f\u16b6\u0d1f\u1e4b\u1e57\u1e5e\u1e64\u1e6b\u1e71\u1e76\u1e7c\u1e88\u1e8e\u1e94\u1e9b\u1ea8\u1884\u189a\u1967\u1eae\u191b\u1eaf\u1eb0\u1870\u1eb1\u1eb2\u1eb3\u1eb4\u1eb5\u18b3\u1995\u1eb6\u1eb7\u1eb8\u18d0\u1eb9\u1eba\u1ebb\u192b\u192c\u1dfa\u1dfe\u1e01\u1e04\u1e07\u1e0a\u1e0d\u1e10\u1e13" + "\u1e2d\u1e2f\u1e30\u0d1f\u1e31\u1e32\u1e33\u1e34\u1e35\u16ef\u16ea\u1e37\u1e38\u1e3a\u1e3b\u179e\u1e3c\u0fb7\u0d22\u1640\u0d1e\u1e3d\u1665\u166f\u16b6\u0d1f\u1e3f\u1e4b\u1e52\u1e58\u1e5f\u1e65\u1e6a\u1e70\u1e7c\u1e82\u1e88\u1e8f\u1e9c\u1884\u189a\u1967\u1ea2\u191b\u1ea3\u1ea4\u1870\u1ea5\u1ea6\u1ea7\u1ea8\u1ea9\u18b3\u1995\u1eaa\u1eab\u1eac\u18d0\u1ead\u1eae\u1eaf\u192b\u192c\u1dee\u1df2\u1df5\u1df8\u1dfb\u1dfe\u1e01\u1e04\u1e07" +
"\u1e16\u1938\u1ebc\u197c\u1995\u1ebd\u1955\u1dfa\u1dfe\u1e01\u1e04\u1e07\u1e0a\u1e0d\u1e10\u1e13\u1e16\u1ebe\u1ebf\u1ec0\u1ec1\u1ec2\u1ec3\u1ec4\u1ec5\u1ec6\u1ec7\u1ec8\u1ec9\u1eca\u1ecb\u19d6\u19d7\u19d8\u1ecc\u1ecd\u1ece\u19d9\u1ed2\u1ed3\u19da\u19db\u1ed4\u1ed5\u1ed9\u19dc\u1edd\u19dd\u1ee1\u19de\u19df\u19e0\u1ee2\u1ee3\u1ee7\u1eeb\u1eec\u1eed\u1eee\u1eef\u1ef0\u1ef1\u1ef2\u1ef3\u1ef4\u1ef5\u1ef6\u1ef7\u1ef8\u1ef9\u1efa\u1efb" + "\u1e0a\u1938\u1eb0\u197c\u1995\u1eb1\u1955\u1dee\u1df2\u1df5\u1df8\u1dfb\u1dfe\u1e01\u1e04\u1e07\u1e0a\u1eb2\u1eb3\u1eb4\u1eb5\u1eb6\u1eb7\u1eb8\u1eb9\u1eba\u1ebb\u1ebc\u1ebd\u1ebe\u1ebf\u19d6\u19d7\u19d8\u1ec0\u1ec1\u1ec2\u19d9\u1ec6\u1ec7\u19da\u19db\u1ec8\u1ec9\u1ecd\u19dc\u1ed1\u19dd\u1ed5\u19de\u19df\u19e0\u1ed6\u1ed7\u1edb\u1edf\u1ee0\u1ee1\u1ee2\u1ee3\u1ee4\u1ee5\u1ee6\u1ee7\u1ee8\u1ee9\u1eea\u1eeb\u1eec\u1eed\u1eee\u1385" +
"\u1efd\u1eff\u1f01\u1f03\u1385\u1e21\u0f48\u0e0d\u0e19\u0e0e\u0e1c\u1f05\u1f06\u1f07\u1f08\u1f09\u1f0a\u1c35\u111c\u04f5\u1f0b\u1f0c\u1f0d\u1f0e\u1f0f\u1120\u1121\u1423\u1f10\u1cd4\u138c\u1125\u1126\u083b\u1672\u1f11\u1f12\u0005\u0000\u0000\u0000\u0000\u0004\u0000\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000" + "\u1e15\u0f48\u0e0d\u0e19\u0e0e\u0e1c\u1eef\u1ef0\u1ef1\u1ef2\u1ef3\u1ef4\u1c35\u1c43\u1ef5\u1ef6\u1ef7\u1ef8\u1ef9\u1120\u1121\u1efa\u1672\u1efb\u1efc\u0005\u0000\u0000\u0000\u0000\u0004\u0000\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0005\u0000\u0000\u0000\u0000\u0001\u0001\u0001\u0008\u0000\u0000" +
"\u0000\u0005\u0000\u0000\u0000\u0000\u0001\u0001\u0001\u0008\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0002\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0002\u0000\u0001\u0002\u0000\u0001\u0001\u0001\u0002\u0000\u000c\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0007\u0000\u0000\u0000\u0000\u0000\u0000\u0006\u0000" + "\u0000\u0000\u0000\u0000\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0002\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0002\u0000\u0001\u0002\u0000\u0001\u0001\u0001\u0002\u0000\u000c\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0007\u0000\u0000\u0000\u0000\u0000\u0000\u0006\u0000\u0000\u0000\u0000\u0000\u0007\u0000\u0000\u0000\u0000\u0000\u0000\u0006" +
"\u0000\u0000\u0000\u0000\u0007\u0000\u0000\u0000\u0000\u0000\u0000\u0006\u0000\u0000\u0000\u0000\u0000\u0005\u0000\u0000\u0000\u0000\u0006\u0000\u0000\u0000\u0000\u0000\u000c\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0006\u0000\u0000\u0000\u0000\u0000\u0006\u0000\u0000\u0000\u0000\u0000\u0007\u0000\u0000\u0000\u0000\u0000\u0000\r\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + "\u0000\u0000\u0000\u0000\u0000\u0005\u0000\u0000\u0000\u0000\u0006\u0000\u0000\u0000\u0000\u0000\u000c\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0006\u0000\u0000\u0000\u0000\u0000\u0006\u0000\u0000\u0000\u0000\u0000\u0007\u0000\u0000\u0000\u0000\u0000\u0000\r\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0006\u0000\u0000\u0000\u0000\u0000\u0001\u0001\u0001\u0001\u0001\u0001" +
"\u0006\u0000\u0000\u0000\u0000\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0004\u0000\u0000\u0000\u0001\u0001\u0001\u0004\u0000\u0000\u0000\u0004\u0000\u0000\u0000\u0004\u0000\u0000\u0000\u0001\u0001\u0004\u0000\u0000\u0000\u0004\u0000\u0000\u0000\u0001\u0001\u0001\u0001\u0001" + "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0004\u0000\u0000\u0000\u0001\u0001\u0001\u0004\u0000\u0000\u0000\u0004\u0000\u0000\u0000\u0004\u0000\u0000\u0000\u0001\u0001\u0004\u0000\u0000\u0000\u0004\u0000\u0000\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001" +
"\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0002\u0000\u0002\u0000\u0002\u0000\u0002\u0000\u0002\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f1e\u1f1f\u1f20\u1f21\u1f22\u1f23\u1f24\u1f25\u1f26\u1f27\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f33\u1f34\u1f35\u1f36\u1f37\u1f38\u1f39\u1f3a\u1f3b\u1f3c\u0001\u0001\u0001\u0001\u0001" + "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f08\u1f09\u1f0a\u1f0b\u1f0c\u1f0d\u1f0e\u1f0f\u1f10\u1f11\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f1d\u1f1e\u1f1f\u1f20\u1f21\u1f22\u1f23\u1f24\u1f25\u1f26\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f32\u1f33\u1f34\u1f35\u1f36\u1f37\u1f38\u1f39\u1f3a\u1f3b\u0001\u0001\u0001\u0001\u0001\u0001" +
"\u0001\u0001\u0001\u0001\u0001\u000b\u1f48\u1f49\u1f4a\u1f4b\u1f4c\u1f4d\u1f4e\u1f4f\u1f50\u1f51\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f5d\u1f5e\u1f5f\u1f60\u1f61\u1f62\u1f63\u1f64\u1f65\u1f66\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f72\u1f73\u1f74\u1f75\u1f76\u1f77\u1f78\u1f79\u1f7a\u1f7b\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f87\u1f88\u1f89" + "\u0001\u0001\u0001\u0001\u000b\u1f47\u1f48\u1f49\u1f4a\u1f4b\u1f4c\u1f4d\u1f4e\u1f4f\u1f50\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f5c\u1f5d\u1f5e\u1f5f\u1f60\u1f61\u1f62\u1f63\u1f64\u1f65\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f71\u1f72\u1f73\u1f74\u1f75\u1f76\u1f77\u1f78\u1f79\u1f7a\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f86\u1f87\u1f88\u1f89" +
"\u1f8a\u1f8b\u1f8c\u1f8d\u1f8e\u1f8f\u1f90\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u000b\u1f9c\u1f9d\u1f9e\u1f9f\u1fa0\u1fa1\u1fa2\u1fa3\u1fa4\u1fa5\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0071\u0f55\u0d0b\u2017\u201a\u201d\u201e\u201f\u2020\u2021\u2022\u2023\u2024\u1ec6\u1ec7\u2025\u2026\u2027\u2028\u2029\u202a\u202b\u202c\u202d\u202e\u202f\u2030\u2031\u2032\u2033\u2034\u2035\u2036\u1ef1" + "\u1f8a\u1f8b\u1f8c\u1f8d\u1f8e\u1f8f\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u006f\u0f55\u0d0b\u1fff\u2002\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u200c\u1eba\u1ebb\u200d\u200e\u200f\u2010\u2011\u2012\u2013\u2014\u2015\u2016\u2017\u2018\u2019\u201a\u201b\u201c\u201d\u201e\u1ee5\u1eb4\u201f\u1eb5\u2020\u2021\u1eec\u2022\u2023\u2024\u2025\u2026\u2027\u2028\u2029\u202a\u202b\u202c\u202d\u202e\u202f\u2030\u2031" +
"\u1ec0\u2037\u1ec1\u2038\u2039\u1ef8\u203a\u203b\u203c\u203d\u203e\u203f\u2040\u2041\u2042\u2043\u2044\u2045\u2046\u2047\u2048\u2049\u204a\u204b\u204c\u204d\u204e\u204f\u2050\u2051\u0f48\u2052\u2053\u2054\u2055\u2056\u2057\u2058\u2059\u205a\u205b\u205c\u205d\u205e\u205f\u2061\u2063\u2064\u2067\u206a\u206d\u206e\u0f48\u0e0d\u0e19\u0e0e\u0e1c\u1f07\u1f08\u1f09\u1f0a\u1c43\u1c48\u1c9e\u1ca2\u1ca5\u1ca8\u206f\u2070\u2071\u2072\u2073" + "\u2032\u2033\u2034\u2035\u2036\u2037\u2038\u2039\u203a\u203c\u203e\u2040\u2042\u0f48\u2044\u2045\u2046\u2047\u2048\u2049\u204a\u204b\u204c\u204d\u204e\u204f\u2050\u2051\u2053\u2055\u2056\u2059\u205c\u205f\u2060\u0f48\u0e0d\u0e19\u0e0e\u0e1c\u1ef1\u1ef2\u1ef3\u1ef4\u2061\u2062\u2063\u2064\u2065\u2066\u2067\u2068\u2069\u206a\u206b\u0003\u0000\u0000\u0003\u0000\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001" +
"\u2074\u2075\u2076\u2077\u2078\u2079\u207a\u0003\u0000\u0000\u0003\u0000\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001" + "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0002\u0000\u0002\u0000\u0002\u0000\u0002\u0000\u0002\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0002\u0000\u0002\u0000\u0001\u0003\u0000" +
"\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0002\u0000\u0002\u0000\u0001\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0006\u2080\u2083\u2086\u2089\u208c\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0003\u0000\u0000").toCharArray(); "\u0000\u0003\u0000\u0000\u0003\u0000\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001").toCharArray();
public static final int accent_aigu = 1; public static final int accent_aigu = 1;
public static final int accent_arrows = 130; public static final int accent_arrows = 130;
@@ -265,12 +265,12 @@ public final class ComposeKeyData
public static final int accent_trema = 1172; public static final int accent_trema = 1172;
public static final int compose = 1270; public static final int compose = 1270;
public static final int fn = 7423; public static final int fn = 7423;
public static final int numpad_bengali = 7955; public static final int numpad_bengali = 7933;
public static final int numpad_devanagari = 7976; public static final int numpad_devanagari = 7954;
public static final int numpad_gujarati = 7997; public static final int numpad_gujarati = 7975;
public static final int numpad_hindu = 8018; public static final int numpad_hindu = 7996;
public static final int numpad_kannada = 8039; public static final int numpad_kannada = 8017;
public static final int numpad_persian = 8060; public static final int numpad_persian = 8038;
public static final int numpad_tamil = 8081; public static final int numpad_tamil = 8059;
public static final int shift = 8102; public static final int shift = 8080;
} }

View File

@@ -5,9 +5,14 @@ import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.KeyEvent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import juloo.keyboard2.prefs.CustomExtraKeysPreference; import juloo.keyboard2.prefs.CustomExtraKeysPreference;
import juloo.keyboard2.prefs.ExtraKeysPreference; import juloo.keyboard2.prefs.ExtraKeysPreference;
import juloo.keyboard2.prefs.LayoutsPreference; import juloo.keyboard2.prefs.LayoutsPreference;
@@ -23,6 +28,10 @@ public final class Config
public final float labelTextSize; public final float labelTextSize;
public final float sublabelTextSize; public final float sublabelTextSize;
public final KeyboardData.Row bottom_row;
public final KeyboardData.Row number_row;
public final KeyboardData num_pad;
// From preferences // From preferences
/** [null] represent the [system] layout. */ /** [null] represent the [system] layout. */
public List<KeyboardData> layouts; public List<KeyboardData> layouts;
@@ -85,6 +94,16 @@ public final class Config
keyPadding = res.getDimension(R.dimen.key_padding); keyPadding = res.getDimension(R.dimen.key_padding);
labelTextSize = 0.33f; labelTextSize = 0.33f;
sublabelTextSize = 0.22f; sublabelTextSize = 0.22f;
try
{
number_row = KeyboardData.load_number_row(res);
bottom_row = KeyboardData.load_bottom_row(res);
num_pad = KeyboardData.load_num_pad(res);
}
catch (Exception e)
{
throw new RuntimeException(e.getMessage()); // Not recoverable
}
// from prefs // from prefs
refresh(res); refresh(res);
// initialized later // initialized later
@@ -131,7 +150,7 @@ public final class Config
float swipe_scaling = Math.min(dm.widthPixels, dm.heightPixels) / 10.f * dpi_ratio; float swipe_scaling = Math.min(dm.widthPixels, dm.heightPixels) / 10.f * dpi_ratio;
float swipe_dist_value = Float.valueOf(_prefs.getString("swipe_dist", "15")); float swipe_dist_value = Float.valueOf(_prefs.getString("swipe_dist", "15"));
swipe_dist_px = swipe_dist_value / 25.f * swipe_scaling; swipe_dist_px = swipe_dist_value / 25.f * swipe_scaling;
slide_step_px = 0.4f * swipe_scaling; slide_step_px = 0.2f * swipe_scaling;
vibrate_custom = _prefs.getBoolean("vibrate_custom", false); vibrate_custom = _prefs.getBoolean("vibrate_custom", false);
vibrate_duration = _prefs.getInt("vibrate_duration", 20); vibrate_duration = _prefs.getInt("vibrate_duration", 20);
longPressTimeout = _prefs.getInt("longpress_timeout", 600); longPressTimeout = _prefs.getInt("longpress_timeout", 600);
@@ -197,6 +216,190 @@ public final class Config
_prefs.edit().putBoolean("clipboard_history_enabled", e).commit(); _prefs.edit().putBoolean("clipboard_history_enabled", e).commit();
} }
KeyValue action_key()
{
// Update the name to avoid caching in KeyModifier
return (actionLabel == null) ? null : KeyValue.makeActionKey(actionLabel);
}
/** Update the layout according to the configuration.
* - Remove the switching key if it isn't needed
* - Remove "localized" keys from other locales (not in 'extra_keys')
* - 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)
{
final KeyValue action_key = action_key();
// Extra keys are removed from the set as they are encountered during the
// first iteration then automatically added.
final Map<KeyValue, KeyboardData.PreferredPos> extra_keys = new HashMap<KeyValue, KeyboardData.PreferredPos>();
final Set<KeyValue> remove_keys = new HashSet<KeyValue>();
// Make sure the config key is accessible to avoid being locked in a custom
// layout.
extra_keys.put(KeyValue.getKeyByName("config"), KeyboardData.PreferredPos.ANYWHERE);
extra_keys.putAll(extra_keys_param);
extra_keys.putAll(extra_keys_custom);
if (extra_keys_subtype != null && kw.locale_extra_keys)
{
Set<KeyValue> present = new HashSet<KeyValue>();
present.addAll(kw.getKeys().keySet());
present.addAll(extra_keys_param.keySet());
present.addAll(extra_keys_custom.keySet());
extra_keys_subtype.compute(extra_keys,
new ExtraKeys.Query(kw.script, present));
}
KeyboardData.Row added_number_row = null;
if (add_number_row && !show_numpad)
added_number_row = modify_number_row(number_row, kw);
if (added_number_row != null)
remove_keys.addAll(added_number_row.getKeys(0).keySet());
if (kw.bottom_row)
kw = kw.insert_row(bottom_row, kw.rows.size());
kw = kw.mapKeys(new KeyboardData.MapKeyValues() {
public KeyValue apply(KeyValue key, boolean localized)
{
boolean is_extra_key = extra_keys.containsKey(key);
if (is_extra_key)
extra_keys.remove(key);
if (localized && !is_extra_key)
return null;
if (remove_keys.contains(key))
return null;
switch (key.getKind())
{
case Event:
switch (key.getEvent())
{
case CHANGE_METHOD_PICKER:
if (switch_input_immediate)
return KeyValue.getKeyByName("change_method_prev");
return key;
case ACTION:
return (swapEnterActionKey && action_key != null) ?
KeyValue.getKeyByName("enter") : action_key;
case SWITCH_FORWARD:
return (layouts.size() > 1) ? key : null;
case SWITCH_BACKWARD:
return (layouts.size() > 2) ? key : null;
case SWITCH_VOICE_TYPING:
case SWITCH_VOICE_TYPING_CHOOSER:
return shouldOfferVoiceTyping ? key : null;
}
break;
case Keyevent:
switch (key.getKeyevent())
{
case KeyEvent.KEYCODE_ENTER:
return (swapEnterActionKey && action_key != null) ? action_key : key;
}
break;
case Modifier:
switch (key.getModifier())
{
case SHIFT:
if (double_tap_lock_shift)
return key.withFlags(key.getFlags() | KeyValue.FLAG_LOCK);
}
break;
}
return key;
}
});
if (show_numpad)
kw = kw.addNumPad(modify_numpad(num_pad, kw));
if (extra_keys.size() > 0)
kw = kw.addExtraKeys(extra_keys.entrySet().iterator());
if (added_number_row != null)
kw = kw.insert_row(added_number_row, 0);
return kw;
}
/** Handle the numpad layout. The [main_kw] is used to adapt the numpad to
the main layout's script. */
public KeyboardData modify_numpad(KeyboardData kw, KeyboardData main_kw)
{
final KeyValue action_key = action_key();
final int map_digit = KeyModifier.modify_numpad_script(main_kw.numpad_script);
return kw.mapKeys(new KeyboardData.MapKeyValues() {
public KeyValue apply(KeyValue key, boolean localized)
{
switch (key.getKind())
{
case Event:
switch (key.getEvent())
{
case ACTION:
return (swapEnterActionKey && action_key != null) ?
KeyValue.getKeyByName("enter") : action_key;
}
break;
case Keyevent:
switch (key.getKeyevent())
{
case KeyEvent.KEYCODE_ENTER:
return (swapEnterActionKey && action_key != null) ? action_key : key;
}
break;
case Char:
char prev_c = key.getChar();
char c = prev_c;
if (inverse_numpad)
c = inverse_numpad_char(c);
if (map_digit != -1)
{
KeyValue modified = ComposeKey.apply(map_digit, c);
if (modified != null) // Was modified by script
return modified;
}
if (prev_c != c) // Was inverted
return key.withChar(c);
break;
}
return key;
}
});
}
static KeyboardData.MapKeyValues numpad_script_map(String numpad_script)
{
final int map_digit = KeyModifier.modify_numpad_script(numpad_script);
if (map_digit == -1)
return null;
return new KeyboardData.MapKeyValues() {
public KeyValue apply(KeyValue key, boolean localized)
{
switch (key.getKind())
{
case Char:
KeyValue modified = ComposeKey.apply(map_digit, key.getChar());
if (modified != null)
return modified;
break;
}
return key;
}
};
}
/** Modify the pin entry layout. [main_kw] is used to map the digits into the
same script. */
public KeyboardData modify_pinentry(KeyboardData kw, KeyboardData main_kw)
{
KeyboardData.MapKeyValues m = numpad_script_map(main_kw.numpad_script);
return m == null ? kw : kw.mapKeys(m);
}
/** Modify the number row according to [main_kw]'s script. */
public KeyboardData.Row modify_number_row(KeyboardData.Row row,
KeyboardData main_kw)
{
KeyboardData.MapKeyValues m = numpad_script_map(main_kw.numpad_script);
return m == null ? row : row.mapKeys(m);
}
private float get_dip_pref(DisplayMetrics dm, String pref_name, float def) private float get_dip_pref(DisplayMetrics dm, String pref_name, float def)
{ {
float value; float value;
@@ -243,6 +446,20 @@ public final class Config
} }
} }
char inverse_numpad_char(char c)
{
switch (c)
{
case '7': return '1';
case '8': return '2';
case '9': return '3';
case '1': return '7';
case '2': return '8';
case '3': return '9';
default: return c;
}
}
private static Config _globalConfig = null; private static Config _globalConfig = null;
public static void initGlobalConfig(SharedPreferences prefs, Resources res, public static void initGlobalConfig(SharedPreferences prefs, Resources res,
@@ -250,7 +467,6 @@ public final class Config
{ {
migrate(prefs); migrate(prefs);
_globalConfig = new Config(prefs, res, handler); _globalConfig = new Config(prefs, res, handler);
LayoutModifier.init(_globalConfig, res);
} }
public static Config globalConfig() public static Config globalConfig()

View File

@@ -2,9 +2,7 @@ package juloo.keyboard2;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.os.Looper; import android.os.Looper;
import android.os.Handler;
import android.text.InputType; import android.text.InputType;
import android.view.KeyCharacterMap;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedText;
@@ -29,10 +27,10 @@ public final class KeyEventHandler
[setSelection] could be used instead. */ [setSelection] could be used instead. */
boolean _move_cursor_force_fallback = false; boolean _move_cursor_force_fallback = false;
public KeyEventHandler(IReceiver recv) public KeyEventHandler(Looper looper, IReceiver recv)
{ {
_recv = recv; _recv = recv;
_autocap = new Autocapitalisation(recv.getHandler(), _autocap = new Autocapitalisation(looper,
this.new Autocapitalisation_callback()); this.new Autocapitalisation_callback());
_mods = Pointers.Modifiers.EMPTY; _mods = Pointers.Modifiers.EMPTY;
} }
@@ -98,9 +96,11 @@ public final class KeyEventHandler
case Keyevent: send_key_down_up(key.getKeyevent()); break; case Keyevent: send_key_down_up(key.getKeyevent()); break;
case Modifier: break; case Modifier: break;
case Editing: handle_editing_key(key.getEditing()); break; case Editing: handle_editing_key(key.getEditing()); break;
case Compose_pending: _recv.set_compose_pending(true); break; case Compose_pending:
case Slider: handle_slider(key.getSlider(), key.getSliderRepeat()); break; _recv.set_compose_pending(true);
case Macro: evaluate_macro(key.getMacro()); break; break;
case Cursor_move: move_cursor(key.getCursorMove()); break;
case Complex: send_complex_key(key.getComplexKind(), key.getComplex()); break;
} }
update_meta_state(old_mods); update_meta_state(old_mods);
} }
@@ -147,11 +147,11 @@ public final class KeyEventHandler
if (down) if (down)
{ {
_meta_state = _meta_state | meta_flags; _meta_state = _meta_state | meta_flags;
send_keyevent(KeyEvent.ACTION_DOWN, eventCode, _meta_state); send_keyevent(KeyEvent.ACTION_DOWN, eventCode);
} }
else else
{ {
send_keyevent(KeyEvent.ACTION_UP, eventCode, _meta_state); send_keyevent(KeyEvent.ACTION_UP, eventCode);
_meta_state = _meta_state & ~meta_flags; _meta_state = _meta_state & ~meta_flags;
} }
} }
@@ -182,28 +182,23 @@ public final class KeyEventHandler
} }
} }
/*
* Don't set KeyEvent.FLAG_SOFT_KEYBOARD.
*/
void send_key_down_up(int keyCode) void send_key_down_up(int keyCode)
{ {
send_key_down_up(keyCode, _meta_state); send_keyevent(KeyEvent.ACTION_DOWN, keyCode);
send_keyevent(KeyEvent.ACTION_UP, keyCode);
} }
/** Ignores currently pressed system modifiers. */ void send_keyevent(int eventAction, int eventCode)
void send_key_down_up(int keyCode, int metaState)
{
send_keyevent(KeyEvent.ACTION_DOWN, keyCode, metaState);
send_keyevent(KeyEvent.ACTION_UP, keyCode, metaState);
}
void send_keyevent(int eventAction, int eventCode, int metaState)
{ {
InputConnection conn = _recv.getCurrentInputConnection(); InputConnection conn = _recv.getCurrentInputConnection();
if (conn == null) if (conn == null)
return; return;
conn.sendKeyEvent(new KeyEvent(1, 1, eventAction, eventCode, 0, conn.sendKeyEvent(new KeyEvent(1, 1, eventAction, eventCode, 0, _meta_state));
metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE));
if (eventAction == KeyEvent.ACTION_UP) if (eventAction == KeyEvent.ACTION_UP)
_autocap.event_sent(eventCode, metaState); _autocap.event_sent(eventCode, _meta_state);
} }
void send_text(CharSequence text) void send_text(CharSequence text)
@@ -224,6 +219,16 @@ public final class KeyEventHandler
conn.performContextMenuAction(id); conn.performContextMenuAction(id);
} }
void send_complex_key(KeyValue.Complex.Kind kind, KeyValue.Complex val)
{
switch (kind)
{
case StringWithSymbol:
send_text(((KeyValue.Complex.StringWithSymbol)val).str);
break;
}
}
@SuppressLint("InlinedApi") @SuppressLint("InlinedApi")
void handle_editing_key(KeyValue.Editing ev) void handle_editing_key(KeyValue.Editing ev)
{ {
@@ -240,9 +245,6 @@ public final class KeyEventHandler
case REPLACE: send_context_menu_action(android.R.id.replaceText); break; case REPLACE: send_context_menu_action(android.R.id.replaceText); break;
case ASSIST: send_context_menu_action(android.R.id.textAssist); break; case ASSIST: send_context_menu_action(android.R.id.textAssist); break;
case AUTOFILL: send_context_menu_action(android.R.id.autofill); break; case AUTOFILL: send_context_menu_action(android.R.id.autofill); break;
case DELETE_WORD: send_key_down_up(KeyEvent.KEYCODE_DEL, KeyEvent.META_CTRL_ON | KeyEvent.META_CTRL_LEFT_ON); break;
case FORWARD_DELETE_WORD: send_key_down_up(KeyEvent.KEYCODE_FORWARD_DEL, KeyEvent.META_CTRL_ON | KeyEvent.META_CTRL_LEFT_ON); break;
case SELECTION_CANCEL: cancel_selection(); break;
} }
} }
@@ -260,20 +262,6 @@ public final class KeyEventHandler
return conn.getExtractedText(_move_cursor_req, 0); return conn.getExtractedText(_move_cursor_req, 0);
} }
/** [r] might be negative, in which case the direction is reversed. */
void handle_slider(KeyValue.Slider s, int r)
{
switch (s)
{
case Cursor_left: move_cursor(-r); break;
case Cursor_right: move_cursor(r); break;
case Cursor_up: move_cursor_vertical(-r); break;
case Cursor_down: move_cursor_vertical(r); break;
case Selection_cursor_left: move_cursor_sel(r, true); break;
case Selection_cursor_right: move_cursor_sel(r, false); break;
}
}
/** Move the cursor right or left, if possible without sending key events. /** Move the cursor right or left, if possible without sending key events.
Unlike arrow keys, the selection is not removed even if shift is not on. Unlike arrow keys, the selection is not removed even if shift is not on.
Falls back to sending arrow keys events if the editor do not support Falls back to sending arrow keys events if the editor do not support
@@ -284,8 +272,15 @@ public final class KeyEventHandler
if (conn == null) if (conn == null)
return; return;
ExtractedText et = get_cursor_pos(conn); ExtractedText et = get_cursor_pos(conn);
if (et != null && can_set_selection(conn)) int system_mods =
KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON | KeyEvent.META_META_ON;
// Fallback to sending key events
if (_move_cursor_force_fallback || et == null
|| (_meta_state & system_mods) != 0)
{ {
move_cursor_fallback(d);
return;
}
int sel_start = et.selectionStart; int sel_start = et.selectionStart;
int sel_end = et.selectionEnd; int sel_end = et.selectionEnd;
// Continue expanding the selection even if shift is not pressed // Continue expanding the selection even if shift is not pressed
@@ -302,150 +297,24 @@ public final class KeyEventHandler
if ((_meta_state & KeyEvent.META_SHIFT_ON) == 0) if ((_meta_state & KeyEvent.META_SHIFT_ON) == 0)
sel_start = sel_end; sel_start = sel_end;
} }
if (conn.setSelection(sel_start, sel_end)) if (!conn.setSelection(sel_start, sel_end))
return; // Fallback to sending key events if [setSelection] failed
}
move_cursor_fallback(d); move_cursor_fallback(d);
} }
/** Move one of the two side of a selection. If [sel_left] is true, the left /** Send arrow keys as a fallback for editors that do not support
position is moved, otherwise the right position is moved. */ [getExtractedText] like Termux. */
void move_cursor_sel(int d, boolean sel_left)
{
InputConnection conn = _recv.getCurrentInputConnection();
if (conn == null)
return;
ExtractedText et = get_cursor_pos(conn);
if (et != null && can_set_selection(conn))
{
int sel_start = et.selectionStart;
int sel_end = et.selectionEnd;
if (sel_left == (sel_start <= sel_end))
sel_start += d;
else
sel_end += d;
if (conn.setSelection(sel_start, sel_end))
return; // Fallback to sending key events if [setSelection] failed
}
move_cursor_fallback(d);
}
/** Returns whether the selection can be set using [conn.setSelection()].
This can happen on Termux or when system modifiers are activated for
example. */
boolean can_set_selection(InputConnection conn)
{
final int system_mods =
KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON | KeyEvent.META_META_ON;
return !_move_cursor_force_fallback && (_meta_state & system_mods) == 0;
}
void move_cursor_fallback(int d) void move_cursor_fallback(int d)
{ {
if (d < 0) while (d < 0)
send_key_down_up_repeat(KeyEvent.KEYCODE_DPAD_LEFT, -d);
else
send_key_down_up_repeat(KeyEvent.KEYCODE_DPAD_RIGHT, d);
}
/** Move the cursor up and down. This sends UP and DOWN key events that might
make the focus exit the text box. */
void move_cursor_vertical(int d)
{ {
if (d < 0) send_key_down_up(KeyEvent.KEYCODE_DPAD_LEFT);
send_key_down_up_repeat(KeyEvent.KEYCODE_DPAD_UP, -d); d++;
else
send_key_down_up_repeat(KeyEvent.KEYCODE_DPAD_DOWN, d);
} }
while (d > 0)
void evaluate_macro(KeyValue[] keys)
{ {
if (keys.length == 0) send_key_down_up(KeyEvent.KEYCODE_DPAD_RIGHT);
return; d--;
// Ignore modifiers that are activated at the time the macro is evaluated
mods_changed(Pointers.Modifiers.EMPTY);
evaluate_macro_loop(keys, 0, Pointers.Modifiers.EMPTY, _autocap.pause());
} }
/** Evaluate the macro asynchronously to make sure event are processed in the
right order. */
void evaluate_macro_loop(final KeyValue[] keys, int i, Pointers.Modifiers mods, final boolean autocap_paused)
{
boolean should_delay = false;
KeyValue kv = KeyModifier.modify(keys[i], mods);
if (kv != null)
{
if (kv.hasFlagsAny(KeyValue.FLAG_LATCH))
{
// Non-special latchable keys clear latched modifiers
if (!kv.hasFlagsAny(KeyValue.FLAG_SPECIAL))
mods = Pointers.Modifiers.EMPTY;
mods = mods.with_extra_mod(kv);
}
else
{
key_down(kv, false);
key_up(kv, mods);
mods = Pointers.Modifiers.EMPTY;
}
should_delay = wait_after_macro_key(kv);
}
i++;
if (i >= keys.length) // Stop looping
{
_autocap.unpause(autocap_paused);
}
else if (should_delay)
{
// Add a delay before sending the next key to avoid race conditions
// causing keys to be handled in the wrong order. Notably, KeyEvent keys
// handling is scheduled differently than the other edit functions.
final int i_ = i;
final Pointers.Modifiers mods_ = mods;
_recv.getHandler().postDelayed(new Runnable() {
public void run()
{
evaluate_macro_loop(keys, i_, mods_, autocap_paused);
}
}, 1000/30);
}
else
evaluate_macro_loop(keys, i, mods, autocap_paused);
}
boolean wait_after_macro_key(KeyValue kv)
{
switch (kv.getKind())
{
case Keyevent:
case Editing:
case Event:
return true;
case Slider:
return _move_cursor_force_fallback;
default:
return false;
}
}
/** Repeat calls to [send_key_down_up]. */
void send_key_down_up_repeat(int event_code, int repeat)
{
while (repeat-- > 0)
send_key_down_up(event_code);
}
void cancel_selection()
{
InputConnection conn = _recv.getCurrentInputConnection();
if (conn == null)
return;
ExtractedText et = get_cursor_pos(conn);
if (et == null) return;
final int curs = et.selectionStart;
// Notify the receiver as Android's [onUpdateSelection] is not triggered.
if (conn.setSelection(curs, curs));
_recv.selection_state_changed(false);
} }
public static interface IReceiver public static interface IReceiver
@@ -453,9 +322,7 @@ public final class KeyEventHandler
public void handle_event_key(KeyValue.Event ev); public void handle_event_key(KeyValue.Event ev);
public void set_shift_state(boolean state, boolean lock); public void set_shift_state(boolean state, boolean lock);
public void set_compose_pending(boolean pending); public void set_compose_pending(boolean pending);
public void selection_state_changed(boolean selection_is_ongoing);
public InputConnection getCurrentInputConnection(); public InputConnection getCurrentInputConnection();
public Handler getHandler();
} }
class Autocapitalisation_callback implements Autocapitalisation.Callback class Autocapitalisation_callback implements Autocapitalisation.Callback

View File

@@ -36,7 +36,7 @@ public final class KeyModifier
case Modifier: case Modifier:
return modify(k, mod.getModifier()); return modify(k, mod.getModifier());
case Compose_pending: case Compose_pending:
return apply_compose_pending(mod.getPendingCompose(), k); return ComposeKey.apply(mod.getPendingCompose(), k);
case Hangul_initial: case Hangul_initial:
if (k.equals(mod)) // Allow typing the initial in letter form if (k.equals(mod)) // Allow typing the initial in letter form
return KeyValue.makeStringKey(k.getString(), KeyValue.FLAG_GREYED); return KeyValue.makeStringKey(k.getString(), KeyValue.FLAG_GREYED);
@@ -82,7 +82,6 @@ public final class KeyModifier
case HOOK_ABOVE: return apply_compose(k, ComposeKeyData.accent_hook_above); case HOOK_ABOVE: return apply_compose(k, ComposeKeyData.accent_hook_above);
case DOUBLE_GRAVE: return apply_compose(k, ComposeKeyData.accent_double_grave); case DOUBLE_GRAVE: return apply_compose(k, ComposeKeyData.accent_double_grave);
case ARROW_RIGHT: return apply_combining_char(k, "\u20D7"); case ARROW_RIGHT: return apply_combining_char(k, "\u20D7");
case SELECTION_MODE: return apply_selection_mode(k);
default: return k; default: return k;
} }
} }
@@ -123,44 +122,30 @@ public final class KeyModifier
} }
} }
/** Keys that do not match any sequence are greyed. */
private static KeyValue apply_compose_pending(int state, KeyValue kv)
{
switch (kv.getKind())
{
case Char:
case String:
KeyValue res = ComposeKey.apply(state, kv);
// Grey-out characters not part of any sequence.
if (res == null)
return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
return res;
/* Tapping compose again exits the pending sequence. */
case Compose_pending:
return KeyValue.getKeyByName("compose_cancel");
/* These keys are not greyed. */
case Event:
case Modifier:
return kv;
/* Other keys cannot be part of sequences. */
default:
return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
}
}
/** Apply the given compose state or fallback to the dead_char. */ /** Apply the given compose state or fallback to the dead_char. */
private static KeyValue apply_compose_or_dead_char(KeyValue k, int state, char dead_char) private static KeyValue apply_compose_or_dead_char(KeyValue k, int state, char dead_char)
{ {
KeyValue r = ComposeKey.apply(state, k); switch (k.getKind())
{
case Char:
char c = k.getChar();
KeyValue r = ComposeKey.apply(state, c);
if (r != null) if (r != null)
return r; return r;
}
return apply_dead_char(k, dead_char); return apply_dead_char(k, dead_char);
} }
private static KeyValue apply_compose(KeyValue k, int state) private static KeyValue apply_compose(KeyValue k, int state)
{ {
KeyValue r = ComposeKey.apply(state, k); switch (k.getKind())
return (r != null) ? r : k; {
case Char:
KeyValue r = ComposeKey.apply(state, k.getChar());
if (r != null)
return r;
}
return k;
} }
private static KeyValue apply_dead_char(KeyValue k, char dead_char) private static KeyValue apply_dead_char(KeyValue k, char dead_char)
@@ -194,19 +179,18 @@ public final class KeyModifier
if (mapped != null) if (mapped != null)
return mapped; return mapped;
} }
KeyValue r = ComposeKey.apply(ComposeKeyData.shift, k);
if (r != null)
return r;
switch (k.getKind()) switch (k.getKind())
{ {
case Char: case Char:
char kc = k.getChar(); char kc = k.getChar();
KeyValue r = ComposeKey.apply(ComposeKeyData.shift, kc);
if (r != null)
return r;
char c = Character.toUpperCase(kc); char c = Character.toUpperCase(kc);
return (kc == c) ? k : k.withChar(c); return (kc == c) ? k : k.withChar(c);
case String: case String:
String ks = k.getString(); String s = Utils.capitalize_string(k.getString());
String s = Utils.capitalize_string(ks); return KeyValue.makeStringKey(s, k.getFlags());
return s.equals(ks) ? k : KeyValue.makeStringKey(s, k.getFlags());
default: return k; default: return k;
} }
} }
@@ -223,13 +207,11 @@ public final class KeyModifier
switch (k.getKind()) switch (k.getKind())
{ {
case Char: case Char:
case String: KeyValue r = ComposeKey.apply(ComposeKeyData.fn, k.getChar());
KeyValue r = ComposeKey.apply(ComposeKeyData.fn, k);
return (r != null) ? r : k; return (r != null) ? r : k;
case Keyevent: name = apply_fn_keyevent(k.getKeyevent()); break; case Keyevent: name = apply_fn_keyevent(k.getKeyevent()); break;
case Event: name = apply_fn_event(k.getEvent()); break; case Event: name = apply_fn_event(k.getEvent()); break;
case Placeholder: name = apply_fn_placeholder(k.getPlaceholder()); break; case Placeholder: name = apply_fn_placeholder(k.getPlaceholder()); break;
case Editing: name = apply_fn_editing(k.getEditing()); break;
} }
return (name == null) ? k : KeyValue.getKeyByName(name); return (name == null) ? k : KeyValue.getKeyByName(name);
} }
@@ -275,16 +257,6 @@ public final class KeyModifier
} }
} }
private static String apply_fn_editing(KeyValue.Editing p)
{
switch (p)
{
case UNDO: return "redo";
case PASTE: return "pasteAsPlainText";
default: return null;
}
}
private static KeyValue apply_ctrl(KeyValue k) private static KeyValue apply_ctrl(KeyValue k)
{ {
if (_modmap != null) if (_modmap != null)
@@ -367,58 +339,10 @@ public final class KeyModifier
/** Modify a key affected by a round-trip or a clockwise circle gesture. */ /** Modify a key affected by a round-trip or a clockwise circle gesture. */
private static KeyValue apply_gesture(KeyValue k) private static KeyValue apply_gesture(KeyValue k)
{ {
KeyValue modified = apply_shift(k); KeyValue shifted = apply_shift(k);
if (modified != null && !modified.equals(k)) if (shifted == null || shifted.equals(k))
return modified; return apply_fn(k);
modified = apply_fn(k); return shifted;
if (modified != null && !modified.equals(k))
return modified;
String name = null;
switch (k.getKind())
{
case Modifier:
switch (k.getModifier())
{
case SHIFT: name = "capslock"; break;
}
break;
case Keyevent:
switch (k.getKeyevent())
{
case KeyEvent.KEYCODE_DEL: name = "delete_word"; break;
case KeyEvent.KEYCODE_FORWARD_DEL: name = "forward_delete_word"; break;
}
break;
}
return (name == null) ? k : KeyValue.getKeyByName(name);
}
private static KeyValue apply_selection_mode(KeyValue k)
{
String name = null;
switch (k.getKind())
{
case Char:
switch (k.getChar())
{
case ' ': name = "selection_cancel"; break;
}
break;
case Slider:
switch (k.getSlider())
{
case Cursor_left: name = "selection_cursor_left"; break;
case Cursor_right: name = "selection_cursor_right"; break;
}
break;
case Keyevent:
switch (k.getKeyevent())
{
case KeyEvent.KEYCODE_ESCAPE: name = "selection_cancel"; break;
}
break;
}
return (name == null) ? k : KeyValue.getKeyByName(name);
} }
/** Compose the precomposed initial with the medial [kv]. */ /** Compose the precomposed initial with the medial [kv]. */

View File

@@ -59,7 +59,6 @@ public final class KeyValue implements Comparable<KeyValue>
BREVE, BREVE,
BAR, BAR,
FN, FN,
SELECTION_MODE,
} // Last is be applied first } // Last is be applied first
public static enum Editing public static enum Editing
@@ -76,15 +75,11 @@ public final class KeyValue implements Comparable<KeyValue>
SHARE, SHARE,
ASSIST, ASSIST,
AUTOFILL, AUTOFILL,
DELETE_WORD,
FORWARD_DELETE_WORD,
SELECTION_CANCEL,
} }
public static enum Placeholder public static enum Placeholder
{ {
REMOVED, REMOVED,
COMPOSE_CANCEL,
F11, F11,
F12, F12,
SHINDOT, SHINDOT,
@@ -95,54 +90,56 @@ public final class KeyValue implements Comparable<KeyValue>
public static enum Kind public static enum Kind
{ {
Char, Keyevent, Event, Compose_pending, Hangul_initial, Hangul_medial, Char, String, Keyevent, Event, Compose_pending, Hangul_initial,
Modifier, Editing, Placeholder, Hangul_medial, Modifier, Editing, Placeholder,
String, // [_payload] is also the string to output, value is unused. Cursor_move, // Value is encoded as a 16-bit integer.
Slider, // [_payload] is a [KeyValue.Slider], value is slider repeatition. Complex, // [_payload] is a [KeyValue.Complex], value is [Complex.Kind].
Macro, // [_payload] is a [KeyValue.Macro], value is unused.
} }
private static final int FLAGS_OFFSET = 20; private static final int FLAGS_OFFSET = 19;
private static final int KIND_OFFSET = 28; private static final int KIND_OFFSET = 28;
// Key stay activated when pressed once. // Behavior flags.
public static final int FLAG_LATCH = (1 << FLAGS_OFFSET << 0); public static final int FLAG_LATCH = (1 << FLAGS_OFFSET << 0);
// Key can be locked by typing twice when enabled in settings // Key can be locked by typing twice
public static final int FLAG_DOUBLE_TAP_LOCK = (1 << FLAGS_OFFSET << 1); public static final int FLAG_LOCK = (1 << FLAGS_OFFSET << 1);
// Special keys are not repeated. // Special keys are not repeated and don't clear latched modifiers.
// Special latchable keys don't clear latched modifiers.
public static final int FLAG_SPECIAL = (1 << FLAGS_OFFSET << 2); public static final int FLAG_SPECIAL = (1 << FLAGS_OFFSET << 2);
// Whether the symbol should be greyed out. For example, keys that are not // Whether the symbol should be greyed out. For example, keys that are not
// part of the pending compose sequence. // part of the pending compose sequence.
public static final int FLAG_GREYED = (1 << FLAGS_OFFSET << 3); public static final int FLAG_GREYED = (1 << FLAGS_OFFSET << 3);
// The special font is required to render this key. // Rendering flags.
public static final int FLAG_KEY_FONT = (1 << FLAGS_OFFSET << 4); public static final int FLAG_KEY_FONT = (1 << FLAGS_OFFSET << 4); // special font file
// 25% smaller symbols public static final int FLAG_SMALLER_FONT = (1 << FLAGS_OFFSET << 5); // 25% smaller symbols
public static final int FLAG_SMALLER_FONT = (1 << FLAGS_OFFSET << 5); public static final int FLAG_SECONDARY = (1 << FLAGS_OFFSET << 6); // dimmer
// Dimmer symbol // Used by [Pointers].
public static final int FLAG_SECONDARY = (1 << FLAGS_OFFSET << 6);
// Free: (1 << FLAGS_OFFSET << 7) // Free: (1 << FLAGS_OFFSET << 7)
// Free: (1 << FLAGS_OFFSET << 8)
// Ranges for the different components // Ranges for the different components
private static final int FLAGS_BITS = (0b11111111 << FLAGS_OFFSET); // 8 bits wide private static final int FLAGS_BITS =
FLAG_LATCH | FLAG_LOCK | FLAG_SPECIAL | FLAG_GREYED | FLAG_KEY_FONT |
FLAG_SMALLER_FONT | FLAG_SECONDARY;
private static final int KIND_BITS = (0b1111 << KIND_OFFSET); // 4 bits wide private static final int KIND_BITS = (0b1111 << KIND_OFFSET); // 4 bits wide
private static final int VALUE_BITS = 0b11111111111111111111; // 20 bits wide private static final int VALUE_BITS = ~(FLAGS_BITS | KIND_BITS); // 20 bits wide
static static
{ {
check((FLAGS_BITS & KIND_BITS) == 0); // No overlap with kind check((FLAGS_BITS & KIND_BITS) == 0); // No overlap
check(~(FLAGS_BITS | KIND_BITS) == VALUE_BITS); // No overlap with value
check((FLAGS_BITS | KIND_BITS | VALUE_BITS) == ~0); // No holes check((FLAGS_BITS | KIND_BITS | VALUE_BITS) == ~0); // No holes
// No kind is out of range // No kind is out of range
check((((Kind.values().length - 1) << KIND_OFFSET) & ~KIND_BITS) == 0); check((((Kind.values().length - 1) << KIND_OFFSET) & ~KIND_BITS) == 0);
} }
/** [_payload.toString()] is the symbol that is rendered on the keyboard. */ /**
private final Comparable _payload; * The symbol that is rendered on the keyboard as a [String].
* Except for keys of kind:
* - [String], this is also the string to output.
* - [Complex], this is an instance of [KeyValue.Complex].
*/
private final Object _payload;
/** This field encodes three things: Kind (KIND_BITS), flags (FLAGS_BITS) and /** This field encodes three things: Kind, flags and value. */
value (VALUE_BITS).
The meaning of the value depends on the kind. */
private final int _code; private final int _code;
public Kind getKind() public Kind getKind()
@@ -164,7 +161,9 @@ public final class KeyValue implements Comparable<KeyValue>
When [getKind() == Kind.String], also the string to send. */ When [getKind() == Kind.String], also the string to send. */
public String getString() public String getString()
{ {
return _payload.toString(); if (getKind() == Kind.Complex)
return ((Complex)_payload).getSymbol();
return (String)_payload;
} }
/** Defined only when [getKind() == Kind.Char]. */ /** Defined only when [getKind() == Kind.Char]. */
@@ -216,29 +215,28 @@ public final class KeyValue implements Comparable<KeyValue>
return (_code & VALUE_BITS); return (_code & VALUE_BITS);
} }
/** Defined only when [getKind() == Kind.Slider]. */ /** Defined only when [getKind() == Kind.Cursor_move]. */
public Slider getSlider() public short getCursorMove()
{ {
return (Slider)_payload; return (short)(_code & VALUE_BITS);
} }
/** Defined only when [getKind() == Kind.Slider]. */ /** Defined only when [getKind() == Kind.Complex]. */
public int getSliderRepeat() public Complex getComplex()
{ {
return ((int)(short)(_code & VALUE_BITS)); return (Complex)_payload;
} }
/** Defined only when [getKind() == Kind.Macro]. */ /** Defined only when [getKind() == Kind.Complex]. */
public KeyValue[] getMacro() public Complex.Kind getComplexKind()
{ {
return ((Macro)_payload).keys; return Complex.Kind.values()[(_code & VALUE_BITS)];
} }
/* Update the char and the symbol. */ /* Update the char and the symbol. */
public KeyValue withChar(char c) public KeyValue withChar(char c)
{ {
return new KeyValue(String.valueOf(c), Kind.Char, c, return new KeyValue(String.valueOf(c), Kind.Char, c, getFlags());
getFlags() & ~(FLAG_KEY_FONT | FLAG_SMALLER_FONT));
} }
public KeyValue withKeyevent(int code) public KeyValue withKeyevent(int code)
@@ -248,31 +246,7 @@ public final class KeyValue implements Comparable<KeyValue>
public KeyValue withFlags(int f) public KeyValue withFlags(int f)
{ {
return new KeyValue(_payload, _code, _code, f); return new KeyValue(_payload, (_code & KIND_BITS), (_code & VALUE_BITS), f);
}
public KeyValue withSymbol(String symbol)
{
int flags = getFlags() & ~(FLAG_KEY_FONT | FLAG_SMALLER_FONT);
switch (getKind())
{
case Char:
case Keyevent:
case Event:
case Compose_pending:
case Hangul_initial:
case Hangul_medial:
case Modifier:
case Editing:
case Placeholder:
if (symbol.length() > 1)
flags |= FLAG_SMALLER_FONT;
return new KeyValue(symbol, _code, _code, flags);
case Macro:
return makeMacro(symbol, getMacro(), flags);
default:
return makeMacro(symbol, new KeyValue[]{ this }, flags);
}
} }
@Override @Override
@@ -281,7 +255,6 @@ public final class KeyValue implements Comparable<KeyValue>
return sameKey((KeyValue)obj); return sameKey((KeyValue)obj);
} }
@Override
public int compareTo(KeyValue snd) public int compareTo(KeyValue snd)
{ {
// Compare the kind and value first, then the flags. // Compare the kind and value first, then the flags.
@@ -291,9 +264,9 @@ public final class KeyValue implements Comparable<KeyValue>
d = _code - snd._code; d = _code - snd._code;
if (d != 0) if (d != 0)
return d; return d;
// Calls [compareTo] assuming that if [_code] matches, then [_payload] are if (getKind() == Kind.Complex)
// of the same class. return ((Complex)_payload).compareTo((Complex)snd._payload);
return _payload.compareTo(snd._payload); return ((String)_payload).compareTo((String)snd._payload);
} }
/** Type-safe alternative to [equals]. */ /** Type-safe alternative to [equals]. */
@@ -301,7 +274,7 @@ public final class KeyValue implements Comparable<KeyValue>
{ {
if (snd == null) if (snd == null)
return false; return false;
return _code == snd._code && _payload.compareTo(snd._payload) == 0; return _code == snd._code && _payload.equals(snd._payload);
} }
@Override @Override
@@ -316,15 +289,19 @@ public final class KeyValue implements Comparable<KeyValue>
return "[KeyValue " + getKind().toString() + "+" + getFlags() + "+" + value + " \"" + getString() + "\"]"; return "[KeyValue " + getKind().toString() + "+" + getFlags() + "+" + value + " \"" + getString() + "\"]";
} }
private KeyValue(Comparable p, int kind, int value, int flags) private KeyValue(Object p, int kind, int value, int flags)
{ {
if (p == null)
throw new NullPointerException("KeyValue payload cannot be null");
_payload = p; _payload = p;
_code = (kind & KIND_BITS) | (flags & FLAGS_BITS) | (value & VALUE_BITS); _code = (kind & KIND_BITS) | (flags & FLAGS_BITS) | (value & VALUE_BITS);
} }
public KeyValue(Comparable p, Kind k, int v, int f) public KeyValue(Complex p, Complex.Kind value, int flags)
{
this((Object)p, (Kind.Complex.ordinal() << KIND_OFFSET), value.ordinal(),
flags);
}
public KeyValue(String p, Kind k, int v, int f)
{ {
this(p, (k.ordinal() << KIND_OFFSET), v, f); this(p, (k.ordinal() << KIND_OFFSET), v, f);
} }
@@ -336,7 +313,7 @@ public final class KeyValue implements Comparable<KeyValue>
private static KeyValue charKey(int symbol, char c, int flags) private static KeyValue charKey(int symbol, char c, int flags)
{ {
return charKey(String.valueOf((char)symbol), c, flags | FLAG_KEY_FONT); return charKey(String.valueOf((char)symbol), c, flags);
} }
private static KeyValue modifierKey(String symbol, Modifier m, int flags) private static KeyValue modifierKey(String symbol, Modifier m, int flags)
@@ -394,12 +371,13 @@ public final class KeyValue implements Comparable<KeyValue>
return editingKey(String.valueOf((char)symbol), action, FLAG_KEY_FONT); return editingKey(String.valueOf((char)symbol), action, FLAG_KEY_FONT);
} }
/** A key that slides the property specified by [s] by the amount specified /** A key that moves the cursor [d] times to the right. If [d] is negative,
with [repeatition]. */ it moves the cursor [abs(d)] times to the left. */
public static KeyValue sliderKey(Slider s, int repeatition) public static KeyValue cursorMoveKey(int d)
{ {
// Casting to a short then back to a int to preserve the sign bit. int symbol = (d < 0) ? 0xE008 : 0xE006;
return new KeyValue(s, Kind.Slider, (short)repeatition & 0xFFFF, return new KeyValue(String.valueOf((char)symbol), Kind.Cursor_move,
((short)d) & 0xFFFF,
FLAG_SPECIAL | FLAG_SECONDARY | FLAG_KEY_FONT); FLAG_SPECIAL | FLAG_SECONDARY | FLAG_KEY_FONT);
} }
@@ -409,12 +387,6 @@ public final class KeyValue implements Comparable<KeyValue>
return new KeyValue("", Kind.Placeholder, id.ordinal(), 0); return new KeyValue("", Kind.Placeholder, id.ordinal(), 0);
} }
private static KeyValue placeholderKey(int symbol, Placeholder id, int flags)
{
return new KeyValue(String.valueOf((char)symbol), Kind.Placeholder,
id.ordinal(), flags | FLAG_KEY_FONT);
}
public static KeyValue makeStringKey(String str) public static KeyValue makeStringKey(String str)
{ {
return makeStringKey(str, 0); return makeStringKey(str, 0);
@@ -483,11 +455,10 @@ public final class KeyValue implements Comparable<KeyValue>
return new KeyValue(str, Kind.String, 0, flags | FLAG_SMALLER_FONT); return new KeyValue(str, Kind.String, 0, flags | FLAG_SMALLER_FONT);
} }
public static KeyValue makeMacro(String symbol, KeyValue[] keys, int flags) public static KeyValue makeStringKeyWithSymbol(String str, String symbol, int flags)
{ {
if (symbol.length() > 1) return new KeyValue(new Complex.StringWithSymbol(str, symbol),
flags |= FLAG_SMALLER_FONT; Complex.Kind.StringWithSymbol, flags);
return new KeyValue(new Macro(keys, symbol), Kind.Macro, 0, flags);
} }
/** Make a modifier key for passing to [KeyModifier]. */ /** Make a modifier key for passing to [KeyModifier]. */
@@ -496,24 +467,25 @@ public final class KeyValue implements Comparable<KeyValue>
return new KeyValue("", Kind.Modifier, mod.ordinal(), 0); return new KeyValue("", Kind.Modifier, mod.ordinal(), 0);
} }
/** Return a key by its name. If the given name doesn't correspond to any public static KeyValue parseKeyDefinition(String str)
special key, it is parsed with [KeyValueParser]. */
public static KeyValue getKeyByName(String name)
{ {
KeyValue k = getSpecialKeyByName(name); if (str.length() < 2 || str.charAt(0) != ':')
if (k != null) return makeStringKey(str);
return k;
try try
{ {
return KeyValueParser.parse(name); return KeyValueParser.parse(str);
} }
catch (KeyValueParser.ParseError _e) catch (KeyValueParser.ParseError _e)
{ {
return makeStringKey(name); return makeStringKey(str);
} }
} }
public static KeyValue getSpecialKeyByName(String name) /**
* Return a key by its name. If the given name doesn't correspond to a key
* defined in this function, it is passed to [parseStringKey] as a fallback.
*/
public static KeyValue getKeyByName(String name)
{ {
switch (name) switch (name)
{ {
@@ -526,7 +498,7 @@ public final class KeyValue implements Comparable<KeyValue>
case "\\\\": return makeStringKey("\\"); case "\\\\": return makeStringKey("\\");
/* Modifiers and dead-keys */ /* Modifiers and dead-keys */
case "shift": return modifierKey(0xE00A, Modifier.SHIFT, FLAG_DOUBLE_TAP_LOCK); case "shift": return modifierKey(0xE00A, Modifier.SHIFT, 0);
case "ctrl": return modifierKey("Ctrl", Modifier.CTRL, 0); case "ctrl": return modifierKey("Ctrl", Modifier.CTRL, 0);
case "alt": return modifierKey("Alt", Modifier.ALT, 0); case "alt": return modifierKey("Alt", Modifier.ALT, 0);
case "accent_aigu": return diacritic(0xE050, Modifier.AIGU); case "accent_aigu": return diacritic(0xE050, Modifier.AIGU);
@@ -625,9 +597,9 @@ public final class KeyValue implements Comparable<KeyValue>
case "esc": return keyeventKey("Esc", KeyEvent.KEYCODE_ESCAPE, FLAG_SMALLER_FONT); case "esc": return keyeventKey("Esc", KeyEvent.KEYCODE_ESCAPE, FLAG_SMALLER_FONT);
case "enter": return keyeventKey(0xE00E, KeyEvent.KEYCODE_ENTER, 0); case "enter": return keyeventKey(0xE00E, KeyEvent.KEYCODE_ENTER, 0);
case "up": return keyeventKey(0xE005, KeyEvent.KEYCODE_DPAD_UP, 0); case "up": return keyeventKey(0xE005, KeyEvent.KEYCODE_DPAD_UP, 0);
case "right": return keyeventKey(0xE006, KeyEvent.KEYCODE_DPAD_RIGHT, FLAG_SMALLER_FONT); case "right": return keyeventKey(0xE006, KeyEvent.KEYCODE_DPAD_RIGHT, 0);
case "down": return keyeventKey(0xE007, KeyEvent.KEYCODE_DPAD_DOWN, 0); case "down": return keyeventKey(0xE007, KeyEvent.KEYCODE_DPAD_DOWN, 0);
case "left": return keyeventKey(0xE008, KeyEvent.KEYCODE_DPAD_LEFT, FLAG_SMALLER_FONT); case "left": return keyeventKey(0xE008, KeyEvent.KEYCODE_DPAD_LEFT, 0);
case "page_up": return keyeventKey(0xE002, KeyEvent.KEYCODE_PAGE_UP, 0); case "page_up": return keyeventKey(0xE002, KeyEvent.KEYCODE_PAGE_UP, 0);
case "page_down": return keyeventKey(0xE003, KeyEvent.KEYCODE_PAGE_DOWN, 0); case "page_down": return keyeventKey(0xE003, KeyEvent.KEYCODE_PAGE_DOWN, 0);
case "home": return keyeventKey(0xE00B, KeyEvent.KEYCODE_MOVE_HOME, FLAG_SMALLER_FONT); case "home": return keyeventKey(0xE00B, KeyEvent.KEYCODE_MOVE_HOME, FLAG_SMALLER_FONT);
@@ -654,7 +626,7 @@ public final class KeyValue implements Comparable<KeyValue>
/* Spaces */ /* Spaces */
case "\\t": return charKey("\\t", '\t', 0); // Send the tab character case "\\t": return charKey("\\t", '\t', 0); // Send the tab character
case "\\n": return charKey("\\n", '\n', 0); // Send the newline character case "\\n": return charKey("\\n", '\n', 0); // Send the newline character
case "space": return charKey(0xE00D, ' ', FLAG_SMALLER_FONT | FLAG_GREYED); case "space": return charKey(0xE00D, ' ', FLAG_KEY_FONT | FLAG_SMALLER_FONT | FLAG_GREYED);
case "nbsp": return charKey("\u237d", '\u00a0', FLAG_SMALLER_FONT); case "nbsp": return charKey("\u237d", '\u00a0', FLAG_SMALLER_FONT);
case "nnbsp": return charKey("\u2423", '\u202F', FLAG_SMALLER_FONT); case "nnbsp": return charKey("\u2423", '\u202F', FLAG_SMALLER_FONT);
@@ -698,9 +670,9 @@ public final class KeyValue implements Comparable<KeyValue>
case "meteg": return charKey("\u05DE\u05BD", '\u05BD', 0); // or siluq or sof-pasuq case "meteg": return charKey("\u05DE\u05BD", '\u05BD', 0); // or siluq or sof-pasuq
case "meteg_placeholder": return placeholderKey(Placeholder.METEG); case "meteg_placeholder": return placeholderKey(Placeholder.METEG);
/* intending/preventing ligature - supported by many scripts*/ /* intending/preventing ligature - supported by many scripts*/
case "zwj": return charKey(0xE019, '\u200D', 0); // zero-width joiner (provides ligature) case "zwj": return charKey("zwj", '\u200D', 0); // zero-width joiner (provides ligature)
case "zwnj": case "zwnj":
case "halfspace": return charKey(0xE018, '\u200C', 0); // zero-width non joiner case "halfspace": return charKey("", '\u200C', 0); // zero-width non joiner
/* Editing keys */ /* Editing keys */
case "copy": return editingKey(0xE030, Editing.COPY); case "copy": return editingKey(0xE030, Editing.COPY);
@@ -711,23 +683,15 @@ public final class KeyValue implements Comparable<KeyValue>
case "pasteAsPlainText": return editingKey(0xE035, Editing.PASTE_PLAIN); case "pasteAsPlainText": return editingKey(0xE035, Editing.PASTE_PLAIN);
case "undo": return editingKey(0xE036, Editing.UNDO); case "undo": return editingKey(0xE036, Editing.UNDO);
case "redo": return editingKey(0xE037, Editing.REDO); case "redo": return editingKey(0xE037, Editing.REDO);
case "delete_word": return editingKey(0xE01B, Editing.DELETE_WORD); case "cursor_left": return cursorMoveKey(-1);
case "forward_delete_word": return editingKey(0xE01C, Editing.FORWARD_DELETE_WORD); case "cursor_right": return cursorMoveKey(1);
case "cursor_left": return sliderKey(Slider.Cursor_left, 1);
case "cursor_right": return sliderKey(Slider.Cursor_right, 1);
case "cursor_up": return sliderKey(Slider.Cursor_up, 1);
case "cursor_down": return sliderKey(Slider.Cursor_down, 1);
case "selection_cancel": return editingKey("Esc", Editing.SELECTION_CANCEL, FLAG_SMALLER_FONT);
case "selection_cursor_left": return sliderKey(Slider.Selection_cursor_left, -1); // Move the left side of the selection
case "selection_cursor_right": return sliderKey(Slider.Selection_cursor_right, 1);
// These keys are not used // These keys are not used
case "replaceText": return editingKey("repl", Editing.REPLACE); case "replaceText": return editingKey("repl", Editing.REPLACE);
case "textAssist": return editingKey(0xE038, Editing.ASSIST); case "textAssist": return editingKey(0xE038, Editing.ASSIST);
case "autofill": return editingKey("auto", Editing.AUTOFILL); case "autofill": return editingKey("auto", Editing.AUTOFILL);
/* The compose key */ /* The compose key */
case "compose": return makeComposePending(0xE016, ComposeKeyData.compose, FLAG_SECONDARY); case "compose": return makeComposePending(0xE016, ComposeKeyData.compose, FLAG_SECONDARY | FLAG_SMALLER_FONT | FLAG_SPECIAL);
case "compose_cancel": return placeholderKey(0xE01A, Placeholder.COMPOSE_CANCEL, FLAG_SECONDARY);
/* Placeholder keys */ /* Placeholder keys */
case "removed": return placeholderKey(Placeholder.REMOVED); case "removed": return placeholderKey(Placeholder.REMOVED);
@@ -769,10 +733,8 @@ public final class KeyValue implements Comparable<KeyValue>
case "": case "": case "": case "":
return makeStringKey(name, FLAG_SMALLER_FONT); return makeStringKey(name, FLAG_SMALLER_FONT);
/* Internal keys */ /* The key is not one of the special ones. */
case "selection_mode": return makeInternalModifier(Modifier.SELECTION_MODE); default: return parseKeyDefinition(name);
default: return null;
} }
} }
@@ -783,50 +745,48 @@ public final class KeyValue implements Comparable<KeyValue>
throw new RuntimeException("Assertion failure"); throw new RuntimeException("Assertion failure");
} }
public static enum Slider public static abstract class Complex
{ {
Cursor_left(0xE008), public abstract String getSymbol();
Cursor_right(0xE006),
Cursor_up(0xE005),
Cursor_down(0xE007),
Selection_cursor_left(0xE008),
Selection_cursor_right(0xE006);
final String symbol; /** [compareTo] can assume that [snd] is an instance of the same class. */
public abstract int compareTo(Complex snd);
Slider(int symbol_) public boolean equals(Object snd)
{ {
symbol = String.valueOf((char)symbol_); if (snd instanceof Complex)
return compareTo((Complex)snd) == 0;
return false;
} }
@Override /** [hashCode] will be called on this class. */
public String toString() { return symbol; }
};
public static final class Macro implements Comparable<Macro> /** The kind is stored in the [value] field of the key. */
public static enum Kind
{ {
public final KeyValue[] keys; StringWithSymbol,
}
public static final class StringWithSymbol extends Complex
{
public final String str;
private final String _symbol; private final String _symbol;
public Macro(KeyValue[] keys_, String sym_) public StringWithSymbol(String _str, String _sym)
{ {
keys = keys_; str = _str;
_symbol = sym_; _symbol = _sym;
} }
public String toString() { return _symbol; } public String getSymbol() { return _symbol; }
@Override public int compareTo(Complex _snd)
public int compareTo(Macro snd)
{ {
int d = keys.length - snd.keys.length; StringWithSymbol snd = (StringWithSymbol)_snd;
int d = str.compareTo(snd.str);
if (d != 0) return d; if (d != 0) return d;
for (int i = 0; i < keys.length; i++)
{
d = keys[i].compareTo(snd.keys[i]);
if (d != 0) return d;
}
return _symbol.compareTo(snd._symbol); return _symbol.compareTo(snd._symbol);
} }
}
}; };
} }

View File

@@ -1,22 +1,14 @@
package juloo.keyboard2; package juloo.keyboard2;
import java.util.ArrayList;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /**
Parse a key definition. The syntax for a key definition is: Parse a key definition. The syntax for a key definition is:
- [(symbol):(key_action)]
- [:(kind) (attributes):(payload)]. - [:(kind) (attributes):(payload)].
- If [str] doesn't start with a [:] character, it is interpreted as an - If [str] doesn't start with a [:] character, it is interpreted as an
arbitrary string key. arbitrary string key.
[key_action] is:
- ['Arbitrary string']
- [(key_action),(key_action),...]
- [keyevent:(code)]
- [(key_name)]
For the different kinds and attributes, see doc/Possible-key-values.md. For the different kinds and attributes, see doc/Possible-key-values.md.
Examples: Examples:
@@ -26,118 +18,6 @@ Examples:
*/ */
public final class KeyValueParser public final class KeyValueParser
{ {
static Pattern KEYDEF_TOKEN;
static Pattern QUOTED_PAT;
static Pattern WORD_PAT;
static public KeyValue parse(String input) throws ParseError
{
int symbol_ends = 0;
final int input_len = input.length();
while (symbol_ends < input_len && input.charAt(symbol_ends) != ':')
symbol_ends++;
if (symbol_ends == 0) // Old syntax
return Starting_with_colon.parse(input);
if (symbol_ends == input_len) // String key
return KeyValue.makeStringKey(input);
String symbol = input.substring(0, symbol_ends);
init();
Matcher m = KEYDEF_TOKEN.matcher(input);
m.region(symbol_ends + 1, input_len);
KeyValue first_key = parse_key_def(m);
if (!parse_comma(m)) // Input is a single key def with a specified symbol
return first_key.withSymbol(symbol);
// Input is a macro
ArrayList<KeyValue> keydefs = new ArrayList<KeyValue>();
keydefs.add(first_key);
do { keydefs.add(parse_key_def(m)); }
while (parse_comma(m));
return KeyValue.makeMacro(symbol, keydefs.toArray(new KeyValue[]{}), 0);
}
static void init()
{
if (KEYDEF_TOKEN != null)
return;
KEYDEF_TOKEN = Pattern.compile("'|,|keyevent:|(?:[^\\\\',]+|\\\\.)+");
QUOTED_PAT = Pattern.compile("((?:[^'\\\\]+|\\\\')*)'");
WORD_PAT = Pattern.compile("[a-zA-Z0-9_]+|.");
}
static KeyValue key_by_name_or_str(String str)
{
KeyValue k = KeyValue.getSpecialKeyByName(str);
if (k != null)
return k;
return KeyValue.makeStringKey(str);
}
static KeyValue parse_key_def(Matcher m) throws ParseError
{
if (!match(m, KEYDEF_TOKEN))
parseError("Expected key definition", m);
String token = m.group(0);
switch (token)
{
case "'": return parse_string_keydef(m);
case ",": parseError("Unexpected comma", m); return null;
case "keyevent:": return parse_keyevent_keydef(m);
default: return key_by_name_or_str(remove_escaping(token));
}
}
static KeyValue parse_string_keydef(Matcher m) throws ParseError
{
if (!match(m, QUOTED_PAT))
parseError("Unterminated quoted string", m);
return KeyValue.makeStringKey(remove_escaping(m.group(1)));
}
static KeyValue parse_keyevent_keydef(Matcher m) throws ParseError
{
if (!match(m, WORD_PAT))
parseError("Expected keyevent code", m);
int eventcode = 0;
try { eventcode = Integer.parseInt(m.group(0)); }
catch (Exception _e)
{ parseError("Expected an integer payload", m); }
return KeyValue.keyeventKey("", eventcode, 0);
}
/** Returns [true] if the next token is a comma, [false] if it is the end of the input. Throws an error otherwise. */
static boolean parse_comma(Matcher m) throws ParseError
{
if (!match(m, KEYDEF_TOKEN))
return false;
String token = m.group(0);
if (!token.equals(","))
parseError("Expected comma instead of '"+ token + "'", m);
return true;
}
static String remove_escaping(String s)
{
if (!s.contains("\\"))
return s;
StringBuilder out = new StringBuilder(s.length());
final int len = s.length();
int prev = 0, i = 0;
for (; i < len; i++)
if (s.charAt(i) == '\\')
{
out.append(s, prev, i);
prev = i + 1;
}
out.append(s, prev, i);
return out.toString();
}
/**
Parse a key definition starting with a [:]. This is the old syntax and is
kept for compatibility.
*/
final static class Starting_with_colon
{
static Pattern START_PAT; static Pattern START_PAT;
static Pattern ATTR_PAT; static Pattern ATTR_PAT;
static Pattern QUOTED_PAT; static Pattern QUOTED_PAT;
@@ -184,7 +64,7 @@ public final class KeyValueParser
payload = parseSingleQuotedString(m); payload = parseSingleQuotedString(m);
if (symbol == null) if (symbol == null)
return KeyValue.makeStringKey(payload, flags); return KeyValue.makeStringKey(payload, flags);
return KeyValue.makeStringKey(payload, flags).withSymbol(symbol); return KeyValue.makeStringKeyWithSymbol(payload, symbol, flags);
case "char": case "char":
payload = parsePayloadWord(m); payload = parsePayloadWord(m);
@@ -254,14 +134,6 @@ public final class KeyValueParser
PAYLOAD_START_PAT = Pattern.compile("\\s*:"); PAYLOAD_START_PAT = Pattern.compile("\\s*:");
WORD_PAT = Pattern.compile("[a-zA-Z0-9_]*"); WORD_PAT = Pattern.compile("[a-zA-Z0-9_]*");
} }
}
static boolean match(Matcher m, Pattern pat)
{
try { m.region(m.end(), m.regionEnd()); } catch (Exception _e) {}
m.usePattern(pat);
return m.lookingAt();
}
static void parseError(String msg, Matcher m) throws ParseError static void parseError(String msg, Matcher m) throws ParseError
{ {
@@ -273,7 +145,8 @@ public final class KeyValueParser
StringBuilder msg_ = new StringBuilder("Syntax error"); StringBuilder msg_ = new StringBuilder("Syntax error");
try try
{ {
msg_.append(" at token '").append(m.group(0)).append("'"); char c = m.group(0).charAt(0);
msg_.append(" at character '").append(c).append("'");
} catch (IllegalStateException _e) {} } catch (IllegalStateException _e) {}
msg_.append(" at position "); msg_.append(" at position ");
msg_.append(i); msg_.append(i);

View File

@@ -6,7 +6,6 @@ import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.inputmethodservice.InputMethodService; import android.inputmethodservice.InputMethodService;
import android.os.Build.VERSION; import android.os.Build.VERSION;
import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.text.InputType; import android.text.InputType;
import android.util.Log; import android.util.Log;
@@ -39,7 +38,6 @@ public class Keyboard2 extends InputMethodService
private ViewGroup _emojiPane = null; private ViewGroup _emojiPane = null;
private ViewGroup _clipboard_pane = null; private ViewGroup _clipboard_pane = null;
public int actionId; // Action performed by the Action key. public int actionId; // Action performed by the Action key.
private Handler _handler;
private Config _config; private Config _config;
@@ -64,7 +62,7 @@ public class Keyboard2 extends InputMethodService
{ {
if (_currentSpecialLayout != null) if (_currentSpecialLayout != null)
return _currentSpecialLayout; return _currentSpecialLayout;
return LayoutModifier.modify_layout(current_layout_unmodified()); return _config.modify_layout(current_layout_unmodified());
} }
void setTextLayout(int l) void setTextLayout(int l)
@@ -94,13 +92,13 @@ public class Keyboard2 extends InputMethodService
/** Load a layout that contains a numpad. */ /** Load a layout that contains a numpad. */
KeyboardData loadNumpad(int layout_id) KeyboardData loadNumpad(int layout_id)
{ {
return LayoutModifier.modify_numpad(KeyboardData.load(getResources(), layout_id), return _config.modify_numpad(KeyboardData.load(getResources(), layout_id),
current_layout_unmodified()); current_layout_unmodified());
} }
KeyboardData loadPinentry(int layout_id) KeyboardData loadPinentry(int layout_id)
{ {
return LayoutModifier.modify_pinentry(KeyboardData.load(getResources(), layout_id), return _config.modify_pinentry(KeyboardData.load(getResources(), layout_id),
current_layout_unmodified()); current_layout_unmodified());
} }
@@ -109,8 +107,7 @@ public class Keyboard2 extends InputMethodService
{ {
super.onCreate(); super.onCreate();
SharedPreferences prefs = DirectBootAwarePreferences.get_shared_preferences(this); SharedPreferences prefs = DirectBootAwarePreferences.get_shared_preferences(this);
_handler = new Handler(getMainLooper()); _keyeventhandler = new KeyEventHandler(getMainLooper(), this.new Receiver());
_keyeventhandler = new KeyEventHandler(this.new Receiver());
Config.initGlobalConfig(prefs, getResources(), _keyeventhandler); Config.initGlobalConfig(prefs, getResources(), _keyeventhandler);
prefs.registerOnSharedPreferenceChangeListener(this); prefs.registerOnSharedPreferenceChangeListener(this);
_config = Config.globalConfig(); _config = Config.globalConfig();
@@ -295,9 +292,8 @@ public class Keyboard2 extends InputMethodService
private void updateSoftInputWindowLayoutParams() { private void updateSoftInputWindowLayoutParams() {
final Window window = getWindow().getWindow(); final Window window = getWindow().getWindow();
// On API >= 35, Keyboard2View behaves as edge-to-edge // On API >= 30, Keyboard2View behaves as edge-to-edge
// APIs 30 to 34 have visual artifact when edge-to-edge is enabled if (VERSION.SDK_INT >= 30)
if (VERSION.SDK_INT >= 35)
{ {
WindowManager.LayoutParams wattrs = window.getAttributes(); WindowManager.LayoutParams wattrs = window.getAttributes();
wattrs.layoutInDisplayCutoutMode = wattrs.layoutInDisplayCutoutMode =
@@ -362,8 +358,6 @@ public class Keyboard2 extends InputMethodService
{ {
super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, candidatesStart, candidatesEnd); super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, candidatesStart, candidatesEnd);
_keyeventhandler.selection_updated(oldSelStart, newSelStart); _keyeventhandler.selection_updated(oldSelStart, newSelStart);
if ((oldSelStart == oldSelEnd) != (newSelStart == newSelEnd))
_keyboardView.set_selection_state(newSelStart != newSelEnd);
} }
@Override @Override
@@ -482,20 +476,10 @@ public class Keyboard2 extends InputMethodService
_keyboardView.set_compose_pending(pending); _keyboardView.set_compose_pending(pending);
} }
public void selection_state_changed(boolean selection_is_ongoing)
{
_keyboardView.set_selection_state(selection_is_ongoing);
}
public InputConnection getCurrentInputConnection() public InputConnection getCurrentInputConnection()
{ {
return Keyboard2.this.getCurrentInputConnection(); return Keyboard2.this.getCurrentInputConnection();
} }
public Handler getHandler()
{
return _handler;
}
} }
private IBinder getConnectionToken() private IBinder getConnectionToken()

View File

@@ -47,7 +47,6 @@ public class Keyboard2View extends View
private float _marginBottom; private float _marginBottom;
private Theme _theme; private Theme _theme;
private Theme.Computed _tc;
private static RectF _tmpRect = new RectF(); private static RectF _tmpRect = new RectF();
@@ -105,6 +104,11 @@ public class Keyboard2View extends View
_keyboard = kw; _keyboard = kw;
_shift_kv = KeyValue.getKeyByName("shift"); _shift_kv = KeyValue.getKeyByName("shift");
_shift_key = _keyboard.findKeyWithValue(_shift_kv); _shift_key = _keyboard.findKeyWithValue(_shift_kv);
if (_shift_key == null)
{
_shift_kv = _shift_kv.withFlags(_shift_kv.getFlags() | KeyValue.FLAG_LOCK);
_shift_key = _keyboard.findKeyWithValue(_shift_kv);
}
_compose_kv = KeyValue.getKeyByName("compose"); _compose_kv = KeyValue.getKeyByName("compose");
_compose_key = _keyboard.findKeyWithValue(_compose_kv); _compose_key = _keyboard.findKeyWithValue(_compose_kv);
KeyModifier.set_modmap(_keyboard.modmap); KeyModifier.set_modmap(_keyboard.modmap);
@@ -139,13 +143,6 @@ public class Keyboard2View extends View
set_fake_ptr_latched(_compose_key, _compose_kv, pending, false); set_fake_ptr_latched(_compose_key, _compose_kv, pending, false);
} }
/** Called from [Keybard2.onUpdateSelection]. */
public void set_selection_state(boolean selection_state)
{
set_fake_ptr_latched(KeyboardData.Key.EMPTY,
KeyValue.getKeyByName("selection_mode"), selection_state, true);
}
public KeyValue modifyKey(KeyValue k, Pointers.Modifiers mods) public KeyValue modifyKey(KeyValue k, Pointers.Modifiers mods)
{ {
return KeyModifier.modify(k, mods); return KeyModifier.modify(k, mods);
@@ -267,7 +264,7 @@ public class Keyboard2View extends View
int insets_bottom = 0; int insets_bottom = 0;
// LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS is set in [Keyboard2#updateSoftInputWindowLayoutParams]. // LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS is set in [Keyboard2#updateSoftInputWindowLayoutParams].
// and keyboard is allowed do draw behind status/navigation bars // and keyboard is allowed do draw behind status/navigation bars
if (VERSION.SDK_INT >= 35) if (VERSION.SDK_INT >= 30)
{ {
WindowMetrics metrics = WindowMetrics metrics =
((WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE)) ((WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE))
@@ -303,15 +300,14 @@ public class Keyboard2View extends View
DisplayMetrics dm = getContext().getResources().getDisplayMetrics(); DisplayMetrics dm = getContext().getResources().getDisplayMetrics();
width = dm.widthPixels; width = dm.widthPixels;
} }
_marginLeft = Math.max(_config.horizontal_margin, insets_left);
_marginRight = Math.max(_config.horizontal_margin, insets_right);
_marginBottom = _config.margin_bottom + insets_bottom;
_keyWidth = (width - _marginLeft - _marginRight) / _keyboard.keysWidth;
_tc = new Theme.Computed(_theme, _config, _keyWidth);
int height = int height =
(int)(_config.keyHeight * _keyboard.keysHeight (int)(_config.keyHeight * _keyboard.keysHeight
+ _config.marginTop + _marginBottom); + _config.marginTop + _marginBottom);
setMeasuredDimension(width, height); setMeasuredDimension(width, height);
_marginLeft = Math.max(_config.horizontal_margin, insets_left);
_marginRight = Math.max(_config.horizontal_margin, insets_right);
_marginBottom = _config.margin_bottom + insets_bottom;
_keyWidth = (width - _marginLeft - _marginRight) / _keyboard.keysWidth;
} }
@Override @Override
@@ -349,27 +345,34 @@ public class Keyboard2View extends View
{ {
// Set keyboard background opacity // Set keyboard background opacity
getBackground().setAlpha(_config.keyboardOpacity); getBackground().setAlpha(_config.keyboardOpacity);
float y = _tc.margin_top; // Set keys opacity
_theme.keyBgPaint.setAlpha(_config.keyOpacity);
_theme.keyDownBgPaint.setAlpha(_config.keyActivatedOpacity);
_theme.keyBorderPaint.setAlpha(_config.keyOpacity);
float key_vertical_margin = _config.key_vertical_margin * _config.keyHeight;
float key_horizontal_margin = _config.key_horizontal_margin * _keyWidth;
// Add half of the key margin on the left and on the top as it's then added
// on the right and on the bottom of every keys.
float y = _config.marginTop + key_vertical_margin / 2;
for (KeyboardData.Row row : _keyboard.rows) for (KeyboardData.Row row : _keyboard.rows)
{ {
y += row.shift * _config.keyHeight; y += row.shift * _config.keyHeight;
float x = _marginLeft + _tc.margin_left; float x = _marginLeft + key_horizontal_margin / 2;
float keyH = row.height * _config.keyHeight - _tc.vertical_margin; float keyH = row.height * _config.keyHeight - key_vertical_margin;
for (KeyboardData.Key k : row.keys) for (KeyboardData.Key k : row.keys)
{ {
x += k.shift * _keyWidth; x += k.shift * _keyWidth;
float keyW = _keyWidth * k.width - _tc.horizontal_margin; float keyW = _keyWidth * k.width - key_horizontal_margin;
boolean isKeyDown = _pointers.isKeyDown(k); boolean isKeyDown = _pointers.isKeyDown(k);
Theme.Computed.Key tc_key = isKeyDown ? _tc.key_activated : _tc.key; drawKeyFrame(canvas, x, y, keyW, keyH, isKeyDown);
drawKeyFrame(canvas, x, y, keyW, keyH, tc_key);
if (k.keys[0] != null) if (k.keys[0] != null)
drawLabel(canvas, k.keys[0], keyW / 2f + x, y, keyH, isKeyDown, tc_key); drawLabel(canvas, k.keys[0], keyW / 2f + x, y, keyH, isKeyDown);
for (int i = 1; i < 9; i++) for (int i = 1; i < 9; i++)
{ {
if (k.keys[i] != null) if (k.keys[i] != null)
drawSubLabel(canvas, k.keys[i], x, y, keyW, keyH, i, isKeyDown, tc_key); drawSubLabel(canvas, k.keys[i], x, y, keyW, keyH, i, isKeyDown);
} }
drawIndication(canvas, k, x, y, keyW, keyH, _tc); drawIndication(canvas, k, x, y, keyW, keyH);
x += _keyWidth * k.width; x += _keyWidth * k.width;
} }
y += row.height * _config.keyHeight; y += row.height * _config.keyHeight;
@@ -384,32 +387,42 @@ public class Keyboard2View extends View
/** Draw borders and background of the key. */ /** Draw borders and background of the key. */
void drawKeyFrame(Canvas canvas, float x, float y, float keyW, float keyH, void drawKeyFrame(Canvas canvas, float x, float y, float keyW, float keyH,
Theme.Computed.Key tc) boolean isKeyDown)
{ {
float r = tc.border_radius; float r = _theme.keyBorderRadius;
float w = tc.border_width; if (_config.borderConfig)
r = _config.customBorderRadius * _keyWidth;
float w = (_config.borderConfig) ? _config.customBorderLineWidth : _theme.keyBorderWidth;
float padding = w / 2.f; float padding = w / 2.f;
if (isKeyDown)
w = _theme.keyBorderWidthActivated;
_tmpRect.set(x + padding, y + padding, x + keyW - padding, y + keyH - padding); _tmpRect.set(x + padding, y + padding, x + keyW - padding, y + keyH - padding);
canvas.drawRoundRect(_tmpRect, r, r, tc.bg_paint); canvas.drawRoundRect(_tmpRect, r, r,
isKeyDown ? _theme.keyDownBgPaint : _theme.keyBgPaint);
if (w > 0.f) if (w > 0.f)
{ {
_theme.keyBorderPaint.setStrokeWidth(w);
float overlap = r - r * 0.85f + w; // sin(45°) float overlap = r - r * 0.85f + w; // sin(45°)
drawBorder(canvas, x, y, x + overlap, y + keyH, tc.border_left_paint, tc); drawBorder(canvas, x, y, x + overlap, y + keyH, _theme.keyBorderColorLeft);
drawBorder(canvas, x + keyW - overlap, y, x + keyW, y + keyH, tc.border_right_paint, tc); drawBorder(canvas, x + keyW - overlap, y, x + keyW, y + keyH, _theme.keyBorderColorRight);
drawBorder(canvas, x, y, x + keyW, y + overlap, tc.border_top_paint, tc); drawBorder(canvas, x, y, x + keyW, y + overlap, _theme.keyBorderColorTop);
drawBorder(canvas, x, y + keyH - overlap, x + keyW, y + keyH, tc.border_bottom_paint, tc); drawBorder(canvas, x, y + keyH - overlap, x + keyW, y + keyH, _theme.keyBorderColorBottom);
} }
} }
/** Clip to draw a border at a time. This allows to call [drawRoundRect] /** Clip to draw a border at a time. This allows to call [drawRoundRect]
several time with the same parameters but a different Paint. */ several time with the same parameters but a different Paint. */
void drawBorder(Canvas canvas, float clipl, float clipt, float clipr, void drawBorder(Canvas canvas, float clipl, float clipt, float clipr,
float clipb, Paint paint, Theme.Computed.Key tc) float clipb, int color)
{ {
float r = tc.border_radius; Paint p = _theme.keyBorderPaint;
float r = _theme.keyBorderRadius;
if (_config.borderConfig)
r = _config.customBorderRadius * _keyWidth;
canvas.save(); canvas.save();
canvas.clipRect(clipl, clipt, clipr, clipb); canvas.clipRect(clipl, clipt, clipr, clipb);
canvas.drawRoundRect(_tmpRect, r, r, paint); p.setColor(color);
canvas.drawRoundRect(_tmpRect, r, r, p);
canvas.restore(); canvas.restore();
} }
@@ -434,21 +447,21 @@ public class Keyboard2View extends View
return sublabel ? _theme.subLabelColor : _theme.labelColor; return sublabel ? _theme.subLabelColor : _theme.labelColor;
} }
private void drawLabel(Canvas canvas, KeyValue kv, float x, float y, private void drawLabel(Canvas canvas, KeyValue kv, float x, float y, float keyH, boolean isKeyDown)
float keyH, boolean isKeyDown, Theme.Computed.Key tc)
{ {
kv = modifyKey(kv, _mods); kv = modifyKey(kv, _mods);
if (kv == null) if (kv == null)
return; return;
float textSize = scaleTextSize(kv, _config.labelTextSize, keyH); float textSize = scaleTextSize(kv, _config.labelTextSize, keyH);
Paint p = tc.label_paint(kv.hasFlagsAny(KeyValue.FLAG_KEY_FONT), textSize); Paint p = _theme.labelPaint(kv.hasFlagsAny(KeyValue.FLAG_KEY_FONT));
p.setColor(labelColor(kv, isKeyDown, false)); p.setColor(labelColor(kv, isKeyDown, false));
p.setAlpha(_config.labelBrightness);
p.setTextSize(textSize);
canvas.drawText(kv.getString(), x, (keyH - p.ascent() - p.descent()) / 2f + y, p); canvas.drawText(kv.getString(), x, (keyH - p.ascent() - p.descent()) / 2f + y, p);
} }
private void drawSubLabel(Canvas canvas, KeyValue kv, float x, float y, private void drawSubLabel(Canvas canvas, KeyValue kv, float x, float y,
float keyW, float keyH, int sub_index, boolean isKeyDown, float keyW, float keyH, int sub_index, boolean isKeyDown)
Theme.Computed.Key tc)
{ {
Paint.Align a = LABEL_POSITION_H[sub_index]; Paint.Align a = LABEL_POSITION_H[sub_index];
Vertical v = LABEL_POSITION_V[sub_index]; Vertical v = LABEL_POSITION_V[sub_index];
@@ -456,8 +469,10 @@ public class Keyboard2View extends View
if (kv == null) if (kv == null)
return; return;
float textSize = scaleTextSize(kv, _config.sublabelTextSize, keyH); float textSize = scaleTextSize(kv, _config.sublabelTextSize, keyH);
Paint p = tc.sublabel_paint(kv.hasFlagsAny(KeyValue.FLAG_KEY_FONT), textSize, a); Paint p = _theme.subLabelPaint(kv.hasFlagsAny(KeyValue.FLAG_KEY_FONT), a);
p.setColor(labelColor(kv, isKeyDown, true)); p.setColor(labelColor(kv, isKeyDown, true));
p.setAlpha(_config.labelBrightness);
p.setTextSize(textSize);
float subPadding = _config.keyPadding; float subPadding = _config.keyPadding;
if (v == Vertical.CENTER) if (v == Vertical.CENTER)
y += (keyH - p.ascent() - p.descent()) / 2f; y += (keyH - p.ascent() - p.descent()) / 2f;
@@ -476,13 +491,34 @@ public class Keyboard2View extends View
} }
private void drawIndication(Canvas canvas, KeyboardData.Key k, float x, private void drawIndication(Canvas canvas, KeyboardData.Key k, float x,
float y, float keyW, float keyH, Theme.Computed tc) float y, float keyW, float keyH)
{
boolean special_font = false;
String indic;
int indic_length;
float text_size;
if (k.indication != null)
{
indic = k.indication;
indic_length = indic.length();
text_size = keyH * _config.sublabelTextSize * _config.characterSize;
}
else if (k.anticircle != null)
{
indic = k.anticircle.getString();
// 3 character limit like regular labels
indic_length = Math.min(indic.length(), 3);
special_font = k.anticircle.hasFlagsAny(KeyValue.FLAG_KEY_FONT);
text_size = scaleTextSize(k.anticircle, _config.sublabelTextSize, keyH);
}
else
{ {
if (k.indication == null || k.indication.equals(""))
return; return;
Paint p = tc.indication_paint; }
p.setTextSize(keyH * _config.sublabelTextSize * _config.characterSize); Paint p = _theme.indicationPaint(special_font);
canvas.drawText(k.indication, 0, k.indication.length(), p.setColor(_theme.subLabelColor);
p.setTextSize(text_size);
canvas.drawText(indic, 0, indic_length,
x + keyW / 2f, (keyH - p.ascent() - p.descent()) * 4/5 + y, p); x + keyW / 2f, (keyH - p.ascent() - p.descent()) * 4/5 + y, p);
} }

View File

@@ -31,8 +31,6 @@ public final class KeyboardData
public final String name; public final String name;
/** Whether the bottom row should be added. */ /** Whether the bottom row should be added. */
public final boolean bottom_row; public final boolean bottom_row;
/** Whether the number row is included in the layout and thus another one shouldn't be added. */
public final boolean embedded_number_row;
/** Whether extra keys from [method.xml] should be added to this layout. */ /** Whether extra keys from [method.xml] should be added to this layout. */
public final boolean locale_extra_keys; public final boolean locale_extra_keys;
/** Position of every keys on the layout, see [getKeys()]. */ /** Position of every keys on the layout, see [getKeys()]. */
@@ -241,7 +239,6 @@ public final class KeyboardData
if (!expect_tag(parser, "keyboard")) if (!expect_tag(parser, "keyboard"))
throw error(parser, "Expected tag <keyboard>"); throw error(parser, "Expected tag <keyboard>");
boolean bottom_row = attribute_bool(parser, "bottom_row", true); boolean bottom_row = attribute_bool(parser, "bottom_row", true);
boolean embedded_number_row = attribute_bool(parser, "embedded_number_row", false);
boolean locale_extra_keys = attribute_bool(parser, "locale_extra_keys", true); boolean locale_extra_keys = attribute_bool(parser, "locale_extra_keys", true);
float specified_kw = attribute_float(parser, "width", 0f); float specified_kw = attribute_float(parser, "width", 0f);
String script = parser.getAttributeValue(null, "script"); String script = parser.getAttributeValue(null, "script");
@@ -272,7 +269,7 @@ public final class KeyboardData
} }
} }
float kw = (specified_kw != 0f) ? specified_kw : compute_max_width(rows); float kw = (specified_kw != 0f) ? specified_kw : compute_max_width(rows);
return new KeyboardData(rows, kw, modmap, script, numpad_script, name, bottom_row, embedded_number_row, locale_extra_keys); return new KeyboardData(rows, kw, modmap, script, numpad_script, name, bottom_row, locale_extra_keys);
} }
private static float compute_max_width(List<Row> rows) private static float compute_max_width(List<Row> rows)
@@ -291,7 +288,7 @@ public final class KeyboardData
} }
protected KeyboardData(List<Row> rows_, float kw, Modmap mm, String sc, protected KeyboardData(List<Row> rows_, float kw, Modmap mm, String sc,
String npsc, String name_, boolean bottom_row_, boolean embedded_number_row_, boolean locale_extra_keys_) String npsc, String name_, boolean bottom_row_, boolean locale_extra_keys_)
{ {
float kh = 0.f; float kh = 0.f;
for (Row r : rows_) for (Row r : rows_)
@@ -304,7 +301,6 @@ public final class KeyboardData
keysWidth = Math.max(kw, 1f); keysWidth = Math.max(kw, 1f);
keysHeight = kh; keysHeight = kh;
bottom_row = bottom_row_; bottom_row = bottom_row_;
embedded_number_row = embedded_number_row_;
locale_extra_keys = locale_extra_keys_; locale_extra_keys = locale_extra_keys_;
} }
@@ -312,7 +308,7 @@ public final class KeyboardData
protected KeyboardData(KeyboardData src, List<Row> rows) protected KeyboardData(KeyboardData src, List<Row> rows)
{ {
this(rows, compute_max_width(rows), src.modmap, src.script, this(rows, compute_max_width(rows), src.modmap, src.script,
src.numpad_script, src.name, src.bottom_row, src.embedded_number_row, src.locale_extra_keys); src.numpad_script, src.name, src.bottom_row, src.locale_extra_keys);
} }
public static class Row public static class Row
@@ -405,6 +401,9 @@ public final class KeyboardData
public final float width; public final float width;
/** Extra empty space on the left of the key. */ /** Extra empty space on the left of the key. */
public final float shift; public final float shift;
/** Keys 2 and 3 are repeated as the finger moves laterally on the key.
Used for the left and right arrow keys on the space bar. */
public final boolean slider;
/** String printed on the keys. It has no other effect. */ /** String printed on the keys. It has no other effect. */
public final String indication; public final String indication;
@@ -412,18 +411,17 @@ public final class KeyboardData
public static final int F_LOC = 1; public static final int F_LOC = 1;
public static final int ALL_FLAGS = F_LOC; public static final int ALL_FLAGS = F_LOC;
protected Key(KeyValue[] ks, KeyValue antic, int f, float w, float s, String i) protected Key(KeyValue[] ks, KeyValue antic, int f, float w, float s, boolean sl, String i)
{ {
keys = ks; keys = ks;
anticircle = antic; anticircle = antic;
keysflags = f; keysflags = f;
width = Math.max(w, 0f); width = Math.max(w, 0f);
shift = Math.max(s, 0f); shift = Math.max(s, 0f);
slider = sl;
indication = i; indication = i;
} }
static final Key EMPTY = new Key(new KeyValue[9], null, 0, 1.f, 1.f, null);
/** Read a key value attribute that have a synonym. Having both synonyms /** Read a key value attribute that have a synonym. Having both synonyms
present at the same time is an error. present at the same time is an error.
Returns [null] if the attributes are not present. */ Returns [null] if the attributes are not present. */
@@ -489,10 +487,11 @@ public final class KeyboardData
KeyValue anticircle = parse_nonloc_key_attr(parser, "anticircle"); KeyValue anticircle = parse_nonloc_key_attr(parser, "anticircle");
float width = attribute_float(parser, "width", 1f); float width = attribute_float(parser, "width", 1f);
float shift = attribute_float(parser, "shift", 0.f); float shift = attribute_float(parser, "shift", 0.f);
boolean slider = attribute_bool(parser, "slider", false);
String indication = parser.getAttributeValue(null, "indication"); String indication = parser.getAttributeValue(null, "indication");
while (parser.next() != XmlPullParser.END_TAG) while (parser.next() != XmlPullParser.END_TAG)
continue; continue;
return new Key(ks, anticircle, keysflags, width, shift, indication); return new Key(ks, anticircle, keysflags, width, shift, slider, indication);
} }
/** Whether key at [index] as [flag]. */ /** Whether key at [index] as [flag]. */
@@ -504,7 +503,8 @@ public final class KeyboardData
/** New key with the width multiplied by 's'. */ /** New key with the width multiplied by 's'. */
public Key scaleWidth(float s) public Key scaleWidth(float s)
{ {
return new Key(keys, anticircle, keysflags, width * s, shift, indication); return new Key(keys, anticircle, keysflags, width * s, shift, slider,
indication);
} }
public void getKeys(Map<KeyValue, KeyPos> dst, int row, int col) public void getKeys(Map<KeyValue, KeyPos> dst, int row, int col)
@@ -525,12 +525,12 @@ public final class KeyboardData
for (int j = 0; j < keys.length; j++) ks[j] = keys[j]; for (int j = 0; j < keys.length; j++) ks[j] = keys[j];
ks[i] = kv; ks[i] = kv;
int flags = (keysflags & ~(ALL_FLAGS << i)); int flags = (keysflags & ~(ALL_FLAGS << i));
return new Key(ks, anticircle, flags, width, shift, indication); return new Key(ks, anticircle, flags, width, shift, slider, indication);
} }
public Key withShift(float s) public Key withShift(float s)
{ {
return new Key(keys, anticircle, keysflags, width, s, indication); return new Key(keys, anticircle, keysflags, width, s, slider, indication);
} }
public boolean hasValue(KeyValue kv) public boolean hasValue(KeyValue kv)
@@ -556,7 +556,7 @@ public final class KeyboardData
for (int i = 0; i < ks.length; i++) for (int i = 0; i < ks.length; i++)
if (k.keys[i] != null) if (k.keys[i] != null)
ks[i] = apply(k.keys[i], k.keyHasFlag(i, Key.F_LOC)); ks[i] = apply(k.keys[i], k.keyHasFlag(i, Key.F_LOC));
return new Key(ks, k.anticircle, k.keysflags, k.width, k.shift, k.indication); return new Key(ks, k.anticircle, k.keysflags, k.width, k.shift, k.slider, k.indication);
} }
} }

View File

@@ -1,216 +0,0 @@
package juloo.keyboard2;
import android.content.res.Resources;
import android.view.KeyEvent;
import java.util.TreeMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public final class LayoutModifier
{
static Config globalConfig;
static KeyboardData.Row bottom_row;
static KeyboardData.Row number_row;
static KeyboardData num_pad;
/** Update the layout according to the configuration.
* - Remove the switching key if it isn't needed
* - Remove "localized" keys from other locales (not in 'extra_keys')
* - 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 static KeyboardData modify_layout(KeyboardData kw)
{
// Extra keys are removed from the set as they are encountered during the
// first iteration then automatically added.
final TreeMap<KeyValue, KeyboardData.PreferredPos> extra_keys = new TreeMap<KeyValue, KeyboardData.PreferredPos>();
final Set<KeyValue> remove_keys = new HashSet<KeyValue>();
// Make sure the config key is accessible to avoid being locked in a custom
// layout.
extra_keys.put(KeyValue.getKeyByName("config"), KeyboardData.PreferredPos.ANYWHERE);
extra_keys.putAll(globalConfig.extra_keys_param);
extra_keys.putAll(globalConfig.extra_keys_custom);
// Number row and numpads are added after the modification pass to allow
// removing the number keys from the main layout.
KeyboardData.Row added_number_row = null;
KeyboardData added_numpad = null;
if (globalConfig.show_numpad)
{
added_numpad = modify_numpad(num_pad, kw);
remove_keys.addAll(added_numpad.getKeys().keySet());
}
else if (globalConfig.add_number_row && !kw.embedded_number_row) // The numpad removes the number row
{
added_number_row = modify_number_row(number_row, kw);
remove_keys.addAll(added_number_row.getKeys(0).keySet());
}
// Add the bottom row before computing the extra keys
if (kw.bottom_row)
kw = kw.insert_row(bottom_row, kw.rows.size());
// Compose keys to add to the layout
// 'extra_keys_keyset' reflects changes made to 'extra_keys'
Set<KeyValue> extra_keys_keyset = extra_keys.keySet();
// 'kw_keys' contains the keys present on the layout without any extra keys
Set<KeyValue> kw_keys = kw.getKeys().keySet();
if (globalConfig.extra_keys_subtype != null && kw.locale_extra_keys)
{
Set<KeyValue> present = new HashSet<KeyValue>(kw_keys);
present.addAll(extra_keys_keyset);
globalConfig.extra_keys_subtype.compute(extra_keys,
new ExtraKeys.Query(kw.script, present));
}
kw = kw.mapKeys(new KeyboardData.MapKeyValues() {
public KeyValue apply(KeyValue key, boolean localized)
{
if (localized && !extra_keys.containsKey(key))
return null;
if (remove_keys.contains(key))
return null;
return modify_key(key);
}
});
if (added_numpad != null)
kw = kw.addNumPad(added_numpad);
// Add extra keys that are not on the layout (including 'loc' keys)
extra_keys_keyset.removeAll(kw_keys);
if (extra_keys.size() > 0)
kw = kw.addExtraKeys(extra_keys.entrySet().iterator());
// Avoid adding extra keys to the number row
if (added_number_row != null)
kw = kw.insert_row(added_number_row, 0);
return kw;
}
/** Handle the numpad layout. The [main_kw] is used to adapt the numpad to
the main layout's script. */
public static KeyboardData modify_numpad(KeyboardData kw, KeyboardData main_kw)
{
final int map_digit = KeyModifier.modify_numpad_script(main_kw.numpad_script);
return kw.mapKeys(new KeyboardData.MapKeyValues() {
public KeyValue apply(KeyValue key, boolean localized)
{
switch (key.getKind())
{
case Char:
char prev_c = key.getChar();
char c = prev_c;
if (globalConfig.inverse_numpad)
c = inverse_numpad_char(c);
if (map_digit != -1)
{
KeyValue modified = ComposeKey.apply(map_digit, c);
if (modified != null) // Was modified by script
return modified;
}
if (prev_c != c) // Was inverted
return key.withChar(c);
return key; // Don't fallback into [modify_key]
}
return modify_key(key);
}
});
}
/** Modify the pin entry layout. [main_kw] is used to map the digits into the
same script. */
public static KeyboardData modify_pinentry(KeyboardData kw, KeyboardData main_kw)
{
KeyboardData.MapKeyValues m = numpad_script_map(main_kw.numpad_script);
return m == null ? kw : kw.mapKeys(m);
}
/** Modify the number row according to [main_kw]'s script. */
static KeyboardData.Row modify_number_row(KeyboardData.Row row,
KeyboardData main_kw)
{
KeyboardData.MapKeyValues m = numpad_script_map(main_kw.numpad_script);
return m == null ? row : row.mapKeys(m);
}
static KeyboardData.MapKeyValues numpad_script_map(String numpad_script)
{
final int map_digit = KeyModifier.modify_numpad_script(numpad_script);
if (map_digit == -1)
return null;
return new KeyboardData.MapKeyValues() {
public KeyValue apply(KeyValue key, boolean localized)
{
KeyValue modified = ComposeKey.apply(map_digit, key);
return (modified != null) ? modified : key;
}
};
}
/** Modify keys on the main layout and on the numpad according to the config.
*/
static KeyValue modify_key(KeyValue orig)
{
switch (orig.getKind())
{
case Event:
switch (orig.getEvent())
{
case CHANGE_METHOD_PICKER:
if (globalConfig.switch_input_immediate)
return KeyValue.getKeyByName("change_method_prev");
break;
case ACTION:
if (globalConfig.actionLabel == null)
return null; // Remove the action key
if (globalConfig.swapEnterActionKey)
return KeyValue.getKeyByName("enter");
return KeyValue.makeActionKey(globalConfig.actionLabel);
case SWITCH_FORWARD:
return (globalConfig.layouts.size() > 1) ? orig : null;
case SWITCH_BACKWARD:
return (globalConfig.layouts.size() > 2) ? orig : null;
case SWITCH_VOICE_TYPING:
case SWITCH_VOICE_TYPING_CHOOSER:
return globalConfig.shouldOfferVoiceTyping ? orig : null;
}
break;
case Keyevent:
switch (orig.getKeyevent())
{
case KeyEvent.KEYCODE_ENTER:
if (globalConfig.swapEnterActionKey && globalConfig.actionLabel != null)
return KeyValue.makeActionKey(globalConfig.actionLabel);
break;
}
break;
}
return orig;
}
static char inverse_numpad_char(char c)
{
switch (c)
{
case '7': return '1';
case '8': return '2';
case '9': return '3';
case '1': return '7';
case '2': return '8';
case '3': return '9';
default: return c;
}
}
public static void init(Config globalConfig_, Resources res)
{
globalConfig = globalConfig_;
try
{
number_row = KeyboardData.load_number_row(res);
bottom_row = KeyboardData.load_bottom_row(res);
num_pad = KeyboardData.load_num_pad(res);
}
catch (Exception e)
{
throw new RuntimeException(e.getMessage()); // Not recoverable
}
}
}

View File

@@ -16,7 +16,7 @@ public final class Pointers implements Handler.Callback
public static final int FLAG_P_LATCHABLE = 1; public static final int FLAG_P_LATCHABLE = 1;
public static final int FLAG_P_LATCHED = (1 << 1); public static final int FLAG_P_LATCHED = (1 << 1);
public static final int FLAG_P_FAKE = (1 << 2); public static final int FLAG_P_FAKE = (1 << 2);
public static final int FLAG_P_DOUBLE_TAP_LOCK = (1 << 3); public static final int FLAG_P_LOCKABLE = (1 << 3);
public static final int FLAG_P_LOCKED = (1 << 4); public static final int FLAG_P_LOCKED = (1 << 4);
public static final int FLAG_P_SLIDING = (1 << 5); public static final int FLAG_P_SLIDING = (1 << 5);
/** Clear latched (only if also FLAG_P_LATCHABLE set). */ /** Clear latched (only if also FLAG_P_LATCHABLE set). */
@@ -86,10 +86,10 @@ public final class Pointers implements Handler.Callback
/** The key must not be already latched . */ /** The key must not be already latched . */
void add_fake_pointer(KeyboardData.Key key, KeyValue kv, boolean locked) void add_fake_pointer(KeyboardData.Key key, KeyValue kv, boolean locked)
{ {
int flags = pointer_flags_of_kv(kv) | FLAG_P_FAKE | FLAG_P_LATCHED; Pointer ptr = new Pointer(-1, key, kv, 0.f, 0.f, Modifiers.EMPTY);
ptr.flags = FLAG_P_FAKE | FLAG_P_LATCHED;
if (locked) if (locked)
flags |= FLAG_P_LOCKED; ptr.flags |= FLAG_P_LOCKED;
Pointer ptr = new Pointer(-1, key, kv, 0.f, 0.f, Modifiers.EMPTY, flags);
_ptrs.add(ptr); _ptrs.add(ptr);
_handler.onPointerFlagsChanged(false); _handler.onPointerFlagsChanged(false);
} }
@@ -153,8 +153,7 @@ public final class Pointers implements Handler.Callback
if (latched != null) // Already latched if (latched != null) // Already latched
{ {
removePtr(ptr); // Remove dupplicate removePtr(ptr); // Remove dupplicate
// Toggle lockable key, except if it's a fake pointer if ((latched.flags & FLAG_P_LOCKABLE) != 0) // Toggle lockable key
if ((latched.flags & (FLAG_P_FAKE | FLAG_P_DOUBLE_TAP_LOCK)) == FLAG_P_DOUBLE_TAP_LOCK)
lockPointer(latched, false); lockPointer(latched, false);
else // Otherwise, unlatch else // Otherwise, unlatch
{ {
@@ -205,7 +204,7 @@ public final class Pointers implements Handler.Callback
// The other key already "own" the latched modifiers and will clear them. // The other key already "own" the latched modifiers and will clear them.
Modifiers mods = getModifiers(isOtherPointerDown()); Modifiers mods = getModifiers(isOtherPointerDown());
KeyValue value = _handler.modifyKey(key.keys[0], mods); KeyValue value = _handler.modifyKey(key.keys[0], mods);
Pointer ptr = make_pointer(pointerId, key, value, x, y, mods); Pointer ptr = new Pointer(pointerId, key, value, x, y, mods);
_ptrs.add(ptr); _ptrs.add(ptr);
startLongPress(ptr); startLongPress(ptr);
_handler.onPointerDown(value, false); _handler.onPointerDown(value, false);
@@ -234,9 +233,8 @@ public final class Pointers implements Handler.Callback
private KeyValue getNearestKeyAtDirection(Pointer ptr, int direction) private KeyValue getNearestKeyAtDirection(Pointer ptr, int direction)
{ {
KeyValue k; KeyValue k;
// [i] is [0, -1, 1, -2, 2], scanning a 1/4 of the circle's area, centered // [i] is [0, -1, 1, -2, 2, ...]
// on the initial direction. for (int i = 0; i > -4; i = (~i>>31) - i)
for (int i = 0; i > -2; i = (~i>>31) - i)
{ {
int d = (direction + i + 16) % 16; int d = (direction + i + 16) % 16;
// Don't make the difference between a key that doesn't exist and a key // Don't make the difference between a key that doesn't exist and a key
@@ -255,7 +253,7 @@ public final class Pointers implements Handler.Callback
return; return;
if (ptr.hasFlagsAny(FLAG_P_SLIDING)) if (ptr.hasFlagsAny(FLAG_P_SLIDING))
{ {
ptr.sliding.onTouchMove(ptr, x, y); ptr.sliding.onTouchMove(ptr, x);
return; return;
} }
@@ -295,9 +293,13 @@ public final class Pointers implements Handler.Callback
ptr.value = new_value; ptr.value = new_value;
ptr.flags = pointer_flags_of_kv(new_value); ptr.flags = pointer_flags_of_kv(new_value);
// Start sliding mode // Sliding mode is entered when key5 or key6 is down on a slider key.
if (new_value.getKind() == KeyValue.Kind.Slider) if (ptr.key.slider &&
startSliding(ptr, x, y, dx, dy, new_value); (new_value.equals(ptr.key.getKeyValue(5))
|| new_value.equals(ptr.key.getKeyValue(6))))
{
startSliding(ptr, x);
}
_handler.onPointerDown(new_value, true); _handler.onPointerDown(new_value, true);
} }
@@ -313,7 +315,6 @@ public final class Pointers implements Handler.Callback
ptr.value = apply_gesture(ptr, ptr.gesture.get_gesture()); ptr.value = apply_gesture(ptr, ptr.gesture.get_gesture());
restartLongPress(ptr); restartLongPress(ptr);
ptr.flags = 0; // Special behaviors are ignored during a gesture. ptr.flags = 0; // Special behaviors are ignored during a gesture.
_handler.onPointerFlagsChanged(true); // Vibrate
} }
} }
} }
@@ -367,7 +368,7 @@ public final class Pointers implements Handler.Callback
/** Make a pointer into the locked state. */ /** Make a pointer into the locked state. */
private void lockPointer(Pointer ptr, boolean shouldVibrate) private void lockPointer(Pointer ptr, boolean shouldVibrate)
{ {
ptr.flags = (ptr.flags & ~FLAG_P_DOUBLE_TAP_LOCK) | FLAG_P_LOCKED; ptr.flags = (ptr.flags & ~FLAG_P_LOCKABLE) | FLAG_P_LOCKED;
_handler.onPointerFlagsChanged(shouldVibrate); _handler.onPointerFlagsChanged(shouldVibrate);
} }
@@ -451,21 +452,15 @@ public final class Pointers implements Handler.Callback
// Sliding // Sliding
/** When sliding is ongoing, key events are handled by the [Slider] class. void startSliding(Pointer ptr, float x)
[kv] must be of kind [Slider]. */
void startSliding(Pointer ptr, float x, float y, float dx, float dy, KeyValue kv)
{ {
int r = kv.getSliderRepeat();
int dirx = dx < 0 ? -r : r;
int diry = dy < 0 ? -r : r;
stopLongPress(ptr); stopLongPress(ptr);
ptr.flags |= FLAG_P_SLIDING; ptr.flags |= FLAG_P_SLIDING;
ptr.sliding = new Sliding(x, y, dirx, diry, kv.getSlider()); ptr.sliding = new Sliding(x);
_handler.onPointerHold(kv, ptr.modifiers);
} }
/** Return the [FLAG_P_*] flags that correspond to pressing [kv]. */ /** Return the [FLAG_P_*] flags that correspond to pressing [kv]. */
int pointer_flags_of_kv(KeyValue kv) static int pointer_flags_of_kv(KeyValue kv)
{ {
int flags = 0; int flags = 0;
if (kv.hasFlagsAny(KeyValue.FLAG_LATCH)) if (kv.hasFlagsAny(KeyValue.FLAG_LATCH))
@@ -475,9 +470,8 @@ public final class Pointers implements Handler.Callback
flags |= FLAG_P_CLEAR_LATCHED | FLAG_P_CANT_LOCK; flags |= FLAG_P_CLEAR_LATCHED | FLAG_P_CANT_LOCK;
flags |= FLAG_P_LATCHABLE; flags |= FLAG_P_LATCHABLE;
} }
if (_config.double_tap_lock_shift && if (kv.hasFlagsAny(KeyValue.FLAG_LOCK))
kv.hasFlagsAny(KeyValue.FLAG_DOUBLE_TAP_LOCK)) flags |= FLAG_P_LOCKABLE;
flags |= FLAG_P_DOUBLE_TAP_LOCK;
return flags; return flags;
} }
@@ -518,13 +512,6 @@ public final class Pointers implements Handler.Callback
// Pointers // Pointers
Pointer make_pointer(int p, KeyboardData.Key k, KeyValue v, float x, float y,
Modifiers m)
{
int flags = (v == null) ? 0 : pointer_flags_of_kv(v);
return new Pointer(p, k, v, x, y, m, flags);
}
private static final class Pointer private static final class Pointer
{ {
/** -1 when latched. */ /** -1 when latched. */
@@ -546,7 +533,7 @@ public final class Pointers implements Handler.Callback
/** [null] when not in sliding mode. */ /** [null] when not in sliding mode. */
public Sliding sliding; public Sliding sliding;
public Pointer(int p, KeyboardData.Key k, KeyValue v, float x, float y, Modifiers m, int f) public Pointer(int p, KeyboardData.Key k, KeyValue v, float x, float y, Modifiers m)
{ {
pointerId = p; pointerId = p;
key = k; key = k;
@@ -555,7 +542,7 @@ public final class Pointers implements Handler.Callback
downX = x; downX = x;
downY = y; downY = y;
modifiers = m; modifiers = m;
flags = f; flags = (v == null) ? 0 : pointer_flags_of_kv(v);
timeoutWhat = -1; timeoutWhat = -1;
sliding = null; sliding = null;
} }
@@ -571,55 +558,34 @@ public final class Pointers implements Handler.Callback
/** Accumulated distance since last event. */ /** Accumulated distance since last event. */
float d = 0.f; float d = 0.f;
/** The slider speed changes depending on the pointer speed. */ /** The slider speed changes depending on the pointer speed. */
float speed = 0.5f; float speed = 1.f;
/** Coordinate of the last move. */ /** Coordinate of the last move. */
float last_x; float last_x;
float last_y; /** [System.currentTimeMillis()] at the time of the last move. */
/** [System.currentTimeMillis()] at the time of the last move. Equals to long last_move_ms;
[-1] when the sliding hasn't started yet. */
long last_move_ms = -1;
/** The property which is being slided. */
KeyValue.Slider slider;
/** Direction of the initial movement, positive if sliding to the right and
negative if sliding to the left. */
int direction_x;
int direction_y;
public Sliding(float x, float y, int dirx, int diry, KeyValue.Slider s) public Sliding(float x)
{ {
last_x = x; last_x = x;
last_y = y; last_move_ms = System.currentTimeMillis();
slider = s;
direction_x = dirx;
direction_y = diry;
} }
static final float SPEED_SMOOTHING = 0.7f; static final float SPEED_SMOOTHING = 0.7f;
/** Avoid absurdly large values. */ /** Avoid absurdly large values. */
static final float SPEED_MAX = 4.f; static final float SPEED_MAX = 4.f;
public void onTouchMove(Pointer ptr, float x, float y) public void onTouchMove(Pointer ptr, float x)
{ {
// Start sliding only after the pointer has travelled an other distance. d += (x - last_x) * speed / _config.slide_step_px;
// This allows to trigger the slider movements only once with a short update_speed(x);
// swipe.
float travelled = Math.abs(x - last_x) + Math.abs(y - last_y);
if (last_move_ms == -1)
{
if (travelled < _config.swipe_dist_px)
return;
last_move_ms = System.currentTimeMillis();
}
d += ((x - last_x) * direction_x + (y - last_y) * direction_y)
* speed / _config.slide_step_px;
update_speed(travelled, x, y);
// Send an event when [abs(d)] exceeds [1]. // Send an event when [abs(d)] exceeds [1].
int d_ = (int)d; int d_ = (int)d;
if (d_ != 0) if (d_ != 0)
{ {
d -= d_; d -= d_;
_handler.onPointerHold(KeyValue.sliderKey(slider, d_), int key_index = (d_ < 0) ? 5 : 6;
ptr.modifiers); ptr.value = _handler.modifyKey(ptr.key.keys[key_index], ptr.modifiers);
send_key(ptr, Math.abs(d_));
} }
} }
@@ -632,18 +598,43 @@ public final class Pointers implements Handler.Callback
_handler.onPointerFlagsChanged(false); _handler.onPointerFlagsChanged(false);
} }
/** Send the pressed key [n] times. */
void send_key(Pointer ptr, int n)
{
if (ptr.value == null)
return;
// Avoid looping if possible to avoid lag while sliding fast
KeyValue multiplied = multiply_key(ptr.value, n);
if (multiplied != null)
_handler.onPointerHold(multiplied, ptr.modifiers);
else
for (int i = 0; i < n; i++)
_handler.onPointerHold(ptr.value, ptr.modifiers);
}
/** Return a key performing the same action as [kv] but [n] times. Returns
[null] if [kv] cannot be multiplied. */
KeyValue multiply_key(KeyValue kv, int n)
{
switch (kv.getKind())
{
case Cursor_move:
return KeyValue.cursorMoveKey(kv.getCursorMove() * n);
}
return null;
}
/** [speed] is computed from the elapsed time and distance traveled /** [speed] is computed from the elapsed time and distance traveled
between two move events. Exponential smoothing is used to smooth out between two move events. Exponential smoothing is used to smooth out
the noise. Sets [last_move_ms] and [last_pos]. */ the noise. Sets [last_move_ms] and [last_x]. */
void update_speed(float travelled, float x, float y) void update_speed(float x)
{ {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
float instant_speed = Math.min(SPEED_MAX, float instant_speed = Math.min(SPEED_MAX,
travelled / (float)(now - last_move_ms) + 1.f); Math.abs(x - last_x) / (float)(now - last_move_ms) + 1.f);
speed = speed + (instant_speed - speed) * SPEED_SMOOTHING; speed = speed + (instant_speed - speed) * SPEED_SMOOTHING;
last_move_ms = now; last_move_ms = now;
last_x = x; last_x = x;
last_y = y;
} }
} }

View File

@@ -9,11 +9,9 @@ import android.util.AttributeSet;
public class Theme public class Theme
{ {
// Key colors public final Paint keyBgPaint = new Paint();
public final int colorKey; public final Paint keyDownBgPaint = new Paint();
public final int colorKeyActivated; public final Paint keyBorderPaint = new Paint();
// Label colors
public final int lockedColor; public final int lockedColor;
public final int activatedColor; public final int activatedColor;
public final int labelColor; public final int labelColor;
@@ -21,7 +19,6 @@ public class Theme
public final int secondaryLabelColor; public final int secondaryLabelColor;
public final int greyedLabelColor; public final int greyedLabelColor;
// Key borders
public final float keyBorderRadius; public final float keyBorderRadius;
public final float keyBorderWidth; public final float keyBorderWidth;
public final float keyBorderWidthActivated; public final float keyBorderWidthActivated;
@@ -33,12 +30,19 @@ public class Theme
public final int colorNavBar; public final int colorNavBar;
public final boolean isLightNavBar; public final boolean isLightNavBar;
private final Paint _keyLabelPaint;
private final Paint _specialKeyLabelPaint;
private final Paint _keySubLabelPaint;
private final Paint _specialKeySubLabelPaint;
private final Paint _indicationPaint;
private final Paint _specialIndicationPaint;
public Theme(Context context, AttributeSet attrs) public Theme(Context context, AttributeSet attrs)
{ {
getKeyFont(context); // _key_font will be accessed
TypedArray s = context.getTheme().obtainStyledAttributes(attrs, R.styleable.keyboard, 0, 0); TypedArray s = context.getTheme().obtainStyledAttributes(attrs, R.styleable.keyboard, 0, 0);
colorKey = s.getColor(R.styleable.keyboard_colorKey, 0); int colorKey = s.getColor(R.styleable.keyboard_colorKey, 0);
colorKeyActivated = s.getColor(R.styleable.keyboard_colorKeyActivated, 0); keyBgPaint.setColor(colorKey);
keyDownBgPaint.setColor(s.getColor(R.styleable.keyboard_colorKeyActivated, 0));
// colorKeyboard = s.getColor(R.styleable.keyboard_colorKeyboard, 0); // colorKeyboard = s.getColor(R.styleable.keyboard_colorKeyboard, 0);
colorNavBar = s.getColor(R.styleable.keyboard_navigationBarColor, 0); colorNavBar = s.getColor(R.styleable.keyboard_navigationBarColor, 0);
isLightNavBar = s.getBoolean(R.styleable.keyboard_windowLightNavigationBar, false); isLightNavBar = s.getBoolean(R.styleable.keyboard_windowLightNavigationBar, false);
@@ -53,11 +57,37 @@ public class Theme
keyBorderRadius = s.getDimension(R.styleable.keyboard_keyBorderRadius, 0); keyBorderRadius = s.getDimension(R.styleable.keyboard_keyBorderRadius, 0);
keyBorderWidth = s.getDimension(R.styleable.keyboard_keyBorderWidth, 0); keyBorderWidth = s.getDimension(R.styleable.keyboard_keyBorderWidth, 0);
keyBorderWidthActivated = s.getDimension(R.styleable.keyboard_keyBorderWidthActivated, 0); keyBorderWidthActivated = s.getDimension(R.styleable.keyboard_keyBorderWidthActivated, 0);
keyBorderPaint.setStyle(Paint.Style.STROKE);
keyBorderColorLeft = s.getColor(R.styleable.keyboard_keyBorderColorLeft, colorKey); keyBorderColorLeft = s.getColor(R.styleable.keyboard_keyBorderColorLeft, colorKey);
keyBorderColorTop = s.getColor(R.styleable.keyboard_keyBorderColorTop, colorKey); keyBorderColorTop = s.getColor(R.styleable.keyboard_keyBorderColorTop, colorKey);
keyBorderColorRight = s.getColor(R.styleable.keyboard_keyBorderColorRight, colorKey); keyBorderColorRight = s.getColor(R.styleable.keyboard_keyBorderColorRight, colorKey);
keyBorderColorBottom = s.getColor(R.styleable.keyboard_keyBorderColorBottom, colorKey); keyBorderColorBottom = s.getColor(R.styleable.keyboard_keyBorderColorBottom, colorKey);
s.recycle(); s.recycle();
_keyLabelPaint = initLabelPaint(Paint.Align.CENTER, null);
_keySubLabelPaint = initLabelPaint(Paint.Align.LEFT, null);
Typeface specialKeyFont = getKeyFont(context);
_specialKeyLabelPaint = initLabelPaint(Paint.Align.CENTER, specialKeyFont);
_specialKeySubLabelPaint = initLabelPaint(Paint.Align.LEFT, specialKeyFont);
_indicationPaint = initLabelPaint(Paint.Align.CENTER, null);
_specialIndicationPaint = initLabelPaint(Paint.Align.CENTER, specialKeyFont);
}
public Paint labelPaint(boolean special_font)
{
Paint p = special_font ? _specialKeyLabelPaint : _keyLabelPaint;
return p;
}
public Paint subLabelPaint(boolean special_font, Paint.Align align)
{
Paint p = special_font ? _specialKeySubLabelPaint : _keySubLabelPaint;
p.setTextAlign(align);
return p;
}
public Paint indicationPaint(boolean special_font)
{
return special_font ? _specialIndicationPaint : _indicationPaint;
} }
/** Interpolate the 'value' component toward its opposite by 'alpha'. */ /** Interpolate the 'value' component toward its opposite by 'alpha'. */
@@ -70,7 +100,7 @@ public class Theme
return Color.HSVToColor(hsv); return Color.HSVToColor(hsv);
} }
Paint initIndicationPaint(Paint.Align align, Typeface font) Paint initLabelPaint(Paint.Align align, Typeface font)
{ {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setTextAlign(align); paint.setTextAlign(align);
@@ -87,104 +117,4 @@ public class Theme
_key_font = Typeface.createFromAsset(context.getAssets(), "special_font.ttf"); _key_font = Typeface.createFromAsset(context.getAssets(), "special_font.ttf");
return _key_font; return _key_font;
} }
public static final class Computed
{
public final float vertical_margin;
public final float horizontal_margin;
public final float margin_top;
public final float margin_left;
public final Paint indication_paint;
public final Key key;
public final Key key_activated;
public Computed(Theme theme, Config config, float keyWidth)
{
vertical_margin = config.key_vertical_margin * config.keyHeight;
horizontal_margin = config.key_horizontal_margin * keyWidth;
// Add half of the key margin on the left and on the top as it's also
// added on the right and on the bottom of every keys.
margin_top = config.marginTop + vertical_margin / 2;
margin_left = horizontal_margin / 2;
key = new Key(theme, config, keyWidth, false);
key_activated = new Key(theme, config, keyWidth, true);
indication_paint = init_label_paint(config, null);
indication_paint.setColor(theme.subLabelColor);
}
public static final class Key
{
public final Paint bg_paint = new Paint();
public final Paint border_left_paint;
public final Paint border_top_paint;
public final Paint border_right_paint;
public final Paint border_bottom_paint;
public final float border_width;
public final float border_radius;
final Paint _label_paint;
final Paint _special_label_paint;
final Paint _sublabel_paint;
final Paint _special_sublabel_paint;
public Key(Theme theme, Config config, float keyWidth, boolean activated)
{
bg_paint.setColor(activated ? theme.colorKeyActivated : theme.colorKey);
if (config.borderConfig)
{
border_radius = config.customBorderRadius * keyWidth;
border_width = config.customBorderLineWidth;
}
else
{
border_radius = theme.keyBorderRadius;
border_width = activated ? theme.keyBorderWidthActivated : theme.keyBorderWidth;
}
bg_paint.setAlpha(activated ? config.keyActivatedOpacity : config.keyOpacity);
border_left_paint = init_border_paint(config, border_width, theme.keyBorderColorLeft);
border_top_paint = init_border_paint(config, border_width, theme.keyBorderColorTop);
border_right_paint = init_border_paint(config, border_width, theme.keyBorderColorRight);
border_bottom_paint = init_border_paint(config, border_width, theme.keyBorderColorBottom);
_label_paint = init_label_paint(config, null);
_special_label_paint = init_label_paint(config, _key_font);
_sublabel_paint = init_label_paint(config, null);
_special_sublabel_paint = init_label_paint(config, _key_font);
}
public Paint label_paint(boolean special_font, float text_size)
{
Paint p = special_font ? _special_label_paint : _label_paint;
p.setTextSize(text_size);
return p;
}
public Paint sublabel_paint(boolean special_font, float text_size, Paint.Align align)
{
Paint p = special_font ? _special_sublabel_paint : _sublabel_paint;
p.setTextSize(text_size);
p.setTextAlign(align);
return p;
}
}
static Paint init_border_paint(Config config, float border_width, int color)
{
Paint p = new Paint();
p.setAlpha(config.keyOpacity);
p.setStyle(Paint.Style.STROKE);
p.setStrokeWidth(border_width);
p.setColor(color);
return p;
}
static Paint init_label_paint(Config config, Typeface font)
{
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
p.setTextAlign(Paint.Align.CENTER);
p.setAlpha(config.labelBrightness);
if (font != null)
p.setTypeface(font);
return p;
}
}
} }

View File

@@ -11,7 +11,6 @@ import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype; import android.view.inputmethod.InputMethodSubtype;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.Toast;
import java.util.AbstractMap.SimpleEntry; import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -71,8 +70,6 @@ class VoiceImeSwitcher
} }
}) })
.create(); .create();
if (ime_display_names.size() == 0)
dialog.setMessage(ims.getResources().getString(R.string.toast_no_voice_input));
Utils.show_dialog_on_ime(dialog, ims.getWindow().getWindow().getDecorView().getWindowToken()); Utils.show_dialog_on_ime(dialog, ims.getWindow().getWindow().getDecorView().getWindowToken());
} }

View File

@@ -41,7 +41,7 @@ public class CustomExtraKeysPreference extends ListGroupPreference<String>
if (key_names != null) if (key_names != null)
{ {
for (String key_name : key_names) for (String key_name : key_names)
kvs.put(KeyValue.getKeyByName(key_name), KeyboardData.PreferredPos.DEFAULT); kvs.put(KeyValue.parseKeyDefinition(key_name), KeyboardData.PreferredPos.DEFAULT);
} }
return kvs; return kvs;
} }

View File

@@ -51,10 +51,6 @@ public class ExtraKeysPreference extends PreferenceCategory
"", "",
"ª", "ª",
"º", "º",
"zwj",
"zwnj",
"nbsp",
"nnbsp",
"tab", "tab",
"esc", "esc",
"page_up", "page_up",
@@ -72,8 +68,6 @@ public class ExtraKeysPreference extends PreferenceCategory
"pasteAsPlainText", "pasteAsPlainText",
"undo", "undo",
"redo", "redo",
"delete_word",
"forward_delete_word",
"superscript", "superscript",
"subscript", "subscript",
"f11_placeholder", "f11_placeholder",
@@ -146,7 +140,6 @@ public class ExtraKeysPreference extends PreferenceCategory
static String key_description(Resources res, String name) static String key_description(Resources res, String name)
{ {
int id = 0; int id = 0;
String additional_info = null;
switch (name) switch (name)
{ {
case "capslock": id = R.string.key_descr_capslock; break; case "capslock": id = R.string.key_descr_capslock; break;
@@ -154,39 +147,13 @@ public class ExtraKeysPreference extends PreferenceCategory
case "compose": id = R.string.key_descr_compose; break; case "compose": id = R.string.key_descr_compose; break;
case "copy": id = R.string.key_descr_copy; break; case "copy": id = R.string.key_descr_copy; break;
case "cut": id = R.string.key_descr_cut; break; case "cut": id = R.string.key_descr_cut; break;
case "end": case "end": id = R.string.key_descr_end; break;
id = R.string.key_descr_end; case "home": id = R.string.key_descr_home; break;
additional_info = format_key_combination(new String[]{"fn", "right"}); case "page_down": id = R.string.key_descr_page_down; break;
break; case "page_up": id = R.string.key_descr_page_up; break;
case "home":
id = R.string.key_descr_home;
additional_info = format_key_combination(new String[]{"fn", "left"});
break;
case "page_down":
id = R.string.key_descr_page_down;
additional_info = format_key_combination(new String[]{"fn", "down"});
break;
case "page_up":
id = R.string.key_descr_page_up;
additional_info = format_key_combination(new String[]{"fn", "up"});
break;
case "paste": id = R.string.key_descr_paste; break; case "paste": id = R.string.key_descr_paste; break;
case "pasteAsPlainText": case "pasteAsPlainText": id = R.string.key_descr_pasteAsPlainText; break;
id = R.string.key_descr_pasteAsPlainText; case "redo": id = R.string.key_descr_redo; break;
additional_info = format_key_combination(new String[]{"fn", "paste"});
break;
case "redo":
id = R.string.key_descr_redo;
additional_info = format_key_combination(new String[]{"fn", "undo"});
break;
case "delete_word":
id = R.string.key_descr_delete_word;
additional_info = format_key_combination_gesture(res, "backspace");
break;
case "forward_delete_word":
id = R.string.key_descr_forward_delete_word;
additional_info = format_key_combination_gesture(res, "forward_delete");
break;
case "selectAll": id = R.string.key_descr_selectAll; break; case "selectAll": id = R.string.key_descr_selectAll; break;
case "shareText": id = R.string.key_descr_shareText; break; case "shareText": id = R.string.key_descr_shareText; break;
case "subscript": id = R.string.key_descr_subscript; break; case "subscript": id = R.string.key_descr_subscript; break;
@@ -197,32 +164,6 @@ public class ExtraKeysPreference extends PreferenceCategory
case "ª": id = R.string.key_descr_ª; break; case "ª": id = R.string.key_descr_ª; break;
case "º": id = R.string.key_descr_º; break; case "º": id = R.string.key_descr_º; break;
case "switch_clipboard": id = R.string.key_descr_clipboard; break; case "switch_clipboard": id = R.string.key_descr_clipboard; break;
case "zwj": id = R.string.key_descr_zwj; break;
case "zwnj": id = R.string.key_descr_zwnj; break;
case "nbsp": id = R.string.key_descr_nbsp; break;
case "nnbsp": id = R.string.key_descr_nnbsp; break;
case "accent_aigu":
case "accent_grave":
case "accent_double_aigu":
case "accent_dot_above":
case "accent_circonflexe":
case "accent_tilde":
case "accent_cedille":
case "accent_trema":
case "accent_ring":
case "accent_caron":
case "accent_macron":
case "accent_ogonek":
case "accent_breve":
case "accent_slash":
case "accent_bar":
case "accent_dot_below":
case "accent_hook_above":
case "accent_horn":
case "accent_double_grave":
id = R.string.key_descr_dead_key;
break;
case "combining_dot_above": case "combining_dot_above":
case "combining_double_aigu": case "combining_double_aigu":
@@ -269,11 +210,8 @@ public class ExtraKeysPreference extends PreferenceCategory
break; break;
} }
if (id == 0) if (id == 0)
return additional_info; return null;
String descr = res.getString(id); return res.getString(id);
if (additional_info != null)
descr += "" + additional_info;
return descr;
} }
static String key_title(String key_name, KeyValue kv) static String key_title(String key_name, KeyValue kv)
@@ -286,63 +224,10 @@ public class ExtraKeysPreference extends PreferenceCategory
return kv.getString(); return kv.getString();
} }
/** Format a key combination */
static String format_key_combination(String[] keys)
{
StringBuilder out = new StringBuilder();
for (int i = 0; i < keys.length; i++)
{
if (i > 0) out.append(" + ");
out.append(KeyValue.getKeyByName(keys[i]).getString());
}
return out.toString();
}
/** Explain a gesture on a key */
static String format_key_combination_gesture(Resources res, String key_name)
{
return res.getString(R.string.key_descr_gesture) + " + "
+ KeyValue.getKeyByName(key_name).getString();
}
static KeyboardData.PreferredPos key_preferred_pos(String key_name) static KeyboardData.PreferredPos key_preferred_pos(String key_name)
{ {
switch (key_name) switch (key_name)
{ {
case "cut":
return new KeyboardData.PreferredPos(KeyValue.getKeyByName("x"),
new KeyboardData.KeyPos[]{
new KeyboardData.KeyPos(2, 2, 8),
new KeyboardData.KeyPos(2, -1, 8),
new KeyboardData.KeyPos(-1, -1, 8),
});
case "copy":
return new KeyboardData.PreferredPos(KeyValue.getKeyByName("c"),
new KeyboardData.KeyPos[]{
new KeyboardData.KeyPos(2, 3, 8),
new KeyboardData.KeyPos(2, -1, 8),
new KeyboardData.KeyPos(-1, -1, 8),
});
case "paste":
return new KeyboardData.PreferredPos(KeyValue.getKeyByName("v"),
new KeyboardData.KeyPos[]{
new KeyboardData.KeyPos(2, 4, 8),
new KeyboardData.KeyPos(2, -1, 8),
new KeyboardData.KeyPos(-1, -1, 8),
});
case "undo":
return new KeyboardData.PreferredPos(KeyValue.getKeyByName("z"),
new KeyboardData.KeyPos[]{
new KeyboardData.KeyPos(2, 1, 8),
new KeyboardData.KeyPos(2, -1, 8),
new KeyboardData.KeyPos(-1, -1, 8),
});
case "redo":
return new KeyboardData.PreferredPos(KeyValue.getKeyByName("y"),
new KeyboardData.KeyPos[]{
new KeyboardData.KeyPos(0, -1, 8),
new KeyboardData.KeyPos(-1, -1, 8),
});
case "f11_placeholder": case "f11_placeholder":
return new KeyboardData.PreferredPos(KeyValue.getKeyByName("9"), return new KeyboardData.PreferredPos(KeyValue.getKeyByName("9"),
new KeyboardData.KeyPos[]{ new KeyboardData.KeyPos[]{
@@ -359,16 +244,6 @@ public class ExtraKeysPreference extends PreferenceCategory
new KeyboardData.KeyPos(0, -1, 3), new KeyboardData.KeyPos(0, -1, 3),
new KeyboardData.KeyPos(0, -1, 4), new KeyboardData.KeyPos(0, -1, 4),
}); });
case "delete_word":
return new KeyboardData.PreferredPos(KeyValue.getKeyByName("backspace"),
new KeyboardData.KeyPos[]{
new KeyboardData.KeyPos(-1, -1, 3),
});
case "forward_delete_word":
return new KeyboardData.PreferredPos(KeyValue.getKeyByName("backspace"),
new KeyboardData.KeyPos[]{
new KeyboardData.KeyPos(-1, -1, 4),
});
} }
return KeyboardData.PreferredPos.DEFAULT; return KeyboardData.PreferredPos.DEFAULT;
} }
@@ -413,6 +288,8 @@ public class ExtraKeysPreference extends PreferenceCategory
static class ExtraKeyCheckBoxPreference extends CheckBoxPreference static class ExtraKeyCheckBoxPreference extends CheckBoxPreference
{ {
boolean _key_font;
public ExtraKeyCheckBoxPreference(Context ctx, String key_name, public ExtraKeyCheckBoxPreference(Context ctx, String key_name,
boolean default_checked) boolean default_checked)
{ {
@@ -425,7 +302,7 @@ public class ExtraKeysPreference extends PreferenceCategory
setKey(pref_key_of_key_name(key_name)); setKey(pref_key_of_key_name(key_name));
setDefaultValue(default_checked); setDefaultValue(default_checked);
setTitle(title); setTitle(title);
setSingleLineTitle(false); _key_font = kv.hasFlagsAny(KeyValue.FLAG_KEY_FONT);
} }
@Override @Override
@@ -433,7 +310,7 @@ public class ExtraKeysPreference extends PreferenceCategory
{ {
super.onBindView(view); super.onBindView(view);
TextView title = (TextView)view.findViewById(android.R.id.title); TextView title = (TextView)view.findViewById(android.R.id.title);
title.setTypeface(Theme.getKeyFont(getContext())); title.setTypeface(_key_font ? Theme.getKeyFont(getContext()) : null);
} }
} }
} }

View File

@@ -1,42 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<keyboard name="ФЦУЖЭН (Монгол)" script="cyrillic">
<row>
<key key0="ф" key2="1" key4="loc esc"/>
<key key0="ц" key1="~" key2="2" key3="\@"/>
<key key0="у" key1="!" key2="3" key3="\#"/>
<key key0="ж" key2="4" key3="$"/>
<key key0="э" key2="5" key3="%"/>
<key key0="н" key2="6" key3="^"/>
<key key0="г" key2="7" key3="&amp;"/>
<key key0="ш" key1="щ" key2="8" key3="*"/>
<key key0="ү" key2="9" key3="(" key4=")"/>
<key key0="з" key2="0"/>
<key key0="к"/>
</row>
<row>
<key key0="й" key1="loc tab" key2="`"/>
<key key0="ы"/>
<key key0="б"/>
<key key0="ө"/>
<key key0="а"/>
<key key0="х"/>
<key key0="р" key2="-" key3="_"/>
<key key0="о" key2="=" key3="+"/>
<key key0="л" key3="{" key4="}"/>
<key key0="д" key3="[" key4="]"/>
<key key0="п" key2="|" key3="\\"/>
</row>
<row>
<key key0="shift" key2="loc capslock"/>
<key key0="я"/>
<key key0="ч"/>
<key key0="ё" key1="е"/>
<key key0="с"/>
<key key0="м" key2="&lt;" key3="."/>
<key key0="и" key2=">" key3=","/>
<key key0="т" key1="₮" key2="\?" key3="/"/>
<key key0="ь" key1="ъ" key2=":" key3=";"/>
<key key0="в" key1="ю" key2="&quot;" key3="'"/>
<key key0="backspace" key2="delete"/>
</row>
</keyboard>

View File

@@ -8,32 +8,32 @@
<fn a="у" b="у̂" /> <fn a="у" b="у̂" />
<fn a="cursor_left" b="home" /> <fn a="cursor_left" b="home" />
<fn a="cursor_right" b="end" /> <fn a="cursor_right" b="end" />
<ctrl a="љ" b="љ:q" /> <ctrl a="љ" b=":char symbol='љ':q" />
<ctrl a="њ" b="њ:w" /> <ctrl a="њ" b=":char symbol='њ':w" />
<ctrl a="е" b="е:e" /> <ctrl a="е" b=":char symbol='е':e" />
<ctrl a="р" b="р:r" /> <ctrl a="р" b=":char symbol='р':r" />
<ctrl a="т" b="т:t" /> <ctrl a="т" b=":char symbol='т':t" />
<ctrl a="ж" b="ж:y" /> <ctrl a="ж" b=":char symbol='ж':y" />
<ctrl a="у" b="у:u" /> <ctrl a="у" b=":char symbol='у':u" />
<ctrl a="и" b="и:i" /> <ctrl a="и" b=":char symbol='и':i" />
<ctrl a="о" b="о:o" /> <ctrl a="о" b=":char symbol='о':o" />
<ctrl a="п" b="п:p" /> <ctrl a="п" b=":char symbol='п':p" />
<ctrl a="а" b="а:a" /> <ctrl a="а" b=":char symbol='а':a" />
<ctrl a="с" b="с:s" /> <ctrl a="с" b=":char symbol='с':s" />
<ctrl a="д" b="д:d" /> <ctrl a="д" b=":char symbol='д':d" />
<ctrl a="ф" b="ф:f" /> <ctrl a="ф" b=":char symbol='ф':f" />
<ctrl a="г" b="г:g" /> <ctrl a="г" b=":char symbol='г':g" />
<ctrl a="х" b="х:h" /> <ctrl a="х" b=":char symbol='х':h" />
<ctrl a="ј" b="ј:j" /> <ctrl a="ј" b=":char symbol='ј':j" />
<ctrl a="к" b="к:k" /> <ctrl a="к" b=":char symbol='к':k" />
<ctrl a="л" b="л:l" /> <ctrl a="л" b=":char symbol='л':l" />
<ctrl a="з" b="з:z" /> <ctrl a="з" b=":char symbol='з':z" />
<ctrl a="џ" b="џ:x" /> <ctrl a="џ" b=":char symbol='џ':x" />
<ctrl a="ц" b="ц:c" /> <ctrl a="ц" b=":char symbol='ц':c" />
<ctrl a="в" b="в:v" /> <ctrl a="в" b=":char symbol='в':v" />
<ctrl a="б" b="б:b" /> <ctrl a="б" b=":char symbol='б':b" />
<ctrl a="н" b="н:n" /> <ctrl a="н" b=":char symbol='н':n" />
<ctrl a="м" b="м:m" /> <ctrl a="м" b=":char symbol='м':m" />
</modmap> </modmap>
<row> <row>
<key key0="љ" ne="1" se="loc esc"/> <key key0="љ" ne="1" se="loc esc"/>

View File

@@ -1,29 +1,30 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<keyboard name="देवनागरी (हिंदी)-2" script="devanagari"> <keyboard name="देवनागरी (हिंदी)-2" script="devanagari">
<row> <row>
<key shift="0.35" width="0.9" c="क" nw="ख" ne="घ" sw="ङ" se="ग"/> <key shift="0.35" width="0.9" key0="क" key1="ख" key2="घ" key3="ङ" key4="ग"/>
<key width="0.9" c="च" nw="छ" ne="झ" sw="ञ" se="ज"/> <key width="0.9" key0="च" key1="छ" key2="झ" key3="ञ" key4="ज"/>
<key width="0.9" c="ट" nw="ठ" ne="ढ" sw="ण" se="ड" anticircle="७" indication="७"/> <key width="0.9" key0="ट" key1="ठ" key2="ढ" key3="ण" key4="ड"/>
<key width="0.9" c="त" nw="थ" ne="ध" sw="न" se="द" anticircle="८" indication="८"/> <key width="0.9" key0="त" key1="थ" key2="ध" key3="न" key4="द"/>
<key width="0.9" c="प" nw="फ" ne="भ" sw="म" se="ब" anticircle="९" indication="९"/> <key width="0.9" key0="प" key1="फ" key2="भ" key3="म" key4="ब"/>
<key width="0.9" c="र" nw="ज्ञ" ne="ल" sw="य" se="व"/> <key width="0.9" key0="र" key1="ज्ञ" key2="ल" key3="य" key4="व"/>
<key width="0.9" c="ह" nw="श" ne="ळ" sw="स" se="ष"/> <key width="0.9" key0="ह" key1="श" key2="ळ" key3="स" key4="ष"/>
</row> </row>
<row> <row>
<key shift="0.35" width="0.9" c="ा" nw="अ" ne="आ"/> <key shift="0.35" width="0.9" key0="ा" key1="अ" key2="आ"/>
<key width="0.9" c="ि" nw="इ"/> <key width="0.9" key0="ि" key1="इ"/>
<key width="0.9" c="ी" nw="ई" anticircle="४" indication="४"/> <key width="0.9" key0="ी" key1="ई"/>
<key width="0.9" c="ु" nw="उ" ne="ऊ" se="ू" anticircle="५" indication="५"/> <key width="0.9" key0="ु" key1="उ" key2="ऊ" key4="ू"/>
<key width="0.9" c="े" nw="ए" ne="ऋ" se="ृ" anticircle="६" indication="६"/> <key width="0.9" key0="े" key1="ए" key2="ऋ" key4="ृ"/>
<key width="0.9" c="ै" nw="ऐ" ne="ऌ" se="ॢ"/> <key width="0.9" key0="ै" key1="ऐ" key2="ऌ" key4="ॢ"/>
<key width="0.9" c="ो" nw="ओ" ne="औ" se="ौ"/> <key width="0.9" key0="ो" key1="ओ" key2="औ" key4="ौ"/>
</row> </row>
<row> <row>
<key c="" se="\@"/> <key key0="" key2="*" key4="\@"/>
<key c="ँ" nw="₹" ne="॑" sw="ॖ" se="॓" anticircle="" indication=""/> <key key0="ँ" key1="₹" key2="॑" key3="ॖ" key4="॓"/>
<key c="ं" nw="ॐ" ne="" sw="" se="&quot;" anticircle="१" indication="१"/> <key key0="ं" key1="ॐ" key2="" key3="" key4="&quot;"/>
<key c="" nw="," ne=";" sw="!" se="\?" anticircle="२" indication="२"/> <key key0="" key1="," key2=";" key3="!" key4="\?"/>
<key c="़" nw="॰" sw="-" se="" anticircle="" indication=""/> <key key0="़" key1="॰" key2="" key3="-" key4=""/>
<key width="2" c="backspace"/> <key key0="५" key1="१" key2="३" key3="७" key4="९" key5="४" key6="६" key7="२" key8="८"/>
<key key0="backspace" key2="delete"/>
</row> </row>
</keyboard> </keyboard>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<keyboard name="ಕನ್ನಡ - Kannada" script="kannada"> <keyboard name="ಕನ್ನಡ" script="kannada">
<row> <row>
<key key0="ಕ" key1="ಖ" key2="ಘ" key3="ಙ" key4="ಗ"/> <key key0="ಕ" key1="ಖ" key2="ಘ" key3="ಙ" key4="ಗ"/>
<key key0="ಚ" key1="ಛ" key2="ಝ" key3="ಞ" key4="ಜ"/> <key key0="ಚ" key1="ಛ" key2="ಝ" key3="ಞ" key4="ಜ"/>
@@ -7,7 +7,7 @@
<key key0="ತ" key1="ಥ" key2="ಧ" key3="ನ" key4="ದ"/> <key key0="ತ" key1="ಥ" key2="ಧ" key3="ನ" key4="ದ"/>
<key key0="ಪ" key1="ಫ" key2="ಭ" key3="ಮ" key4="ಬ"/> <key key0="ಪ" key1="ಫ" key2="ಭ" key3="ಮ" key4="ಬ"/>
<key key0="ಯ" key1="ರ" key2="ವ" key3="ಱ" key4="ಲ" key8="ೞ"/> <key key0="ಯ" key1="ರ" key2="ವ" key3="ಱ" key4="ಲ" key8="ೞ"/>
<key key0="ಶ" key1="ಷ" key2="ಹ" key3="ಳ" key4="ಸ"/> <key key0="ಶ" key1="ಷ" key2="ಹ" key3="ಳ" key4="ಸ" key8="※"/>
</row> </row>
<row> <row>
<key key0="ಾ" key1="ಅ" key2="ಆ"/> <key key0="ಾ" key1="ಅ" key2="ಆ"/>
@@ -19,11 +19,11 @@
<key key0="ೋ" key1="ಓ" key2="ಔ" key4="ೌ"/> <key key0="ೋ" key1="ಓ" key2="ಔ" key4="ೌ"/>
</row> </row>
<row> <row>
<key key0="್" key1="\@" key2="&amp;" key3="zwnj" key4="zwj" key8="಼"/> <key key0="್" key1="\@" key2="&amp;" key8="಼"/>
<key key0="" key1="₹" key2="卐" key3="!" key4="\?" key7="ॐ"/> <key key0="" key1="₹" key2="卐" key3="!" key4="\?" key7="ॐ"/>
<key key0="ಃ" key5="ೲ" key6="ೱ" key7="ಽ"/> <key key0="ಃ" key5="ೲ" key6="ೱ" key7="ಽ"/>
<key key0="।" key1="'" key2="&quot;" key3="." key4="," key6="॥"/> <key key0="।" key1="'" key2="&quot;" key3="." key4="," key5="" key6="॥" key8="॰"/>
<key key0="" key1=":" key2=";" key3="-" key4="_"/> <key key0="" key3="-" key4="_" key5=":" key6=";" key8=""/>
<key key0="೫" key1="೧" key2="೩" key3="೭" key4="೯" key5="೪" key6="೬" key7="೨" key8="೮"/> <key key0="೫" key1="೧" key2="೩" key3="೭" key4="೯" key5="೪" key6="೬" key7="೨" key8="೮"/>
<key key0="backspace" key2="delete"/> <key key0="backspace" key2="delete"/>
</row> </row>

View File

@@ -1,92 +1,27 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- https://neo-layout.org/Layouts/bone/ --> <!-- https://neo-layout.org/Layouts/bone/ -->
<keyboard name="Bone" script="latin" embedded_number_row="true"> <keyboard name="Bone" bottom_row="false" script="latin">
<modmap> <!-- first row + characters from number row:
<!-- shift on number row:
1234567890 -> °§ℓ»«$€„“”
-->
<shift a="1" b="°"/>
<shift a="2" b="§"/>
<shift a="3" b=""/>
<shift a="4" b="»"/>
<shift a="5" b="«"/>
<shift a="6" b="$"/>
<shift a="7" b="€"/>
<shift a="8" b="„"/>
<shift a="9" b="“"/>
<shift a="0" b="”"/>
<!-- shift on bottom row:
,. -> –•
-->
<shift a="," b=""/>
<shift a="." b="•"/>
</modmap>
<!-- number row:
left of numbers:
accent_circonflexe/superscript
accent_caron/subscript
accent_dot_above
accent_hook_above/accent_horn
accent_dot_below
numbers:
1234567890
°§ℓ»«$€„“” -> shift modmap
¹²³›‹¢¥‚‘’
₁₂₃♀♂⚥ϰ⟨⟩₀v
right of numbers:
accent_grave
accent_cedille/accent_ogonek
accent_ring
accent_trema
accent_rough_breathing (not implemented yet)
accent_macron/accent_macron_below (not implemented yet)
-->
<row>
<!--left side-->
<key width="0.5" key0="loc accent_circonflexe" nw="superscript"/>
<key key0="1" ne="¹" se="₁" nw="loc accent_caron" n="subscript"/>
<key key0="2" ne="²" se="₂" nw="↻"/>
<key key0="3" ne="³" se="₃" nw="loc accent_dot_above"/>
<key key0="4" ne="" se="♀" nw="loc accent_hook_above" n="loc accent_horn"/>
<key key0="5" ne="" se="♂" nw="loc accent_dot_below"/>
<!--right side-->
<key key0="6" nw="¢" sw="⚥" ne="loc accent_macron"/>
<key key0="7" nw="¥" sw="ϰ"/>
<key key0="8" nw="" sw="⟨" ne="loc accent_trema"/>
<key key0="9" nw="" sw="⟩" ne="loc accent_ring"/>
<key key0="0" nw="" sw="₀" ne="loc accent_cedille" n="loc accent_ogonek"/>
<key width="0.5" key0="loc accent_grave"/>
</row>
<!-- first row:
jduaxphlmwß jduaxphlmwß
…_[]^!<>=&ſ …_[]^!<>=&ſ
°§ℓ»«$€„“”—
from the accent key on this row: ›‹¢¥‚‘’
accent_aigu
accent_tilde
accent_double_aigu
accent_slash/accent_bar
accent_smooth_breathing (not implemented yet)
accent_breve
--> -->
<row> <row>
<!--left side--> <!--left side-->
<key key0="j" se="" n="loc esc"/> <key key0="j" key2="°" key4="…"/>
<key key0="d" se="_"/> <key key0="d" key2="§" key4="_"/>
<key key0="u" se="["/> <key key0="u" key2="" key4="["/>
<key key0="a" se="]"/> <key key0="a" key2="»" key4="]" key1=""/>
<key key0="x" se="^"/> <key key0="x" key2="«" key4="^" key1=""/>
<!--center--> <!--middle-->
<key key0="p" s="!" ne="loc accent_breve"/> <key key0="p" key7="¢" key8="!"/>
<!--right side--> <!--right side-->
<key key0="h" sw="&lt;"/> <key key0="h" key1="€" key3="&lt;" key4="7" key2="/>
<key key0="l" sw="&gt;" ne="loc accent_double_aigu"/> <key key0="l" key1="„" key3="&gt;" key4="8" key2=""/>
<key key0="m" sw="=" ne="loc accent_slash" n="loc accent_bar"/> <key key0="m" key1="" key3="=" key4="9" key2=""/>
<key key0="w" sw="&amp;" ne="loc accent_tilde"/> <key key0="w" key1="”" key3="&amp;" key2=""/>
<key key0="ß" sw="ſ" n="loc accent_aigu"/> <key key0="ß" key1="" key3="ſ"/>
</row> </row>
<!--second row: <!--second row:
ctieobnrsgq ctieobnrsgq
@@ -94,19 +29,19 @@
--> -->
<row> <row>
<!--left side--> <!--left side-->
<key key0="c" se="\\" ne="loc tab"/> <key key0="c" key4="\\"/>
<key key0="t" se="/"/> <key key0="t" key4="/"/>
<key key0="i" se="{"/> <key key0="i" key4="{"/>
<key key0="e" se="}"/> <key key0="e" key4="}"/>
<key key0="o" se="*"/> <key key0="o" key4="*"/>
<!--center--> <!--middle-->
<key key0="b" s="\?"/> <key key0="b" key8="\?"/>
<!--right side--> <!--right side-->
<key key0="n" sw="("/> <key key0="n" key3="(" key4="4"/>
<key key0="r" sw=")"/> <key key0="r" key3=")" key4="5"/>
<key key0="s" sw="-"/> <key key0="s" key3="-" key4="6"/>
<key key0="g" sw=":"/> <key key0="g" key3=":"/>
<key key0="q" sw="\@"/> <key key0="q" key3="@"/>
</row> </row>
<!--third row -> compressed to also fit shift and backspace: <!--third row -> compressed to also fit shift and backspace:
fvüäöyz,.k fvüäöyz,.k
@@ -114,18 +49,24 @@
--> -->
<row> <row>
<!--left side--> <!--left side-->
<key width="1.5" key0="shift" <key width="1.5" key0="shift" key4="\#"/>
se="\#"/> <key key0="f" key4="$"/>
<key key0="f" se="$"/> <key key0="v" key4="|"/>
<key key0="v" se="|"/> <key key0="ü" key4="~"/>
<key key0="ü" se="~"/> <key key0="ä" key4="`"/>
<key key0="ä" se="`"/>
<!--right side--> <!--right side-->
<key key0="ö" sw="+"/> <key key0="ö" key3="+"/>
<key key0="y" sw="%"/> <key key0="y" key3="%" key4="1"/>
<key key0="z" sw="," nw="&quot;"/> <key key0="z" key3="," key1="&quot;" key4="2"/>
<key key0="k" sw="." nw="&apos;"/> <key key0="k" key3="." key1="&apos;" key4="3"/>
<key width="1.5" key0="backspace" <key width="1.5" key0="backspace" key3=";" key1="delete"/>
sw=";" nw="delete"/> </row>
<!--bottom row-->
<row height="0.95">
<key width="1.8" key0="ctrl" key2="loc meta" key4="switch_numeric"/>
<key width="1.2" key0="fn" key1="loc alt" key2="loc change_method" key3="switch_emoji" key4="config"/>
<key width="5.0" key0="space" key7="switch_forward" key8="0"/>
<key width="1.2" key5="left" key6="right" key7="up" key8="down"/>
<key width="1.8" key0="enter" key3="action"/>
</row> </row>
</keyboard> </keyboard>

View File

@@ -43,7 +43,7 @@
<row height="0.95"> <row height="0.95">
<key width="1.7" key0="ctrl" key1="loc switch_greekmath" key2="loc meta" key4="switch_numeric"/> <key width="1.7" key0="ctrl" key1="loc switch_greekmath" key2="loc meta" key4="switch_numeric"/>
<key width="1.1" key0="fn" key1="loc alt" key2="loc change_method" key3="switch_emoji" key4="config"/> <key width="1.1" key0="fn" key1="loc alt" key2="loc change_method" key3="switch_emoji" key4="config"/>
<key width="4.4" key0="space" key7="switch_forward" key8="switch_backward" key5="cursor_left" key6="cursor_right"/> <key width="4.4" key0="space" key7="switch_forward" key8="switch_backward" key5="cursor_left" key6="cursor_right" slider="true"/>
<key width="1.1" key0="loc compose" key7="up" key6="right" key5="left" key8="down" key1="loc home" key2="loc page_up" key3="loc end" key4="loc page_down"/> <key width="1.1" key0="loc compose" key7="up" key6="right" key5="left" key8="down" key1="loc home" key2="loc page_up" key3="loc end" key4="loc page_down"/>
<key key0="j" key4=";"/> <key key0="j" key4=";"/>
<key width="1.7" key0="enter" key1="loc voice_typing" key2="action"/> <key width="1.7" key0="enter" key1="loc voice_typing" key2="action"/>

View File

@@ -1,50 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<keyboard name="QWERTY (APL)" script="latin" embedded_number_row="true">
<row height="0.75">
<key c="1" nw="⌶" ne="¨" se="!"/>
<key c="2" nw="¯" ne="⍫" se="@" sw="`"/>
<key c="3" nw="&lt;" ne="⍒" se="#" sw="~"/>
<key c="4" nw="≤" ne="⍋" se="$"/>
<key c="5" nw="=" ne="⌽" se="%"/>
<key c="6" nw="≥" ne="⍉" sw="^"/>
<key c="7" nw=">" ne="⊖" sw="&amp;" se="|"/>
<key c="8" nw="≠" ne="⍟" se="∞" sw="*"/>
<key c="9" nw="" ne="⍱" sw="("/>
<key c="0" nw="∧" ne="⍲" sw=")"/>
</row>
<row>
<key c="q" ne="?" se="loc esc"/>
<key c="w" ne="⍵" sw="'" se="&quot;"/>
<key c="e" nw="∊" ne="⍷"/>
<key c="r" nw="" sw="←"/>
<key c="t" nw="⍨" se="→"/>
<key c="y" nw="↑" ne="⌹" se="÷" sw="-"/>
<key c="u" nw="↓" ne="⍮" se="×" sw="+"/>
<key c="i" nw="" ne="⍸" sw="[" se="{"/>
<key c="o" nw="○" ne="⍥" sw="]" se="}"/>
<key c="p" nw="⍣" sw="⍬"/>
</row>
<row>
<key c="a" ne="" se="loc tab"/>
<key c="s" nw="⌈" ne="ᑈ" se="«"/>
<key c="d" nw="⌊" ne="ᐵ" se="»"/>
<key c="f" s="…"/>
<key c="g" nw="∇" s="_"/>
<key c="h" nw="∆"/>
<key c="j" nw="∘" ne="⍤" w="⊣" e="⊢"/>
<key c="k" ne="⌸"/>
<key c="l" nw="⎕" ne="⌷" se="⍪"/>
<key c=";" n="⋄" s=","/>
</row>
<row>
<key c="shift" e="loc capslock"/>
<key c="z" nw="⊂" se="⍝"/>
<key c="x" nw="⊃"/>
<key c="c" nw="∩" ne="⍛" sw="." se=":"/>
<key c="v" nw="" ne="√"/>
<key c="b" nw="⊥" ne="⍎" sw="⌿" se="⍀"/>
<key c="n" nw="" ne="⍕" sw="/" se="\\"/>
<key c="m" nw="≡" ne="≢" sw="∥" se="⍠"/>
<key width="2" c="backspace" e="delete"/>
</row>
</keyboard>

View File

@@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<keyboard name="QWERTY (Azərbaycanca)" script="latin">
<modmap>
<shift a="i" b="İ" />
<shift a="ı" b="I" />
</modmap>
<row>
<key key0="q" key2="1" key4="loc esc"/>
<key key0="ü" key1="~" key2="2" key3="\@" key4="w"/>
<key key0="e" key1="!" key2="3" key3="\#" key4="loc €"/>
<key key0="r" key2="4" key3="$"/>
<key key0="t" key2="5" key3="%"/>
<key key0="y" key2="6" key3="^"/>
<key key0="u" key2="7" key3="&amp;"/>
<key key0="i" key2="8" key3="*"/>
<key key0="o" key2="9" key3="("/>
<key key0="p" key2="0" key3=")"/>
<key key0="ö"/>
</row>
<row>
<key key0="a" key1="loc tab" key2="`"/>
<key key0="s" key2="loc §" key3="loc ß"/>
<key key0="d"/>
<key key0="f"/>
<key key0="g" key2="-" key3="_" key4="ğ"/>
<key key0="h" key2="=" key3="+"/>
<key key0="j" key4="}" key3="{"/>
<key key0="k" key3="[" key4="]"/>
<key key0="l" key2="|" key3="\\"/>
<key key0="ı"/>
<key key0="ə"/>
</row>
<row>
<key width="1.5" key0="shift" key2="loc capslock"/>
<key key0="z"/>
<key key0="x" key2="loc †"/>
<key key0="c" key2="&lt;" key3="." key4="ç"/>
<key key0="v" key2="&gt;" key3="," />
<key key0="b" key2="\?" key3="/"/>
<key key0="n" key2=":" key3=";"/>
<key key0="m" key2="&quot;" key3="'" key4="₼"/>
<key key0="ş"/>
<key width="1.5" key0="backspace" key2="delete"/>
</row>
</keyboard>

View File

@@ -1,50 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<keyboard name="QWERTY (BQN)" script="latin" embedded_number_row="true">
<row height="0.75">
<key c="1" nw="˘" ne="⎉" se="!"/>
<key c="2" nw="¨" ne="⚇" se="@" sw="`"/>
<key c="3" nw="⁼" ne="⍟" se="#" sw="~"/>
<key c="4" nw="⌜" ne="◶" se="$"/>
<key c="5" nw="´" ne="⊘" se="%"/>
<key c="6" nw="˝" ne="⎊" sw="^"/>
<key c="7" sw="&amp;" se="|"/>
<key c="8" nw="∞" sw="*" se="\\"/>
<key c="9" nw="⟨" ne="¯" sw="("/>
<key c="0" nw="⟩" ne="•" sw=")"/>
</row>
<row>
<key c="q" nw="⌽" ne="˜" se="loc esc"/>
<key c="w" nw="𝕨" sw="'" se="&quot;"/>
<key c="e" nw="∊" ne="⍷"/>
<key c="r" nw="↑" ne="𝕣" sw="←" se="⇐"/>
<key c="t" nw="∧" ne="⍋" sw="↩&#xFE0E;:↩" se="→"/>
<key c="y" nw="¬" ne="√" se="÷" sw="-"/>
<key c="u" nw="⊔" ne="⋆" se="×" sw="+"/>
<key c="i" nw="⊏" ne="⊑" sw="[" se="{"/>
<key c="o" nw="⊐" ne="⊒" sw="]" se="}"/>
<key c="p" nw="π" ne=""/>
</row>
<row>
<key c="a" ne="⍉" se="loc tab"/>
<key c="s" nw="𝕤"/>
<key c="d" nw="↕&#xFE0E;:↕" se="∾"/>
<key c="f" nw="𝕗" se="≍"/>
<key c="g" nw="𝕘" s="_"/>
<key c="h" nw="⊸" ne="«"/>
<key c="j" nw="∘" w="⊣" e="⊢"/>
<key c="k" nw="○" ne="⌾"/>
<key c="l" nw="⟜" ne="»"/>
<key c=";" w="·" n="⋄" s=","/>
</row>
<row>
<key c="shift" e="loc capslock"/>
<key c="z" nw="⥊" ne="⋈"/>
<key c="x" nw="𝕩"/>
<key c="c" nw="↓" ne="˙" sw="." se=":"/>
<key c="v" nw="" ne="⍒" s="‿"/>
<key c="b" s="⌊" n="⌈"/>
<key c="n" nw="≤" ne="≥" n="≠" sw="&lt;" se="&gt;" s="="/>
<key c="m" nw="≡" ne="≢" sw="/" se="?"/>
<key width="2" c="backspace" e="delete"/>
</row>
</keyboard>

View File

@@ -27,11 +27,11 @@
<key width="1.5" key0="shift" key2="loc capslock"/> <key width="1.5" key0="shift" key2="loc capslock"/>
<key key0="z" key2="|" key3="\\"/> <key key0="z" key2="|" key3="\\"/>
<key key0="x" key2="loc †"/> <key key0="x" key2="loc †"/>
<key key0="c" key1="loc accent_cedille" key2="&lt;"/> <key key0="c" key1="loc accent_cedille" key2="&lt;" key3="."/>
<key key0="v" key2="&gt;" key3="loc accent_tilde"/> <key key0="v" key2="&gt;" key3=","/>
<key key0="b" key2="\?" key3="/"/> <key key0="b" key2="\?" key3="/"/>
<key key0="n" key2=":" key3="," key4=";"/> <key key0="n" key1="loc accent_tilde" key2=":" key3=";"/>
<key key0="m" key3="."/> <key key0="m"/>
<key width="1.5" key0="backspace" key2="delete"/> <key width="1.5" key0="backspace" key2="delete"/>
</row> </row>
</keyboard> </keyboard>

View File

@@ -1,40 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<keyboard name="QWERTY (Lietuviškai)" script="latin">
<row>
<key key0="q" key2="1" key4="loc esc"/>
<key key0="w" key1="~" key2="2" key3="\@"/>
<key key0="e" key1="!" key2="3" key3="\#" key4="ę"/>
<key key0="r" key2="4" key3="$"/>
<key key0="t" key2="5" key3="%"/>
<key key0="y" key2="6" key3="^"/>
<key key0="u" key2="7" key3="&amp;" key4="ū"/>
<key key0="i" key2="8" key3="*" key4="į"/>
<key key0="o" key2="9" key3="("/>
<key key0="p" key2="0" key3=")"/>
</row>
<row>
<key key0="a" key1="loc tab" key2="`" key4="ą"/>
<key key0="s" key2="loc §" key3="loc ß" key4="š"/>
<key key0="d"/>
<key key0="f"/>
<key key0="g" key2="-" key3="_"/>
<key key0="h" key2="=" key3="+"/>
<key key0="j" key4="}" key3="{"/>
<key key0="k" key3="[" key4="]"/>
<key key0="l" key2="|" key3="\\"/>
<key key0="ė" key4="€"/>
</row>
<row>
<key key0="shift" key2="loc capslock"/>
<key key0="z" key4="ž"/>
<key key0="x" key2="loc †"/>
<key key0="c" key2="&lt;" key3="." key4="č"/>
<key key0="v" key2="&gt;" key3=","/>
<key key0="b" key2="\?" key3="/"/>
<key key0="n" key2=":" key3=";"/>
<key key0="m" key2="&quot;" key3="'"/>
<key key0="ų"/>
<key key0="backspace" key2="delete"/>
</row>
</keyboard>

View File

@@ -1,42 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<keyboard name="QWERTY (Malti)" script="latin">
<row>
<key c="q" ne="1" se="loc esc"/>
<key c="w" nw="~" ne="2" sw="\@"/>
<key c="e" nw="!" ne="3" sw="\#" se="è"/>
<key c="r" ne="4" sw="$"/>
<key c="t" ne="5" sw="%"/>
<key c="y" ne="6" sw="^"/>
<key c="u" ne="7" sw="&amp;" se="ù"/>
<key c="i" ne="8" sw="*" se="ì"/>
<key c="o" ne="9" sw="(" se="ò"/>
<key c="p" ne="0" sw=")"/>
<key c="ġ"/>
</row>
<row>
<key c="a" nw="loc tab" ne="`" se="à"/>
<key c="s" ne="loc §" sw="loc ß"/>
<key c="d"/>
<key c="f" sw="€"/>
<key c="g" ne="-" sw="_"/>
<key c="h" ne="=" sw="+"/>
<key c="j" se="}" sw="{"/>
<key c="k" sw="[" se="]"/>
<key c="l" ne="|" sw="\\"/>
<key c="ħ"/>
<key c="ż"/>
</row>
<row>
<key width="1.5" c="shift" ne="loc capslock"/>
<key c="z"/>
<key c="x" ne="loc †"/>
<key c="c" ne="&lt;" sw="."/>
<key c="v" ne="&gt;" sw=","/>
<key c="b" ne="\?" sw="/"/>
<key c="n" ne=":" sw=";"/>
<key c="m" ne="&quot;" sw="'"/>
<key c="ċ"/>
<key width="1.5" c="backspace" ne="delete"/>
</row>
</keyboard>

View File

@@ -1,40 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<keyboard name="QWERTY (Oʻzbekcha)" script="latin">
<row>
<key key0="q" key2="1" key4="loc esc"/>
<key key0="w" key1="~" key2="2" key3="\@"/>
<key key0="e" key1="!" key2="3" key3="\#" key4="loc €"/>
<key key0="r" key2="4" key3="$"/>
<key key0="t" key2="5" key3="%"/>
<key key0="y" key2="6" key3="^"/>
<key key0="u" key2="7" key3="&amp;"/>
<key key0="i" key2="8" key3="*"/>
<key key0="o" key2="9" key3="("/>
<key key0="p" key2="0" key3=")"/>
</row>
<row>
<key key0="a" key1="loc tab" key2="`"/>
<key key0="s" key2="loc §" key3="loc ß"/>
<key key0="d"/>
<key key0="f"/>
<key key0="g" key2="-" key3="_"/>
<key key0="h" key2="=" key3="+"/>
<key key0="j" key4="}" key3="{"/>
<key key0="k" key3="[" key4="]"/>
<key key0="l" key2="|" key3="\\"/>
<key key0="ʻ"/>
</row>
<row>
<key key0="shift" key2="loc capslock"/>
<key key0="z"/>
<key key0="x" key2="loc †"/>
<key key0="c" key2="&lt;" key3="."/>
<key key0="v" key2="&gt;" key3=","/>
<key key0="b" key2="\?" key3="/"/>
<key key0="n" key2=":" key3=";"/>
<key key0="m" key2="&quot;" key3="'"/>
<key key0="ʼ"/>
<key key0="backspace" key2="delete"/>
</row>
</keyboard>

View File

@@ -10,7 +10,7 @@
<key key0="f" key2="7" key3="&amp;"/> <key key0="f" key2="7" key3="&amp;"/>
<key key0="u" key2="8" key3="*"/> <key key0="u" key2="8" key3="*"/>
<key key0="p" key2="9" key3="(" key4=")"/> <key key0="p" key2="9" key3="(" key4=")"/>
<key key0=";" key2="0" key3=":"/> <key key0=";" key2="0" key3="|"/>
</row> </row>
<row> <row>
<key key0="a" key1="loc tab" key2="`" shift="0"/> <key key0="a" key1="loc tab" key2="`" shift="0"/>
@@ -22,16 +22,16 @@
<key key0="n" key2="=" key3="+"/> <key key0="n" key2="=" key3="+"/>
<key key0="e" key4="}" key3="{"/> <key key0="e" key4="}" key3="{"/>
<key key0="o" key3="[" key4="]"/> <key key0="o" key3="[" key4="]"/>
<key key0="i" key2="|" key3="\\"/> <key key0="i" key3="\\"/>
</row> </row>
<row> <row>
<key width="1.5" key0="shift" key2="loc capslock"/> <key width="1.5" key0="shift" key2="loc capslock"/>
<key key0="z"/> <key key0="z"/>
<key key0="x" key2="loc †"/> <key key0="x" key2="loc †"/>
<key key0="m"/> <key key0="m" key2="&lt;" key3="."/>
<key key0="c" key2="&lt;" key3="."/> <key key0="c" key2="&gt;" key3=","/>
<key key0="v" key2="&gt;" key3=","/> <key key0="v" key2="\?" key3="/"/>
<key key0="k" key2="\?" key3="/"/> <key key0="k" key2=":"/>
<key key0="l" key2="&quot;" key3="'"/> <key key0="l" key2="&quot;" key3="'"/>
<key width="1.5" key0="backspace" key2="delete"/> <key width="1.5" key0="backspace" key2="delete"/>
</row> </row>

View File

@@ -35,17 +35,4 @@
<key key0="அ" key2="&quot;" key3="ஆ" key4="'"/> <key key0="அ" key2="&quot;" key3="ஆ" key4="'"/>
<key width="1.5" key0="backspace" key2="delete"/> <key width="1.5" key0="backspace" key2="delete"/>
</row> </row>
<modmap>
<shift a="௹" b="₨"/>
<shift a="ய" b="௰"/>
<shift a="ஒ" b="ௐ"/>
<shift a="ள" b="௱"/>
<shift a="ச" b="௲"/>
<shift a="வ" b="௳"/>
<ctrl a="ய" b="a"/>
<ctrl a="எ" b="v"/>
<ctrl a="உ" b="c"/>
<ctrl a="ஒ" b="x"/>
</modmap>
</keyboard> </keyboard>

View File

Before

Width:  |  Height:  |  Size: 699 B

After

Width:  |  Height:  |  Size: 699 B

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Inspired from https://commons.wikimedia.org/w/index.php?curid=20206736 -->
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" version="1.1" viewBox="0 0 200 200">
<g fill="none">
<line x1="100" y1="45" x2="100" y2="155" stroke="#000" stroke-width="10"/>
<circle cx="100" cy="100" r="55" stroke="#000" stroke-width="10"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 403 B

View File

@@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
width="251.2084"
height="346.34631"
viewBox="0 0 251.2084 346.34631"
id="svg50"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs50" />
<path
d="m 111.45948,263.67139 -0.65968,70.83632 26.479,0.0651 0.65968,-70.83632 z"
id="path53"
style="stroke-width:1.25499" />
<path
d="m 111.87085,177.09327 -0.65625,70.83632 26.47901,0.0651 0.65625,-70.83632 z"
style="stroke-width:1.25499"
id="path52" />
<path
d="m 112.28491,90.517092 -0.65625,70.836328 26.47901,0.0651 0.65625,-70.836323 z"
id="path51"
style="stroke-width:1.25499" />
<path
d="m 112.69897,3.9389651 -0.65625,70.8363279 26.47901,0.06504 0.65625,-70.8363283 z"
id="path50"
style="stroke-width:1.25499" />
<path
id="path18"
style="fill:#000000;fill-opacity:1;stroke-linejoin:miter"
d="m 65.820312,83.498047 c -4.593515,0.215306 -6.152677,5.268685 -8.898203,8.213199 C 38.278151,116.62976 19.634192,141.54828 0.99023438,166.4668 c -2.83750458,4.46126 1.03756942,8.71774 3.73179282,12.07004 19.1846708,24.78419 38.2012768,49.71196 57.4908638,74.40652 3.198651,3.27254 9.151508,0.0604 8.39063,-4.39354 -0.03125,-53.23977 0.06249,-106.48588 -0.04687,-159.721695 0.24461,-2.714275 -2.014228,-5.25621 -4.736339,-5.330078 z" />
<path
id="path19"
style="fill:#000000;fill-opacity:1;stroke-linejoin:miter"
d="m 185.38672,83.498047 c -5.14905,0.277288 -4.93792,6.038398 -4.78323,9.856942 0.0195,52.075841 -0.0391,104.155561 0.0293,156.228991 0.0165,4.63683 6.78367,6.42764 9.15539,2.46706 20.15696,-26.20997 40.46312,-52.31451 60.52686,-78.59034 2.188,-3.88246 -0.2104,-7.62612 -2.75553,-10.54349 -19.30825,-25.80639 -38.61649,-51.61277 -57.92474,-77.419163 -0.96774,-1.321423 -2.61948,-2.087177 -4.24805,-2 z" />
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
width="258.20947"
height="330.63379"
viewBox="0 0 258.20947 330.63379"
id="svg50"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs50" />
<path
d="m 114.99631,259.7326 -0.65625,70.8362 26.47901,0.065 0.65625,-70.8364 z"
style="stroke-width:1.25499"
id="path53" />
<path
d="m 115.4111,173.1544 -0.65966,70.8363 26.47901,0.065 0.65966,-70.8363 z"
style="stroke-width:1.25499"
id="path52" />
<path
d="m 115.82516,86.57631 -0.65966,70.83629 26.47901,0.065 0.65966,-70.83629 z"
style="stroke-width:1.25499"
id="path51" />
<path
d="m 116.23924,0 -0.65968,70.83631 26.479,0.063 0.65968,-70.8363 z"
style="stroke-width:1.25499"
id="path50" />
<path
id="path43"
style="fill:#000000;fill-opacity:1;stroke-linejoin:miter"
d="m 6.3793735,79.95371 c -4.91171,-0.117 -6.96523998,4.5372 -6.23632998,8.7416 0.0169,52.30119 -0.0339,104.60579 0.0254,156.90489 -0.004,4.8047 7.01418998,6.4658 9.32575998,2.3238 21.4081905,-26.4719 42.9958305,-52.8314 64.2914205,-79.3739 1.89802,-4.4107 -2.77165,-7.4685 -4.82563,-10.8076 -19.43572,-25.2809 -38.87144,-50.5619 -58.30716,-75.84279 -0.9851505,-1.3076 -2.6435405,-2.0564 -4.2734605,-1.946 z" />
<path
id="path44"
style="fill:#000000;fill-opacity:1;stroke-linejoin:miter"
d="m 251.90671,79.95371 c -4.60754,0.1655 -6.23591,5.2156 -9.03067,8.1332 -19.42905,25.37169 -39.0573,50.60479 -58.36179,76.06309 -2.00684,4.4938 2.93232,7.4651 5.07245,10.7946 20.08843,24.6814 40.02595,49.4983 60.20868,74.0951 3.21461,3.2216 9.10409,-0.01 8.34768,-4.4336 0,-53.0855 0,-106.1711 0,-159.25659 0.0923,-3.5089 -3.25795,-5.067 -6.23635,-5.3958 z" />
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Inspired from https://commons.wikimedia.org/w/index.php?curid=20206736 -->
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" version="1.1" viewBox="0 0 200 200">
<g fill="none">
<line x1="100" y1="45" x2="100" y2="155" stroke="#000" stroke-width="10"/>
<circle cx="100" cy="100" r="55" stroke="#000" stroke-width="10"/>
<line x1="45" y1="45" x2="155" y2="155" stroke="#000" stroke-width="10"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 481 B

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Based on materialdesignicons.com backspace-outline -->
<svg
version="1.1"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1" />
<path
id="text3"
style="font-weight:600;font-size:13.3333px;font-family:FreeSans;-inkscape-font-specification:'FreeSans Semi-Bold'"
d="m 17.517249,16.883978 c -0.599999,0 -1.199997,0 -1.799996,0 -0.542221,-2.528883 -1.084441,-5.057765 -1.626662,-7.5866476 -0.528888,2.5288826 -1.057775,5.0577646 -1.586663,7.5866476 -0.599998,0 -1.199997,0 -1.799995,0 -0.9155533,-3.239992 -1.8311066,-6.479984 -2.7466599,-9.7199755 0.706665,0 1.4133299,0 2.1199949,0 0.502221,2.4266605 1.004442,4.8533215 1.506663,7.2799815 0.502221,-2.426661 1.004441,-4.853321 1.506662,-7.2799815 0.657776,0 1.315553,0 1.973329,0 0.524443,2.4311048 1.048886,4.8622095 1.573329,7.2933145 0.484443,-2.431105 0.968887,-4.8622097 1.45333,-7.2933145 0.706665,0 1.413329,0 2.119994,0 C 19.3128,10.403994 18.415024,13.643986 17.517249,16.883978 Z M 22,3 c 1.232984,-0.040548 2.168377,1.1810823 2,2.36 -0.0069,4.6147431 0.01374,9.230179 -0.01033,13.844488 C 23.906211,20.390581 22.701093,21.155835 21.58,21 16.677486,20.9972 11.77479,21.0056 6.8723901,20.9958 5.6427252,20.925088 5.1783178,19.667046 4.5442984,18.812248 3.0295323,16.541498 1.5147661,14.270749 0,12 1.8548324,9.2326362 3.6795639,6.4439141 5.5533789,3.6900195 6.2693382,2.7489141 7.4877473,3.0506966 8.5000001,3 13,3 17.5,3 22,3 Z m 0,2 C 17,5 12,5 7,5 5.4266667,7.3333333 3.8533333,9.6666667 2.28,12 c 1.5733333,2.333333 3.1466667,4.666667 4.72,7 5,0 10,0 15,0 0,-4.666667 0,-9.3333333 0,-14 z" />
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Based on materialdesignicons.com backspace-reverse-outline -->
<svg
version="1.1"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1" />
<path
id="text3"
style="font-weight:600;font-size:13.3333px;font-family:FreeSans;-inkscape-font-specification:'FreeSans Semi-Bold'"
d="m 13.559976,16.719975 c -0.599999,0 -1.199997,0 -1.799996,0 -0.542221,-2.528883 -1.084441,-5.057765 -1.626662,-7.586648 -0.5288876,2.528883 -1.0577752,5.057765 -1.5866628,7.586648 -0.5999985,0 -1.1999969,0 -1.7999954,0 -0.9155532,-3.239992 -1.8311065,-6.479984 -2.7466597,-9.7199759 0.7066649,0 1.4133297,0 2.1199946,0 0.502221,2.4266606 1.0044419,4.8533209 1.5066629,7.2799819 0.5022209,-2.426661 1.0044419,-4.8533213 1.5066628,-7.2799819 0.6577762,0 1.3155526,0 1.9733286,0 0.524443,2.431105 1.048886,4.8622099 1.573329,7.2933149 0.484443,-2.431105 0.968887,-4.8622099 1.45333,-7.2933149 0.706665,0 1.413329,0 2.119994,0 -0.897775,3.2399919 -1.795551,6.4799839 -2.693326,9.7199759 z M 2,3 C 0.76701608,2.9594518 -0.16837714,4.1810822 0,5.36 0.00686259,9.9747431 -0.01373935,14.590179 0.01032577,19.204488 0.09378911,20.390581 1.2989069,21.155835 2.42,21 c 4.902514,-0.0028 9.80521,0.0056 14.70761,-0.0042 1.229665,-0.07074 1.694072,-1.328782 2.328092,-2.18358 C 20.970468,16.541498 22.485234,14.270749 24,12 22.145168,9.2326362 20.320436,6.4439141 18.446621,3.6900195 17.730662,2.7489141 16.512253,3.0506966 15.5,3 11,3 6.5,3 2,3 Z m 0,2 c 5,0 10,0 15,0 1.573333,2.3333333 3.146667,4.6666667 4.72,7 C 20.146667,14.333333 18.573333,16.666667 17,19 12,19 7,19 2,19 2,14.333333 2,9.6666667 2,5 Z" />
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 878 B

After

Width:  |  Height:  |  Size: 878 B

View File

Before

Width:  |  Height:  |  Size: 888 B

After

Width:  |  Height:  |  Size: 888 B

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 342 B

After

Width:  |  Height:  |  Size: 342 B

View File

Before

Width:  |  Height:  |  Size: 344 B

After

Width:  |  Height:  |  Size: 344 B

View File

Before

Width:  |  Height:  |  Size: 342 B

After

Width:  |  Height:  |  Size: 342 B

View File

Before

Width:  |  Height:  |  Size: 343 B

After

Width:  |  Height:  |  Size: 343 B

View File

Before

Width:  |  Height:  |  Size: 364 B

After

Width:  |  Height:  |  Size: 364 B

View File

Before

Width:  |  Height:  |  Size: 654 B

After

Width:  |  Height:  |  Size: 654 B

View File

Before

Width:  |  Height:  |  Size: 450 B

After

Width:  |  Height:  |  Size: 450 B

View File

Before

Width:  |  Height:  |  Size: 453 B

After

Width:  |  Height:  |  Size: 453 B

View File

Before

Width:  |  Height:  |  Size: 274 B

After

Width:  |  Height:  |  Size: 274 B

View File

Before

Width:  |  Height:  |  Size: 391 B

After

Width:  |  Height:  |  Size: 391 B

View File

Before

Width:  |  Height:  |  Size: 520 B

After

Width:  |  Height:  |  Size: 520 B

View File

Before

Width:  |  Height:  |  Size: 564 B

After

Width:  |  Height:  |  Size: 564 B

View File

Before

Width:  |  Height:  |  Size: 554 B

After

Width:  |  Height:  |  Size: 554 B

View File

Before

Width:  |  Height:  |  Size: 292 B

After

Width:  |  Height:  |  Size: 292 B

View File

Before

Width:  |  Height:  |  Size: 433 B

After

Width:  |  Height:  |  Size: 433 B

View File

Before

Width:  |  Height:  |  Size: 473 B

After

Width:  |  Height:  |  Size: 473 B

View File

Before

Width:  |  Height:  |  Size: 785 B

After

Width:  |  Height:  |  Size: 785 B

8
srcs/special_font/16.svg Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- By Vectorization: Mrmw - Own work using: iso.org/obp/graphics/grs/8f631f6d-89af-4962-bd14-a94dd3c1a2bf 200.png, Public Domain, https://commons.wikimedia.org/w/index.php?curid=20206736 -->
<svg width="200" height="200" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
<g fill="none">
<rect x="22.5" y="33.5" width="103" height="132" stroke="#000" stroke-width="5"/>
<circle cx="125.5" cy="99.5" r="66" stroke="#000" stroke-width="5"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 519 B

View File

Before

Width:  |  Height:  |  Size: 483 B

After

Width:  |  Height:  |  Size: 483 B

Some files were not shown because too many files have changed in this diff Show More