Harley wanted a pink/violet keyboard. The alternates use the exact violet sampled
from his own UI accent (#c67dff); letters are pink (#ff8ad8), activated keys
(shift/Esc/123+) are filled violet (#a855f7) with dark glyphs, caps-lock is
periwinkle blue (#9db8ff), background is violet-black (#100a1c). Contrast checked:
9.13 / 7.19 / 9.92 / 4.9 :1. Five edits: themes.xml style, arrays.xml entries+values
(kept index-aligned), strings.xml label, Config.java case.
- UsageGauge: WireGuard-only JSON fetch, cached, background thread, stale-aware
- Gauge key: gradient fill rises with the tightest Codex window, %.1f of today's
DeepSeek spend, red below a $1.00 balance, flat grey when stale/offline
- Display-only: marker lives in the key indication field, no character, touch swallowed
- Settings entries; cleartext permitted only for 10.10.10.1
- ComposeKey: composing to U+00A0 keeps the named nbsp key, since adding a layout
key perturbs the generated compose table and would otherwise emit the display glyph
- 5 new unit tests; all 21 tests pass
Standalone top-row emoji key replaced by a badge in the Alt key key2 swipe slot, drawn as a smile-in-a-circle glyph: new special-font codepoint 0xE01D from Font Awesome face-smile, rebuilt into assets/special_font.ttf with fontforge. Corner slots carry FLAG_SECONDARY so labelColor dims them to secondaryLabelColor; the badge overrides to _theme.labelColor to match the rest of the keyboard labels, and is identified by its codepoint rather than an Event or Kind accessor, because those are only valid for specific kinds and crashed the IME when called unguarded in the draw path. Swipe toward the key top-right to reach it; the config gear stays in the bottom-left. check_layout.output excluded on purpose - unrelated latn_neo2 drift.
KeyValue.getEditing is only defined when getKind is Kind.Editing. _code is overloaded, so on a character key it holds the character and Editing.values() indexed with it threw ArrayIndexOutOfBoundsException length=16 index=113 from drawLabel, crashing the IME on every draw. The phone was rolled back to the previous build first, then this fix was installed. Verified no crash after reinstall.
The indicator is the space bar label itself (Editing.SPACE_BAR), so it needs no extra UI. Keyboard2 repaints the keyboard view every 60s while the input view is visible. Regenerated ComposeKeyData follows the layout change (moving the tilde and equals keys changes which keys compose), which is also what made the two unit tests pass again: they were failing on a stale generated state, not on real behaviour.
switch_emoji uses a normal-font smiley label: 0xE001 is the joypad glyph in this fork. Peak dot: UTC Mon-Fri 01-04 and 06-10 pink, else blue; refreshes every 60s while the keyboard is visible.
- '!' moved to bottom-left of '1' (q sw), removed from e ne
- Dash on o sw, underscore on o se
- ':' on l sw (replaced backslash)
- Bottom row: Ctrl | Alt | Space | Fn | Enter
- Fn moved right of space bar, corner swipes cleaned up
- Voice typing moved from Enter to Fn bottom-left (key6)
- Clipboard on Ctrl bottom-left (key6)
- New 'tux' key: META modifier displayed as Tux penguin (0xE002)
from special_font/002.svg, toggleable (latch+double-tap lock)
- Enter only has action corner (key2), no voice typing
- Config (settings) kept on Fn up-swipe (key1)
- Top row numbers moved from ne (top-right) to nw (top-left) per request
- Existing nw symbols (tilde, !) shifted to ne positions
- Shift restored in z-row (normal key width)
- Backspace now normal key width (no more 1.5x)
- Fn key now has corner swipes: config, change_method, emoji, switch_numeric
- Bottom row: Fn | Ctrl | Alt | Space | Enter
- Joypad no longer uses displacement-accumulation (useless on space bar).
- After long-press space bar, determine direction from finger offset vs origin.
- Direction locks, fires one cursor event, then auto-repeats at
longPressInterval rate via _longpress_handler.
- Changing finger direction updates the lock (fires in new dir immediately).
- Returning finger to dead zone stops auto-repeat.
- Removed SPEED_VERTICAL_MULT and startup threshold:space bar has no room.
- Space bar icon changed to 0xE001 (4-directional arrows).
- Space bar long-press now activates Joypad cursor mode
(long-press detected in handleLongPress before key-repeat)
- Removed separate cursor_joystick key from bottom row
- Widened space bar (4.2 → 6.0) to compensate
- Bottom row: Shift | Fn | Ctrl | Alt | Space (joypad on long-press) | Enter
- Removed redundant shift key from latn_qwerty_us.xml third row
(shift is now on the bottom row only)
- Rebuilt assets/special_font.ttf to include 001.svg (4-directional
joystick icon at codepoint 0xE001)
When the layout is split, insert a middle column showing the
complete_first, complete_second, etc.. keys.
These keys are rendered without borders and background with a new role.
The suggestion bar is hidden for split layouts. The intention is to gain
much needed vertical space.
* Add tests
* Fix compose-space sequences not working
KeyModifier didn't pass editing keys to ComposeKey.
* Cleanup test code
* Show the nbsp symbol when typing compose-space-space
The number pane and the pin entry layouts are split in landscape
orientation. Instead of inserting empty space in the middle of the
layout, the numpad is duplicated. The other keys are not duplicated.
This adds the new "Stateful" kind of keys, for which the symbol is
dynamically computed from the app's state. This is implemented with a
hook directly in KeyValue.
3 keys are added for accessing the 3 words on the candidates view.
* Automatically split layouts in landscape
This inserts empty space in the center of layouts when in landscape
orientation. The keys are smaller and pushed to the edges of the screen.
This way, the fingers don't have to reach the center of the screen,
which is inconvenient in landscape orientation.
* Duplicate keys that are on the middle
Keys that are almost aligned on the middle of the screen are duplicated
on both sides. These keys are most probably hit with both thumbs.
This is especially useful for large keys like the space bar on the
bottom row.
* Split the bottom row
* Add an option to control layout splitting
* Different color for action keys and space bar
Keys can be made darker or dimmer individually in layouts.
This is done by setting the new 'role' attributes. Roles are "normal",
"action" and "space_bar".
The "action" role is intended to be used for keys like shift, backspace
and other keys from the bottom row.
Themes and special layouts are updated.
* Set 'role="action"' for shift and backspace keys, the number row and numpad.
* check_layout.py: Check that some keys have a role
Since SDK 29, calling setSystemGestureExclusionRects is mandatory to
continue supporting the keyboard's gestures but since SDK 30, this is
done automatically.
The option can be set to "Show everything" to show the keyboard even
when a physical keyboard is present.
This is a list preference to allow adding a "Show suggestions" option
later.
* gen_method_xml.py: Add missing dictionary for English
* gen_method_xml.py: Propagate dictionary specified in default locales
For example, propagate the dictionary specified for 'en' to 'en-IN',
'en-NG', etc..
* Use the dictionary en_US for locale en_CA
* Refactor: Move DeviceLocales instance to Config
Allows accesses from CandidatesView.
* Show the current locale when no dictionary is installed
This helps understand why installing a dictionary doesn't remove the
message asking to install a dictionary.
The "Install" button is removed and the message is more informative.
* Update translation files
* Fix unwanted mutation of background drawable
* Add a background color under suggestions
Suggestions might be unreadable when the keyboard opacity is very low
(eg. black on black).
The new background is normally invisible, unless the opacity option is
not set to 100%. The corner are rounded like the keys on the keyboard.
* Add themes attributes for suggestion background
Future themes can use them.
* gen_method_xml.py: Warn for unused dictionaries
Helps catch missing locales.
* Add languages for which a dictionary is available
Make dictionaries are available to more languages. Extra keys are added
for as many languages as possible but no layout is added.
Some languages are still not added, mainly because they use a script
that the keyboard doesn't support yet:
pa, gu, or, te, mai, sat, km, iw, zgh, sd, ml, sa
The "en" locale, which was meant to be the default for English locales
that are not in the list, was used instead of exact locales like "en_US".
The "en" locale was also used as the default locale for languages that
are not in the list at all. The "en_GB" locale is used for this instead.
* Fix the spacebar in Hangul combining
The encoding for the spacebar changed and the Hangul combining code was
not updated.
* Change the default layout for Korean
Run the tests before building the debug APK in CI. This checks that the
unit tests pass and that the generated files are uptodate.
Doesn't fail if the generated files are outdated. Instead, the APK is
built with them updated.
* Fix crash when typing space in the middle of a word
* Don't trigger autocorrect when the cursor is not at the end of a word
This prevented from editing a word that was already typed.
* Don't undo autocorrect at the wrong time
Backspace was trying to undo autocorrect even after some other action
were done after the last autocorrect. This ensures that the keyboard
remembers accurately the last action.
* Better spell check with cursor in the middle of a word
Suggestions are based on the entire word and no longer the part of the
word just before the cursor. Also, tapping a suggestion or the space bar
autocorrect replaces the entire word.
* Reduce the number of calls to refresh_current_word
While the cursor moves, calls to refresh_current_word are now only done
when the cursor exits the current word.
This prevents the same suggestions to be presented again and autocorrect
to be activated again when pressing space.
This extra space is wanted because pressing the spacebar triggered
autocorrect in the first place.
* Update cdict
* scripts/subst_of_compose.py: Compute substitutions
from compose mappings. They are used when building dictionaries.
* Add substitutions compose data
* Better suggestion with diacritics
This improves the suggestions for words that contain diacritics and
uppercase letters.
This works by stripping diacritics both when building the dictionaries
(using word aliases added in cdict: https://github.com/Julow/cdict/pull/3)
and during lookup. Cdict then takes care of resolving the correct word.
The substitutions are generated using mappings from `fn`, `shift` and
all the `accent_*` modifiers into srcs/compose/substitutions.json
This can be updated easily when more mappings are added.
* Switch dictionary when language changes
The dictionary was otherwise updated by closing and opening the keyboard
again.
* Refresh suggestions immediately after language switch
For example, typing "dictionarirs" suggests "dictionaries" but moving
the cursor away and back results in no suggestion. Because the lookback
was 10 characters long, the keyboard was seeing "ctionarirs".
* shell.nix: bump platform version to match target
* shell.nix: make gradlew work on NixOS
This removes the wrapper provided by `shell.nix`. Folks expect the
`./gradlew` wrapper to work, so this approach is more straightforward.
* Helper for whether a slider is vertical
* Only accumulate delta for the current slider's direction
* Slow down horizontal cursor movement while ctrl is held
Suggestions were previously case-sensitive, which gave very bad results
for the first word of a sentence.
This makes sure that the suggestions for capitalized words are as good
as for all lower-case words and that the suggestion doesn't turn the
uppercase letter into lower case.
* Refactor: Implement the space key as an editing action
The space key is no longer a CHAR key but now an EDITING key. This
allows changing the behavior of the space bar while allowing custom
layout users to define a key outputing a space as before.
KeyModifier and ComposeKey are updated to treat the space key as before.
* Enter the best suggestion when the space bar is pressed
* Refactor: Implement backspace as an editing action
* Undo suggestion when delete is pressed
The delete key (backspace internally) undoes the suggestion if the last
action done was entering the suggestion with either the space bar or the
candidates view.
* Add an option to enable space bar autocomplete
This option is off by default. Undoing a completion with backspace works
in any case.
* Refactor: Track selection emptyness in CurrentlyTypedWord
This removes an expensive RPC call.
* Refactor: KeyValue constants
Add constants for keys that are accessed from the app's code. This
simplifies the fake pointer handling in Keyboard2View.
* Refactor: Pre-compute action key replacement
The action key and the enter swap are pre-computed in EditorConfig. This
simplifies the code.
The color of labels on a pressed key that were not the label being
activated (eg. the labels on the corners when activating the label in
the centre) was not correct.
This adds dictionary-based spell checking to the keyboard. The keyboard looks at the word being typed and matches it against a dictionary to either complete the rest of the word or find alternative spellings.
The core of this feature is implemented in cdict, which is included as a
submodule in vendor/cidct.
Cdict is developped at https://github.com/Julow/cdict
The dictionaries are hosted at https://github.com/Julow/Unexpected-Keyboard-dictionaries/
The wordlists used to build the dictionaries are the same ones used by
HeliBoard from https://codeberg.org/Helium314/aosp-dictionaries
- Add an activity accessible from the launcher app that lists available
dictionaries with a download button.
The DictionaryListView view shows the list of available dictionaries and
handles downloading and installing them.
- The Dictionaries class manages installed dictionaries. Dictionaries are
installed as individual files into the app's private directory.
- Available dictionaries are listed in dictionaries.xml, which is generated
when building Unexpected-Keyboard-dictionaries.
method.xml mentions the dictionary name for each locales.
* Refactor: Create subpackage 'suggestions'
* Candidates view: Status message when no dictionary installed
Show a message on the candidates view instead of leaving it empty. A
button points to the dictionary installation activity.
* Add an option to disable the suggestions
* Refactor: Remove Config.should_show_candidates_view
This was moved to EditorConfig.
* Don't disable text suggestions in some text boxes
* Suggestion text size matching settings
The candidates view height is based on the height of keyboard rows and
the suggestion text size is based on the size of labels on the keys.
This is influenced by symbol size and keyboard height options.
It was possible to define a loop that would crash the app with the
following modmap:
<ctrl a="left" b="left:ctrl,left"/>
With this change, modmap are not taken into account while evaluating
macros. The modmap above modifies ctrl+left into ctrl+left.
The "Switch to the last used keyboard" is renamed to "Switching between
input methods" and allows to select "Switch to last used", which was the
default in older releases.
* Add the small capital letters dead key
It can be added to the keyboard from the settings or into custom layouts
as `accent_small_caps`.
Add all the symbols listed on https://en.wikipedia.org/wiki/Small_caps
The color resources starting with `@android:color/system_` are not
available on API < 31.
No effort is made to implement the Monet feature on Android 9. Instead,
the monet themes look like the Dark and Light themes.
* Refactor: Split DeviceLocales out of Keyboard2
This moves the code from Keyboard2 that handles the active IME subtypes
and the current one.
The goal is to access this information from the dictionary activity
while simplifying the code of Keyboard2.
* Refresh the candidates view when subtype changes
This fixes the status message being inconsistently shown.
* Refactor: Load DeviceLocales less often
Previously, [DeviceLocales.load()] was called everytime the keyboard was
shown on the screen. This operation is moderately costly and only need
to be done when the IME subtype changes.
* EditorConfig: Fix crash on Android 9
The `CurrentlyTypedWord` class tracks the word that is being typed. It's
implemented on the same model as Autocapitalisation and avoid expensive
IPC calls when possible.
The `Suggestions` class is where the suggestion lookup should go. It
currently just echoes the current word.
The `CandidatesView` is implemented as a `LinearLayout` that is divided
horizontally with up to 3 `TextView`. It might in the future contain
buttons on the sides.
The candidate view is nested into the input view rather than using
Android's `setCandidatesView` and callbacks as the API is unreliable and
complicated.
The first suggestion goes in the middle to be more accessible. The
second suggestion goes on the right to be more accessible to the
right-handed, because it must go somewhere.
Locale are now defined in `gen_method_xml.py` in a more convenient and
checked way. It contains both the locale definition and the generation
script.
`method.xml` is generated with:
gradle test
The goal is to support dictionaries for spell checking.
* Fix background crash in clipboard history service
The clipboard history service might crash when the connection between
the keyboard and the system is in a bad state.
* Fix race condition in clipboard history service
The clipboard history service callback appears to be called concurrently
leading to concurrent accesses to data and to concurrent calls to
'on_clipboard_history_change'. Access are now synchronized.
* Fix clipboard manager crash when device is locked
The output APKs used to be named 'juloo.keyboard2.apk' are now named
'Unexpected-Keyboard-release.apk' since the Gradle upgrade and the rule
setting it hasn't been working since.
* Disable selection mode in text editors
Selection mode removes the space bar key (which is replaced by the Esc
key) and can be annoying in Emacs for example.
Text editor users probably have the `esc` key available.
* Refactor: Move EditorInfo related code to EditorConfig
Add the new EditorConfig class that handles configuration extracted from
the EditorInfo. It is accessible from the Config class for convenience.
This aims at reducing the length of already large classes and group the
code that was spread over several classes.
* Delete srcs/layouts/armenian_ph_am.xml
There is a phonetic layout which is used in old typewriters
* Amendments according to GOST 6431-90
* Russian traditional layout cyrl_jiuken.xml
* Create cyrl_yawerty.xml
Added ЯВЕРТЫ layout
* Update cyrl_jcuken_ru.xml
Typo fixed
* Added QZERTY layout for Italian and Latin
* refactor: Better printing for KeyValue in tests
* Fix parsing of escaped characters in macros
The parsing code was bugged with custom macros like `symbol:\abc` and
`symbol:\\abc`.
The genEmojis rule makes a network request and must not be done during a
regular build.
The compileComposeSequences updates a file that is checked in the
repository and doesn't need to be updated in a regular build. Both are
now handled like 'genLayoutsList'.
The height of row set with `<row height="...">` cannot be lower than 0.5
to avoid rendering problems.
This restriction is not necessary when the row has no key and is lifted
in this case.
* Changed Python scripts so they work on my machine
file open() used default encoding (cp1252 on my machine) but the text is utf-8, had to specify encoding in check_layout.py
This allows assigning mappings to letters without changing the Shift
mappings and making uppercase impossible to type.
For gestures, the Shift modifier is still applied first, unless a custom
mapping for <fn/> is set for the key.
* Add option 'Space bar slider sensitivity'
* Fix slider moving the cursor twice at the beginning
The slider was generating two events when first activated.
Since 2bed42857.
* Make slider less sensitive for the first step
This moves the second slider step approximately 40% further and takes the
new sensitivity option into account.
Allows moving the cursor by one spot more easily.
This adds the English, Hausa, Yoruba and Igbo languages for Nigeria. The
goal is to add the ₦ symbol as well as basic support for these
languages. No layout is added.
The diffs created by sync_translations.py creates conflicts with the
changes made on Weblate. It is disable to make merging translations from
Weblate easier.
The label size was computed against the width of keys on the keyboard,
which resulted in a different label size on different layouts.
Notably, it made the labels very small on a 11 columns layout and
relatively larger on the numpad.
The label size is now computed against a baseline of 1/10 of the width
of the screen.
* add majuscules to compose
* add tse to compose
* added reverse ya FN to modernize it FROM the older form
* fix accent FN and add reverse arabic-heh FN
* little improvements and additions
* QoL improvements for Kurdish Sorani
This changes layout switching logic to detect screen width rather than increasingly specific portrait/landscape/unfolded state.
This reduces number of different auto-layouts back to 2: narrow devices (such as a phone in portrait) and wide devices (such as a phone in landscape or a tablet).
Make vertical sliders slower. The intention is to make the up/down
slider slower, as we have less visibility and do smaller movements in
that direction.
* Fix extra bottom margin when navbar buttons absent
Fix the extra space that was appearing when the gesture-navigation bar
didn't contain the "switch IME" or "close IME" buttons.
This was found on OneUI 7 with the two "keyboard key" related options
turned off.
* Remove unneeded nav bar detection and width computation
Emptying the selection with the spacebar slider puts the selection mode
in an unexpected state. This checks that this doesn't happen.
The selection ends can now cross each other, reversing the selection
order. Special care is made to make sure that the sliders go in the
expected direction.
Pointers is changed to send a `onPointerDown` for the first slider event
instead of a `onPointerHold`. This event is detected in
`KeyEventHandler` and the selection ends are reordered if needed when
sliding again.
* Add <row scale=""> attribute
Scale the width of the keys in the row to match a value. Useful to
remove space on the right of the row without adding a 'width' attribute
to each key.
* layouts: Use the 'scale=""' attribute in builtin layouts
This removes the very specific 'width' values.
The calculation for the size of each rows now avoid making the keyboard
bigger than the screen if the Keyboard Height option is unusually high.
The height calculation with the default settings is changed slightly, it
is now assuming that a layout is 3.95 rows high instead of 4. This is
because the bottom row is usually 0.95% the size of other rows.
The label size is computed relatively to the width of the keyboard when
the height is larger than 3/2 of the width. This ensures that the labels
have a reasonable size when the keyboard height increases.
* Add AndroidX WindowManager
unfortunately, this seems to be the only way to get fold state, native Android APIs are internal. To add this, we need to update some dependencies, raise java version and raise compile SDK.
* adds separate layouts and separate layout settings for folded and unfolded state of the device.
The affected settings are:
+ the margin bottom settings
+ the horizontal margin settings
+ the keyboard height settings
* Update shell.nix
The distance at which a swipe was considered successful was reduced in
188c682 to allow making circle gestures on a key that also had a slider.
It was also useful in reducing accidental sliding.
This is impractical for normal typing so it is reverted. The reduced
range continues to be used for sliders.
The number row option is changed into a ListPreference and controls whether the number row contains symbols or not.
Co-authored-by: Joey Schaff <j@jaoh.xyz>
* 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.
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 +72,73 @@ 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
# Unexpected Keyboard [<img src="https://hosted.weblate.org/widget/unexpected-keyboard/svg-badge.svg" alt="État de la traduction" />](https://hosted.weblate.org/engage/unexpected-keyboard/)
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..).
⚠️ Google wants to kill the open-source Android community.
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.
See [keepandroidopen.org](https://keepandroidopen.org/) and the [F-Droid blog](https://f-droid.org/en/2025/09/29/google-developer-registration-decree.html).
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 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.
Improve the application translations [using Weblate](https://hosted.weblate.org/engage/unexpected-keyboard/).
[<img src="https://hosted.weblate.org/widget/unexpected-keyboard/multi-auto.svg" alt="État de la traduction" />](https://hosted.weblate.org/engage/unexpected-keyboard/)
## Contributing
For instructions on building the application, see
[Contributing](CONTRIBUTING.md).
## Acknowledgement
The [NLnet foundation](https://nlnet.nl/) funded the work on the spell checking feature.
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://domportera.github.io/app-unexpected-keyboard-layout-editor/). 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"?>
<keyboard name="Simple example" script="latin">
<row>
<key c="a" />
<key c="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/blob/master/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/blob/master/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 the following optional property:
*`height`: The height of the row: a positive floating-point value.
*`scale`: A positive floating-point value. If present, scale the width of each key so that the total is equal to the specified value, in key width unit.
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.
(A row of keys is drawn with a minimum height of 0.5 even if you specify a smaller value for `height`. There is no such minimum for a row without keys, such as a spacer row.)
## 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:
<TABLE ALIGN=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 the `<fn />` mappings. Otherwise, they are defined by the Shift mappings (including the `<shift />` mappings), then, if that did not modify the key, the builtin 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.
### Default mappings
Unexpected Keyboard's built-in mappings are not expressed as a modmap but by a series of .json files in `https://github.com/Julow/Unexpected-Keyboard/tree/master/srcs/compose`. For example, the mappings for `fn` are in [`fn.json`](https://github.com/Julow/Unexpected-Keyboard/blob/master/srcs/compose/fn.json). These built-in mappings are common to every language.
## 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 `\` (unless followed by n or t), `?`, `#`, and `@` do not need to be escaped when writing custom layouts. When writing a layout to be included in the app (in [srcs/layouts](https://github.com/Julow/Unexpected-Keyboard/tree/master/srcs/layouts)), they are represented 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.
The values with `cursor_` are new in v1.31.0. Previous custom layouts specified the slider with `slider="true"`, which should be removed.
## 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. `ȁ`
`accent_small_caps` | Small capital letters. `ᴀ`
`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.)
## Arabic
These are the diacritics for Arabic
Value | Meaning
:------ | :------
`combining_fatha` | َ
`combining_dammah` | ُ
`combining_kasra` | ِ
`combining_sukun` | ْ
`combining_shaddah` | ّ
`combining_hamza_above` | ٔ
`combining_hamza_below` | ٕ
## 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.
`hide_self` | Hide the keyboard.
## Suggestions
Value | Meaning
:---- | :------
`complete_first` | Enter the best suggestion (the one in the middle)
`complete_second` | Enter the second best suggestion (the right one)
`complete_third` | Enter the third best suggestion (the left one)
`complete_emoji` | Enter the emoji suggestion
## Unused
These keys are known to do nothing.
`replaceText`, `textAssist`,
`autofill`, `removed`
## Placeholders
These keys are normally hidden unless the Fn modifier is activated.
Fitur utamanya adalah Anda dapat mengetik lebih banyak karakter dengan menggeser tombol ke arah sudut.
Aplikasi ini awalnya dirancang untuk programmer yang menggunakan Termux.
Sekarang sempurna untuk penggunaan sehari-hari.
Aplikasi ini tidak berisi iklan dan Open Source.
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.