* Selection mode: Space to cancel the selection
This adds the "selection mode", which is activated when text is selected
in the text box. The selection mode is exited when the selection is
cleared.
While the selection mode is activated, the Space and Esc keys are
modified into the "selection cancel" key, which remove the selection
without changing the text.
The space bar is otherwise easy to type by accident during a selection
and causes the selected text to be deleted.
* Selection mode: Move each ends of selection separately with slider
When the selection mode is activated, the space bar sliders change how
they affect the selection:
- The left side of the slider moves the left position of the selection.
To shrink the selection from the left side, the slider must be
activated by sliding to the left, extending the selection
temporarilly, then by sliding to the right.
- The right side of the slider affects the right position if the
selection.
* Construct a single handler
* Add a delay after a Keyevent key in a macro
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.
* Add introductory text to the tables
And mention characters that don't have escapes
* Turn tables around
Tables should be structured by what the user wants, not by what the code does.
* Address Julow review #1
- Merge tables, no matter which rule requires escaping; "in the usual way for XML" applies to both
- 3 escapes not mandatory removed from table to new ¶ below
- Found one more symbol → legend
* doc: Clarify escaping of comma and colon per #915
These keys are the equivalent of ctrl+backspace and ctrl+delete,
respectively.
They can be reached with Gesture+backspace and Gesture+delete
respectively.
Many kind of KeyValues don't need to be wrapped into a Macro to show a
specific symbol. This is especially useful as Macro keys are not
affected by modifiers.
The parser is changed to have a fast-path when a key value is not a
macro.
* Massage Intro
Start with definition, then use cases, then valid syntax.
Use "legend" rather than "symbol" for the visible legend on the keyboard
Rephrase to avoid "exhaustive". Other simplifications.
* Edit section "Modifiers"
Separate into two tables, each preceded by relevant introduction
* Shuffle sections
Retitle "Special keys"; as used in the Intro, this term refers to all the keywords in this file.
Put two contrasting sections together, add "In contrast," and reword.
Add "macro" keys that behave as if a sequence of keys is typed.
Macro can be added to custom layouts or through the "Add keys to the
keyboard option". The syntax is:
symbol:key1,key2,..
The symbol cannot contain a : character. 'key1', 'key2', etc.. are:
- 'String with \' escaping'
The key will generate the specified string.
- keyevent:123
The key will send a keyevent.
- The name of any special key
* layouts/latn_bone.xml: use new syntax and add most missing keys
new syntax: n/s/e/w/ne/nw/se/sw instead of key{1..8}
Some keys were missing keys according to the tests, this adds them in a
similar way to latn_neo2.
Only `switch_forward` didn't fit (because of the 0
at the bottom of the spacebar).
* layouts/latn_bone.xml: even better bone
- use number row to unclutter rest of keyboard
- use modmap for special shift functions of bone layout
- add missing loc characters
- use standard bottom bar
- add diacritics from the 3 dead key keys on bone
- 2 small keys left and right of the number row (don't fit all 6
diacritics, so they leak onto the number keys)
- row 1 is full too, so the dead keys from the left of that row leak
onto the keys there as well
open questions:
- should bone rely on the math layer or use modmap?
- possibility to combine diacritics?
This moves some computations that used to be done during onDraw into the
new Theme.Computed class. This also removes Paint objects from the Theme
class, making it data-only.
This is a requirement for making some keys render differently.
Change the format of check_layout.output to avoid adding any logs for
layouts that do not trigger any warning.
Fix the check_layout CI, which was broken since check_layout.py was
changed to take arguments.
Set the flag FLAG_SOFT_KEYBOARD when sending key events stops Discord
from sending message when typing Enter.
The other values are the same that are sent when using sendDownUpKeyEvents().
Implement up and down cursor movement slider. This is not added to any
layout yet due to the undesirable behavior when moving the focus out of
the text box being edited.
Setting 'slider="true"' on a key is no longer enough to make a slider,
the key must also be of kind 'Slider'.
Only the KeyValue that started sliding is now considered, they can be
generated with negative values. This allows keys that don't have the
complementary cursor movement key on the opposite direction.
This will help implement other kind of sliders as well as up/down
sliders.
and use 'toString()' instead of 'getSymbol()'.
This removes unecessary casts when computing symbols and comparing key
values. This will make adding other kind of keys easier.
Moving the cursor by 1 position is hard because the finger has to travel
far enough to activate the slider but then becomes very sensitive.
With this change, swiping on the space bar slider will immediately move
the cursor by 1 position but the slider will activate only if the finger
travel an other swiping distance.
This doesn't fix a bug but remove some tricky code. The shift key is no
longer different when the "double tap for capslock" option is on.
The handling of the option is moved to Pointer instead and becomes
simpler.
* Update kann_kannada.xml
Added zwnj & zwj
1. zwnj used for writing non Kannada words or names like Leo Tolstoy as ಲಿಯೊ ಟಾಲ್ಸ್ಟಾಯ್ (also can be written as ಲಿಯೊ ಟಾಲ್ಸ್ಟಾಯ್)
2. zwj used for writing ಅರ್ಕ as ಅರ್ಕ
Removed unecessary symbols not present in Kannada language:
1. ∪ is a set symbol, a similar symbol is used in Carnatic music, unfortunately not present in Unicode
2. ॰ used only in Devanagari
3. • bullet, not a character or alphabet in Kannada (Can't remember why I added it, maybe because I use it personally in non markdown texts)
* Update kann_kannada.xml
Cleaning up more
1. Removed ※, not found in other kannada keyboards
2. Moved `:` & `;` on the key so that its easier to swipe
The code expect that the payload is never null but there are now a lot
of public constructor functions for KeyValue that don't check for this
property.
On API 30 to 34, the status bar changes color when the keyboard appears
and disappears. A ghost of the changed status bar is animated by the
same animation used for the keyboard, which is unexpected.
Layout modifying functions are removed from Config to LayoutModifier as
static classes.
The two classes are (weakly) mutually dependent, the refactoring is
purely for the purpose of making shorter classes.
The only change is that 'modify_numpad' is changed to remove duplicated
code. This has the side effect of making the "double tap for caps lock"
option affect the shift key in the numpad.
The keyboard background now extends under the system bars and display
cutout on Android 15 but the keys do not.
The back and IME switching buttons that appear in the navigation bar require
special care to not overlap with the keyboard.
The launcher and settings activity are also fixed.
Appending the ':' character to a sequence result forces it to be a
string final state. This will cause a KeyValue lookup that would
normally not happen for single-character results.
This is useful to make Tamil letters smaller, even when they are the
result of a Shift.
Sequences longer than two characters were not read correctly from json
files, creating conflicts and causing dropped sequences.
The detection of collision in sequences is also improved. Two colliding
sequences are removed.
The attribute 'c' specifies the symbol in the center of a key, just like
'key0'. This adds consistency with the cardinal direction attributes and
is intended to make layouts more readable.
Replace the short video with an animated vector image that shows the
swipe gesture.
This is much lighter and reliable than the mp4 video, which failed to
play on many devices.
Source for the image of the key is in inkscape SVG format in srcs/res
and is converted to an android drawable when needed. The swipe animation
is hand-written.
Add the ':char' syntax for defining character keys with a different
symbol.
This new kind of keys is used to implement Ctrl combinations in the
Serbian Cyrillic layout without showing latin letters while the Ctrl
modifier is activated.
This allows to add new kinds of keys that need more data without making
KeyValue's footprint bigger for common keys.
This changes the [_symbol] field into [_payload], which holds the same
as the previous field for more common keys but can hold bigger objects
for keys of the new "Complex" kind.
This also adds a complex key: String keys with a symbol different than
the outputted string.
Unit tests are added as the Java language is not helpful in making
robust code.
* shell.nix: fix gradle error
error was:
> \> Task :compileDebugJavaWithJavac FAILED
> error: Source option 7 is no longer supported. Use 8 or later.
> error: Target option 7 is no longer supported. Use 8 or later.
fixed by overriding the jdk version for gradle to openjdk17
* layouts/latn_bone: fix layout
- fix alignment with tabs mess
- make like actual bone layout, instead of trying to fit it into a 10 key
wide keyboard
- fixes missing üäö
- fix missing $
- moves q and ß where they belong
- remove all of the diacritic keys (they can be added through the
settings as extra keys)
- kept the number row extra keys integration into top row
- kept the idea of compressing , and . into the swipe actions of the
bottom row
- kept the number keys as key4 in the layer4 positions (instead of
moving them to a number row, which i also considered)
Put new example in Examples section; put all overview material at start; use "modmap" for the modmap tag but "mapping" for the various subtags; set out each subtag separately; stop illustrating example mappings as complete modmap.
Include comprehensive ctrl modmap, enabling the use of ctrl modifier with Serbian Cyrillic keys. Remove clunky fn modmap previously used for just a few actions such as cut/copy/paste/etc.
The 'ctrl' modmap is different from the other modmaps as it also applies
the built-in Ctrl modifier to the resulting character, even if it was
first modified by the custom modmap.
For example, this will map Ctrl+в to Ctrl+V (not to v):
<ctrl a="в" b="v"/>
This is intended to add keyboard shortcuts in non-latin layouts.
A caveat is that the latin character appears on the keyboard while Ctrl
is activated.
Adds Serbian Latin QWERTY layout. Serbian language uses both Latin and Cyrillic as its official scripts, and this variant should cover anyone from Serbo-Croatian speaking group that uses Latin script.
Adds Serbian Cyrillic layout. Modmap of Fn key allows for desktop-like easier access to actions such as selectAll, copy, paste, etc. This is because, unlike desktop systems, on mobile ctrl does not combine with cyrillic keys to perform actions.
Allow combining circumflex \u0302 for Cyrillic vowels, enabling users to express themselves accurately.
ја сам са̂м = I am alone
ја сам сам = I am am
да = yes
да̂ = give
код = at
ко̂д = code
Similar to #437 for aigo.
This allows adding more compose sequences without modifying
en_US_UTF_8_Compose.pre.
This is done by grouping sequences files that should be merged together
into a directory. This also allows moving keysymdef.h into that
directory.
* Fix persian's half-space invisibility
* Add a 0.5 space before ظ in persian
* Change the place of چ in persian
* Change the width of backspace in persian
* Rename zwnj to halfspace in KeyValue.java and beng_provat layout
This was hoped to fix a random layouts to be shown by default to users
of unsupported languages. This breaks language switching using the
system dialog.
The arabic layout was used as the default on devices where all the
installed languages are not supported by the keyboard. This is not
intended.
This is probably caused by 'getCurrentInputMethodSubtype' returning the
first layout in the list of disabled subtypes in alphabetical or
language tag order.
Re-ordering the subtypes in method.xml had no effect.
Setting 'overridesImplicitlyEnabledSubtype' in method.xml has no
measured effect.
* Post-edit on Metadata
① Tell reader exactly what to type to disable locale_extra_keys, as with prev. bullet
② Values should be quoted
③ Rephrase one passive
* locale_extra_keys obviates 2nd example under modmap
This adds the clipboard pane, which allows to save an arbitrary number of
clipboards and to paste them later. The key can be disabled in settings.
Checking the "Recently copied text" checkbox will cause the keyboard to keep a
temporary history of copied text. This history can only contain 3 elements
which expire after 5 minutes.
If this is unchecked, no history is collected.
History entries can be pinned into the persisted list of pins.
Internally "key repeat" is reword into "long press" when the same
mechanism was used for both features.
The constraint that 'timeoutWhat' must be set to '-1' when no message is
expected has been lifted to simplify the code.
The long press timeout is used for long press on keys that do not
repeat, for example the keyboard switching key.
This must be detached from the key repeat as it might be disableable in
the future and more keys might be longpressable.
This adds some errors:
- 'script' or 'numpad_script' is set an empty string.
- Multiple '<modmap>' elements.
- 'shift', 'width' and 'height' on every nodes that support them are
clamped to a valid value.
* Modmap: Where to put it; cancelling built-in mods (#665)
* Correct per Julow: not only Euro layouts
* Post-edit: Doesn't depend on "built-in" layout
* P-vs-L: Change "That is to say", sentence is not a restatement
* Discussion with Julow: Swipe graphic to HTML; at most one modmap
* Swipes: Center tables
This replaces the switch cases in KeyModifier.java with JSON files, one
for each diacritic.
The number of states increases from 6727 to 7377. The apk size slightly
decreases (around 3kb).
Encoding errors in the compose data compiler due to:
- 'UTF-16' adds a BOM, use 'UTF-16-LE' instead
- 'str.encode' returns a byte array, use 'array' to have a 16-bit char
array.
Parse key names from keysymdef.h, which is distributed with Xorg. The
Greek, Cyrillic and Hebrew sequences referenced these keysyms.
This increases the number of sequences from 2043 to 2668.
Change the compose state machine definition to allow final states that
are wider than 16-bits.
This increases the number of sequences that can be used from
en_US_UTF_8_Compose.pre from 2013 to 2043 (of 3201).
This adds the new 'anticircle' attribute to layouts '<key>' elements
that configure the key to send when doing a anti-clockwise circle
gesture on it.
Labels are drawn the same way as indication.
Updated docs.
This happen when opening the settings from the launcher activity without
ever opening the keyboard.
To remove this bug entirely, the KeyboardData.init method is removed,
the pieces needing initialization are now cached in Config.
This implements clockwise/anticlockwise circle and round trip gestures
inspired by Messagease.
The circle gestures start after a small threshold to avoid making the
regular swipe too hard to aim.
The gestures do:
- circle: The center symbol with Shift applied, with a fallback on Fn
- round trip: Same as the circle gesture but applied to a side symbol
- anticlockwise circle: Nothing currently. It is intended to be made
configurable per-layout in the future.
The new Gesture class keeps track of what the pointer is doing while it moves
on a key. It replaces the 'selected_direction' integer.
- Removing unused information (names and descriptions) from the Emoji class
- Creating a Gradle task that generates a more efficient res/raw/emojis.txt file from the most recent Unicode standard
- Saving recently used emoji preferences as emoji values rather than names
- Migrating old user preferences to the new system
* Hangul support
This works with two new kinds of keys (Hangul_initial and Hangul_medial)
that carry a precomposed hangul syllable and act as modifiers.
The hangul syllables are composed algorithmically.
* Add shift layer to Dubeolsik layout
* Make slider speed independent from swipe distance
Swipe distances other than the default resulted in a slider that were
not easy to control.
* refactor: Add class Pointers.Sliding
It holds the states and the code needed to make the slider work.
'Pointer.sliding' is set to [null] when sliding is not in progress.
The implementation is changed not to depend on [downX] and [dx] but
instead use the pointer's [x] coordinate directly.
* Move the cursor further for faster slides
In sliding mode, compute the speed of the pointer and use it to increase
at which the cursor moves.
* refactor: Separate kind for cursor movement keys
This allows to define a key that moves the cursor more than one position
at a time.
This will be used to avoid lag during fast slider movements.
* Reduce lag when sliding quickly on the spacebar
Avoid sending key events in a loop while sliding quickly in a cursor
movement key. Key of kind Cursor_move are "multiplied", meaning a single
key event represents a movement of more than one position, reducing the
number of key events sent.
This is only for cursor move keys.
Due to the modmap, the cache must be cleared when switching layout to or
from a layout that contain a modmap.
This is broken since 3f6b6fd23, which moves the modmap handling into
KeyModifier.
Thanks to the previous commit, a modifier key can now be more complex
than just a KeyValue.Modifier. This allows a more elegant implementation
of the compose key, that could be taken as a base for other features
(eg. unicode hex entry, hangul)
The COMPOSE_PENDING modifier is removed as keys of kind Compose_pending
can act as a modifier. This has the advantage of highlighting the key
that was last pressed in the sequence.
Rules are added to Pointers: Non-special but latchable keys must clear
latches and cannot be locked with a long press. These rules were not
needed before but were intended.
Allow keys of a kind other than Modifier to be a modifier.
This requires writing a compareTo function for KeyValue. Fields are
compared in this order: Kind, value, flags, symbol.
'FLAG_LOCKED' and 'FLAG_FAKE_PTR' are only used within Pointers.
Define new flags in Pointers and remove these from KeyValue. Also allows
to define new flags.
Metadata directories were renamed while adding store descriptions into
strings files for simplicity.
This interferes with releases so is released.
An hardcoded lookup table is used instead.
Shift locked via the "caps lock" key use the "fake pointer" mechanism
that is also used by auto-capitalisation.
Make sure that unlatching a fake pointer do not disabled a locked
modifier.
The implementation is moved into the Pointers class for a safer API and
easier implementation.
Add éèàç directly to the layout, which removes the corresponding dead
keys.
Remove the requirement for ù and ÿ from method.xml, which are extremely
rare and can be typed via the compose key.
* Relicense layouts under CC0
Layout definitions are licensed differently from the rest of the
application source code to allow use in other projects related or
unrelated to Unexpected Keyboard.
Some layouts are not re-licensed and their original copyright continues
to apply. The copyright notice is added at the top of the files.
* Contributing: Mention layout licensing
* CI: Run 'check_layout.py'
Ensures that 'check_layout.output' is not outdated.
Also, update it.
* CI: Check new store descriptions
When a store description is added, 'python3 sync_translations.py' leaves
an untracked file that is not checked.
This makes sure that untracked store descriptions are noticed in CI.
Themes do not dim secondary keys the same way due to the "offset"
mechanism. Instead, use a ratio that is the same for every themes.
It's still possible to override this ratio per theme.
The kind field wasn't large enough to hold the new Compose_pending kind.
The flags field is reduced in size by removing a free spot.
The FLAGS_BITS mask is defined in a safer way.
compile.py implements a parser for X11's Compose.pre files. A lot of
code is necessary to interpret character names but thanksfully, the name
of most characters is contained in the file.
The state machine is compiled into two char arrays which unfortunately
requires an expensive initialisation and allocation.
The COMPOSE_PENDING modifier indicate whether a compose sequence is in
progress. The new key of kind Compose_pending sets the current state of
the sequence.
The compose sequences are compiled into a state machine by a python
script into a compact encoding.
The state of the pending compose is determined by the index of a state.
The pin entry layout shouldn't be inverted as the letter indications
would be meaningless and the order would be opposite to what the option
specifies.
The enter and action key are swapped as the automatic swapping is also
removed.
Incompatible APIs were used in the custom layouts and the extra keys
options.
Add @TargetApi annotations to help catch similar issues in the future
with the help of 'gradle lint'.
Android 3.0 (API level 11) was released in Feb 2011.
These versions were already unsupported due to unavoidable calls to:
- MotionEvent.getActionMasked() (API 8)
And avoidable calls to:
- SharedPreferences.Editor.putStringSet() (API 11)
This makes translation easier as there's a single file to edit at.
Existing short and full descriptions are conserved.
sync_translations.py takes care of updating the metadata files.
The metadata directories are renamed to match the language codes used in `res/`.
Contributing guidelines are updated accordingly.
This allows to use modifiers in combination with other inputs like a
mouse click, for example under termux-x11.
The key down event and notification about modifiers changing are sent
down to KeyEventHandler. A mutable state remember for which modifier
down events have been sent.
When pressing down a modifier with one finger and typing with the
other, it might appear that the modifier is released after the first
time an other key is pressed and then pressed and released for the
following keys.
This prevents unintentionally type two modified keys instead of one
when the second key is pressed while the other is not yet released.
This separates the layout definitions from the special layouts
(bottom_row, greekmath) and other unrelated files (method, settings).
This is also a more intuitive location for layouts and make the resource
directory easier to navigate.
Under the hood, layouts are copied back into
build/generated-resources/xml.
To detect voice IMEs, Unexpected Keyboard calls InputMethodManager.getEnabledInputMethodList
Internally, this method eventually calls a method that returns a filtered list of packages that may not include the installed voice IME, and thus Unexpected Keyboard unexpectedly claims no voice input is installed because it can't see it.
The fix is to explicitly state in the manifest that we want to query for other IMEs, based on https://developer.android.com/training/package-visibility/declaring
This is not an issue with Google's voice input or other preinstalled voice inputs because they usually have android:forceQueryable=true, but this is an issue with third-party voice inputs such as FUTO Voice Input. Launching the voice input app after activating the keyboard also usually makes the package visible, so a consistent way to replicate this issue on modern Android is to reboot the device and try triggering voice input from the keyboard
Android's shouldOfferSwitchingToNextInputMethod() method might return
false when an other IME is installed, perhaps when the other IME doesn't
specify android:supportsSwitchingToNextInputMethod="true".
Tapping shift might call `Utils.capitalize_string` on some symbols
(notably custom keys), which crashes on empty string.
This also happens on builtin layouts with `key1="\"`.
This reverts commits ef03dfed5c and
ff01678ba6.
The "vibration duration" slider is bought back.
The "vibration enabled" option is replaced by "custom vibration", which switch between the system haptic feedback or the custom vibration.
The slider is greyed when "custom vibration" is unchecked and is
allowed to have a value of 0 to disable vibrations within the app.
The intermediate values "light", "medium" and "strong" are removed and
no migration of the setting is made.
Bring a popup for choosing the voice IME when the voice key is pressed
for the first time or the list of voice IMEs installed on the device
change.
A preference stores the last selected IME and the last seen list of
IMEs.
This reverts the Tusinian layout (1af4e45) and instead introduce a new
arabic PC layout with arabic numbers.
Layouts are renamed:
- arab_pc => arab_pc_hindu
- arab_pc_tn => arab_pc
This new attribute is now used instead of 'script' for modifying the
numpad according to the selected layout's script.
If not provided, it defaults to the value of 'script'.
Update OpenJDK to version 17, Android build tools to 33.0.1 and platform to 33.
These are required to build with Gradle.
Add Gradle to the environment, which must be wrapped to fix a
permissions issue. Setting `GRADLE_OPTS` has no effect as it seems not
to be passed down to the daemon.
Remember the selected layout in portrait and landscape mode
independently.
This allows to define a layout specific to landscape without having to
switch manually.
`method.xml` is now able to specify a preferred position for each extra
keys in term of an other key to which it should be placed nearby.
It's implemented for French as an example.
`KeyboardData.getKeys()` now returns a map of the keys present on the
layout to their position. Positions are the row, column and swipe
direction.
The computed map is cached in the KeyboardData object as it might be
accessed later by `findKeyWithValue`, which now do less work.
The initial capitalisation state given by the editor
(`info.initialCapsMode`) is always 0 in many editors.
For some text input types, update the state when typing starts,
disregarding the value given by `info.initialCapsMode`.
The numeric layout and the optional right hand side numpad are modified
to show the digits belonging to the script used in the current layout.
The numpads are still defined as it was before. The digits are changed
in `modify_numpad` if needed.
Implement the combinations that were previously not possible and were
commented out.
Also remove `apply_dead_char` and `apply_combining` and make all
dead-keys definitions uniform.
Change the API of `KeyModifier.Map_char` to allow returning a string
instead of a single 16 bits char.
This allows to return combining diacritics.
This also gets rid of `apply_map_or_dead_char`, maps can have their own
fallback.
The slider was repeatedly sending arrow keys, which change the focused
input when the end of a text box is hit.
A new key is added that implements cursor movements using the
`InputConnection` API.
The new keys are defined as `KeyValue.Editing`, which are no longer only
context menu actions.
The behavior when a selection has started is changed. The selection is
modified instead of cleared even when shift isn't pressed or the
selection would become empty.
Fallbacks to sending arrow keys for editors that do not support the API,
like Termux.
Settings defined with `get_dip_pref` had a wrong default value on first
launch.
The "right" default value was used after the shared preferences are
populated.
Adapted from qwertz DE to match qwertz fr_CH layout.
Added all missing characters with accents needed in French while leaving the most common Swiss German characters as it is on the Swiss layout PC keyboard.
Re-organized some special characters to be in a similar position than the PC layout.
* Add locale fr-CH
The new `layouts` preference replaces three previous preferences:
layout
second_layout
custom_layout
Add a preference migration function, which first migration is to
migrate layouts into the new preference.
The migration must also be called from the SettingsActivity as it might
use a different preference store due to the boot-aware preference copy.
This merges the "Layouts" option with the "Custom layout" option.
A custom layout becomes an item in the "Layouts" list among the other
layouts. It's possible to add several custom layouts.
Selecting the "Custom layout" item in the list opens a second dialog for
entering the layout description.
Layouts are serialized as JSON object and are decoded solely in the
LayoutsPreference class.
Allow items to be of any class instead of strings.
Item serialization and deserialization methods are in a separate class
because they are also used in a static context.
Several non-string keys can have a large label that shouldn't be elided,
for example ctrl, meta, send.
Also, change the cutoff to 3 characters as labels are easily colliding.
The dead-key is replaced by its alternative if there's only one
specified.
Extra keys from every subtypes must be merged together to be able to
make this check.
For each extra key, a list of alternative can be specified. An extra key
won't be added to the keyboard if all its alternatives are already
present on it.
This is useful to avoid having the dead key for an accent and the
accented letters at the same time.
The two layout selection options are replaced by a ListGroupPreference
that allow to enter an arbitrary amount of layouts.
The "switch_second" and "switch_second_back" keys are replaced by
"switch_forward" and "switch_backward", which allow to cycle through the
selected layouts in two directions.
Layouts are changed to place these two key on the space bar.
The backward key is not shown if there's only two layouts.
* Add section mark as an extra key in QWERTY-like layouts that don't have it already
* Add dagger (also double dagger) as an extra key in QWERTY-like layouts
This new class will help write more logs. The LogPrinter is no longer
created everytime the keyboard is opened.
An error log is added if failing to load the custom extra keys.
This is a new section in the extra keys option that allows to enter
arbitrary strings which are then added to the keyboard.
A new string is needed for the title of the section, Android's icons and
strings are used as much as possible to avoid adding more strings.
Keys are stored in the preferences as a JSON array of strings.
The current approach is hard to maintain, for example the last key
"autofill" was not displayed.
This implements a PreferenceGroup that contains the check boxes for
every extra keys without involving listing the preferences in
settings.xml.
A custom layout is used to remove the 'title' text view.
The list of extra keys is moved into the new class.
'ExtraKeyCheckBoxPreference' becomes a nested class.
These symbols have special meaning when in `res/xml` and are escaped in
standard layouts.
The backslash is not stripped when parsed from the custom layout option.
Treat these backslashed keys specifically to allow standard layouts to
be passed back to the custom layout option.
This function is no longer an hardcoded list of layout ids. It's
replaced by a linear scan of the previously generated array and a new
corresponding array of resource ids.
`gen_layouts.py` lists the layouts in `res/xml` and generate the
`pref_layout_values` and `pref_layout_entries` arrays into
`res/values/layouts.xml`.
These arrays are hard to maintain as the order has to match, which is
fragile.
This relies on every layouts having a `name` attribute.
Added Romanian characters to the keyboard layout and changed the positioning
corner for the secondary characters that were conflicting with the
newly-introduced romanian characters
Added Romanian translations
Allows to define a locale's script in 'method.xml' and use that to add
the extra keys for a locale to layouts of the same script only.
A locale of an undefined script will add its extra keys to every
layouts. A layout of an undefined script will have the extra keys of all
the enabled locales.
On API level < 12 or on some rare cases, `refreshSubtypeLayout` was not
called, making `_localeTextLayout` uninitialized.
This might also happen if `getExtraValueOf` returns an invalid layout name.
eg. `method.xml` contains an invalid layout name.
`KeyCharacterMap.getDeadChar` seems to not give the expected result on
Android 4.0. This might affect many more dead key combinations that are
not fixed by this commit.
The script `check_layout.py` checks some properties about layouts.
No check is an error.
The result of running this script on every layouts is stored in the file
`check_layout.output`, which is useful to track changes.
Add make rules to run this script as well as `sync_translations`.
The `KeyEventHandler` class is intended to handle every keys and to call
into the main class through a limited API.
However, this is not true for `Event` keys, which in practice had each a
corresponding API call.
The new key switches to any installed "voice" input method.
If several input methods matches, no effort is made to choose.
Might misbehave with some input methods other than Google's on API < 28.
It is placed on the middle of the arrows on the bottom bar. It is
enabled by default and can be removed in the "Extra keys" option.
The key is not removed from the keyboard if no voice input method
exists.
The newer haptic feedback API that is used instead of the vibrator
service since ef03dfe doesn't work for everyone.
The new vibration option allow to choose both the newer API ("system")
and the older API ("strong", "medium", "light").
Specify the behavior of shift for a layout. This is intended for locales
that use the same alphabet but have different capital letters (eg.
Bengali).
The modmap is defined like this:
<keyboard>
<modmap>
<shift a="a" b="A"/>
</modmap>
</keyboard>
This unconditionally removes all pointers (touches) pressing modifiers
which are not already locked, avoiding that the (currently) latched
modifier will be locked aventually.
This can be verfified while sliding the space bar to move the cursor
left or right.
Closes#319.
This activity points to the system settings page for enabling input
methods. This is purely a shortcut but is expected by many users.
It could be made more useful in the future or hidden whenever the
keyboard is enabled.
The previous algorithm did not cut the circle into 16 equal parts.
The division by 2pi yielded numbers smaller than 16, which no longer
made sense after the cast to int.
'Keyboard.Key' now contains an array of size 9, giving each keyvalue an
index. The algorithm for finding the nearest key during a swipe now
needs 16 segments, which are now calculated as an angle.
The algorithm does one more interation instead of 2 more, slightly
reducing the sensitivity of corner values. The 'getAtDirection' function
is moved into the Pointers class to clearly separate the two systems.
The 'edgekey' attribute is now obsolete but is kept for compatibility.
The flag is removed internally, key index are simply translated.
Similarly, the 'slider' attribute now act on keys at index 5 and 6
instead of 2 and 3.
The 'keysHeight' field needs to be updated. As this class is not
intended to be mutable, copy the list of rows and call the constructor.
Also remove an unecessary component of the keyboard height calculation.
A new option changes the "change_method" into the new
"change_method_prev". It switch to the previously used input method.
A long press on "change_method_prev" sends "change_method".
A new section is added in the settings and existing options are moved.
Refactor, follow up of 90b7944. Add a modification step to the "special"
layouts: numpad, greekmath, pin entry.
Remove the apply_key0 function, which is not expressive enough.
Add an enum instead of yet an other "switch_" function.
Send key events for the left or right arrow as the finger slides on the
space bar.
Can be used to select text by holding shift. Works under Termux.
Events are sent linearly as the finger travels. The distance between
each events is defined from the swiping distance divided by 4.
'slider="true"' can be set on a key that have 'edgekeys="true"'.
'key2' and 'key3' represent the right and left keys.
It allowed to modulate the repeat speed of some keys (arrow, backspace,
delete) by move the finger farther or closer to the key.
In practice, this wasn't pratical and doesn't seem popular. It is
removed in favor of a better mechanism for moving the cursor.
Stay on the secondary layout after a config refresh or onStartInputView.
The information is kept until the keyboard is restarted.
Additionally, move tweaking the secondary layout to the Config class now
that physical equality is not needed.
Values like 'characterSize' and 'horizontalMargin' can't be fed back into the default value because they are not of the same unit.
To avoid this happening again, change the way the default value is defined for every options.
The 'key_height' dimension was no longer used.
The most requested keys are undo and redo. Unfortunatly redo doesn't
work reliably.
The other context menu actions like share, assist and autofill are added
even thought they are rarely useful or implemented.
* Add option for keyboard opacity (transparency). Keyboard background, keys and pressed keys can be adjusted separately.
* Make the borders transparent as well
* Moved setAlphas outside drawKeyFrame to top of onDraw method
setInputView() was not called when the view was re-created through
refresh_config(). Also, the refresh_config() function was not able to
properly set the current layout.
Now keep the default layout (_localeTextLayout) and the current non-text
layout (if any, _currentSpecialLayout) separately to be able to refresh
them later.
setInputView() is called everytime the view is created instead of by
onStartInputView() specifically.
The setting activity now save the preferences to the protected storage
in onStop() instead of listening for onSharedPreferenceChanged.
The callback might not be called if the "default" shared preferences is
different from the shared preferences actually used. This is unexpected
but seems to happen half of the time on Android 12.
Since f1ce6ab, this callback is critical to update the keyboard.
Restarting the application can no longer solve these issues.
Some users reported that 25% of the screen height is too high on their
screen. This doesn't seem to be a good way to define the height but
until it is improved, allow smaller values.
Add an option for specifying an XML layout description as a string.
The option is a bit rough at the moment:
- No documentation, users have to be aware of the keyboard's code to use
this option.
- No error are shown, the layout will fallback to qwerty on error.
The new script makes sure that strings files don't contain obsolete
strings but also ease the job of contributors by adding missing
translations as comments.
A Github Action ensures that translations stay in sync over time.
This function has been introduced in API 19 and deprecated in API 28.
There was no version check for API 19 but instead of adding these,
simply remove the feature for API under 28.
Themes can define the color of each borders independently. Every borders
must have the same width for now. It's possible to set a different width
when the key is activated, thought this is only used to remove borders.
The 4 themes are updated to take advantage of borders.
Remove the code dealing with InputMethodConnection from 'Keyboard2' and
move it into 'KeyEventHandler', where more editing actions can now be
implemented.
Autocapitalisation is also moved, the IReceiver interface is simplified.
The dpi values "xdpi" and "ydpi" can have wildly different values on
different devices.
The new computation defines a baseline and only take into account the
dpi values as a ratio.
On a 480dpi screen (in both directions), this decrease the value by
about 18%. This new distance felt better during testing.
A new option allow to choose a secondary layout, the switching key is
placed on the top edge of the space bar.
The "Programming layout" option was basically doing that but it was
possible to choose from a few layouts only. It is improved and renamed.
The 'LayoutListPreference' allows setting the string for the first entry
but otherwise share the rest of the array.
Add nice icons from materialdesignicons.
Store preferences in device protected storage, which is available before
the device is unlocked.
The keyboard was crashing when trying to access the encrypted
preferences.
The emoji pane uses a separate preferences file, the old data is lost.
The SettingsActivity can't easily use the new preferences storage.
Instead, it continues to use the "default" preferences store, which is
copied back to the protected storage when needed.
The 'accent_slash' was missing in the extra keys setting.
Allow to type more latin letters "with oblique stroke" or "with stroke"
that visually have an oblique bar, that were not added to 'accent_bar'.
There seems to be no "DayNight" theme compatible with older version of
android outside of the androidx library.
Using 'Theme.DeviceDefault' which is a dark theme, even if it doesn't
sounds like. Detect if a light theme should be used at activity
creation.
Similar to 'qwertz' but is wider to show äöü on dedicated keys. Some
punctuations are rebalanced to use the space better.
The default layout for de_DE is changed.
The key enable caps lock immediately. It does nothing if caps lock is
already enabled.
It is not present on the keyboard by default but a place is defined on
every layout, top-right of the shift key. It can be enabled in the
settings.
The icon is from materialdesignicons.com.
* Rename resulting CI artifact
Add details to the name of the artifact, to distiguish downloads of it between multiple branches while testing
* Update CI to nodejs16 and improve artifact naming
This mode is annoying to some users and is disabled in most text views.
The keyboard has a fixed sized relative to the height of the screen in
landscape mode. The keyboard can't take more space than expected,
currently.
This might cause problems in the future and might be hidden behind an
option if one is found. Every text views so far seemed to behave fine.
In Turkish, upper case of 'iı' is 'İI' but Java's toUpperCase will
return 'II'.
To make 'İ' accessible, make it the shift of 'ı'. This has the
inconvenient of swapping i and ı on the keyboard.
* Added Czech translation and layout
Translated keyboard and created Czech multilingual "practical" layout for faster typing and typing in commonly used languages (German, Slovak + French w/accents)
* Update (Rephrase) full_description.txt
... to better suit the language and naturally promote keyboard's features and possibilities to a wider audience.
The Fn+switch_numeric shortcut might be hard to discover or too slow for
heavy users.
A location is allocated for the key so it has a consistent placement.
Allows to add more keys to the keyboard from a predefined list.
The implementation doesn't use MultiSelectListPreference because it
doesn't seem possible to change the item layout to properly show the
rendered symbols.
Change the capitalisation algorithm to use Android's
'getCursorCapsMode'. This requires a bit of cursor calculations but
should feel more standard.
The auto completion only triggers after a space is typed or backspace is
pressed.
Modifiers can be locked with a long press. The key repeat mechanism is re-used
and the press timeout is the same.
Every modifiers can be locked that way, not only the "lockable" ones.
The previous behavior can be enabled in the settings (for shift only)
but the default is changed.
Keep track of end-of-sentence characters while typing and automatically
enable shift when appropriate.
The last few characters just before the cursor need to be queried in
some cases: Begin of input, cursor has moved or text is deleted.
This might have a performance cost.
This normally only enable shift but it also needs to disable shift when
the cursor moves.
Bring back the "Vibration" option.
The duration option isn't added back because the vibration settings are
still handled by Android. In fact, the option has no effect if the
vibration are disabled in the system settings.
This partially reverts commit ef03dfed5c.
The "f11_placeholder" and "f12_placeholder" keys were equals since
31d6a70.
Add an incrementing id into the unused key value to differentiate
placeholder values.
The "loc " prefix for predefining a place for an "extra key" was broken
since 31d6a70.
The FLAG_LOCALIZED flag cannot be used anymore, as adding it to any key
would turn it into a different key that wouldn't be recognized by parts
of the code comparing the keys (placing the extra keys).
Add an other layer in KeyboardData to store such informations.
This makes KeyValue objects smaller. 'equals' and 'hashCode' are now
implemented too. Key names are still used to recognise keys with special
meaning, but not for comparing keys anymore.
Negative values for internal events are preventing further refactoring.
Add a new kind of key and split internal events (now Event) and
Android's key events (now Keyevent).
Use enums events and modifiers outside of the KeyValue class.
Internally, they are converted to and from integer.
These two fields couldn't have an interesting value at the same time.
As we can no longer rely on a special value to distinguish between
what's the kind, the kind of the key is explicitly encoded in the two
most significative bits of the _flags field.
Extra nice thing: This removes the special values 'EVENT_NONE' and 'CHAR_NONE'.
Two advantages:
- No need to distinguish modifiers in KeyEventHandler. The KeyValue is
enough to decide what action to do.
- Keys are never a Char and Event at the same time, fields can be
merged.
The meaning of the public fields of KeyValue was quite complicated and
not handled consistently accross the app.
Make these fields private and add a more abstract API on top.
The meaning of these fields changed recently and it wasn't an easy
change. I plan on making more changes in the future.
There was no free bits left to add new modifiers. Instead of increasing
the width of the 'flags' field, refactor the way modifiers are
represented and used.
Modifers are now represented as independent values and stored in the
'code' field. A flag is added to distinguish between modifiers and keys
with a key event.
The most notable change is that modifiers can no longer be or-ed into a
single value but have to be represented as an array.
The '0' has been moved because it was hard to type due to being close to
the edge of the screen.
This is fixed in a more elegant way in a27c644, there's no reason to
keep the '0' in an inconsistent place anymore.
Layouts no longer need to mention every localized keys and dead keys.
They are now placed automatically starting from the second row on the
bottom-right corner.
The "loc " prefix is not removed to still be able to define a more
optimal and consistent placement for some extra keys (eg. 'ß' near 's').
Programming layouts no longer need to place every dead keys.
Each layouts can chose which key are localized instead of specifying it
globally for each key.
Important keys are no longer removed from layouts if the 'extra_keys'
mechanism is not working properly. This can happen if language tags
specified in method.xml don't match the user's language.
Removed some currency symbols from some layouts. They are all in the Fn
layer.
The "closest key" logic must be careful not to reveal keys removed by a
modifier.
Must check [_handler.onPointerSwipe] for every candidate values.
[selected_value] is changed back to [selected_direction].
This adds a new bug: When the direction change, the selected value might
not change but a vibration will be triggered anyway.
getAtDirection was too hard to maintain and might contain bugs.
Change slightly the meaning of directions and implement a the nearest
key calculation as a loop.
Since SDK 21, applications can set the background color of the
navigation bar. This is normally simply an item in a theme but it is
more complicated for keyboards.
When typing fast, a second key might be pressed before the first is
released.
Clearing modifiers earlier would prevent this but would break modifiers
placed in corners (especially the accent keys). Instead, don't take
latched modifiers into account when registering the second press.
A new flag is needed to not interfere with holding modifers, which is
merged with the norepeat flag.
The required version of fontforge (from 2020!) is not available in many
distros. This is an annoying for contributors and greatly complicated
the CI and F-Droid scripts.
The generated font file is now included in the sources. Fontforge is
still needed when adding new glyphs but this is not a common operation.
Requires two new diacritics: ogonek and dot_above.
The new accents are also added to the Latvian layout as the two language
can be close but not to the other localized layouts. A new mechanism is
needed to reproducibly add extra keys to layouts without manual
placement.
A file will be generated inside the local `_build/` folder, called `debug.keystore.asc`
You can copy the content of this file, and with that, paste it into a new github secret in your repo settings.
The secret must be named `DEBUG_KEYSTORE`
If the build succeeds, the debug apk is located in `build/outputs/apk/debug/app-debug.apk`.
## Debugging on your phone
First [Enable adb debugging on your device](https://developer.android.com/studio/command-line/adb#Enabling).
Then connect your phone to your computer using an USB cable or wireless
Then connect your phone to your computer using an USB cable or via wireless
debugging.
If you use Android Studio, this process will be automatic and you don't have to
follow this guide anymore.
And finally, install the application with:
```sh
make installd
./gradlew installDebug
```
The debug version of the application won't be removed, both versions will stay
installed at the same time.
The application must be enabled in the settings:
System > Languages & input > On-screen keyboard > Manage on-screen keyboards.
The released version of the application won't be removed, both versions will
be installed at the same time.
## Debugging the application: INSTALL_FAILED_UPDATE_INCOMPATIBLE
`make installd` can fail with the following error message:
`./gradlew installDebug` can fail with the following error message:
```
adb: failed to install _build/juloo.keyboard2.debug.apk: Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE: Package juloo.keyboard2.debug signatures do not match previously installed version; ignoring!]
make: *** [Makefile:20: installd] Error 1
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':installDebug'.
> java.util.concurrent.ExecutionException: com.android.builder.testing.api.DeviceException: com.android.ddmlib.InstallException: INSTALL_FAILED_UPDATE_INCOMPATIBLE: Existing package juloo.keyboard2.debug signatures do not match newer version; ignoring!
```
The application can't be "updated" because the temporary certificate has been
@@ -73,31 +66,142 @@ The application must be enabled again in the settings.
```sh
adb uninstall juloo.keyboard2.debug
make installd
./gradlew installDebug
```
## Specifying a debug signing certificate on Github Actions
It's possible to specify the signing certificate that the automated build
should use.
After you successfully run `./gradlew asssembleDebug`, (thus a debug.keystore
exists) you can use this second command to generate a base64 stringified
Makes sure to specify the `name` attribute like in `latn_qwerty_us.xml`,
otherwise the layout won't be added to the app.
The layout file must be placed in the `srcs/layouts` directory and named
according to:
- script (`latn` for latin, etc..)
- layout name (eg. the name of a standard)
- country code (or language code if more adequate)
Then, run `./gradlew genLayoutsList` to add the layout to the app.
The last step will update the file `res/values/layouts.xml`, that you should
not edit directly.
Run `./gradlew checkKeyboardLayouts` to check some properties about your
layout. This will change the file `check_layout.output`, which you should
commit.
Layouts are CC0 licensed by default. If you do not want your layout to be
released into the public domain, add a copyright notice at the top of the file
and a mention in `srcs/layouts/LICENSE`.
#### Adding a programming layout
A programming layout must contain all ASCII characters.
The current programming layouts are: QWERTY, Dvorak and Colemak.
See for example, Dvorak, added in https://github.com/Julow/Unexpected-Keyboard/pull/16
It's best to leave free spots on the layout for language-specific symbols that
are added automatically when necessary.
These symbols are defined in `res/xml/method.xml` (`extra_keys`).
It's possible to place extra keys with the `loc` prefix. These keys are
normally hidden unless they are needed.
Some users cannot easily type the characters close the the edges of the screen
due to a bulky phone case. It is best to avoid placing important characters
there (such as the digits or punctuation).
#### Adding a localized layout
Localized layouts (a layout specific to a language) are gladly accepted.
See for example: 4333575 (Bulgarian), 88e2175 (Latvian), 133b6ec (German).
This keyboard is intended for programmers. If your language uses the Latin script, make sure it is possible to type every letters on the QWERTY keyboard.
This is generally done using dead-keys, for example: 0bf7ff5 (Latvian), 573c13f (Swedish).
It is also possible to add some characters that are hidden in other languages, for example 93e84ba (ß), though the space is limited.
They don't need to contain every ASCII characters (although it's useful in
passwords) and dead-keys.
### Add a programming layout
### Adding support for a language
A programming layout must contains every ASCII characters as well as every dead-keys.
Currently, the only example is QWERTY.
Supported locales are defined in `res/xml/method.xml`.
### Translations
The attributes `languageTag` and `imeSubtypeLocale` define a locale, the
attribute `imeSubtypeExtraValue` defines the default layout and the dead-keys
and other extra keys to show.
Translations are always welcome ! See for example: 1723288 (Latvian), baf867a (French).
The app can be translated by writing `res/values-<language code>/strings.xml` (for example `values-fr`, `values-lv`), based on the default: `res/values/strings.xml` (English).
The list of language tags (generally two letters)
and locales (generally of the form `xx_XX`)
can be found in this [stackoverflow answer](https://stackoverflow.com/a/7989085)
The store description is found in `metadata/android/<locale>/`, `short_description.txt` and `full_description.txt`.
The full description changes very infrequently (it was changed once in 6 years). But if it changes too much, outdated translation might be removed.
### Updating translations
Translating changelogs is not useful because they evolve too fast. Changelogs are generally written entirely just before a release, translating them would delay releases too much. Old changelogs are not shown to anyone currently.
The text used in the app is written in `res/values-<language_tag>/strings.xml`.
This app is a virtual keyboard for Android. The main features are easy typing of every ASCII character using the swipe gesture, dead keys for accents and modifier keys and the presence of special keys (tab, esc, arrows, etc..).
The keyboard shows up to 4 extra characters in the corners of each key. These extra characters are hit by swiping the finger on the key.
Highlight of some of the features:
- Every character and special keys that are also available on a PC keyboard. This is perfect for using applications like Termux.
- This includes Tab, Esc, the arrows and function keys, but also Ctrl and Alt !
- Accented keys are accessible using dead keys. First activate the accent, then type the accented letter.
- Very light and fast. Use 500x times less space than Google's keyboard and 15x times less than the default keyboard. No ad, no tracking.
- Multiple layouts: QWERTY, QWERTZ, AZERTY. Themes: White, Dark, OLED Black. And many other options.
Like any other virtual keyboards, it must be enabled in the system settings. Open the System Settings and go to:
System > Languages & input > On-screen keyboard > Manage on-screen keyboards.
The main feature is that you can type more characters by swiping the keys towards the corners.
This application was originally designed for programmers using Termux.
Now perfect for everyday use.
This application contains no ads, doesn't make any network requests and is Open Source.
Usage: to apply the symbols located in the corners of each key, slide your finger in the direction of the symbols. For example, the Settings are opened by sliding in the left down corner.
* [Calculator++](https://git.bubu1.eu/Bubu/android-calculatorpp) - Calculator with a similar UX, swipe to corners for advanced math symbols and operators.
You select a key layout for Unexpected Keyboard by calling up the Settings page (swipe the gear icon) and, at the top of the page, either tapping an existing layout or tapping _Add an alternate layout_. This displays a menu of available layouts. You can define your own layout by choosing _Custom layout_ at the bottom of this menu. Unexpected Keyboard now displays code in the XML format. You make changes by replacing this with different code and tapping OK.
We recommend you keep your work in a file outside Unexpected Keyboard (named something like `MyChanges.xml`). If you installed a new version of Unexpected from a different website (with a different signature), then the work you did solely by editing the XML inside Unexpected would be lost.
Put initial contents into your file in one of these ways:
* Copypaste the code Unexpected displays for _Custom layout_.
* Make a copy of one of the built-in layouts found in [`/srcs/layouts`](https://github.com/Julow/Unexpected-Keyboard/tree/master/srcs/layouts).
* Use the [web-based editor](https://unexpected-keyboard-layout-editor.lixquid.com/). Interact with this web page to define keys and swipes and move keys to desired positions, and it will write the XML code for you. You can make the web page put the XML in a text file or copy it to the clipboard.
When you have prepared suitable XML code in one of these ways, copy it to the clipboard and paste it into Unexpected Keyboard.
## XML language overview
A layout XML file comprises tags that start with `<` and end with `>`.
* Every layout file starts with this declaration:
`<?xml version="1.0" encoding="utf-8"?>`
* Certain tags come in pairs—an opening tag and a closing tag—and apply to everything between them.
* The `<keyboard>`...`</keyboard>` pair says that the material between them is the definition of your keyboard. There can be only one of these.
* The `<row>`...`</row>` pair encloses the definition of a single row.
* An optional `<modmap>`...`</modmap>` pair contains instructions if you want to change the behavior of a modifier key such as Shift.
* Stand-alone tags include `<key`...`/>`, which defines a single key.
A tag can have properties, defined using an equals sign and a pair of ASCII double quotes. For example, `<key c="a" />` defines the "a" key. The `c` property of the `key` tag says which key you are defining, and the tag's location inside `<row>`...`</row>` specifies where it will go in the row.
### Example
Here is a complete keyboard file with a single row containing an "a" key on the left and a "b" key on the right:
<?xml version="1.0" encoding="utf-8"?>
<keyboardname="Simple example"script="latin">
<row>
<keyc="a"/>
<keyc="b"/>
</row>
</keyboard>
## Keyboard metadata
The `<keyboard>`...`</keyboard>` pair follows the declaration tag and encloses the whole keyboard. The following properties may be used (The first two appear in the example above):
*`name`: The name of the keyboard. The name you specify will appear in the Settings menu. If not present, the layout will just appear as “Custom layout”.
*`script`: The (main) writing system that the keyboard supports. The possible values are `arabic`, `armenian`, `bengali`, `cyrillic`, `devanagari`, `gujarati`, `hangul`, `hebrew`, `latin`, `persian`, `shavian`, and `urdu`. It defaults to `latin`.
*`numpad_script`: The script to use for the numpad. This is useful for scripts where a different, non-ASCII set of numerals is used, like Devanagari and Arabic. It defaults to the same as `script`.
*`bottom_row`: Whether or not to show the built-in bottom row. It accepts `true` or `false`, and defaults to `true`. If your custom layout defines the bottom row, then specify `bottom_row="false"` to disable the built-in bottom row.
+ 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).
*`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"`.
## Row
The `<row>`...`</row>` pair encloses one row on the keyboard. It has only one optional property:
*`height`: The height of the row: a positive floating-point value.
A row's default height is 1.0 (one quarter of the keyboard height specified on the Settings menu). The `height` property makes the row taller or shorter than this. For example, if you define a 5-row keyboard but one row has `height="0.7"`, then the keyboard's total height is 4.7 units. If the total is different from 4.0, the keyboard will be taller or shorter than that specified in Settings.
## Key
The `<key />` tag defines a key on the keyboard. Its position in the sequence of keys inside `<row>`...`</row>` indicates its position in the row from left to right. What the key does is defined by optional properties.
### Taps
What the key does when tapped is defined by the optional `c` property. For example, `<key c="a" />` defines the "a" key. Unexpected Keyboard provides a legend in the middle of the key.
When the Shift modifier is tapped, the "a" key becomes the "A" key and the legend temporarily changes. The Fn modifier makes a different change. You can override this behavior with a modmap (see below).
### Swipes
The following optional properties define the effects of swipes:
*`n`, `ne`, `e`, `se`, `s`, `sw`, `w`, `nw`: What the key should do when it is swiped in the direction of that compass point. ("North" means upward and "East" is to the right.)
*`key1` through `key8` is an older way to achieve the same effects. The directions are ordered as follows:
<TABLEALIGN=CENTER>
<TR>
<TD>key1</TD><TD>key7</TD><TD>key2</TD>
</TR>
<TR>
<TD>key5</TD><TD>key0</TD><TD>key6</TD>
</TR>
<TR>
<TD>key3</TD><TD>key8</TD><TD>key4</TD>
</TR>
</TABLE>
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.
*`anticircle`: The key value to send when doing an anti-clockwise gesture on the key.
### Layout
A key may have the following properties to control the row's layout:
*`width`: The width of the key, a positive floating-point value. It defaults to 1.0
*`shift`: How much empty space to add to the left of this key, a non-negative floating-point value. It defaults to 0.0
Normally, a key's width is 1.0 unit. Unexpected Keyboard occupies the full width of the screen, and the row defining the highest number of units (in widths plus shifts) is as wide as the screen. A row whose width is a smaller number of units has empty space on the right.
### Extra legend
*`indication`: An optional extra legend to show under the main label. For example, `<key c="2" indication="ABC" />` displays ABC at the bottom of the 2 key, as on a pinpad or some telephones. If the key also defines a downward swipe with `s` or `key8`, the legends overlap.
### Possible key values
Built-in strings that assign a special function to a key are described in [this page](Possible-key-values.md). For example, `se="copy"` means a southeasterly swipe produces the Copy key. If a key value does not match any of the built-in strings, it outputs that text _verbatim_. For example, `c="a"` simply outputs the letter a.
In a layout, a key value can also start with the `loc` prefix. These are place-holders; the tap or swipe does nothing unless enabled through the "Add keys to keyboard" option in the Settings menu, or implicitly enabled by the language the device is set to use. For example, `ne="loc accent_aigu"` says that a northeast swipe produces the acute accent combinatorial key—if enabled.
## Modmap
The `<modmap>`...`</modmap>` pair encloses custom mappings for modifier keys. The modmap is placed inside the `<keyboard>`...`</keyboard>` pair, but outside any row. A layout can have at most one modmap. It can contain any number of mappings. Each mapping has an `a` property and a `b` property and maps the `a` key to the `b` key. Valid values are listed in [Possible key values](Possible-key-values.md).
The following mappings are supported:
```xml
<shifta="before"b="after"/>
```
This means that when the Shift modifier is on, the key `before` is changed into `after`.
```xml
<fna="before"b="after"/>
```
This means that when the Fn modifier is on, the key `before` is changed into `after`.
```xml
<ctrla="before"b="after"/>
```
This means that when the Ctrl modifier is on, the key `before` is changed into `after`. The `<ctrl />` mapping is special in that the Ctrl modifier is applied to `after` after the mapping.
The clockwise circle and the round-trip gestures are affected by both `<shift />` and `<fn />` mappings. The Shift mappings are used first and if that did not modify the key, the Fn mappings are used instead.
### Examples
① Turkish keyboards use the Latin alphabet, but when "i" is shifted, it should produce "İ". This is achieved with the following mapping:
```xml
<shifta="i"b="İ"/>
```
② Cyrillic layouts have no V key. A layout can define Ctrl-V with the following mapping:
```xml
<ctrla="в"b="v"/>
```
This maps Ctrl+в to Ctrl+V—not to v.
## Portrait vs. landscape
Unexpected Keyboard remembers *separately* which layout has last been used in portrait and landscape orientation. So you may have one custom layout for portrait orientation, but another custom layout for landscape orientation, and Unexpected Keyboard will switch between them without your intervention.
## Contributing your layout
The Unexpected Keyboard project enthusiastically accepts user contributions, including custom layouts. (See the guidance for layouts at [CONTRIBUTING.md](https://github.com/Julow/Unexpected-Keyboard/blob/master/CONTRIBUTING.md#Adding-a-layout)).
* Submit a layout that has innovations of possible interest to other users at [Unexpected-Keyboard-layouts](https://github.com/Julow/Unexpected-Keyboard-layouts).
* Propose that your layout be included in the set of built-in layouts by making a Pull Request for an addition to [srcs/layouts](https://github.com/Julow/Unexpected-Keyboard/tree/master/srcs/layouts). Please show that such a layout is standard in your locale or has a substantial number of users.
A key value defines what a key on the keyboard does when pressed or swiped.
Key values appear in the following places:
- In custom layouts, they are the value of: the `c` attribute, the compass-point attributes `nw` ... `se`, and the old-style `key0` ... `key8` attributes.
- Internally, they are used in the definition of the "Add keys to the keyboard" setting.
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`
`\` | `\\`
`&` | `&`
`<` | `<`
`>` | `>`
`"` | `"`
The characters `?`, `#`, and `@` do not need to be escaped when writing custom layouts. Internally, they can be escaped by prepending backslash (by typing `\?`, `\#`, and `\@`).
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.
## Modifiers
System modifiers are sent to the app, which can take app-specific action.
Value | Meaning
:---------- | :------
`shift` | System modifier.
`ctrl` | System modifier.
`alt` | System modifier.
`meta` | System modifier. Equivalent to the Windows key.
The other modifiers take effect only within the keyboard.
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.
`esc`, `enter`,
`up`, `right`,
`down`, `left`,
`page_up`, `page_down`,
`home`, `end`,
`backspace`, `delete`,
`insert`, `scroll_lock`,
`f1`-`f12`,
`tab`, `copy`,
`paste`, `cut`,
`selectAll`, `pasteAsPlainText`,
`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
Value | Meaning
:------ | :------
`space` | Space bar.
`nbsp` | Non-breaking space.
`nnbsp` | Narrow non-breaking space.
`zwj` | Zero-width joiner.
`zwnj` | Zero-width non-joiner.
## Other modifiers and diacritics
Value | Meaning
:------------------- | :------
`accent_aigu` | Acute accent. `á`
`accent_caron` | Háček. `č`
`accent_cedille` | Cedilla. `ç`
`accent_circonflexe` | Circumflex. `â`
`accent_grave` | Grave accent. `à`
`accent_macron` | Macron. `ā`
`accent_ring` | Ring accent. `å`
`accent_tilde` | Tilde. `ã`
`accent_trema` | Dieresis/umlaut. `ä`
`accent_ogonek` | Ogonek. `ą`
`accent_dot_above` | Dot accent. `ż` If applied to the lowercase `i`, removes the dot instead for Turkish. `ı`
`accent_double_aigu` | Double acute accent. `ő`
`accent_slash` | Slash through. `ø`
`accent_arrow_right` | Right arrow above, used to denote a vector. `a⃗`
`accent_breve` | Breve. `ă`
`accent_bar` | Bar/strikethrough. `ɨ`
`accent_dot_below` | Dot below. `ạ`
`accent_horn` | Horn accent. `ơ`
`accent_hook_above` | Hook accent. `ả`
`accent_double_grave` | Double grave accent. `ȁ`
`superscript` | Superscript. `ᵃ`
`subscript` | Subscript. `ₐ`
`ordinal` | Turns `a` and `o` into `ª` and `º`.
`arrows` | Turns `1`-`4` and `6`-`9` into arrows.
`box` | Turns `1`-`9`, `0`, and `.` into single-line, thin box-drawing characters.
## Bidirectional
Value | Meaning
:------ | :------
`lrm` | Left-to-right mark.
`rlm` | Right-to-left mark.
`b(`, `b)`, `b[`, `b]`, `b{`, `b}`, `blt`, `bgt` | Sends the bracket characters, but with mirrored key legends for right-to-left languages. (`blt` and `bgt` print `<` and `>` respectively.)
## Hebrew
Keys ending in `_placeholder` are normally hidden unless the Fn key is pressed.
`switch_text` | Switch to the text layer (main layer).
`switch_numeric` | Switch to the numeric layer.
`switch_emoji` | Switch to the emoji layer.
`switch_back_emoji` | Switch to the text layer from the emoji layer.
`switch_forward` | Change the keyboard layout, as long as Unexpected Keyboard has multiple keyboard layouts enabled in the settings.
`switch_backward` | Change the keyboard layout to the previous one in the list.
`switch_greekmath` | Switch to the Greek & Math Symbols layer.
`switch_clipboard` | Switch to the clipboard pane.
`change_method` | Open the input method picker dialog.
`change_method_prev` | Switch to the previously used input method.
`action` | Performs a special context-sensitive operation related to the Enter key. For example, in the Twitter (X) app, `enter` adds a new line, while `action` posts.
`voice_typing` | Begin voice typing.
`voice_typing_chooser` | Shows a menu where you can choose which voice typing provider to use, then begins voice typing when you make a selection.
`shareText` | Emit a share Intent for the selected text. **Oddity:** This is in CamelCase.
## Unused
These keys are known to do nothing.
`replaceText`, `textAssist`,
`autofill`, `removed`
## Placeholders
These keys are normally hidden unless the Fn modifier is activated.
Легкая клавиатура для пользователей, заботящихся о конфиденциальности.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.