Compare commits
1 Commits
combining_
...
repeat-sen
Author | SHA1 | Date | |
---|---|---|---|
|
8662f3afd4 |
1
.gitattributes
vendored
@@ -1 +0,0 @@
|
|||||||
srcs/juloo.keyboard2/ComposeKeyData.java -diff
|
|
26
.github/workflows/check-layouts.yml
vendored
@@ -1,26 +0,0 @@
|
|||||||
name: Check layouts
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
gen-layouts:
|
|
||||||
name: Generated files
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repo
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- run: python3 gen_layouts.py
|
|
||||||
- name: "Check that the generated 'layouts.xml' is uptodate, otherwise run 'python3 gen_layouts.py'"
|
|
||||||
run: git diff --exit-code
|
|
||||||
check-layouts:
|
|
||||||
name: check_layout.output
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repo
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- run: python3 check_layout.py
|
|
||||||
- name: "Check that the generated 'check_layout.output' is uptodate, otherwise run 'python3 check_layout.py'"
|
|
||||||
run: git diff --exit-code
|
|
16
.github/workflows/check-translations.yml
vendored
@@ -1,16 +0,0 @@
|
|||||||
name: Check translations
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check-translations:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repo
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- run: python3 sync_translations.py
|
|
||||||
- name: "Check that strings files are uptodate, otherwise run 'python3 sync_translations.py'"
|
|
||||||
run: git add -N . && git diff --exit-code
|
|
57
.github/workflows/make-apk.yml
vendored
@@ -9,41 +9,28 @@ jobs:
|
|||||||
Build-Apk:
|
Build-Apk:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/setup-java@v4
|
- name: Install nix
|
||||||
|
uses: cachix/install-nix-action@v15
|
||||||
with:
|
with:
|
||||||
distribution: 'zulu' # See 'Supported distributions' for available options
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
java-version: '17'
|
- uses: cachix/cachix-action@v10
|
||||||
- name: Checkout repo
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Restore debug keystore from GitHub Secrets
|
|
||||||
run: |
|
|
||||||
# Check if exist and use the secret named DEBUG_KEYSTORE
|
|
||||||
# The contents of the secret can be obtained -
|
|
||||||
# from the debug.keystore.asc from you local folder
|
|
||||||
# (refer to CONTRIBUTING.md Using the local debug.keystore on the Github CI actions)
|
|
||||||
if [[ ! "${{ secrets.DEBUG_KEYSTORE }}" = "" ]]; then
|
|
||||||
echo "${{ secrets.DEBUG_KEYSTORE }}" > "debug.keystore.asc"
|
|
||||||
if [[ -s "debug.keystore.asc" ]]; then
|
|
||||||
echo "Restoring debug keystore from GitHub secrets"
|
|
||||||
gpg -d --passphrase "debug0" --batch "debug.keystore.asc" > "debug.keystore"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
- name: Build debug APK
|
|
||||||
uses: gradle/gradle-build-action@v3
|
|
||||||
env:
|
|
||||||
DEBUG_KEYSTORE: "debug.keystore"
|
|
||||||
DEBUG_KEYSTORE_PASSWORD: debug0
|
|
||||||
DEBUG_KEY_ALIAS: debug
|
|
||||||
DEBUG_KEY_PASSWORD: debug0
|
|
||||||
with:
|
with:
|
||||||
arguments: assembleDebug
|
name: julow
|
||||||
- name: Artifact naming
|
signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
|
||||||
run: |
|
- name: Checkout Repo
|
||||||
artifact="${{github.repository_owner}} ${{github.ref_name}}"
|
uses: actions/checkout@v2
|
||||||
artifact="${artifact//\//-}" # replace slashes
|
- name: Cache debug certificate
|
||||||
echo "artifact=${artifact}" >> $GITHUB_ENV
|
uses: actions/cache@v2
|
||||||
- name: Upload debug APK
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
with:
|
||||||
name: "${{env.artifact}} debug_apk"
|
path: _build/debug.keystore
|
||||||
path: build/outputs/apk/debug/*.apk
|
key: debug-keystore
|
||||||
|
- name: Run nix-shell and Make
|
||||||
|
uses: ZenithalHourlyRate/nix-shell-action@v4
|
||||||
|
with:
|
||||||
|
file: shell.nix
|
||||||
|
script: make
|
||||||
|
- name: Save debug apk
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: debug apk
|
||||||
|
path: _build/*.apk
|
||||||
|
11
.gitignore
vendored
@@ -1,12 +1,3 @@
|
|||||||
*.keystore
|
*.keystore
|
||||||
*.keystore.asc
|
_build
|
||||||
/*-keystore.conf
|
/*-keystore.conf
|
||||||
*.iml
|
|
||||||
.gradle
|
|
||||||
/local.properties
|
|
||||||
/.idea
|
|
||||||
.DS_Store
|
|
||||||
/captures
|
|
||||||
/build
|
|
||||||
# Directory _build is not used anymore
|
|
||||||
/_build
|
|
||||||
|
@@ -1,32 +1,18 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:hardwareAccelerated="false">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="juloo.keyboard2" android:versionCode="18" android:versionName="1.13.1" android:hardwareAccelerated="false">
|
||||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="30"/>
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
<application android:label="@string/app_name" android:allowBackup="true" android:icon="@drawable/ic_launcher" android:hardwareAccelerated="false">
|
||||||
|
<service android:name="juloo.keyboard2.Keyboard2" android:label="@string/app_name" android:permission="android.permission.BIND_INPUT_METHOD">
|
||||||
<application android:label="@string/app_name" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:hardwareAccelerated="false">
|
|
||||||
<service android:name="juloo.keyboard2.Keyboard2" android:label="@string/app_name" android:permission="android.permission.BIND_INPUT_METHOD" android:exported="true" android:directBootAware="true">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.view.InputMethod"/>
|
<action android:name="android.view.InputMethod"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<meta-data android:name="android.view.im" android:resource="@xml/method"/>
|
<meta-data android:name="android.view.im" android:resource="@xml/method"/>
|
||||||
</service>
|
</service>
|
||||||
<activity android:name="juloo.keyboard2.SettingsActivity" android:icon="@mipmap/ic_launcher" android:label="@string/settings_activity_label" android:theme="@style/appTheme" android:exported="true" android:directBootAware="true">
|
<activity android:name="juloo.keyboard2.SettingsActivity" android:icon="@drawable/ic_launcher" android:label="@string/settings_activity_label" android:theme="@style/android:Theme.Material">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name="juloo.keyboard2.LauncherActivity" android:icon="@mipmap/ic_launcher" android:theme="@style/appTheme" android:exported="true" android:directBootAware="true">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
</application>
|
</application>
|
||||||
|
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||||
<!-- To query enabled input methods for voice IME detection -->
|
|
||||||
<queries>
|
|
||||||
<intent>
|
|
||||||
<action android:name="android.view.InputMethod" />
|
|
||||||
</intent>
|
|
||||||
</queries>
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
186
CONTRIBUTING.md
@@ -4,60 +4,49 @@ Thanks for contributing :)
|
|||||||
|
|
||||||
## Building the app
|
## Building the app
|
||||||
|
|
||||||
The application uses Gradle and can be used with Android Studio, but using
|
The application doesn't use Gradle and it might be hard to use some features of
|
||||||
Android Studio is not required. The build dependencies are:
|
Android Studio.
|
||||||
- OpenJDK 17
|
|
||||||
|
Fortunately, there's not many dependencies:
|
||||||
|
- OpenJDK 8
|
||||||
- Android SDK: build tools (minimum `28.0.1`), platform `30`
|
- Android SDK: build tools (minimum `28.0.1`), platform `30`
|
||||||
|
- Make sure to have the `$ANDROID_HOME` environment variable set.
|
||||||
|
|
||||||
Python 3 is required to update generated files but not to build the app.
|
For Nix users, there's a `shell.nix` for setting-up the right environment.
|
||||||
|
|
||||||
For Android Studio users, no more setup is needed.
|
|
||||||
|
|
||||||
For Nix users, the right environment can be obtained with `nix-shell ./shell.nix`.
|
|
||||||
Instructions to install Nix are [here](https://wiki.nixos.org/wiki/Nix_Installation_Guide).
|
|
||||||
|
|
||||||
If you don't use Android Studio or Nix, you have to inform Gradle about the
|
|
||||||
location of your Android SDK by either:
|
|
||||||
- Setting the `ANDROID_HOME` environment variable to point to the android sdk or
|
|
||||||
- Creating the file `local.properties` and writing
|
|
||||||
`sdk.dir=<location_of_android_home>` into it.
|
|
||||||
|
|
||||||
Building the debug apk:
|
Building the debug apk:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
./gradlew assembleDebug
|
make
|
||||||
```
|
```
|
||||||
|
|
||||||
Nix users can call gradle directly: `gradle assembleDebug`.
|
If the build succeed, the debug apk is located in
|
||||||
|
`_build/juloo.keyboard2.debug.apk`.
|
||||||
If the build succeeds, the debug apk is located in `build/outputs/apk/debug/app-debug.apk`.
|
|
||||||
|
|
||||||
## Debugging on your phone
|
## Debugging on your phone
|
||||||
|
|
||||||
First [Enable adb debugging on your device](https://developer.android.com/studio/command-line/adb#Enabling).
|
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 via wireless
|
Then connect your phone to your computer using an USB cable or wireless
|
||||||
debugging.
|
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:
|
And finally, install the application with:
|
||||||
```sh
|
```sh
|
||||||
./gradlew installDebug
|
make installd
|
||||||
```
|
```
|
||||||
|
|
||||||
The released version of the application won't be removed, both versions will
|
The debug version of the application won't be removed, both versions will stay
|
||||||
be installed at the same time.
|
installed at the same time.
|
||||||
|
|
||||||
|
The application must be enabled in the settings:
|
||||||
|
System > Languages & input > On-screen keyboard > Manage on-screen keyboards.
|
||||||
|
|
||||||
## Debugging the application: INSTALL_FAILED_UPDATE_INCOMPATIBLE
|
## Debugging the application: INSTALL_FAILED_UPDATE_INCOMPATIBLE
|
||||||
|
|
||||||
`./gradlew installDebug` can fail with the following error message:
|
`make installd` can fail with the following error message:
|
||||||
|
|
||||||
```
|
```
|
||||||
FAILURE: Build failed with an exception.
|
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!]
|
||||||
* What went wrong:
|
make: *** [Makefile:20: installd] Error 1
|
||||||
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
|
The application can't be "updated" because the temporary certificate has been
|
||||||
@@ -66,136 +55,31 @@ The application must be enabled again in the settings.
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
adb uninstall juloo.keyboard2.debug
|
adb uninstall juloo.keyboard2.debug
|
||||||
./gradlew installDebug
|
make installd
|
||||||
```
|
```
|
||||||
|
|
||||||
## 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
|
|
||||||
version of it:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
gpg -c --armor --pinentry-mode loopback --passphrase debug0 --yes "debug.keystore"
|
|
||||||
```
|
|
||||||
|
|
||||||
This will create the file `debug.keystore.asc`, paste its content into a new
|
|
||||||
Github secret named `DEBUG_KEYSTORE`.
|
|
||||||
|
|
||||||
## Guidelines
|
## Guidelines
|
||||||
|
|
||||||
### Adding a layout
|
### Add a localized layout
|
||||||
|
|
||||||
Layouts are defined in XML, see `srcs/layouts/latn_qwerty_us.xml`.
|
Localized layouts (a layout specific to a language) are generally accepted.
|
||||||
An online tool for editing layout files written by @Lixquid is available
|
|
||||||
[here](https://unexpected-keyboard-layout-editor.lixquid.com/).
|
|
||||||
|
|
||||||
Makes sure to specify the `name` attribute like in `latn_qwerty_us.xml`,
|
|
||||||
otherwise the layout won't be added to the app.
|
|
||||||
|
|
||||||
The layout file must be placed in the `srcs/layouts` directory and named
|
|
||||||
according to:
|
|
||||||
- script (`latn` for latin, etc..)
|
|
||||||
- layout name (eg. the name of a standard)
|
|
||||||
- country code (or language code if more adequate)
|
|
||||||
|
|
||||||
Then, run `./gradlew genLayoutsList` to add the layout to the app.
|
|
||||||
|
|
||||||
The last step will update the file `res/values/layouts.xml`, that you should
|
|
||||||
not edit directly.
|
|
||||||
|
|
||||||
Run `./gradlew checkKeyboardLayouts` to check some properties about your
|
|
||||||
layout. This will change the file `check_layout.output`, which you should
|
|
||||||
commit.
|
|
||||||
|
|
||||||
Layouts are CC0 licensed by default. If you do not want your layout to be
|
|
||||||
released into the public domain, add a copyright notice at the top of the file
|
|
||||||
and a mention in `srcs/layouts/LICENSE`.
|
|
||||||
|
|
||||||
#### Adding a programming layout
|
|
||||||
|
|
||||||
A programming layout must contain all ASCII characters.
|
|
||||||
The current programming layouts are: QWERTY, Dvorak and Colemak.
|
|
||||||
|
|
||||||
See for example, Dvorak, added in https://github.com/Julow/Unexpected-Keyboard/pull/16
|
|
||||||
|
|
||||||
It's best to leave free spots on the layout for language-specific symbols that
|
|
||||||
are added automatically when necessary.
|
|
||||||
These symbols are defined in `res/xml/method.xml` (`extra_keys`).
|
|
||||||
|
|
||||||
It's possible to place extra keys with the `loc` prefix. These keys are
|
|
||||||
normally hidden unless they are needed.
|
|
||||||
|
|
||||||
Some users cannot easily type the characters close the the edges of the screen
|
|
||||||
due to a bulky phone case. It is best to avoid placing important characters
|
|
||||||
there (such as the digits or punctuation).
|
|
||||||
|
|
||||||
#### Adding a localized layout
|
|
||||||
|
|
||||||
Localized layouts (a layout specific to a language) are gladly accepted.
|
|
||||||
See for example: 4333575 (Bulgarian), 88e2175 (Latvian), 133b6ec (German).
|
See for example: 4333575 (Bulgarian), 88e2175 (Latvian), 133b6ec (German).
|
||||||
|
|
||||||
They don't need to contain every ASCII characters (although it's useful in
|
This keyboard is intended for programmers. If your language uses the Latin script, make sure it is possible to type every letters on the QWERTY keyboard.
|
||||||
passwords) and dead-keys.
|
This is generally done using dead-keys, for example: 0bf7ff5 (Latvian), 573c13f (Swedish).
|
||||||
|
It is also possible to add some characters that are hidden in other languages, for example 93e84ba (ß), though the space is limited.
|
||||||
|
|
||||||
### Adding support for a language
|
### Add a programming layout
|
||||||
|
|
||||||
Supported locales are defined in `res/xml/method.xml`.
|
A programming layout must contains every ASCII characters as well as every dead-keys.
|
||||||
|
Currently, the only example is QWERTY.
|
||||||
|
|
||||||
The attributes `languageTag` and `imeSubtypeLocale` define a locale, the
|
### Translations
|
||||||
attribute `imeSubtypeExtraValue` defines the default layout and the dead-keys
|
|
||||||
and other extra keys to show.
|
|
||||||
|
|
||||||
The list of language tags (generally two letters)
|
Translations are always welcome ! See for example: 1723288 (Latvian), baf867a (French).
|
||||||
and locales (generally of the form `xx_XX`)
|
The app can be translated by writing `res/values-<language code>/strings.xml` (for example `values-fr`, `values-lv`), based on the default: `res/values/strings.xml` (English).
|
||||||
can be found in this [stackoverflow answer](https://stackoverflow.com/a/7989085)
|
|
||||||
|
|
||||||
### Updating translations
|
The store description is found in `metadata/android/<locale>/`, `short_description.txt` and `full_description.txt`.
|
||||||
|
The full description changes very infrequently (it was changed once in 6 years). But if it changes too much, outdated translation might be removed.
|
||||||
|
|
||||||
The text used in the app is written in `res/values-<language_tag>/strings.xml`.
|
Translating changelogs is not useful because they evolve too fast. Changelogs are generally written entirely just before a release, translating them would delay releases too much. Old changelogs are not shown to anyone currently.
|
||||||
|
|
||||||
The list of language tags can be found in this
|
|
||||||
[stackoverflow answer](https://stackoverflow.com/a/7989085)
|
|
||||||
|
|
||||||
The first part before the `_` is used, for example,
|
|
||||||
`res/values-fr/strings.xml` for French,
|
|
||||||
`res/values-lv/strings.xml` for Latvian.
|
|
||||||
|
|
||||||
Commented-out lines indicate missing translations:
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<!-- <string name="pref_layouts_add">Add an alternate layout</string> -->
|
|
||||||
```
|
|
||||||
|
|
||||||
Remove the `<!--` and `-->` parts and change the text.
|
|
||||||
|
|
||||||
### Adding a translation
|
|
||||||
|
|
||||||
The `res/values-<language_tag>/strings.xml` file must be created by copying the
|
|
||||||
default translation in `res/values/strings.xml`, which contain the structure of
|
|
||||||
the file and the English strings.
|
|
||||||
|
|
||||||
To check that `strings.xml` is formatted correctly, run
|
|
||||||
`python sync_translations.py`. This will modify your files.
|
|
||||||
|
|
||||||
Store descriptions in `fastlane/metadata/android/` are updated automatically.
|
|
||||||
Translating changelogs is not useful.
|
|
||||||
|
|
||||||
The app name might be partially translated, the "Unexpected" word should remain
|
|
||||||
untranslated if possible.
|
|
||||||
|
|
||||||
As translations need to be updated regularly, you can subscribe to this issue
|
|
||||||
to receive a notification when an update is needed:
|
|
||||||
https://github.com/Julow/Unexpected-Keyboard/issues/373
|
|
||||||
|
|
||||||
### Adding key combinations
|
|
||||||
|
|
||||||
Key combinations are defined in `srcs/juloo.keyboard2/KeyModifier.java`.
|
|
||||||
For example, keys modified by the `Fn` key are defined in method
|
|
||||||
`apply_fn_char`.
|
|
||||||
|
|
||||||
Keys with special meaning are defined in `KeyValue.java` in method
|
|
||||||
`getKeyByName`. Their special action are defined in `KeyEventHandler.java` in
|
|
||||||
method `key_up`
|
|
||||||
|
@@ -1,3 +0,0 @@
|
|||||||
github: [ Julow ]
|
|
||||||
liberapay: Julow
|
|
||||||
custom: [ "https://paypal.me/JulesAguillon" ]
|
|
112
Makefile
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
# Configuration
|
||||||
|
|
||||||
|
PACKAGE_NAME = juloo.keyboard2
|
||||||
|
|
||||||
|
ANDROID_PLATFORM_VERSION = android-30
|
||||||
|
JAVA_VERSION = 1.8
|
||||||
|
|
||||||
|
SRC_DIR = srcs
|
||||||
|
ASSETS_DIR = assets
|
||||||
|
RES_DIR = res
|
||||||
|
|
||||||
|
EXTRA_JARS =
|
||||||
|
|
||||||
|
# /
|
||||||
|
|
||||||
|
debug: _build/$(PACKAGE_NAME).debug.apk
|
||||||
|
release: _build/$(PACKAGE_NAME).apk
|
||||||
|
|
||||||
|
installd: _build/$(PACKAGE_NAME).debug.apk
|
||||||
|
adb install "$<"
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf _build/*.dex _build/class _build/gen _build/*.apk _build/*.unsigned-apk \
|
||||||
|
_build/*.idsig
|
||||||
|
|
||||||
|
.PHONY: release debug installd clean
|
||||||
|
|
||||||
|
$(shell mkdir -p _build)
|
||||||
|
|
||||||
|
ifndef ANDROID_HOME
|
||||||
|
$(error ANDROID_HOME not set)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ANDROID_BUILD_TOOLS = $(lastword $(sort $(wildcard $(ANDROID_HOME)/build-tools/*)))
|
||||||
|
ANDROID_PLATFORM = $(ANDROID_HOME)/platforms/$(ANDROID_PLATFORM_VERSION)
|
||||||
|
|
||||||
|
ifeq ($(shell [ -d "$(ANDROID_PLATFORM)" ] && echo ok),)
|
||||||
|
$(error Android platform not found. Want $(ANDROID_PLATFORM_VERSION), \
|
||||||
|
found $(notdir $(wildcard $(ANDROID_HOME)/platforms/*)))
|
||||||
|
endif
|
||||||
|
|
||||||
|
JAVAC_FLAGS = -source $(JAVA_VERSION) -target $(JAVA_VERSION) -encoding utf8
|
||||||
|
|
||||||
|
# Source files
|
||||||
|
|
||||||
|
MANIFEST_FILE = AndroidManifest.xml
|
||||||
|
JAVA_FILES = $(shell find $(SRC_DIR) -name '*.java')
|
||||||
|
RES_FILES = $(shell find $(RES_DIR) -type f)
|
||||||
|
ASSETS_FILES = $(shell find $(ASSETS_DIR) -type f 2>/dev/null)
|
||||||
|
|
||||||
|
# Debug signing
|
||||||
|
|
||||||
|
DEBUG_KEYSTORE = _build/debug.keystore
|
||||||
|
DEBUG_PASSWD = debug0
|
||||||
|
|
||||||
|
$(DEBUG_KEYSTORE):
|
||||||
|
echo y | keytool -genkeypair -dname "cn=d, ou=e, o=b, c=ug" \
|
||||||
|
-alias debug -keypass $(DEBUG_PASSWD) -keystore "$@" \
|
||||||
|
-keyalg rsa -storepass $(DEBUG_PASSWD) -validity 10000
|
||||||
|
|
||||||
|
_build/%.debug.apk: _build/%.debug.unsigned-apk $(DEBUG_KEYSTORE)
|
||||||
|
$(ANDROID_BUILD_TOOLS)/apksigner sign --in "$<" --out "$@" \
|
||||||
|
--ks $(DEBUG_KEYSTORE) --ks-key-alias debug --ks-pass "pass:$(DEBUG_PASSWD)"
|
||||||
|
|
||||||
|
# Debug apk
|
||||||
|
|
||||||
|
_build/$(PACKAGE_NAME).debug.unsigned-apk: AAPT_PACKAGE_FLAGS+=--rename-manifest-package $(PACKAGE_NAME).debug --product debug
|
||||||
|
|
||||||
|
# Release signing
|
||||||
|
|
||||||
|
# %-keystore.conf should declare KEYSTORE, KEYNAME and KEYSTOREPASS
|
||||||
|
# it is interpreted as a shell script
|
||||||
|
_build/%.apk: _build/%.unsigned-apk %-keystore.conf
|
||||||
|
eval `cat $(word 2,$^)` && \
|
||||||
|
$(ANDROID_BUILD_TOOLS)/apksigner sign --in "$<" --out "$@" \
|
||||||
|
--ks "$$KEYSTORE" --ks-key-alias "$$KEYNAME" --ks-pass "pass:$$KEYSTOREPASS"
|
||||||
|
|
||||||
|
# Package
|
||||||
|
|
||||||
|
_build/%.unsigned-apk: _build/%.unaligned-apk
|
||||||
|
$(ANDROID_BUILD_TOOLS)/zipalign -fp 4 "$<" "$@"
|
||||||
|
|
||||||
|
_build/%.unaligned-apk: _build/classes.dex $(MANIFEST_FILE) $(ASSETS_FILES)
|
||||||
|
$(ANDROID_BUILD_TOOLS)/aapt package -f -M $(MANIFEST_FILE) -S $(RES_DIR) \
|
||||||
|
-I $(ANDROID_PLATFORM)/android.jar -F "$@" $(AAPT_PACKAGE_FLAGS)
|
||||||
|
[ -z "$(ASSETS_FILES)" ] || $(ANDROID_BUILD_TOOLS)/aapt add "$@" $(ASSETS_FILES)
|
||||||
|
cd $(@D) && $(ANDROID_BUILD_TOOLS)/aapt add $(@F) classes.dex
|
||||||
|
|
||||||
|
# R.java
|
||||||
|
|
||||||
|
GEN_DIR = _build/gen
|
||||||
|
R_FILE = $(GEN_DIR)/$(subst .,/,$(PACKAGE_NAME))/R.java
|
||||||
|
|
||||||
|
$(R_FILE): $(RES_FILES) $(MANIFEST_FILE)
|
||||||
|
mkdir -p "$(@D)"
|
||||||
|
$(ANDROID_BUILD_TOOLS)/aapt package -f -m -S $(RES_DIR) -J $(GEN_DIR) \
|
||||||
|
-M $(MANIFEST_FILE) -I $(ANDROID_PLATFORM)/android.jar
|
||||||
|
|
||||||
|
# Compile java classes and build classes.dex
|
||||||
|
|
||||||
|
OBJ_DIR = _build/class
|
||||||
|
# A$B.class files are ignored
|
||||||
|
# CLASS_FILES = $(JAVA_FILES:$(SRC_DIR)/%.java=$(OBJ_DIR)/%.class) \
|
||||||
|
# $(R_FILE:$(GEN_DIR)/%.java=$(OBJ_DIR)/%.class)
|
||||||
|
|
||||||
|
_build/classes.dex: $(JAVA_FILES) $(R_FILE)
|
||||||
|
mkdir -p $(OBJ_DIR)
|
||||||
|
javac -d $(OBJ_DIR) $(JAVAC_FLAGS) \
|
||||||
|
-classpath $(ANDROID_PLATFORM)/android.jar:$(EXTRA_JARS) \
|
||||||
|
-sourcepath $(SRC_DIR):$(GEN_DIR) \
|
||||||
|
$^
|
||||||
|
$(ANDROID_BUILD_TOOLS)/d8 --output $(@D) $(OBJ_DIR)/*/*/* $(subst :, ,$(EXTRA_JARS))
|
43
README.md
@@ -1,5 +1,28 @@
|
|||||||
# Unexpected Keyboard
|
# Unexpected Keyboard
|
||||||
|
|
||||||
|
A lightweight virtual keyboard for developers.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
This app is a virtual keyboard for Android. The main features are easy typing of every ASCII character using the swipe gesture, dead keys for accents and modifier keys and the presence of special keys (tab, esc, arrows, etc..).
|
||||||
|
|
||||||
|
The keyboard shows up to 4 extra characters in the corners of each key. These extra characters are hit by swiping the finger on the key.
|
||||||
|
|
||||||
|
Highlight of some of the features:
|
||||||
|
|
||||||
|
- Every character and special keys that are also available on a PC keyboard. This is perfect for using applications like Termux.
|
||||||
|
|
||||||
|
- This includes Tab, Esc, the arrows and function keys, but also Ctrl and Alt !
|
||||||
|
|
||||||
|
- Accented keys are accessible using dead keys. First activate the accent, then type the accented letter.
|
||||||
|
|
||||||
|
- Very light and fast. Use 500x times less space than Google's keyboard and 15x times less than the default keyboard. No ad, no tracking.
|
||||||
|
|
||||||
|
- Multiple layouts: QWERTY, QWERTZ, AZERTY. Themes: White, Dark, OLED Black. And many other options.
|
||||||
|
|
||||||
|
Like any other virtual keyboards, it must be enabled in the system settings. Open the System Settings and go to:
|
||||||
|
System > Languages & input > On-screen keyboard > Manage on-screen keyboards.
|
||||||
|
|
||||||
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||||
alt="Get it on F-Droid"
|
alt="Get it on F-Droid"
|
||||||
height="80">](https://f-droid.org/packages/juloo.keyboard2/)
|
height="80">](https://f-droid.org/packages/juloo.keyboard2/)
|
||||||
@@ -7,26 +30,6 @@
|
|||||||
alt="Get it on Google Play"
|
alt="Get it on Google Play"
|
||||||
height="80">](https://play.google.com/store/apps/details?id=juloo.keyboard2)
|
height="80">](https://play.google.com/store/apps/details?id=juloo.keyboard2)
|
||||||
|
|
||||||
Lightweight and privacy-conscious virtual keyboard for Android.
|
|
||||||
|
|
||||||
https://github.com/Julow/Unexpected-Keyboard/assets/2310568/28f8f6fe-ac13-46f3-8c5e-d62443e16d0d
|
|
||||||
|
|
||||||
The main feature is that you can type more characters by swiping the keys towards the corners.
|
|
||||||
|
|
||||||
This application was originally designed for programmers using Termux.
|
|
||||||
Now perfect for everyday use.
|
|
||||||
|
|
||||||
This application contains no ads, doesn't make any network requests and is Open Source.
|
|
||||||
|
|
||||||
Usage: to apply the symbols located in the corners of each key, slide your finger in the direction of the symbols. For example, the Settings are opened by sliding in the left down corner.
|
|
||||||
|
|
||||||
| <img src="/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png" alt="Screenshot-1" /> | <img src="/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png" alt="Screenshot-2"/> | <img src="/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png" alt="Screenshot-3"/> |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| <img src="/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png" alt="Screenshot-4" /> | <img src="/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png" alt="Screenshot-5" /> | <img src="/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png" alt="Screenshot-6" /> |
|
|
||||||
|
|
||||||
## Similar apps
|
|
||||||
* [Calculator++](https://github.com/Bubu/android-calculatorpp) - Calculator with a similar UX, swipe to corners for advanced math symbols and operators. Works up to Android 13 but maybe unmaintained.
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
For instructions on building the application, see
|
For instructions on building the application, see
|
||||||
|
15
assets/fonts/README.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Fonts
|
||||||
|
|
||||||
|
The glyphs from this font are made by:
|
||||||
|
|
||||||
|
- Home and End
|
||||||
|
Author: @sdrapha
|
||||||
|
|
||||||
|
- Cog
|
||||||
|
Copyright (C) 2016 by Dave Gandy
|
||||||
|
Author: Dave Gandy
|
||||||
|
License: SIL ()
|
||||||
|
|
||||||
|
- Emoticon, PageUp and PageDown
|
||||||
|
IcoMoon-Free is a free vector icon pack by Keyamoon.
|
||||||
|
License: Attribution 4.0 International (CC BY 4.0)
|
BIN
assets/fonts/keys.ttf
Normal file
194
build.gradle
@@ -1,194 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id 'com.android.application' version '8.1.1'
|
|
||||||
}
|
|
||||||
|
|
||||||
android {
|
|
||||||
namespace 'juloo.keyboard2'
|
|
||||||
compileSdk 34
|
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
applicationId "juloo.keyboard2"
|
|
||||||
minSdk 11
|
|
||||||
targetSdkVersion 34
|
|
||||||
versionCode 40
|
|
||||||
versionName "1.28.0"
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
main {
|
|
||||||
manifest.srcFile 'AndroidManifest.xml'
|
|
||||||
java.srcDirs = ['srcs']
|
|
||||||
res.srcDirs = ['res', 'build/generated-resources']
|
|
||||||
assets.srcDirs = ['assets']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
signingConfigs {
|
|
||||||
// Debug builds will always be signed. If no environment variables are set, a default
|
|
||||||
// keystore will be initialized by the task initDebugKeystore and used. This keystore
|
|
||||||
// can be uploaded to GitHub secrets by following instructions in CONTRIBUTING.md
|
|
||||||
// in order to always receive correctly signed debug APKs from the CI.
|
|
||||||
debug {
|
|
||||||
storeFile(System.env.DEBUG_KEYSTORE ? file(System.env.DEBUG_KEYSTORE) : file("debug.keystore"))
|
|
||||||
storePassword(System.env.DEBUG_KEYSTORE_PASSWORD ? "$System.env.DEBUG_KEYSTORE_PASSWORD" : "debug0")
|
|
||||||
keyAlias(System.env.DEBUG_KEY_ALIAS ? "$System.env.DEBUG_KEY_ALIAS" : "debug")
|
|
||||||
keyPassword(System.env.DEBUG_KEY_PASSWORD ? "$System.env.DEBUG_KEY_PASSWORD" : "debug0")
|
|
||||||
}
|
|
||||||
|
|
||||||
release {
|
|
||||||
if (System.env.RELEASE_KEYSTORE) {
|
|
||||||
storeFile file(System.env.RELEASE_KEYSTORE)
|
|
||||||
storePassword "$System.env.RELEASE_KEYSTORE_PASSWORD"
|
|
||||||
keyAlias "$System.env.RELEASE_KEY_ALIAS"
|
|
||||||
keyPassword "$System.env.RELEASE_KEY_PASSWORD"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buildTypes {
|
|
||||||
release {
|
|
||||||
minifyEnabled true
|
|
||||||
shrinkResources true
|
|
||||||
debuggable false
|
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
|
|
||||||
resValue "string", "app_name", "@string/app_name_release"
|
|
||||||
signingConfig signingConfigs.release
|
|
||||||
}
|
|
||||||
|
|
||||||
debug {
|
|
||||||
minifyEnabled false
|
|
||||||
shrinkResources false
|
|
||||||
debuggable true
|
|
||||||
applicationIdSuffix ".debug"
|
|
||||||
resValue "string", "app_name", "@string/app_name_debug"
|
|
||||||
resValue "bool", "debug_logs", "true"
|
|
||||||
signingConfig signingConfigs.debug
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name outputs after the application ID.
|
|
||||||
android.applicationVariants.all { variant ->
|
|
||||||
variant.outputs.all {
|
|
||||||
outputFileName = "${applicationId}.apk"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility JavaVersion.VERSION_1_7
|
|
||||||
targetCompatibility JavaVersion.VERSION_1_7
|
|
||||||
}
|
|
||||||
|
|
||||||
lintOptions {
|
|
||||||
// Translation are already checked by 'syncTranslations'
|
|
||||||
disable 'MissingTranslation'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('buildKeyboardFont') {
|
|
||||||
println "\nBuilding assets/special_font.ttf"
|
|
||||||
mkdir "$buildDir"
|
|
||||||
exec {
|
|
||||||
workingDir "$projectDir/srcs/special_font"
|
|
||||||
def svgFiles = workingDir.listFiles().findAll {
|
|
||||||
it.isFile() && it.name.endsWith(".svg")
|
|
||||||
}
|
|
||||||
commandLine("fontforge", "-lang=ff", "-script", "build.pe", "$buildDir/special_font.ttf", *svgFiles)
|
|
||||||
}
|
|
||||||
copy {
|
|
||||||
from "$buildDir/special_font.ttf"
|
|
||||||
into "assets"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('genEmojis') {
|
|
||||||
println "\nGenerating res/raw/emojis.txt"
|
|
||||||
exec {
|
|
||||||
workingDir = projectDir
|
|
||||||
commandLine "python", "gen_emoji.py"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(Test).configureEach {
|
|
||||||
dependsOn 'genLayoutsList'
|
|
||||||
dependsOn 'checkKeyboardLayouts'
|
|
||||||
dependsOn 'syncTranslations'
|
|
||||||
dependsOn 'compileComposeSequences'
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('genLayoutsList') {
|
|
||||||
println "\nGenerating res/values/layouts.xml"
|
|
||||||
exec {
|
|
||||||
workingDir = projectDir
|
|
||||||
commandLine "python", "gen_layouts.py"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('checkKeyboardLayouts') {
|
|
||||||
println "\nChecking layouts"
|
|
||||||
exec {
|
|
||||||
def layouts = new File(projectDir, "srcs/layouts").listFiles().findAll {
|
|
||||||
it.name.endsWith(".xml")
|
|
||||||
}
|
|
||||||
workingDir = projectDir
|
|
||||||
commandLine("python", "check_layout.py", *layouts)
|
|
||||||
standardOutput = new FileOutputStream("${projectDir}/check_layout.output")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('syncTranslations') {
|
|
||||||
println "\nUpdating translations"
|
|
||||||
exec {
|
|
||||||
workingDir = projectDir
|
|
||||||
commandLine "python", "sync_translations.py"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('compileComposeSequences') {
|
|
||||||
def out = "srcs/juloo.keyboard2/ComposeKeyData.java"
|
|
||||||
println "\nGenerating ${out}"
|
|
||||||
exec {
|
|
||||||
def sequences = new File(projectDir, "srcs/compose").listFiles().findAll {
|
|
||||||
it.name.endsWith(".pre") || it.name.endsWith(".json")
|
|
||||||
}
|
|
||||||
workingDir = projectDir
|
|
||||||
commandLine("python", "srcs/compose/compile.py", *sequences)
|
|
||||||
standardOutput = new FileOutputStream("${projectDir}/${out}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.named("preBuild") {
|
|
||||||
dependsOn += "initDebugKeystore"
|
|
||||||
dependsOn += "copyRawQwertyUS"
|
|
||||||
dependsOn += "copyLayoutDefinitions"
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('initDebugKeystore') {
|
|
||||||
if (!file("debug.keystore").exists()) {
|
|
||||||
println "Initializing default debug keystore"
|
|
||||||
exec {
|
|
||||||
// A shell script might be needed if this line requires input from the user
|
|
||||||
commandLine "keytool", "-genkeypair", "-dname", "cn=d, ou=e, o=b, c=ug", "-alias", "debug", "-keypass", "debug0", "-keystore", "debug.keystore", "-keyalg", "rsa", "-storepass", "debug0", "-validity", "10000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// latn_qwerty_us is used as a raw resource by the custom layout option.
|
|
||||||
tasks.register('copyRawQwertyUS')
|
|
||||||
{
|
|
||||||
copy {
|
|
||||||
from "srcs/layouts/latn_qwerty_us.xml"
|
|
||||||
into "build/generated-resources/raw"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('copyLayoutDefinitions')
|
|
||||||
{
|
|
||||||
copy {
|
|
||||||
from "srcs/layouts"
|
|
||||||
include "*.xml"
|
|
||||||
into "build/generated-resources/xml"
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,133 +0,0 @@
|
|||||||
# arab_alt
|
|
||||||
Layout includes some ASCII punctuation but not all, missing: !, ", ', +, -, /, :, ;, <, =, >, ?, [, \, ], _, |, ~
|
|
||||||
1 warnings
|
|
||||||
# arab_hamvaj_tly
|
|
||||||
Layout includes some ASCII punctuation but not all, missing: ", %, ', ,, /, ;, <, =, >, ?, [, \, ], _, `, {, |, }
|
|
||||||
Layout doesn't define some important keys, missing: loc esc
|
|
||||||
2 warnings
|
|
||||||
# arab_pc
|
|
||||||
Layout includes some ASCII punctuation but not all, missing: !, ', +, ;, ?, \, |
|
|
||||||
1 warnings
|
|
||||||
# arab_pc_ckb
|
|
||||||
Layout includes some ASCII punctuation but not all, missing: ", %, ', +, ,, ., :, ;, <, =, >, ?, `, |, ~
|
|
||||||
1 warnings
|
|
||||||
# arab_pc_hindu
|
|
||||||
Layout includes some ASCII punctuation but not all, missing: !, ', +, ;, ?, \, |
|
|
||||||
1 warnings
|
|
||||||
# arab_pc_ir
|
|
||||||
Layout includes some ASCII punctuation but not all, missing: ", %, ', ,, /, ;, <, =, >, ?, [, \, ], `, {, |, }
|
|
||||||
1 warnings
|
|
||||||
# armenian_ph_am
|
|
||||||
0 warnings
|
|
||||||
# beng_national
|
|
||||||
Layout includes some ASCII punctuation but not all, missing: $
|
|
||||||
1 warnings
|
|
||||||
# beng_provat
|
|
||||||
Layout includes some ASCII punctuation but not all, missing: $, &, *, ., /, <, >, [, \, ], `, {, |, }
|
|
||||||
1 warnings
|
|
||||||
# cyrl_jcuken_ru
|
|
||||||
0 warnings
|
|
||||||
# cyrl_jcuken_uk
|
|
||||||
0 warnings
|
|
||||||
# cyrl_ueishsht
|
|
||||||
0 warnings
|
|
||||||
# cyrl_yaverti
|
|
||||||
Layout includes some ASCII punctuation but not all, missing: ~
|
|
||||||
1 warnings
|
|
||||||
# deva_alt
|
|
||||||
Layout includes some ASCII punctuation but not all, missing: #, $, %, &, ', (, ), +, ., /, :, <, =, >, [, \, ], ^, _, `, {, |, }, ~
|
|
||||||
Layout doesn't define some important keys, missing: loc esc, loc tab
|
|
||||||
2 warnings
|
|
||||||
# deva_inscript
|
|
||||||
Duplicate keys: ।
|
|
||||||
Layout includes some ASCII punctuation but not all, missing: ", $, ', ^, _, `, |
|
|
||||||
2 warnings
|
|
||||||
# grek_qwerty
|
|
||||||
Duplicate keys: ;
|
|
||||||
1 warnings
|
|
||||||
# guj_phonetic_in
|
|
||||||
Duplicate keys: ટ, ડ
|
|
||||||
1 warnings
|
|
||||||
# hang_dubeolsik_kr
|
|
||||||
Layout doesn't define some important keys, missing: loc esc, loc tab
|
|
||||||
1 warnings
|
|
||||||
# hebr_1_il
|
|
||||||
Layout includes some ASCII punctuation but not all, missing: (, ), <, >, [, ], {, }
|
|
||||||
1 warnings
|
|
||||||
# hebr_2_il
|
|
||||||
Layout includes some ASCII punctuation but not all, missing: (, ), <, >, [, ], {, }
|
|
||||||
1 warnings
|
|
||||||
# latn_azerty_fr
|
|
||||||
0 warnings
|
|
||||||
# latn_bepo_fr
|
|
||||||
0 warnings
|
|
||||||
# latn_bone
|
|
||||||
Layout includes some ASCII punctuation but not all, missing: $
|
|
||||||
Layout redefines the bottom row but some important keys are missing, missing: cursor_left, cursor_right, loc compose, loc end, loc home, loc page_down, loc page_up, loc switch_clipboard, loc switch_greekmath, loc voice_typing, switch_backward
|
|
||||||
2 warnings
|
|
||||||
# latn_colemak
|
|
||||||
Some keys contain whitespaces, unexpected: ́
|
|
||||||
1 warnings
|
|
||||||
# latn_dvorak
|
|
||||||
0 warnings
|
|
||||||
# latn_neo2
|
|
||||||
Layout redefines the bottom row but some important keys are missing, missing: loc switch_clipboard
|
|
||||||
1 warnings
|
|
||||||
# latn_qwerty_br
|
|
||||||
0 warnings
|
|
||||||
# latn_qwerty_cz
|
|
||||||
0 warnings
|
|
||||||
# latn_qwerty_da
|
|
||||||
0 warnings
|
|
||||||
# latn_qwerty_es
|
|
||||||
0 warnings
|
|
||||||
# latn_qwerty_gb
|
|
||||||
0 warnings
|
|
||||||
# latn_qwerty_hu
|
|
||||||
0 warnings
|
|
||||||
# latn_qwerty_lv
|
|
||||||
0 warnings
|
|
||||||
# latn_qwerty_no
|
|
||||||
0 warnings
|
|
||||||
# latn_qwerty_pl
|
|
||||||
0 warnings
|
|
||||||
# latn_qwerty_ro
|
|
||||||
0 warnings
|
|
||||||
# latn_qwerty_se
|
|
||||||
Duplicate keys: !, ', ,, -, ., ?
|
|
||||||
1 warnings
|
|
||||||
# latn_qwerty_sk
|
|
||||||
0 warnings
|
|
||||||
# latn_qwerty_tly
|
|
||||||
Duplicate keys: a, c, j, q
|
|
||||||
Layout doesn't define some important keys, missing: loc esc, loc tab
|
|
||||||
2 warnings
|
|
||||||
# latn_qwerty_tr
|
|
||||||
0 warnings
|
|
||||||
# latn_qwerty_us
|
|
||||||
0 warnings
|
|
||||||
# latn_qwerty_vi
|
|
||||||
0 warnings
|
|
||||||
# latn_qwertz
|
|
||||||
0 warnings
|
|
||||||
# latn_qwertz_cz
|
|
||||||
0 warnings
|
|
||||||
# latn_qwertz_cz_multifunctional
|
|
||||||
Layout includes some ASCII punctuation but not all, missing: `
|
|
||||||
1 warnings
|
|
||||||
# latn_qwertz_de
|
|
||||||
0 warnings
|
|
||||||
# latn_qwertz_fr_ch
|
|
||||||
0 warnings
|
|
||||||
# latn_qwertz_hu
|
|
||||||
0 warnings
|
|
||||||
# latn_qwertz_sk
|
|
||||||
Layout includes some ASCII punctuation but not all, missing: `
|
|
||||||
1 warnings
|
|
||||||
# shaw_imperial_en
|
|
||||||
0 warnings
|
|
||||||
# urdu_phonetic_ur
|
|
||||||
Duplicate keys:
|
|
||||||
Layout includes some ASCII punctuation but not all, missing: <, >, ?, `, |, ~
|
|
||||||
Some keys contain whitespaces, unexpected:
|
|
||||||
3 warnings
|
|
110
check_layout.py
@@ -1,110 +0,0 @@
|
|||||||
import xml.etree.ElementTree as ET
|
|
||||||
import sys, os
|
|
||||||
|
|
||||||
warning_count = 0
|
|
||||||
|
|
||||||
KNOWN_NOT_LAYOUT = set([
|
|
||||||
"number_row", "numpad", "pin",
|
|
||||||
"bottom_row", "settings", "method",
|
|
||||||
"greekmath", "numeric", "emoji_bottom_row",
|
|
||||||
"clipboard_bottom_row" ])
|
|
||||||
|
|
||||||
def warn(msg):
|
|
||||||
global warning_count
|
|
||||||
print(msg)
|
|
||||||
warning_count += 1
|
|
||||||
|
|
||||||
def key_list_str(keys):
|
|
||||||
return ", ".join(sorted(list(keys)))
|
|
||||||
|
|
||||||
def missing_some_of(keys, symbols, class_name=None):
|
|
||||||
if class_name is None:
|
|
||||||
class_name = "of [" + ", ".join(symbols) + "]"
|
|
||||||
missing = set(symbols).difference(keys)
|
|
||||||
if len(missing) > 0 and len(missing) != len(symbols):
|
|
||||||
warn("Layout includes some %s but not all, missing: %s" % (
|
|
||||||
class_name, key_list_str(missing)))
|
|
||||||
|
|
||||||
def missing_required(keys, symbols, msg):
|
|
||||||
missing = set(symbols).difference(keys)
|
|
||||||
if len(missing) > 0:
|
|
||||||
warn("%s, missing: %s" % (msg, key_list_str(missing)))
|
|
||||||
|
|
||||||
def unexpected_keys(keys, symbols, msg):
|
|
||||||
unexpected = set(symbols).intersection(keys)
|
|
||||||
if len(unexpected) > 0:
|
|
||||||
warn("%s, unexpected: %s" % (msg, key_list_str(unexpected)))
|
|
||||||
|
|
||||||
# Write to [keys] and [dup].
|
|
||||||
def parse_row_from_et(row, keys, dup):
|
|
||||||
for key in row:
|
|
||||||
for attr in key.keys():
|
|
||||||
if attr.startswith("key"):
|
|
||||||
k = key.get(attr).removeprefix("\\")
|
|
||||||
if k in keys: dup.add(k)
|
|
||||||
keys.add(k)
|
|
||||||
|
|
||||||
def parse_layout(fname):
|
|
||||||
keys = set()
|
|
||||||
dup = set()
|
|
||||||
root = ET.parse(fname).getroot()
|
|
||||||
if root.tag != "keyboard":
|
|
||||||
return None
|
|
||||||
for row in root:
|
|
||||||
parse_row_from_et(row, keys, dup)
|
|
||||||
return root, keys, dup
|
|
||||||
|
|
||||||
def parse_row(fname):
|
|
||||||
keys = set()
|
|
||||||
dup = set()
|
|
||||||
root = ET.parse(fname).getroot()
|
|
||||||
if root.tag != "row":
|
|
||||||
return None
|
|
||||||
parse_row_from_et(root, keys, dup)
|
|
||||||
return root, keys, dup
|
|
||||||
|
|
||||||
def check_layout(layout):
|
|
||||||
root, keys, dup = layout
|
|
||||||
if len(dup) > 0: warn("Duplicate keys: " + key_list_str(dup))
|
|
||||||
missing_some_of(keys, "~!@#$%^&*(){}`[]=\\-_;:/.,?<>'\"+|", "ASCII punctuation")
|
|
||||||
missing_some_of(keys, "0123456789", "digits")
|
|
||||||
missing_required(keys,
|
|
||||||
["loc esc", "loc tab", "backspace", "delete"],
|
|
||||||
"Layout doesn't define some important keys")
|
|
||||||
unexpected_keys(keys,
|
|
||||||
["copy", "paste", "cut", "selectAll", "shareText",
|
|
||||||
"pasteAsPlainText", "undo", "redo" ],
|
|
||||||
"Layout contains editing keys")
|
|
||||||
unexpected_keys(keys,
|
|
||||||
[ "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
|
|
||||||
"f10", "f11", "f12" ],
|
|
||||||
"Layout contains function keys")
|
|
||||||
unexpected_keys(keys, [""], "Layout contains empty strings")
|
|
||||||
unexpected_keys(keys, ["loc"], "Special keyword cannot be a symbol")
|
|
||||||
unexpected_keys(keys, filter(lambda k: k.strip()!=k, keys), "Some keys contain whitespaces")
|
|
||||||
unexpected_keys(keys, ["f11_placeholder", "f12_placeholder"], "These keys are now added automatically")
|
|
||||||
|
|
||||||
_, bottom_row_keys, _ = parse_row("res/xml/bottom_row.xml")
|
|
||||||
|
|
||||||
if root.get("bottom_row") == "false":
|
|
||||||
missing_required(keys, bottom_row_keys,
|
|
||||||
"Layout redefines the bottom row but some important keys are missing")
|
|
||||||
else:
|
|
||||||
unexpected_keys(keys, bottom_row_keys,
|
|
||||||
"Layout contains keys present in the bottom row")
|
|
||||||
|
|
||||||
if root.get("script") == None:
|
|
||||||
warn("Layout doesn't specify a script.")
|
|
||||||
|
|
||||||
for fname in sorted(sys.argv[1:]):
|
|
||||||
layout_id, _ = os.path.splitext(os.path.basename(fname))
|
|
||||||
if layout_id in KNOWN_NOT_LAYOUT:
|
|
||||||
continue
|
|
||||||
layout = parse_layout(fname)
|
|
||||||
if layout == None:
|
|
||||||
print("Not a layout file: %s" % layout_id)
|
|
||||||
else:
|
|
||||||
print("# %s" % layout_id)
|
|
||||||
warning_count = 0
|
|
||||||
check_layout(layout)
|
|
||||||
print("%d warnings" % warning_count)
|
|
@@ -1,132 +0,0 @@
|
|||||||
# Custom layouts
|
|
||||||
You select a key layout for Unexpected Keyboard by calling up the Settings page (swipe the gear icon) and, at the top of the page, either tapping an existing layout or tapping _Add an alternate layout_. This displays a menu of available layouts. You can define your own layout by choosing _Custom layout_ at the bottom of this menu. Unexpected Keyboard now displays code in the XML format. You make changes by replacing this with different code and tapping OK.
|
|
||||||
|
|
||||||
We recommend you keep your work in a file outside Unexpected Keyboard (named something like `MyChanges.xml`). If you installed a new version of Unexpected from a different website (with a different signature), then the work you did solely by editing the XML inside Unexpected would be lost.
|
|
||||||
|
|
||||||
Put initial contents into your file in one of these ways:
|
|
||||||
* Copypaste the code Unexpected displays for _Custom layout_.
|
|
||||||
* Make a copy of one of the built-in layouts found in [`/srcs/layouts`](https://github.com/Julow/Unexpected-Keyboard/tree/master/srcs/layouts).
|
|
||||||
* Use the [web-based editor](https://unexpected-keyboard-layout-editor.lixquid.com/). Interact with this web page to define keys and swipes and move keys to desired positions, and it will write the XML code for you. You can make the web page put the XML in a text file or copy it to the clipboard.
|
|
||||||
|
|
||||||
When you have prepared suitable XML code in one of these ways, copy it to the clipboard and paste it into Unexpected Keyboard.
|
|
||||||
|
|
||||||
## XML language overview
|
|
||||||
A layout XML file comprises tags that start with `<` and end with `>`.
|
|
||||||
* Every layout file starts with this declaration:
|
|
||||||
`<?xml version="1.0" encoding="utf-8"?>`
|
|
||||||
* Certain tags come in pairs—an opening tag and a closing tag—and apply to everything between them.
|
|
||||||
* The `<keyboard>`...`</keyboard>` pair says that the material between them is the definition of your keyboard. There can be only one of these.
|
|
||||||
* The `<row>`...`</row>` pair encloses the definition of a single row.
|
|
||||||
* An optional `<modmap>`...`</modmap>` pair contains instructions if you want to change the behavior of a modifier key such as Shift.
|
|
||||||
* Stand-alone tags include `<key`...`/>`, which defines a single key.
|
|
||||||
|
|
||||||
A tag can have properties, defined using an equals sign and a pair of ASCII double quotes. For example, `<key key0="a" />` defines the "a" key. The `key0` 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 key0="a" />
|
|
||||||
<key key0="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 common 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.
|
|
||||||
* `locale_extra_keys`: Whether Unexpected should add language-dependent extra keys from [method.xml](../res/xml/method.xml) to this layout. It accepts `true` or `false`, and defaults to `true`. To disable these automatic additions, specify `locale_extra_keys="false"`.
|
|
||||||
|
|
||||||
## Row
|
|
||||||
The `<row>`...`</row>` pair encloses one row on the keyboard. It has only one optional property:
|
|
||||||
* `height`: The height of the row: a positive floating-point value.
|
|
||||||
|
|
||||||
A row's default height is 1.0 (one quarter of the keyboard height specified on the Settings menu). The `height` property makes the row taller or shorter than this. For example, if you define a 5-row keyboard but one row has `height="0.7"`, then the keyboard's total height is 4.7 units. If the total is different from 4.0, the keyboard will be taller or shorter than that specified in Settings.
|
|
||||||
|
|
||||||
## Key
|
|
||||||
The `<key />` tag defines a key on the keyboard. Its position in the sequence of keys inside `<row>`...`</row>` indicates its position in the row from left to right. What the key does is defined by optional properties.
|
|
||||||
|
|
||||||
### Taps
|
|
||||||
What the key does when tapped is defined by the optional `key0` property. For example, `<key key0="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.)
|
|
||||||
<TABLE ALIGN=CENTER>
|
|
||||||
<TR>
|
|
||||||
<TD STYLE="width: 6em;">nw</TD><TD>n</TD><TD>ne</TD>
|
|
||||||
</TR>
|
|
||||||
<TR ALIGN=CENTER>
|
|
||||||
<TD>w</TD><TD> </TD><TD>e</TD>
|
|
||||||
</TR>
|
|
||||||
<TR>
|
|
||||||
<TD>sw</TD><TD>s</TD><TD>se</TD>
|
|
||||||
</TR>
|
|
||||||
</TABLE>
|
|
||||||
|
|
||||||
* `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> </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.
|
|
||||||
|
|
||||||
* `slider`: If `slider="true"`, and the key also has `w` and `e` properties, then the key tracks horizontal finger motion precisely and sends the `w` and `e` keystrokes repeatedly. In built-in layouts, this makes the space bar send left and right characters as the user slides on the space bar.
|
|
||||||
* `anticircle`: The key value to send when doing an anti-clockwise gesture on the key.
|
|
||||||
|
|
||||||
### 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 key0="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, `key0="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.
|
|
||||||
|
|
||||||
A modmap can contain the following tags, each of which must have an `a` and a `b` property:
|
|
||||||
* `<shift a="before" b="after" />` If the Shift modifier is on, the key `before` is changed into `after`.
|
|
||||||
* `<fn a="before" b="after" />` If the Fn modifier is on, the key `before` is changed into `after`.
|
|
||||||
|
|
||||||
Valid values for `before` and `after` are listed in [Possible key values](Possible-key-values.md).
|
|
||||||
|
|
||||||
There can be as many of these tags inside `<modmap>` as needed.
|
|
||||||
|
|
||||||
The clockwise circle and the round-trip gestures are affected by both Shift and Fn modmaps. The Shift mappings are used first and if that did not modify the key, the Fn mappings are used instead.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
Turkish keyboards use the Latin alphabet, but when "i" is shifted, it should produce "İ". This is achieved with the following modmap:
|
|
||||||
|
|
||||||
<modmap>
|
|
||||||
<shift a="i" b="İ" />
|
|
||||||
</modmap>
|
|
||||||
|
|
||||||
## 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.
|
|
@@ -1,149 +0,0 @@
|
|||||||
# Key values
|
|
||||||
|
|
||||||
This is an exhaustive list of special values accepted for the `key0` through `key8` or `nw` through `se` attributes on a key.
|
|
||||||
|
|
||||||
Any string that does not exactly match these will be printed verbatim.
|
|
||||||
A key can output multiple characters, but cannot combine multiple built-in key values.
|
|
||||||
|
|
||||||
## Escape codes
|
|
||||||
Value | Escape code for
|
|
||||||
:---- | :------
|
|
||||||
`\?` | `?`
|
|
||||||
`\#` | `#`
|
|
||||||
`\@` | `@`
|
|
||||||
`\n` | Literal newline character. This is different from `enter` and `action` in certain apps.
|
|
||||||
`\t` | Literal tab character. This is different from `tab` in certain apps.
|
|
||||||
`\\` | `\`
|
|
||||||
|
|
||||||
XML escape codes also work, including:
|
|
||||||
|
|
||||||
Value | Escape code for
|
|
||||||
:------- | :------
|
|
||||||
`&` | `&`
|
|
||||||
`<` | `<`
|
|
||||||
`>` | `>`
|
|
||||||
`"` | `"`
|
|
||||||
|
|
||||||
## Modifiers
|
|
||||||
System modifiers are sent to the app, which is free to do whatever they want in response.
|
|
||||||
The other modifiers only exist within the keyboard.
|
|
||||||
Value | Meaning
|
|
||||||
:---------- | :------
|
|
||||||
`shift` | System modifier.
|
|
||||||
`ctrl` | System modifier.
|
|
||||||
`alt` | System modifier.
|
|
||||||
`meta` | System modifier. Equivalent to the Windows key.
|
|
||||||
`fn` | Activates Fn mode, which assigns letters and symbols to special characters. e.g. `fn` `!` = `¡`
|
|
||||||
`compose` | Compose key. Enables composing characters using Linux-like shortcuts; e.g. `Compose` `A` `single quote` types `Á` (A with acute accent).
|
|
||||||
`capslock` | Actives and locks Shift
|
|
||||||
|
|
||||||
## Special 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`, `f1`-`f12`,
|
|
||||||
`tab`, `copy`,
|
|
||||||
`paste`, `cut`,
|
|
||||||
`selectAll`, `pasteAsPlainText`,
|
|
||||||
`undo`, `redo`
|
|
||||||
|
|
||||||
## Whitespace
|
|
||||||
Value | Meaning
|
|
||||||
:------ | :------
|
|
||||||
`space` | Space bar.
|
|
||||||
`nbsp` | Non-breaking space.
|
|
||||||
`nnbsp` | Narrow non-breaking space.
|
|
||||||
`zwj` | Zero-width joiner.
|
|
||||||
`zwnj` | Zero-width non-joiner.
|
|
||||||
|
|
||||||
## Keyboard editing actions
|
|
||||||
These keys perform editing on the text without sending keys that the app can interpret differently or ignore.
|
|
||||||
Value | Meaning
|
|
||||||
:----------------- | :------
|
|
||||||
`cursor_left` | Moves the cursor position to the left directly, without sending a `left` key event.
|
|
||||||
`cursor_right` | Moves the cursor position to the right directly, without sending a `right` key event.
|
|
||||||
|
|
||||||
## Other modifiers and diacritics
|
|
||||||
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. `ả`
|
|
||||||
`superscript` | Superscript. `ᵃ`
|
|
||||||
`subscript` | Subscript. `ₐ`
|
|
||||||
`ordinal` | Turns `a` and `o` into `ª` and `º`.
|
|
||||||
`arrows` | Turns `1`-`4` and `6`-`9` into arrows.
|
|
||||||
`box` | Turns `1`-`9`, `0`, and `.` into single-line, thin box-drawing characters.
|
|
||||||
|
|
||||||
## Bidirectional
|
|
||||||
Value | Meaning
|
|
||||||
:------ | :------
|
|
||||||
`lrm` | Left-to-right mark.
|
|
||||||
`rlm` | Right-to-left mark.
|
|
||||||
`b(`, `b)`, `b[`, `b]`, `b{`, `b}`, `blt`, `bgt` | Sends the bracket characters, but with mirrored key legends for right-to-left languages. (`blt` and `bgt` print `<` and `>` respectively.)
|
|
||||||
|
|
||||||
## Hebrew
|
|
||||||
Keys ending in `_placeholder` are normally hidden unless the Fn key is pressed.
|
|
||||||
|
|
||||||
`qamats`, `patah`,
|
|
||||||
`sheva`, `dagesh`,
|
|
||||||
`hiriq`, `segol`,
|
|
||||||
`tsere`, `holam`,
|
|
||||||
`qubuts`, `hataf_patah`,
|
|
||||||
`hataf_qamats`, `hataf_segol`,
|
|
||||||
`shindot`, `shindot_placeholder`,
|
|
||||||
`sindot`, `sindot_placeholder`,
|
|
||||||
`geresh`, `gershayim`,
|
|
||||||
`maqaf`, `rafe`,
|
|
||||||
`ole`, `ole_placeholder`,
|
|
||||||
`meteg`, `meteg_placeholder`
|
|
||||||
|
|
||||||
## Unexpected Keyboard specific
|
|
||||||
Value | Meaning
|
|
||||||
:--------------------- | :------
|
|
||||||
`config` | Gear icon; opens Unexpected Keyboard settings.
|
|
||||||
`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.
|
|
||||||
`change_method` | Open the input method picker dialog.
|
|
||||||
`change_method_prev` | Switch to the previously used input method.
|
|
||||||
`action` | Performs a special context-sensitive operation related to the Enter key. For example, in the Twitter (X) app, `enter` adds a new line, while `action` posts.
|
|
||||||
`voice_typing` | Begin voice typing.
|
|
||||||
`voice_typing_chooser` | Shows a menu where you can choose which voice typing provider to use, then begins voice typing when you make a selection.
|
|
||||||
`shareText` | Emit a share Intent for the selected text. **Oddity:** This is in CamelCase.
|
|
||||||
|
|
||||||
## Unused
|
|
||||||
These keys are known to do nothing.
|
|
||||||
|
|
||||||
`replaceText`, `textAssist`,
|
|
||||||
`autofill`, `removed`
|
|
||||||
|
|
||||||
## Placeholders
|
|
||||||
These keys are normally hidden unless the Fn modifier is activated.
|
|
||||||
|
|
||||||
`f11_placeholder` | `f12_placeholder`
|
|
908
emoji_gen.py
Normal file
@@ -0,0 +1,908 @@
|
|||||||
|
from enum import Enum
|
||||||
|
import sys
|
||||||
|
|
||||||
|
class Line(Enum):
|
||||||
|
IGNORE = 0
|
||||||
|
GROUP = 1
|
||||||
|
ENTRY = 2
|
||||||
|
|
||||||
|
def parse_line(line):
|
||||||
|
if line.startswith("# group:"):
|
||||||
|
return (Line.GROUP, line.split(":")[1].strip())
|
||||||
|
else:
|
||||||
|
lr = line.split("#", 1)
|
||||||
|
if lr[0] == "" or len(lr) != 2:
|
||||||
|
return (Line.IGNORE, line)
|
||||||
|
else:
|
||||||
|
code, status = lr[0].split(";", 1)
|
||||||
|
desc = lr[1].strip().split(" ", 2)[2]
|
||||||
|
return (Line.ENTRY, (code.strip(), status.strip(), desc))
|
||||||
|
|
||||||
|
def parse_lines(inp):
|
||||||
|
entries = {}
|
||||||
|
group = "none"
|
||||||
|
for line in inp:
|
||||||
|
tok, k = parse_line(line)
|
||||||
|
if tok == Line.GROUP:
|
||||||
|
group = k
|
||||||
|
elif tok == Line.ENTRY:
|
||||||
|
entries.setdefault(group, []).append(k)
|
||||||
|
return entries
|
||||||
|
|
||||||
|
name_map = {
|
||||||
|
"1F44D": ":+1:",
|
||||||
|
"1F44E": ":-1:",
|
||||||
|
"1F4AF": ":100:",
|
||||||
|
"1F522": ":1234:",
|
||||||
|
"1F3B1": ":8ball:",
|
||||||
|
"1F170": ":a:",
|
||||||
|
"1F18E": ":ab:",
|
||||||
|
"1F524": ":abc:",
|
||||||
|
"1F521": ":abcd:",
|
||||||
|
"1F251": ":accept:",
|
||||||
|
"1F6A1": ":aerial_tramway:",
|
||||||
|
"02708": ":airplane:",
|
||||||
|
"023F0": ":alarm_clock:",
|
||||||
|
"1F47D": ":alien:",
|
||||||
|
"1F691": ":ambulance:",
|
||||||
|
"02693": ":anchor:",
|
||||||
|
"1F47C": ":angel:",
|
||||||
|
"1F4A2": ":anger:",
|
||||||
|
"1F620": ":angry:",
|
||||||
|
"1F627": ":anguished:",
|
||||||
|
"1F41C": ":ant:",
|
||||||
|
"1F34E": ":apple:",
|
||||||
|
"02652": ":aquarius:",
|
||||||
|
"02648": ":aries:",
|
||||||
|
"025C0": ":arrow_backward:",
|
||||||
|
"023EC": ":arrow_double_down:",
|
||||||
|
"023EB": ":arrow_double_up:",
|
||||||
|
"02B07": ":arrow_down:",
|
||||||
|
"1F53D": ":arrow_down_small:",
|
||||||
|
"025B6": ":arrow_forward:",
|
||||||
|
"02935": ":arrow_heading_down:",
|
||||||
|
"02934": ":arrow_heading_up:",
|
||||||
|
"02B05": ":arrow_left:",
|
||||||
|
"02199": ":arrow_lower_left:",
|
||||||
|
"02198": ":arrow_lower_right:",
|
||||||
|
"027A1": ":arrow_right:",
|
||||||
|
"021AA": ":arrow_right_hook:",
|
||||||
|
"02B06": ":arrow_up:",
|
||||||
|
"02195": ":arrow_up_down:",
|
||||||
|
"1F53C": ":arrow_up_small:",
|
||||||
|
"02196": ":arrow_upper_left:",
|
||||||
|
"02197": ":arrow_upper_right:",
|
||||||
|
"1F503": ":arrows_clockwise:",
|
||||||
|
"1F504": ":arrows_counterclockwise:",
|
||||||
|
"1F3A8": ":art:",
|
||||||
|
"1F69B": ":articulated_lorry:",
|
||||||
|
"1F632": ":astonished:",
|
||||||
|
"1F45F": ":athletic_shoe:",
|
||||||
|
"1F3E7": ":atm:",
|
||||||
|
"1F171": ":b:",
|
||||||
|
"1F476": ":baby:",
|
||||||
|
"1F37C": ":baby_bottle:",
|
||||||
|
"1F424": ":baby_chick:",
|
||||||
|
"1F6BC": ":baby_symbol:",
|
||||||
|
"1F519": ":back:",
|
||||||
|
"1F6C4": ":baggage_claim:",
|
||||||
|
"1F388": ":balloon:",
|
||||||
|
"02611": ":ballot_box_with_check:",
|
||||||
|
"1F38D": ":bamboo:",
|
||||||
|
"1F34C": ":banana:",
|
||||||
|
"0203C": ":bangbang:",
|
||||||
|
"1F3E6": ":bank:",
|
||||||
|
"1F4CA": ":bar_chart:",
|
||||||
|
"1F488": ":barber:",
|
||||||
|
"026BE": ":baseball:",
|
||||||
|
"1F3C0": ":basketball:",
|
||||||
|
"1F6C0": ":bath:",
|
||||||
|
"1F6C1": ":bathtub:",
|
||||||
|
"1F50B": ":battery:",
|
||||||
|
"1F43B": ":bear:",
|
||||||
|
"1F41D": ":bee:",
|
||||||
|
"1F37A": ":beer:",
|
||||||
|
"1F37B": ":beers:",
|
||||||
|
"1F41E": ":beetle:",
|
||||||
|
"1F530": ":beginner:",
|
||||||
|
"1F514": ":bell:",
|
||||||
|
"1F371": ":bento:",
|
||||||
|
"1F6B4": ":bicyclist:",
|
||||||
|
"1F6B2": ":bike:",
|
||||||
|
"1F459": ":bikini:",
|
||||||
|
"1F426": ":bird:",
|
||||||
|
"1F382": ":birthday:",
|
||||||
|
"026AB": ":black_circle:",
|
||||||
|
"1F0CF": ":black_joker:",
|
||||||
|
"02B1B": ":black_large_square:",
|
||||||
|
"025FE": ":black_medium_small_square:",
|
||||||
|
"025FC": ":black_medium_square:",
|
||||||
|
"02712": ":black_nib:",
|
||||||
|
"025AA": ":black_small_square:",
|
||||||
|
"1F532": ":black_square_button:",
|
||||||
|
"1F33C": ":blossom:",
|
||||||
|
"1F421": ":blowfish:",
|
||||||
|
"1F4D8": ":blue_book:",
|
||||||
|
"1F699": ":blue_car:",
|
||||||
|
"1F499": ":blue_heart:",
|
||||||
|
"1F60A": ":blush:",
|
||||||
|
"1F417": ":boar:",
|
||||||
|
"026F5": ":boat:",
|
||||||
|
"1F4A3": ":bomb:",
|
||||||
|
"1F4D6": ":book:",
|
||||||
|
"1F516": ":bookmark:",
|
||||||
|
"1F4D1": ":bookmark_tabs:",
|
||||||
|
"1F4DA": ":books:",
|
||||||
|
"1F4A5": ":boom:",
|
||||||
|
"1F462": ":boot:",
|
||||||
|
"1F490": ":bouquet:",
|
||||||
|
"1F647": ":bow:",
|
||||||
|
"1F3B3": ":bowling:",
|
||||||
|
"1F466": ":boy:",
|
||||||
|
"1F35E": ":bread:",
|
||||||
|
"1F470": ":bride_with_veil:",
|
||||||
|
"1F309": ":bridge_at_night:",
|
||||||
|
"1F4BC": ":briefcase:",
|
||||||
|
"1F494": ":broken_heart:",
|
||||||
|
"1F41B": ":bug:",
|
||||||
|
"1F4A1": ":bulb:",
|
||||||
|
"1F685": ":bullettrain_front:",
|
||||||
|
"1F684": ":bullettrain_side:",
|
||||||
|
"1F68C": ":bus:",
|
||||||
|
"1F68F": ":busstop:",
|
||||||
|
"1F464": ":bust_in_silhouette:",
|
||||||
|
"1F465": ":busts_in_silhouette:",
|
||||||
|
"1F335": ":cactus:",
|
||||||
|
"1F370": ":cake:",
|
||||||
|
"1F4C6": ":calendar:",
|
||||||
|
"1F4F2": ":calling:",
|
||||||
|
"1F42B": ":camel:",
|
||||||
|
"1F4F7": ":camera:",
|
||||||
|
"0264B": ":cancer:",
|
||||||
|
"1F36C": ":candy:",
|
||||||
|
"1F520": ":capital_abcd:",
|
||||||
|
"02651": ":capricorn:",
|
||||||
|
"1F697": ":car:",
|
||||||
|
"1F4C7": ":card_index:",
|
||||||
|
"1F3A0": ":carousel_horse:",
|
||||||
|
"1F431": ":cat:",
|
||||||
|
"1F408": ":cat2:",
|
||||||
|
"1F4BF": ":cd:",
|
||||||
|
"1F4B9": ":chart:",
|
||||||
|
"1F4C9": ":chart_with_downwards_trend:",
|
||||||
|
"1F4C8": ":chart_with_upwards_trend:",
|
||||||
|
"1F3C1": ":checkered_flag:",
|
||||||
|
"1F352": ":cherries:",
|
||||||
|
"1F338": ":cherry_blossom:",
|
||||||
|
"1F330": ":chestnut:",
|
||||||
|
"1F414": ":chicken:",
|
||||||
|
"1F6B8": ":children_crossing:",
|
||||||
|
"1F36B": ":chocolate_bar:",
|
||||||
|
"1F384": ":christmas_tree:",
|
||||||
|
"026EA": ":church:",
|
||||||
|
"1F3A6": ":cinema:",
|
||||||
|
"1F3AA": ":circus_tent:",
|
||||||
|
"1F307": ":city_sunrise:",
|
||||||
|
"1F306": ":city_sunset:",
|
||||||
|
"1F191": ":cl:",
|
||||||
|
"1F44F": ":clap:",
|
||||||
|
"1F3AC": ":clapper:",
|
||||||
|
"1F4CB": ":clipboard:",
|
||||||
|
"1F550": ":clock1:",
|
||||||
|
"1F559": ":clock10:",
|
||||||
|
"1F565": ":clock1030:",
|
||||||
|
"1F55A": ":clock11:",
|
||||||
|
"1F566": ":clock1130:",
|
||||||
|
"1F55B": ":clock12:",
|
||||||
|
"1F567": ":clock1230:",
|
||||||
|
"1F55C": ":clock130:",
|
||||||
|
"1F551": ":clock2:",
|
||||||
|
"1F55D": ":clock230:",
|
||||||
|
"1F552": ":clock3:",
|
||||||
|
"1F55E": ":clock330:",
|
||||||
|
"1F553": ":clock4:",
|
||||||
|
"1F55F": ":clock430:",
|
||||||
|
"1F554": ":clock5:",
|
||||||
|
"1F560": ":clock530:",
|
||||||
|
"1F555": ":clock6:",
|
||||||
|
"1F561": ":clock630:",
|
||||||
|
"1F556": ":clock7:",
|
||||||
|
"1F562": ":clock730:",
|
||||||
|
"1F557": ":clock8:",
|
||||||
|
"1F563": ":clock830:",
|
||||||
|
"1F558": ":clock9:",
|
||||||
|
"1F564": ":clock930:",
|
||||||
|
"1F4D5": ":closed_book:",
|
||||||
|
"1F510": ":closed_lock_with_key:",
|
||||||
|
"1F302": ":closed_umbrella:",
|
||||||
|
"02601": ":cloud:",
|
||||||
|
"02663": ":clubs:",
|
||||||
|
"1F378": ":cocktail:",
|
||||||
|
"02615": ":coffee:",
|
||||||
|
"1F630": ":cold_sweat:",
|
||||||
|
"1F4A5": ":collision:",
|
||||||
|
"1F4BB": ":computer:",
|
||||||
|
"1F38A": ":confetti_ball:",
|
||||||
|
"1F616": ":confounded:",
|
||||||
|
"1F615": ":confused:",
|
||||||
|
"03297": ":congratulations:",
|
||||||
|
"1F6A7": ":construction:",
|
||||||
|
"1F477": ":construction_worker:",
|
||||||
|
"1F3EA": ":convenience_store:",
|
||||||
|
"1F36A": ":cookie:",
|
||||||
|
"1F192": ":cool:",
|
||||||
|
"1F46E": ":cop:",
|
||||||
|
"000A9": ":copyright:",
|
||||||
|
"1F33D": ":corn:",
|
||||||
|
"1F46B": ":couple:",
|
||||||
|
"1F491": ":couple_with_heart:",
|
||||||
|
"1F48F": ":couplekiss:",
|
||||||
|
"1F42E": ":cow:",
|
||||||
|
"1F404": ":cow2:",
|
||||||
|
"1F4B3": ":credit_card:",
|
||||||
|
"1F319": ":crescent_moon:",
|
||||||
|
"1F40A": ":crocodile:",
|
||||||
|
"1F38C": ":crossed_flags:",
|
||||||
|
"1F451": ":crown:",
|
||||||
|
"1F622": ":cry:",
|
||||||
|
"1F63F": ":crying_cat_face:",
|
||||||
|
"1F52E": ":crystal_ball:",
|
||||||
|
"1F498": ":cupid:",
|
||||||
|
"027B0": ":curly_loop:",
|
||||||
|
"1F4B1": ":currency_exchange:",
|
||||||
|
"1F35B": ":curry:",
|
||||||
|
"1F36E": ":custard:",
|
||||||
|
"1F6C3": ":customs:",
|
||||||
|
"1F300": ":cyclone:",
|
||||||
|
"1F483": ":dancer:",
|
||||||
|
"1F46F": ":dancers:",
|
||||||
|
"1F361": ":dango:",
|
||||||
|
"1F3AF": ":dart:",
|
||||||
|
"1F4A8": ":dash:",
|
||||||
|
"1F4C5": ":date:",
|
||||||
|
"1F333": ":deciduous_tree:",
|
||||||
|
"1F3EC": ":department_store:",
|
||||||
|
"1F4A0": ":diamond_shape_with_a_dot_inside:",
|
||||||
|
"02666": ":diamonds:",
|
||||||
|
"1F61E": ":disappointed:",
|
||||||
|
"1F625": ":disappointed_relieved:",
|
||||||
|
"1F4AB": ":dizzy:",
|
||||||
|
"1F635": ":dizzy_face:",
|
||||||
|
"1F6AF": ":do_not_litter:",
|
||||||
|
"1F436": ":dog:",
|
||||||
|
"1F415": ":dog2:",
|
||||||
|
"1F4B5": ":dollar:",
|
||||||
|
"1F38E": ":dolls:",
|
||||||
|
"1F42C": ":dolphin:",
|
||||||
|
"1F6AA": ":door:",
|
||||||
|
"1F369": ":doughnut:",
|
||||||
|
"1F409": ":dragon:",
|
||||||
|
"1F432": ":dragon_face:",
|
||||||
|
"1F457": ":dress:",
|
||||||
|
"1F42A": ":dromedary_camel:",
|
||||||
|
"1F4A7": ":droplet:",
|
||||||
|
"1F4C0": ":dvd:",
|
||||||
|
"1F4E7": ":e-mail:",
|
||||||
|
"1F442": ":ear:",
|
||||||
|
"1F33E": ":ear_of_rice:",
|
||||||
|
"1F30D": ":earth_africa:",
|
||||||
|
"1F30E": ":earth_americas:",
|
||||||
|
"1F30F": ":earth_asia:",
|
||||||
|
"1F373": ":egg:",
|
||||||
|
"1F346": ":eggplant:",
|
||||||
|
"02734": ":eight_pointed_black_star:",
|
||||||
|
"02733": ":eight_spoked_asterisk:",
|
||||||
|
"1F50C": ":electric_plug:",
|
||||||
|
"1F418": ":elephant:",
|
||||||
|
"02709": ":email:",
|
||||||
|
"1F51A": ":end:",
|
||||||
|
"02709": ":envelope:",
|
||||||
|
"1F4E9": ":envelope_with_arrow:",
|
||||||
|
"1F4B6": ":euro:",
|
||||||
|
"1F3F0": ":european_castle:",
|
||||||
|
"1F3E4": ":european_post_office:",
|
||||||
|
"1F332": ":evergreen_tree:",
|
||||||
|
"02757": ":exclamation:",
|
||||||
|
"1F611": ":expressionless:",
|
||||||
|
"1F453": ":eyeglasses:",
|
||||||
|
"1F440": ":eyes:",
|
||||||
|
"1F44A": ":facepunch:",
|
||||||
|
"1F3ED": ":factory:",
|
||||||
|
"1F342": ":fallen_leaf:",
|
||||||
|
"1F46A": ":family:",
|
||||||
|
"023E9": ":fast_forward:",
|
||||||
|
"1F4E0": ":fax:",
|
||||||
|
"1F628": ":fearful:",
|
||||||
|
"1F43E": ":feet:",
|
||||||
|
"1F3A1": ":ferris_wheel:",
|
||||||
|
"1F4C1": ":file_folder:",
|
||||||
|
"1F525": ":fire:",
|
||||||
|
"1F692": ":fire_engine:",
|
||||||
|
"1F386": ":fireworks:",
|
||||||
|
"1F313": ":first_quarter_moon:",
|
||||||
|
"1F31B": ":first_quarter_moon_with_face:",
|
||||||
|
"1F41F": ":fish:",
|
||||||
|
"1F365": ":fish_cake:",
|
||||||
|
"1F3A3": ":fishing_pole_and_fish:",
|
||||||
|
"0270A": ":fist:",
|
||||||
|
"1F38F": ":flags:",
|
||||||
|
"1F526": ":flashlight:",
|
||||||
|
"1F42C": ":flipper:",
|
||||||
|
"1F4BE": ":floppy_disk:",
|
||||||
|
"1F3B4": ":flower_playing_cards:",
|
||||||
|
"1F633": ":flushed:",
|
||||||
|
"1F301": ":foggy:",
|
||||||
|
"1F3C8": ":football:",
|
||||||
|
"1F463": ":footprints:",
|
||||||
|
"1F374": ":fork_and_knife:",
|
||||||
|
"026F2": ":fountain:",
|
||||||
|
"1F340": ":four_leaf_clover:",
|
||||||
|
"1F193": ":free:",
|
||||||
|
"1F364": ":fried_shrimp:",
|
||||||
|
"1F35F": ":fries:",
|
||||||
|
"1F438": ":frog:",
|
||||||
|
"1F626": ":frowning:",
|
||||||
|
"026FD": ":fuelpump:",
|
||||||
|
"1F315": ":full_moon:",
|
||||||
|
"1F31D": ":full_moon_with_face:",
|
||||||
|
"1F3B2": ":game_die:",
|
||||||
|
"1F48E": ":gem:",
|
||||||
|
"0264A": ":gemini:",
|
||||||
|
"1F47B": ":ghost:",
|
||||||
|
"1F381": ":gift:",
|
||||||
|
"1F49D": ":gift_heart:",
|
||||||
|
"1F467": ":girl:",
|
||||||
|
"1F310": ":globe_with_meridians:",
|
||||||
|
"1F410": ":goat:",
|
||||||
|
"026F3": ":golf:",
|
||||||
|
"1F347": ":grapes:",
|
||||||
|
"1F34F": ":green_apple:",
|
||||||
|
"1F4D7": ":green_book:",
|
||||||
|
"1F49A": ":green_heart:",
|
||||||
|
"02755": ":grey_exclamation:",
|
||||||
|
"02754": ":grey_question:",
|
||||||
|
"1F62C": ":grimacing:",
|
||||||
|
"1F601": ":grin:",
|
||||||
|
"1F600": ":grinning:",
|
||||||
|
"1F482": ":guardsman:",
|
||||||
|
"1F3B8": ":guitar:",
|
||||||
|
"1F52B": ":gun:",
|
||||||
|
"1F487": ":haircut:",
|
||||||
|
"1F354": ":hamburger:",
|
||||||
|
"1F528": ":hammer:",
|
||||||
|
"1F439": ":hamster:",
|
||||||
|
"0270B": ":hand:",
|
||||||
|
"1F45C": ":handbag:",
|
||||||
|
"1F4A9": ":hankey:",
|
||||||
|
"1F425": ":hatched_chick:",
|
||||||
|
"1F423": ":hatching_chick:",
|
||||||
|
"1F3A7": ":headphones:",
|
||||||
|
"1F649": ":hear_no_evil:",
|
||||||
|
"02764": ":heart:",
|
||||||
|
"1F49F": ":heart_decoration:",
|
||||||
|
"1F60D": ":heart_eyes:",
|
||||||
|
"1F63B": ":heart_eyes_cat:",
|
||||||
|
"1F493": ":heartbeat:",
|
||||||
|
"1F497": ":heartpulse:",
|
||||||
|
"02665": ":hearts:",
|
||||||
|
"02714": ":heavy_check_mark:",
|
||||||
|
"02797": ":heavy_division_sign:",
|
||||||
|
"1F4B2": ":heavy_dollar_sign:",
|
||||||
|
"02757": ":heavy_exclamation_mark:",
|
||||||
|
"02796": ":heavy_minus_sign:",
|
||||||
|
"02716": ":heavy_multiplication_x:",
|
||||||
|
"02795": ":heavy_plus_sign:",
|
||||||
|
"1F681": ":helicopter:",
|
||||||
|
"1F33F": ":herb:",
|
||||||
|
"1F33A": ":hibiscus:",
|
||||||
|
"1F506": ":high_brightness:",
|
||||||
|
"1F460": ":high_heel:",
|
||||||
|
"1F52A": ":hocho:",
|
||||||
|
"1F36F": ":honey_pot:",
|
||||||
|
"1F41D": ":honeybee:",
|
||||||
|
"1F434": ":horse:",
|
||||||
|
"1F3C7": ":horse_racing:",
|
||||||
|
"1F3E5": ":hospital:",
|
||||||
|
"1F3E8": ":hotel:",
|
||||||
|
"02668": ":hotsprings:",
|
||||||
|
"0231B": ":hourglass:",
|
||||||
|
"023F3": ":hourglass_flowing_sand:",
|
||||||
|
"1F3E0": ":house:",
|
||||||
|
"1F3E1": ":house_with_garden:",
|
||||||
|
"1F62F": ":hushed:",
|
||||||
|
"1F368": ":ice_cream:",
|
||||||
|
"1F366": ":icecream:",
|
||||||
|
"1F194": ":id:",
|
||||||
|
"1F250": ":ideograph_advantage:",
|
||||||
|
"1F47F": ":imp:",
|
||||||
|
"1F4E5": ":inbox_tray:",
|
||||||
|
"1F4E8": ":incoming_envelope:",
|
||||||
|
"1F481": ":information_desk_person:",
|
||||||
|
"02139": ":information_source:",
|
||||||
|
"1F607": ":innocent:",
|
||||||
|
"02049": ":interrobang:",
|
||||||
|
"1F4F1": ":iphone:",
|
||||||
|
"1F3EE": ":izakaya_lantern:",
|
||||||
|
"1F383": ":jack_o_lantern:",
|
||||||
|
"1F5FE": ":japan:",
|
||||||
|
"1F3EF": ":japanese_castle:",
|
||||||
|
"1F47A": ":japanese_goblin:",
|
||||||
|
"1F479": ":japanese_ogre:",
|
||||||
|
"1F456": ":jeans:",
|
||||||
|
"1F602": ":joy:",
|
||||||
|
"1F639": ":joy_cat:",
|
||||||
|
"1F511": ":key:",
|
||||||
|
"1F51F": ":keycap_ten:",
|
||||||
|
"1F458": ":kimono:",
|
||||||
|
"1F48B": ":kiss:",
|
||||||
|
"1F617": ":kissing:",
|
||||||
|
"1F63D": ":kissing_cat:",
|
||||||
|
"1F61A": ":kissing_closed_eyes:",
|
||||||
|
"1F618": ":kissing_heart:",
|
||||||
|
"1F619": ":kissing_smiling_eyes:",
|
||||||
|
"1F428": ":koala:",
|
||||||
|
"1F201": ":koko:",
|
||||||
|
"1F3EE": ":lantern:",
|
||||||
|
"1F535": ":large_blue_circle:",
|
||||||
|
"1F537": ":large_blue_diamond:",
|
||||||
|
"1F536": ":large_orange_diamond:",
|
||||||
|
"1F317": ":last_quarter_moon:",
|
||||||
|
"1F31C": ":last_quarter_moon_with_face:",
|
||||||
|
"1F606": ":laughing:",
|
||||||
|
"1F343": ":leaves:",
|
||||||
|
"1F4D2": ":ledger:",
|
||||||
|
"1F6C5": ":left_luggage:",
|
||||||
|
"02194": ":left_right_arrow:",
|
||||||
|
"021A9": ":leftwards_arrow_with_hook:",
|
||||||
|
"1F34B": ":lemon:",
|
||||||
|
"0264C": ":leo:",
|
||||||
|
"1F406": ":leopard:",
|
||||||
|
"0264E": ":libra:",
|
||||||
|
"1F688": ":light_rail:",
|
||||||
|
"1F517": ":link:",
|
||||||
|
"1F444": ":lips:",
|
||||||
|
"1F484": ":lipstick:",
|
||||||
|
"1F512": ":lock:",
|
||||||
|
"1F50F": ":lock_with_ink_pen:",
|
||||||
|
"1F36D": ":lollipop:",
|
||||||
|
"027BF": ":loop:",
|
||||||
|
"1F4E2": ":loudspeaker:",
|
||||||
|
"1F3E9": ":love_hotel:",
|
||||||
|
"1F48C": ":love_letter:",
|
||||||
|
"1F505": ":low_brightness:",
|
||||||
|
"024C2": ":m:",
|
||||||
|
"1F50D": ":mag:",
|
||||||
|
"1F50E": ":mag_right:",
|
||||||
|
"1F004": ":mahjong:",
|
||||||
|
"1F4EB": ":mailbox:",
|
||||||
|
"1F4EA": ":mailbox_closed:",
|
||||||
|
"1F4EC": ":mailbox_with_mail:",
|
||||||
|
"1F4ED": ":mailbox_with_no_mail:",
|
||||||
|
"1F468": ":man:",
|
||||||
|
"1F472": ":man_with_gua_pi_mao:",
|
||||||
|
"1F473": ":man_with_turban:",
|
||||||
|
"1F45E": ":mans_shoe:",
|
||||||
|
"1F341": ":maple_leaf:",
|
||||||
|
"1F637": ":mask:",
|
||||||
|
"1F486": ":massage:",
|
||||||
|
"1F356": ":meat_on_bone:",
|
||||||
|
"1F4E3": ":mega:",
|
||||||
|
"1F348": ":melon:",
|
||||||
|
"1F4DD": ":memo:",
|
||||||
|
"1F6B9": ":mens:",
|
||||||
|
"1F687": ":metro:",
|
||||||
|
"1F3A4": ":microphone:",
|
||||||
|
"1F52C": ":microscope:",
|
||||||
|
"1F30C": ":milky_way:",
|
||||||
|
"1F690": ":minibus:",
|
||||||
|
"1F4BD": ":minidisc:",
|
||||||
|
"1F4F4": ":mobile_phone_off:",
|
||||||
|
"1F4B8": ":money_with_wings:",
|
||||||
|
"1F4B0": ":moneybag:",
|
||||||
|
"1F412": ":monkey:",
|
||||||
|
"1F435": ":monkey_face:",
|
||||||
|
"1F69D": ":monorail:",
|
||||||
|
"1F314": ":moon:",
|
||||||
|
"1F393": ":mortar_board:",
|
||||||
|
"1F5FB": ":mount_fuji:",
|
||||||
|
"1F6B5": ":mountain_bicyclist:",
|
||||||
|
"1F6A0": ":mountain_cableway:",
|
||||||
|
"1F69E": ":mountain_railway:",
|
||||||
|
"1F42D": ":mouse:",
|
||||||
|
"1F401": ":mouse2:",
|
||||||
|
"1F3A5": ":movie_camera:",
|
||||||
|
"1F5FF": ":moyai:",
|
||||||
|
"1F4AA": ":muscle:",
|
||||||
|
"1F344": ":mushroom:",
|
||||||
|
"1F3B9": ":musical_keyboard:",
|
||||||
|
"1F3B5": ":musical_note:",
|
||||||
|
"1F3BC": ":musical_score:",
|
||||||
|
"1F507": ":mute:",
|
||||||
|
"1F485": ":nail_care:",
|
||||||
|
"1F4DB": ":name_badge:",
|
||||||
|
"1F454": ":necktie:",
|
||||||
|
"0274E": ":negative_squared_cross_mark:",
|
||||||
|
"1F610": ":neutral_face:",
|
||||||
|
"1F195": ":new:",
|
||||||
|
"1F311": ":new_moon:",
|
||||||
|
"1F31A": ":new_moon_with_face:",
|
||||||
|
"1F4F0": ":newspaper:",
|
||||||
|
"1F196": ":ng:",
|
||||||
|
"1F515": ":no_bell:",
|
||||||
|
"1F6B3": ":no_bicycles:",
|
||||||
|
"026D4": ":no_entry:",
|
||||||
|
"1F6AB": ":no_entry_sign:",
|
||||||
|
"1F645": ":no_good:",
|
||||||
|
"1F4F5": ":no_mobile_phones:",
|
||||||
|
"1F636": ":no_mouth:",
|
||||||
|
"1F6B7": ":no_pedestrians:",
|
||||||
|
"1F6AD": ":no_smoking:",
|
||||||
|
"1F6B1": ":non-potable_water:",
|
||||||
|
"1F443": ":nose:",
|
||||||
|
"1F4D3": ":notebook:",
|
||||||
|
"1F4D4": ":notebook_with_decorative_cover:",
|
||||||
|
"1F3B6": ":notes:",
|
||||||
|
"1F529": ":nut_and_bolt:",
|
||||||
|
"02B55": ":o:",
|
||||||
|
"1F17E": ":o2:",
|
||||||
|
"1F30A": ":ocean:",
|
||||||
|
"1F419": ":octopus:",
|
||||||
|
"1F362": ":oden:",
|
||||||
|
"1F3E2": ":office:",
|
||||||
|
"1F197": ":ok:",
|
||||||
|
"1F44C": ":ok_hand:",
|
||||||
|
"1F646": ":ok_woman:",
|
||||||
|
"1F474": ":older_man:",
|
||||||
|
"1F475": ":older_woman:",
|
||||||
|
"1F51B": ":on:",
|
||||||
|
"1F698": ":oncoming_automobile:",
|
||||||
|
"1F68D": ":oncoming_bus:",
|
||||||
|
"1F694": ":oncoming_police_car:",
|
||||||
|
"1F696": ":oncoming_taxi:",
|
||||||
|
"1F4D6": ":open_book:",
|
||||||
|
"1F4C2": ":open_file_folder:",
|
||||||
|
"1F450": ":open_hands:",
|
||||||
|
"1F62E": ":open_mouth:",
|
||||||
|
"026CE": ":ophiuchus:",
|
||||||
|
"1F4D9": ":orange_book:",
|
||||||
|
"1F4E4": ":outbox_tray:",
|
||||||
|
"1F402": ":ox:",
|
||||||
|
"1F4E6": ":package:",
|
||||||
|
"1F4C4": ":page_facing_up:",
|
||||||
|
"1F4C3": ":page_with_curl:",
|
||||||
|
"1F4DF": ":pager:",
|
||||||
|
"1F334": ":palm_tree:",
|
||||||
|
"1F43C": ":panda_face:",
|
||||||
|
"1F4CE": ":paperclip:",
|
||||||
|
"1F17F": ":parking:",
|
||||||
|
"0303D": ":part_alternation_mark:",
|
||||||
|
"026C5": ":partly_sunny:",
|
||||||
|
"1F6C2": ":passport_control:",
|
||||||
|
"1F43E": ":paw_prints:",
|
||||||
|
"1F351": ":peach:",
|
||||||
|
"1F350": ":pear:",
|
||||||
|
"1F4DD": ":pencil:",
|
||||||
|
"0270F": ":pencil2:",
|
||||||
|
"1F427": ":penguin:",
|
||||||
|
"1F614": ":pensive:",
|
||||||
|
"1F3AD": ":performing_arts:",
|
||||||
|
"1F623": ":persevere:",
|
||||||
|
"1F64D": ":person_frowning:",
|
||||||
|
"1F471": ":person_with_blond_hair:",
|
||||||
|
"1F64E": ":person_with_pouting_face:",
|
||||||
|
"0260E": ":phone:",
|
||||||
|
"1F437": ":pig:",
|
||||||
|
"1F416": ":pig2:",
|
||||||
|
"1F43D": ":pig_nose:",
|
||||||
|
"1F48A": ":pill:",
|
||||||
|
"1F34D": ":pineapple:",
|
||||||
|
"02653": ":pisces:",
|
||||||
|
"1F355": ":pizza:",
|
||||||
|
"1F447": ":point_down:",
|
||||||
|
"1F448": ":point_left:",
|
||||||
|
"1F449": ":point_right:",
|
||||||
|
"0261D": ":point_up:",
|
||||||
|
"1F446": ":point_up_2:",
|
||||||
|
"1F693": ":police_car:",
|
||||||
|
"1F429": ":poodle:",
|
||||||
|
"1F4A9": ":poop:",
|
||||||
|
"1F3E3": ":post_office:",
|
||||||
|
"1F4EF": ":postal_horn:",
|
||||||
|
"1F4EE": ":postbox:",
|
||||||
|
"1F6B0": ":potable_water:",
|
||||||
|
"1F45D": ":pouch:",
|
||||||
|
"1F357": ":poultry_leg:",
|
||||||
|
"1F4B7": ":pound:",
|
||||||
|
"1F63E": ":pouting_cat:",
|
||||||
|
"1F64F": ":pray:",
|
||||||
|
"1F478": ":princess:",
|
||||||
|
"1F44A": ":punch:",
|
||||||
|
"1F49C": ":purple_heart:",
|
||||||
|
"1F45B": ":purse:",
|
||||||
|
"1F4CC": ":pushpin:",
|
||||||
|
"1F6AE": ":put_litter_in_its_place:",
|
||||||
|
"02753": ":question:",
|
||||||
|
"1F430": ":rabbit:",
|
||||||
|
"1F407": ":rabbit2:",
|
||||||
|
"1F40E": ":racehorse:",
|
||||||
|
"1F4FB": ":radio:",
|
||||||
|
"1F518": ":radio_button:",
|
||||||
|
"1F621": ":rage:",
|
||||||
|
"1F683": ":railway_car:",
|
||||||
|
"1F308": ":rainbow:",
|
||||||
|
"0270B": ":raised_hand:",
|
||||||
|
"1F64C": ":raised_hands:",
|
||||||
|
"1F64B": ":raising_hand:",
|
||||||
|
"1F40F": ":ram:",
|
||||||
|
"1F35C": ":ramen:",
|
||||||
|
"1F400": ":rat:",
|
||||||
|
"0267B": ":recycle:",
|
||||||
|
"1F697": ":red_car:",
|
||||||
|
"1F534": ":red_circle:",
|
||||||
|
"000AE": ":registered:",
|
||||||
|
"0263A": ":relaxed:",
|
||||||
|
"1F60C": ":relieved:",
|
||||||
|
"1F501": ":repeat:",
|
||||||
|
"1F502": ":repeat_one:",
|
||||||
|
"1F6BB": ":restroom:",
|
||||||
|
"1F49E": ":revolving_hearts:",
|
||||||
|
"023EA": ":rewind:",
|
||||||
|
"1F380": ":ribbon:",
|
||||||
|
"1F35A": ":rice:",
|
||||||
|
"1F359": ":rice_ball:",
|
||||||
|
"1F358": ":rice_cracker:",
|
||||||
|
"1F391": ":rice_scene:",
|
||||||
|
"1F48D": ":ring:",
|
||||||
|
"1F680": ":rocket:",
|
||||||
|
"1F3A2": ":roller_coaster:",
|
||||||
|
"1F413": ":rooster:",
|
||||||
|
"1F339": ":rose:",
|
||||||
|
"1F6A8": ":rotating_light:",
|
||||||
|
"1F4CD": ":round_pushpin:",
|
||||||
|
"1F6A3": ":rowboat:",
|
||||||
|
"1F3C9": ":rugby_football:",
|
||||||
|
"1F3C3": ":runner:",
|
||||||
|
"1F3C3": ":running:",
|
||||||
|
"1F3BD": ":running_shirt_with_sash:",
|
||||||
|
"1F202": ":sa:",
|
||||||
|
"02650": ":sagittarius:",
|
||||||
|
"026F5": ":sailboat:",
|
||||||
|
"1F376": ":sake:",
|
||||||
|
"1F461": ":sandal:",
|
||||||
|
"1F385": ":santa:",
|
||||||
|
"1F4E1": ":satellite:",
|
||||||
|
"1F606": ":satisfied:",
|
||||||
|
"1F3B7": ":saxophone:",
|
||||||
|
"1F3EB": ":school:",
|
||||||
|
"1F392": ":school_satchel:",
|
||||||
|
"02702": ":scissors:",
|
||||||
|
"0264F": ":scorpius:",
|
||||||
|
"1F631": ":scream:",
|
||||||
|
"1F640": ":scream_cat:",
|
||||||
|
"1F4DC": ":scroll:",
|
||||||
|
"1F4BA": ":seat:",
|
||||||
|
"03299": ":secret:",
|
||||||
|
"1F648": ":see_no_evil:",
|
||||||
|
"1F331": ":seedling:",
|
||||||
|
"1F367": ":shaved_ice:",
|
||||||
|
"1F411": ":sheep:",
|
||||||
|
"1F41A": ":shell:",
|
||||||
|
"1F6A2": ":ship:",
|
||||||
|
"1F455": ":shirt:",
|
||||||
|
"1F4A9": ":shit:",
|
||||||
|
"1F45E": ":shoe:",
|
||||||
|
"1F6BF": ":shower:",
|
||||||
|
"1F4F6": ":signal_strength:",
|
||||||
|
"1F52F": ":six_pointed_star:",
|
||||||
|
"1F3BF": ":ski:",
|
||||||
|
"1F480": ":skull:",
|
||||||
|
"1F634": ":sleeping:",
|
||||||
|
"1F62A": ":sleepy:",
|
||||||
|
"1F3B0": ":slot_machine:",
|
||||||
|
"1F539": ":small_blue_diamond:",
|
||||||
|
"1F538": ":small_orange_diamond:",
|
||||||
|
"1F53A": ":small_red_triangle:",
|
||||||
|
"1F53B": ":small_red_triangle_down:",
|
||||||
|
"1F604": ":smile:",
|
||||||
|
"1F638": ":smile_cat:",
|
||||||
|
"1F603": ":smiley:",
|
||||||
|
"1F63A": ":smiley_cat:",
|
||||||
|
"1F608": ":smiling_imp:",
|
||||||
|
"1F60F": ":smirk:",
|
||||||
|
"1F63C": ":smirk_cat:",
|
||||||
|
"1F6AC": ":smoking:",
|
||||||
|
"1F40C": ":snail:",
|
||||||
|
"1F40D": ":snake:",
|
||||||
|
"1F3C2": ":snowboarder:",
|
||||||
|
"02744": ":snowflake:",
|
||||||
|
"026C4": ":snowman:",
|
||||||
|
"1F62D": ":sob:",
|
||||||
|
"026BD": ":soccer:",
|
||||||
|
"1F51C": ":soon:",
|
||||||
|
"1F198": ":sos:",
|
||||||
|
"1F509": ":sound:",
|
||||||
|
"1F47E": ":space_invader:",
|
||||||
|
"02660": ":spades:",
|
||||||
|
"1F35D": ":spaghetti:",
|
||||||
|
"02747": ":sparkle:",
|
||||||
|
"1F387": ":sparkler:",
|
||||||
|
"02728": ":sparkles:",
|
||||||
|
"1F496": ":sparkling_heart:",
|
||||||
|
"1F64A": ":speak_no_evil:",
|
||||||
|
"1F50A": ":speaker:",
|
||||||
|
"1F4AC": ":speech_balloon:",
|
||||||
|
"1F6A4": ":speedboat:",
|
||||||
|
"02B50": ":star:",
|
||||||
|
"1F31F": ":star2:",
|
||||||
|
"1F303": ":stars:",
|
||||||
|
"1F689": ":station:",
|
||||||
|
"1F5FD": ":statue_of_liberty:",
|
||||||
|
"1F682": ":steam_locomotive:",
|
||||||
|
"1F372": ":stew:",
|
||||||
|
"1F4CF": ":straight_ruler:",
|
||||||
|
"1F353": ":strawberry:",
|
||||||
|
"1F61B": ":stuck_out_tongue:",
|
||||||
|
"1F61D": ":stuck_out_tongue_closed_eyes:",
|
||||||
|
"1F61C": ":stuck_out_tongue_winking_eye:",
|
||||||
|
"1F31E": ":sun_with_face:",
|
||||||
|
"1F33B": ":sunflower:",
|
||||||
|
"1F60E": ":sunglasses:",
|
||||||
|
"02600": ":sunny:",
|
||||||
|
"1F305": ":sunrise:",
|
||||||
|
"1F304": ":sunrise_over_mountains:",
|
||||||
|
"1F3C4": ":surfer:",
|
||||||
|
"1F363": ":sushi:",
|
||||||
|
"1F69F": ":suspension_railway:",
|
||||||
|
"1F613": ":sweat:",
|
||||||
|
"1F4A6": ":sweat_drops:",
|
||||||
|
"1F605": ":sweat_smile:",
|
||||||
|
"1F360": ":sweet_potato:",
|
||||||
|
"1F3CA": ":swimmer:",
|
||||||
|
"1F523": ":symbols:",
|
||||||
|
"1F489": ":syringe:",
|
||||||
|
"1F389": ":tada:",
|
||||||
|
"1F38B": ":tanabata_tree:",
|
||||||
|
"1F34A": ":tangerine:",
|
||||||
|
"02649": ":taurus:",
|
||||||
|
"1F695": ":taxi:",
|
||||||
|
"1F375": ":tea:",
|
||||||
|
"0260E": ":telephone:",
|
||||||
|
"1F4DE": ":telephone_receiver:",
|
||||||
|
"1F52D": ":telescope:",
|
||||||
|
"1F3BE": ":tennis:",
|
||||||
|
"026FA": ":tent:",
|
||||||
|
"1F4AD": ":thought_balloon:",
|
||||||
|
"1F44E": ":thumbsdown:",
|
||||||
|
"1F44D": ":thumbsup:",
|
||||||
|
"1F3AB": ":ticket:",
|
||||||
|
"1F42F": ":tiger:",
|
||||||
|
"1F405": ":tiger2:",
|
||||||
|
"1F62B": ":tired_face:",
|
||||||
|
"02122": ":tm:",
|
||||||
|
"1F6BD": ":toilet:",
|
||||||
|
"1F5FC": ":tokyo_tower:",
|
||||||
|
"1F345": ":tomato:",
|
||||||
|
"1F445": ":tongue:",
|
||||||
|
"1F51D": ":top:",
|
||||||
|
"1F3A9": ":tophat:",
|
||||||
|
"1F69C": ":tractor:",
|
||||||
|
"1F6A5": ":traffic_light:",
|
||||||
|
"1F683": ":train:",
|
||||||
|
"1F686": ":train2:",
|
||||||
|
"1F68A": ":tram:",
|
||||||
|
"1F6A9": ":triangular_flag_on_post:",
|
||||||
|
"1F4D0": ":triangular_ruler:",
|
||||||
|
"1F531": ":trident:",
|
||||||
|
"1F624": ":triumph:",
|
||||||
|
"1F68E": ":trolleybus:",
|
||||||
|
"1F3C6": ":trophy:",
|
||||||
|
"1F379": ":tropical_drink:",
|
||||||
|
"1F420": ":tropical_fish:",
|
||||||
|
"1F69A": ":truck:",
|
||||||
|
"1F3BA": ":trumpet:",
|
||||||
|
"1F455": ":tshirt:",
|
||||||
|
"1F337": ":tulip:",
|
||||||
|
"1F422": ":turtle:",
|
||||||
|
"1F4FA": ":tv:",
|
||||||
|
"1F500": ":twisted_rightwards_arrows:",
|
||||||
|
"1F495": ":two_hearts:",
|
||||||
|
"1F46C": ":two_men_holding_hands:",
|
||||||
|
"1F46D": ":two_women_holding_hands:",
|
||||||
|
"1F239": ":u5272:",
|
||||||
|
"1F234": ":u5408:",
|
||||||
|
"1F23A": ":u55b6:",
|
||||||
|
"1F22F": ":u6307:",
|
||||||
|
"1F237": ":u6708:",
|
||||||
|
"1F236": ":u6709:",
|
||||||
|
"1F235": ":u6e80:",
|
||||||
|
"1F21A": ":u7121:",
|
||||||
|
"1F238": ":u7533:",
|
||||||
|
"1F232": ":u7981:",
|
||||||
|
"1F233": ":u7a7a:",
|
||||||
|
"02614": ":umbrella:",
|
||||||
|
"1F612": ":unamused:",
|
||||||
|
"1F51E": ":underage:",
|
||||||
|
"1F513": ":unlock:",
|
||||||
|
"1F199": ":up:",
|
||||||
|
"0270C": ":v:",
|
||||||
|
"1F6A6": ":vertical_traffic_light:",
|
||||||
|
"1F4FC": ":vhs:",
|
||||||
|
"1F4F3": ":vibration_mode:",
|
||||||
|
"1F4F9": ":video_camera:",
|
||||||
|
"1F3AE": ":video_game:",
|
||||||
|
"1F3BB": ":violin:",
|
||||||
|
"0264D": ":virgo:",
|
||||||
|
"1F30B": ":volcano:",
|
||||||
|
"1F19A": ":vs:",
|
||||||
|
"1F6B6": ":walking:",
|
||||||
|
"1F318": ":waning_crescent_moon:",
|
||||||
|
"1F316": ":waning_gibbous_moon:",
|
||||||
|
"026A0": ":warning:",
|
||||||
|
"0231A": ":watch:",
|
||||||
|
"1F403": ":water_buffalo:",
|
||||||
|
"1F349": ":watermelon:",
|
||||||
|
"1F44B": ":wave:",
|
||||||
|
"03030": ":wavy_dash:",
|
||||||
|
"1F312": ":waxing_crescent_moon:",
|
||||||
|
"1F314": ":waxing_gibbous_moon:",
|
||||||
|
"1F6BE": ":wc:",
|
||||||
|
"1F629": ":weary:",
|
||||||
|
"1F492": ":wedding:",
|
||||||
|
"1F433": ":whale:",
|
||||||
|
"1F40B": ":whale2:",
|
||||||
|
"0267F": ":wheelchair:",
|
||||||
|
"02705": ":white_check_mark:",
|
||||||
|
"026AA": ":white_circle:",
|
||||||
|
"1F4AE": ":white_flower:",
|
||||||
|
"02B1C": ":white_large_square:",
|
||||||
|
"025FD": ":white_medium_small_square:",
|
||||||
|
"025FB": ":white_medium_square:",
|
||||||
|
"025AB": ":white_small_square:",
|
||||||
|
"1F533": ":white_square_button:",
|
||||||
|
"1F390": ":wind_chime:",
|
||||||
|
"1F377": ":wine_glass:",
|
||||||
|
"1F609": ":wink:",
|
||||||
|
"1F43A": ":wolf:",
|
||||||
|
"1F469": ":woman:",
|
||||||
|
"1F45A": ":womans_clothes:",
|
||||||
|
"1F452": ":womans_hat:",
|
||||||
|
"1F6BA": ":womens:",
|
||||||
|
"1F61F": ":worried:",
|
||||||
|
"1F527": ":wrench:",
|
||||||
|
"0274C": ":x:",
|
||||||
|
"1F49B": ":yellow_heart:",
|
||||||
|
"1F4B4": ":yen:",
|
||||||
|
"1F60B": ":yum:",
|
||||||
|
"026A1": ":zap:",
|
||||||
|
"1F4A4": ":zzz:",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Decode hex numbers separated by spaces into a string
|
||||||
|
def decode_points(code):
|
||||||
|
return "".join(map(lambda c: chr(int(c, 16)), code.split()))
|
||||||
|
|
||||||
|
def make_name(code):
|
||||||
|
return ":" + "".join(map(lambda c: "u" + c, code.split())) + ":"
|
||||||
|
|
||||||
|
# def fetch(url):
|
||||||
|
# return request.urlopen(url).read().decode().split("\n")
|
||||||
|
|
||||||
|
# https://unicode.org/Public/emoji/13.1/emoji-test.txt
|
||||||
|
with open(sys.argv[1]) as f:
|
||||||
|
entries = parse_lines(f)
|
||||||
|
|
||||||
|
def keep_emoji(e):
|
||||||
|
code, status, _ = e
|
||||||
|
code = code.split()
|
||||||
|
# Keep only interesting emojis (others are duplicates or won't render well)
|
||||||
|
# Remove skin tone variants, they are accessible through combinations
|
||||||
|
return status in [ "fully-qualified", "component" ] and \
|
||||||
|
not (len(code) > 1 and code[-1] in [ "1F3FB", "1F3FC", "1F3FD", "1F3FE", "1F3FF" ])
|
||||||
|
|
||||||
|
|
||||||
|
for group in entries.values():
|
||||||
|
group = list(filter(keep_emoji, group))
|
||||||
|
print("%d" % len(group))
|
||||||
|
for code, status, desc in group:
|
||||||
|
name = name_map[code] if code in name_map else make_name(code)
|
||||||
|
print("%s %s %s" % (name, decode_points(code), desc))
|
@@ -1,6 +0,0 @@
|
|||||||
Hlavní funkcí je možnost psát více znaků posunutím kláves směrem k rohům.
|
|
||||||
|
|
||||||
Tato aplikace byla původně navržena pro programátory používající Termux.
|
|
||||||
Nyní je ideální pro každodenní použití.
|
|
||||||
|
|
||||||
Tato aplikace neobsahuje žádné reklamy, nevyužívá připojení k síti a je Open Source.
|
|
@@ -1 +0,0 @@
|
|||||||
Nenáročná virtuální klávesnice pro vývojáře.
|
|
@@ -1 +0,0 @@
|
|||||||
Klávesnice Unexpected
|
|
@@ -1,6 +0,0 @@
|
|||||||
Diese Tastatur zeichnet sich dadurch aus, dass man zusätzliche Zeichen durch Wischgesten in Richtung der Tastenecken eingeben kann.
|
|
||||||
|
|
||||||
Die Anwendung wurde ursprünglich für das Programmieren in Termux entwickelt.
|
|
||||||
Mittlerweile ist sie auch für den täglichen Gebrauch perfekt geeignet.
|
|
||||||
|
|
||||||
Diese App enthält keine Werbung, benötigt keinen Netzwerkzugriff und ist quelloffen.
|
|
@@ -1 +0,0 @@
|
|||||||
Eine schlanke, datenschutzfreundliche Bildschirmtastatur für Android.
|
|
@@ -1,21 +0,0 @@
|
|||||||
Translations: Brazilian portuguese (@igorSilCar), Chinese-Simplified (@9-2-1), Korean (@notnickid)
|
|
||||||
New layouts: Swedish (@thabubble), Korean (@notnickid)
|
|
||||||
|
|
||||||
Improved computation of the swipe gesture and fix unstoppable key-repeat on
|
|
||||||
some devices.
|
|
||||||
|
|
||||||
Moved keys away from the edges of the screen and other improvements to the layouts.
|
|
||||||
|
|
||||||
Improved rendering of some symbols.
|
|
||||||
|
|
||||||
Added more characters to the keyboard:
|
|
||||||
- New combinations to Fn (@ArenaL5)
|
|
||||||
- Currency symbols
|
|
||||||
- Added arrow and box symbols (@sdrapha)
|
|
||||||
- F11 and F12.
|
|
||||||
|
|
||||||
Option for making modifiers lockable. (@sdrapha)
|
|
||||||
Fixes to the Spanish layout and other fixes. (@ArenaL5)
|
|
||||||
Many other fixes.
|
|
||||||
|
|
||||||
Huge thanks to the contributors: @igorSilCar, @sdrapha, @ArenaL5, @notnickid, @9-2-1, @thabubble
|
|
@@ -1,25 +0,0 @@
|
|||||||
Quick fix release.
|
|
||||||
|
|
||||||
Previously:
|
|
||||||
|
|
||||||
Translations: Brazilian portuguese (@igorSilCar), Chinese-Simplified (@9-2-1), Korean (@notnickid)
|
|
||||||
New layouts: Swedish (@thabubble), Korean (@notnickid)
|
|
||||||
|
|
||||||
Improved computation of the swipe gesture and fix unstoppable key-repeat on
|
|
||||||
some devices.
|
|
||||||
|
|
||||||
Moved keys away from the edges of the screen and other improvements to the layouts.
|
|
||||||
|
|
||||||
Improved rendering of some symbols.
|
|
||||||
|
|
||||||
Added more characters to the keyboard:
|
|
||||||
- New combinations to Fn (@ArenaL5)
|
|
||||||
- Currency symbols
|
|
||||||
- Added arrow and box symbols (@sdrapha)
|
|
||||||
- F11 and F12.
|
|
||||||
|
|
||||||
Option for making modifiers lockable. (@sdrapha)
|
|
||||||
Fixes to the Spanish layout and other fixes. (@ArenaL5)
|
|
||||||
Many other fixes.
|
|
||||||
|
|
||||||
Huge thanks to the contributors: @igorSilCar, @sdrapha, @ArenaL5, @notnickid, @9-2-1, @thabubble
|
|
@@ -1,4 +0,0 @@
|
|||||||
Fix compatibility with Android 6.
|
|
||||||
Translation improvements.
|
|
||||||
|
|
||||||
Huge thanks to the contributors: @marciozomb13
|
|
@@ -1,7 +0,0 @@
|
|||||||
Support languages: Lithuanian, Hungarian (@tbilles)
|
|
||||||
New layouts: Neo2 (@matthiakl)
|
|
||||||
|
|
||||||
Translation improvements (@polyctena, @marciozomb13)
|
|
||||||
Fix modifiers applied twice when typing quickly. Some other fixes.
|
|
||||||
|
|
||||||
Many thanks to the contributors: @matthiakl, @polyctena, @marciozomb13, @dircsem
|
|
@@ -1,9 +0,0 @@
|
|||||||
New languages: Turkish (@erqan), Dutch (Belgium) (@draxaris1010)
|
|
||||||
New layouts: Turkish (@erqan), Colemak (@dircsem), Hungarian QWERTY
|
|
||||||
|
|
||||||
Less typos: Select the closest key on swipe (@Rodrigodd)
|
|
||||||
Removed settings: Vibration, Show every accents
|
|
||||||
More tweaks to the layouts
|
|
||||||
Fixes to landscape mode, updated translations and more tweaks.
|
|
||||||
|
|
||||||
Thanks to the contributors: @erqan, @draxaris1010, @dircsem, @Rodrigodd, @meanindra
|
|
@@ -1,5 +0,0 @@
|
|||||||
Add back the vibration option.
|
|
||||||
Fix localized keys not in predefined positions.
|
|
||||||
Improvements to layouts.
|
|
||||||
|
|
||||||
Thanks to the contributors: @Thunder-Squirrel
|
|
@@ -1,12 +0,0 @@
|
|||||||
New supported languages: Polish, Ukrainian, Bengali, Norwegian
|
|
||||||
New layouts: Ukrainian, Bengali, Norwegian, Bone, Czech
|
|
||||||
New translations: Brazilian Portuguese, Italian, Russian, Czech
|
|
||||||
|
|
||||||
Hold modifiers to lock, double tap on shift disabled by default.
|
|
||||||
Option to add more keys to the keyboard.
|
|
||||||
Automatic capitalisation at beginning of sentences.
|
|
||||||
Added e-ink oriented theme.
|
|
||||||
New pane for greek letters and mathematical symbols.
|
|
||||||
Improvements to the layouts and various bug fixes.
|
|
||||||
|
|
||||||
Thanks to the contributors: @nanno, @Quantenzitrone, @eandersons, @iamrasel, @ChristianGynnild, @igorSilCar, @CastixGitHub, @94KONG, @ptrm, @Validbit
|
|
@@ -1,7 +0,0 @@
|
|||||||
New supported languages: Hindi, Greek
|
|
||||||
|
|
||||||
Disable fullscreen mode.
|
|
||||||
Improvements to layouts and translations.
|
|
||||||
Various fixes and improvements.
|
|
||||||
|
|
||||||
Thanks to the contributors: @sdrapha, @lpv11, @Raj9039852537, @polyctena
|
|
@@ -1,11 +0,0 @@
|
|||||||
New layouts: QWERTZ (Deutsch)
|
|
||||||
|
|
||||||
Add optional numpad for wide screens.
|
|
||||||
Add pin entry layout for numbers.
|
|
||||||
Remove option "Lockable modifiers".
|
|
||||||
Hide Alt and Meta keys by default.
|
|
||||||
Added more optional keys.
|
|
||||||
Allow typing password on boot.
|
|
||||||
Improvements to the layouts and bug fixes.
|
|
||||||
|
|
||||||
Thanks to the contributors: @geroxyz
|
|
@@ -1,6 +0,0 @@
|
|||||||
Updated translations: Latvian
|
|
||||||
|
|
||||||
Fix crash when typing device password
|
|
||||||
Increase target SDK version to 31
|
|
||||||
|
|
||||||
Thanks to the contributors: @eandersons
|
|
@@ -1,10 +0,0 @@
|
|||||||
New layouts: QWERTY (Polski)
|
|
||||||
|
|
||||||
Allow switching quickly between two layouts.
|
|
||||||
Allow choosing opacity of the keyboard.
|
|
||||||
Improved themes and rendering.
|
|
||||||
Updated translations.
|
|
||||||
Fixed key repeat bug when holding 3 keys.
|
|
||||||
Tweaked the swipe gesture. Added some options.
|
|
||||||
|
|
||||||
Thanks to the contributors: @9-2-1, @ChasmSolacer
|
|
@@ -1 +0,0 @@
|
|||||||
Bug fix release.
|
|
@@ -1,7 +0,0 @@
|
|||||||
New layouts: QWERTZ (Slovak)
|
|
||||||
|
|
||||||
Bugs fixed.
|
|
||||||
Updated translations.
|
|
||||||
Tweaked themes and settings.
|
|
||||||
|
|
||||||
Thanks to the contributors: Jozef Kundlak, @MAKI1LOVE
|
|
@@ -1,10 +0,0 @@
|
|||||||
New translations: Vietnamese
|
|
||||||
New layouts: Hebrew, Vietnamese
|
|
||||||
|
|
||||||
Move the cursor by sliding on the space bar.
|
|
||||||
New ePaper theme.
|
|
||||||
Added number row.
|
|
||||||
Option to switch to the previous keyboard.
|
|
||||||
Updated translations.
|
|
||||||
|
|
||||||
Thanks to the contributors: @K4zoku, @rVnPower, @RamKromberg, @MAKI1LOVE
|
|
@@ -1,7 +0,0 @@
|
|||||||
New layouts: Arabic, Devanagari
|
|
||||||
|
|
||||||
Updated translations.
|
|
||||||
Updated layouts.
|
|
||||||
Bugs fixed.
|
|
||||||
|
|
||||||
Thanks to the contributors: @ChasmSolacer, @mostafaayesh, @lrvideckis, @eandersons, @mscheidemann, @JackDotJS
|
|
@@ -1,3 +0,0 @@
|
|||||||
Bug fixes.
|
|
||||||
|
|
||||||
Thanks to the contributors: @doak
|
|
@@ -1,9 +0,0 @@
|
|||||||
New layouts: Persian, Kurdish, Bengali Provat, Romanian, Czech
|
|
||||||
New languages support: Icelandic
|
|
||||||
Updated translations: Polish, Latvian, Russian, German, Vietnamese, Farsi, Brazilian, French, Simplified Chinese, Romanian
|
|
||||||
|
|
||||||
Voice typing shortcut (can be disabled in settings).
|
|
||||||
Improved vibration settings.
|
|
||||||
Many bug fixes and improvements.
|
|
||||||
|
|
||||||
Thanks to the contributors: @ChasmSolacer, @eandersons, @MAKI1LOVE, @Moini, @polyctena, @rVnPower, @RZHSSNZDH, @vladgba, @marciozomb13, @GoRaN909, @9-2-1, @shmVirus, @GrimPixel, @frimdo
|
|
@@ -1,9 +0,0 @@
|
|||||||
Allow selecting any number of standard and custom layouts.
|
|
||||||
Allow adding custom keys to the keyboard.
|
|
||||||
Changed behavior of auto-added keys (often dead-keys).
|
|
||||||
New layouts.
|
|
||||||
Improved layouts and language support.
|
|
||||||
Improved the space bar slider, and many more.
|
|
||||||
Updated translations.
|
|
||||||
|
|
||||||
Thanks to the contributors: @ChasmSolacer, @ElucGeek, @GoRaN909, @RZHSSNZDH, @Shareef101, @Validbit, @eandersons, @nitsvga, @polyctena, @sdrapha, @syskill
|
|
@@ -1,8 +0,0 @@
|
|||||||
Improved custom layout option.
|
|
||||||
Allow selecting voice typing app with a long press.
|
|
||||||
The numpad can work with other numeral systems.
|
|
||||||
New and updated layouts.
|
|
||||||
New themes.
|
|
||||||
Many small improvements.
|
|
||||||
|
|
||||||
Thanks to the contributors: @pharook, @syskill, @ojas-bhagavath, @lrvideckis, @lyubomirv, @matthiakl, @deftkHD, @V6lhost, @RZHSSNZDH, @RetrogisusDEV, @rafasaurus, @krtsgnr7230, @eandersons, @ChasmSolacer, @Validbit, @polyctena
|
|
@@ -1,7 +0,0 @@
|
|||||||
The custom vibration setting is back.
|
|
||||||
Allow to hide the keyboard switching key.
|
|
||||||
Fixed modifier keys in some development apps.
|
|
||||||
Updated translations.
|
|
||||||
Bug fixes and general improvements.
|
|
||||||
|
|
||||||
Many thanks to the contributors: @abb128, @marciozomb13, @RetrogisusDEV, @Sestowner, @vedamanavi, @krtsgnr7230
|
|
@@ -1,6 +0,0 @@
|
|||||||
New layouts: QWERTY (Slovak), Gujarati phonetic
|
|
||||||
Add Linux Compose key to type a variety of characters using known combinations.
|
|
||||||
Fixed localized numpad and number row.
|
|
||||||
Many improvements and bug fixes.
|
|
||||||
|
|
||||||
Huge thanks to the contributors: @Yogesh-B, @ChasmSolacer, @matthiakl, @Sestowner, @RyanGibb, @BogdanLata, @RetrogisusDEV, @V6lhost, @ErrrorMaxx, @sdrapha, @vedamanavi
|
|
@@ -1,11 +0,0 @@
|
|||||||
MessagEase and Thumb-Key inspired gestures with the anti-clockwise circle being
|
|
||||||
completely configurable.
|
|
||||||
|
|
||||||
Updated emojis.
|
|
||||||
Improved Hangul (Korean) support.
|
|
||||||
Added Danish support.
|
|
||||||
Improved spacebar slider.
|
|
||||||
Updated translations.
|
|
||||||
Various improvements and fixes to the app and layouts.
|
|
||||||
|
|
||||||
Many thanks to the contributors: @alotbsol555 @bkmgit @Cheesebaron @CloneWith @eandersons @JapanYoshi @Julow @la-ninpre @m15a @marciozomb13 @polyctena @solokot @Spike-from-NH @tmqCypher @Validbit
|
|
@@ -1,6 +0,0 @@
|
|||||||
The main feature is that you can type more characters by swiping the keys towards the corners.
|
|
||||||
|
|
||||||
This application was originally designed for programmers using Termux.
|
|
||||||
Now perfect for everyday use.
|
|
||||||
|
|
||||||
This application contains no ads, doesn't make any network requests and is Open Source.
|
|
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 20 KiB |
@@ -1 +0,0 @@
|
|||||||
Lightweight and privacy-conscious virtual keyboard for Android.
|
|
@@ -1 +0,0 @@
|
|||||||
https://www.youtube.com/watch?v=rwGvWesPFX8
|
|
@@ -1,6 +0,0 @@
|
|||||||
La característica principal es que hay acceso a más caractéres deslizando hacia las esquinas de las teclas.
|
|
||||||
|
|
||||||
Esta aplicación fue originalmente diseñada para programadores que usaran Termux.
|
|
||||||
Ahora es perfecta para uso cotidiano.
|
|
||||||
|
|
||||||
La misma no contiene ningún anuncio/publicidad, no realiza peticiones de red y es de Fuente Abierta.
|
|
@@ -1 +0,0 @@
|
|||||||
Un teclado virtual ligero para Android consciente de su privacidad.
|
|
@@ -1,6 +0,0 @@
|
|||||||
La fonctionnalité principale est l'accès rapide à plus de caractères en balayant les touches vers les coins.
|
|
||||||
|
|
||||||
Cette application a été conçue à l'origine pour les programmeurs utilisant Termux.
|
|
||||||
Elle est maintenant parfaite pour une utilisation quotidienne.
|
|
||||||
|
|
||||||
Cette application ne contient pas de publicité, n'accède pas au réseau et est Open Source.
|
|
@@ -1 +0,0 @@
|
|||||||
Clavier virtuel léger et respectueux de la vie privée pour Android.
|
|
@@ -1 +0,0 @@
|
|||||||
Una Tastiera Virtuale Leggera Per La Programmazione
|
|
@@ -1,18 +0,0 @@
|
|||||||
이 앱은 안드로이드용 가상 키보드입니다. 주요 기능은 스와이프 제스처를 사용하여 모든 ASCII 문자를 쉽게 입력할 수 있다는 점과 악센트 및 수정자 키를 위한 데드 키와 특수 키(tab, esc, 방향키 등)이 있다는 것입니다.
|
|
||||||
|
|
||||||
키보드는 각 키의 모서리에 최대 4개의 추가 문자를 표시합니다. 이러한 추가 문자는 키에서 손가락을 스와이프하여 적중됩니다.
|
|
||||||
|
|
||||||
일부 하이라이트 기능:
|
|
||||||
|
|
||||||
- PC 키보드에서 사용할 수 있는 모든 문자 및 특수 키를 사요 가능합니다. 이것은 Termux와 같은 앱을 사용하는 데 효과적입니다.
|
|
||||||
|
|
||||||
- 여기에는 Tab, Esc, 방향키 및 function 키뿐만이 아닌 Ctrl 및 Alt 키도 포함되어 있습니다 !
|
|
||||||
|
|
||||||
- 악센트 키는 데드 키를 사용하여 액세스할 수 있습니다. 먼저 악센트 키를 활성화한 다음 악센트 문자를 입력합니다.
|
|
||||||
|
|
||||||
- 매우 가볍고 빠릅니다. Google 키보드보다 500배, 기본 키보드보다 15배 적은 공간을 사용합니다. 광고와 사용 기록 추적 없음.
|
|
||||||
|
|
||||||
- 다중 레이아웃: QWERTY, QWERTZ, AZERTY. 다양한 테마: White, Dark, OLED Black. 또한 다른 많은 옵션들.
|
|
||||||
|
|
||||||
다른 가상 키보드와 마찬가지로 시스템 설정에서 활성화해야 합니다. 시스템 설정을 열고 다음으로 이동합니다.
|
|
||||||
시스템 > 언어 및 입력 > 키보드 > 키보드 관리.
|
|
@@ -1 +0,0 @@
|
|||||||
개발자들을 위한 가벼운 가상 키보드.
|
|
@@ -1 +0,0 @@
|
|||||||
Unexpected Keyboard
|
|
@@ -1,6 +0,0 @@
|
|||||||
Galvenā iezīme ir iespēja ievadīt vairāk rakstzīmju ar pavilkšanu uz taustiņu stūriem.
|
|
||||||
|
|
||||||
Šī lietotne sākotnēji tika izstrādāta programmētājiem, kas izmanto Termux.
|
|
||||||
Tagad lieliski piemērota izmantošanai ikdienā.
|
|
||||||
|
|
||||||
Šī lietotne nesatur reklāmas, neveic nekādus tīkla pieprasījumus, un tās pirmkods ir pieejams visiem.
|
|
@@ -1 +0,0 @@
|
|||||||
Mazizmēra un privātumu ievērojoša virtuālā Android tastatūra.
|
|
@@ -1 +0,0 @@
|
|||||||
Unexpected Keyboard
|
|
@@ -1,6 +0,0 @@
|
|||||||
Główną cechą tej klawiatury jest możliwość wprowadzania więcej znaków poprzez przesuwanie po klawiszach do ich rogów.
|
|
||||||
|
|
||||||
Ta aplikacja została pierwotnie zaprojektowana z myślą o programistach używających Termuxa.
|
|
||||||
Obecnie nadaje się doskonale do codziennego użytku.
|
|
||||||
|
|
||||||
Aplikacja nie zawiera reklam, nie żąda dostępu do internetu, a jej kod źródłowy jest dostępny publicznie.
|
|
@@ -1 +0,0 @@
|
|||||||
Lekka i dbająca o prywatność klawiatura wirtualna dla Androida.
|
|
@@ -1 +0,0 @@
|
|||||||
Unexpected Keyboard
|
|
@@ -1,6 +0,0 @@
|
|||||||
A principal característica é que você pode digitar mais caracteres deslizando as teclas para os cantos.
|
|
||||||
|
|
||||||
O app foi criado originalmente para desenvolvedores que usam Termux.
|
|
||||||
Agora aperfeiçoado para o uso diário.
|
|
||||||
|
|
||||||
Este aplicativo não contém anúncios, não faz nenhuma solicitação de rede e é Open Source.
|
|
@@ -1 +0,0 @@
|
|||||||
Teclado Unexpected
|
|
@@ -1,6 +0,0 @@
|
|||||||
Funcționalitatea principală este accesul rapid la o mulțime de caractere ASCII prin glisarea către colțurile tastelor.
|
|
||||||
|
|
||||||
Această aplicație a fost concepută inițial pentru programatori care folosec Termux.
|
|
||||||
Este perfectă pentru uzul cotidian.
|
|
||||||
|
|
||||||
Această aplicație nu conține publicitate, nu folosește rețeaua deloc și e Open Source.
|
|
@@ -1 +0,0 @@
|
|||||||
Tastatură virtuală pentru Android, ușoară și respectuoasă cu viața privată.
|
|
@@ -1 +0,0 @@
|
|||||||
Unexpected Keyboard
|
|
@@ -1,6 +0,0 @@
|
|||||||
Главная особенность клавиатуры — это возможность легко напечатать любой ASCII-символ жестами в углы клавиш.
|
|
||||||
|
|
||||||
Приложение изначально было разработано для использования с Termux.
|
|
||||||
На данный момент оно также удобно в повседневном использовании.
|
|
||||||
|
|
||||||
Приложение не содержит рекламы, не осуществляет никаких запросов в сеть и имеет открытый исходный код.
|
|
@@ -1 +0,0 @@
|
|||||||
Легкая клавиатура для пользователей, заботящихся о конфиденциальности.
|
|
@@ -1 +0,0 @@
|
|||||||
Unexpected Keyboard
|
|
@@ -1,6 +0,0 @@
|
|||||||
Bu uygulama özünde tuşların kenarlarından kaydırarak daha fazla karakter yazabilmek amacıyla geliştirildi.
|
|
||||||
|
|
||||||
Bu uygulama aslında Termux kullanıcıları için geliştirildi.
|
|
||||||
Artık gündelik kullanım için de uygun.
|
|
||||||
|
|
||||||
Bu uygulama açık kaynaklıdır. Reklam içermez ve internete bağlanmaz.
|
|
@@ -1 +0,0 @@
|
|||||||
Android için hafif ve güvenlik odaklı bir sanal klavye uygulaması.
|
|
@@ -1 +0,0 @@
|
|||||||
Unexpected Keyboard
|
|
@@ -1,6 +0,0 @@
|
|||||||
Головна особливість полягає в тому, що ви можете вводити більше символів, проводячи клавіші до кутів.
|
|
||||||
|
|
||||||
Ця програма спочатку була розроблена для програмістів, які використовують Termux.
|
|
||||||
Тепер ідеально підходить для щоденного використання.
|
|
||||||
|
|
||||||
Ця програма не містить реклами, не надсилає жодних мережевих запитів і має відкритий код.
|
|
@@ -1 +0,0 @@
|
|||||||
Легка та конфіденційна віртуальна клавіатура для Android.
|
|
@@ -1 +0,0 @@
|
|||||||
Unexpected Keyboard
|
|
@@ -1,6 +0,0 @@
|
|||||||
Chức năng chính là dễ dàng gõ nhiều ký tự bằng cách kéo phím về góc của nó.
|
|
||||||
|
|
||||||
Ứng dụng này ban đầu được thiết kế cho các lập trình viên dùng Termux.
|
|
||||||
Bây giờ đã hoàn hảo cho việc sử dụng hàng ngày.
|
|
||||||
|
|
||||||
Ứng dụng này không chứa quảng cáo, không cần đến mạng, và có mã nguồn mở.
|
|
@@ -1 +0,0 @@
|
|||||||
Bàn phím ảo gọn nhẹ và tôn trọng quyền riêng tư cho Android.
|
|
@@ -1 +0,0 @@
|
|||||||
Unexpected Keyboard
|
|
@@ -1,6 +0,0 @@
|
|||||||
此应用的主要功能是,通过将按键沿四角滑动,您可以输入更多字符。
|
|
||||||
|
|
||||||
此应用最初是为使用 Termux 的程序员而设计的。
|
|
||||||
现在对于日常使用来说也很完美。
|
|
||||||
|
|
||||||
此应用没有广告,不会发送任何网络请求,而且是开源的。
|
|
@@ -1 +0,0 @@
|
|||||||
适用于 Android 的轻量级、注重隐私的虚拟键盘。
|
|
@@ -1 +0,0 @@
|
|||||||
Unexpected Keyboard
|
|
38
gen_emoji.py
@@ -1,38 +0,0 @@
|
|||||||
import urllib.request
|
|
||||||
import os.path
|
|
||||||
|
|
||||||
EMOJIS_PATH = 'res/raw/emojis.txt'
|
|
||||||
EMOJI_TEST_PATH = 'emoji-test.txt'
|
|
||||||
EMOJI_TEST_URL = 'https://unicode.org/Public/emoji/latest/emoji-test.txt'
|
|
||||||
|
|
||||||
def rawEmojiFromCodes(codes):
|
|
||||||
return ''.join([chr(int(c, 16)) for c in codes])
|
|
||||||
|
|
||||||
def getEmojiTestContents():
|
|
||||||
if os.path.exists(EMOJI_TEST_PATH):
|
|
||||||
print(f'Using existing {EMOJI_TEST_PATH}')
|
|
||||||
else:
|
|
||||||
print(f'Downloading {EMOJI_TEST_URL}')
|
|
||||||
urllib.request.urlretrieve(EMOJI_TEST_URL, EMOJI_TEST_PATH)
|
|
||||||
return open(EMOJI_TEST_PATH, mode='r', encoding='UTF-8').read()
|
|
||||||
|
|
||||||
|
|
||||||
emoji_list = []
|
|
||||||
group_indices = []
|
|
||||||
for line in getEmojiTestContents().splitlines():
|
|
||||||
if line.startswith('# group:'):
|
|
||||||
if len(group_indices) == 0 or len(emoji_list) > group_indices[-1]:
|
|
||||||
group_indices.append(len(emoji_list))
|
|
||||||
elif not line.startswith('#') and 'fully-qualified' in line:
|
|
||||||
codes = line.split(';')[0].split()
|
|
||||||
emoji_list.append(rawEmojiFromCodes(codes))
|
|
||||||
|
|
||||||
with open(EMOJIS_PATH, 'w', encoding='UTF-8') as emojis:
|
|
||||||
for e in emoji_list:
|
|
||||||
emojis.write(f'{e}\n')
|
|
||||||
emojis.write('\n')
|
|
||||||
|
|
||||||
emojis.write(' '.join([str(g) for g in group_indices]))
|
|
||||||
emojis.write('\n')
|
|
||||||
|
|
||||||
print(f'Parsed {len(emoji_list)} emojis in {len(group_indices)}')
|
|
@@ -1,64 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
# Generates the list of layouts in res/values/layouts.xml from the layout files
|
|
||||||
# in srcs/layouts. Every layouts must have a 'name' attribute to be listed.
|
|
||||||
|
|
||||||
import itertools as it
|
|
||||||
import sys, os, glob
|
|
||||||
import xml.etree.ElementTree as XML
|
|
||||||
|
|
||||||
# Layouts first in the list (these are the programming layouts). Other layouts
|
|
||||||
# are sorted alphabetically.
|
|
||||||
FIRST_LAYOUTS = [ "latn_qwerty_us", "latn_colemak", "latn_dvorak" ]
|
|
||||||
|
|
||||||
# Read a layout from a file. Returns [None] if [fname] is not a layout.
|
|
||||||
def read_layout(fname):
|
|
||||||
root = XML.parse(fname).getroot()
|
|
||||||
if root.tag != "keyboard":
|
|
||||||
return None
|
|
||||||
return { "name": root.get("name") }
|
|
||||||
|
|
||||||
# Yields the id (based on the file name) and the display name for every layouts
|
|
||||||
def read_layouts(files):
|
|
||||||
for layout_file in files:
|
|
||||||
layout_id, _ = os.path.splitext(os.path.basename(layout_file))
|
|
||||||
layout = read_layout(layout_file)
|
|
||||||
if layout == None:
|
|
||||||
print("Not a layout file: %s" % layout_file)
|
|
||||||
elif layout["name"] == None:
|
|
||||||
print("Layout doesn't have a name: %s" % layout_id)
|
|
||||||
else:
|
|
||||||
yield (layout_id, layout["name"])
|
|
||||||
|
|
||||||
# Sort layouts alphabetically, except for layouts in FIRST_LAYOUTS, which are
|
|
||||||
# placed at the top.
|
|
||||||
# Returns a list. 'layouts' can be an iterator.
|
|
||||||
def sort_layouts(layouts):
|
|
||||||
layouts = dict(layouts)
|
|
||||||
head = [ (lid, layouts.pop(lid)) for lid in FIRST_LAYOUTS ]
|
|
||||||
return head + sorted(layouts.items())
|
|
||||||
|
|
||||||
# Write the XML arrays used in the preferences.
|
|
||||||
def generate_arrays(out, layouts):
|
|
||||||
def mk_array(tag, name, strings_items):
|
|
||||||
elem = XML.Element(tag, name=name)
|
|
||||||
for s in strings_items:
|
|
||||||
item = XML.Element("item")
|
|
||||||
item.text = s
|
|
||||||
elem.append(item)
|
|
||||||
return elem
|
|
||||||
system_item = [ ("system", "@string/pref_layout_e_system") ]
|
|
||||||
custom_item = [ ("custom", "@string/pref_layout_e_custom") ]
|
|
||||||
values_items, entries_items = zip(*(system_item + layouts + custom_item)) # unzip
|
|
||||||
ids_items = map(lambda s: "@xml/%s" % s if s not in ["system", "custom"] else "-1", values_items)
|
|
||||||
root = XML.Element("resources")
|
|
||||||
root.append(XML.Comment(text="DO NOT EDIT. This file is generated, see gen_layouts.py."))
|
|
||||||
root.append(mk_array("string-array", "pref_layout_values", values_items))
|
|
||||||
root.append(mk_array("string-array", "pref_layout_entries", entries_items))
|
|
||||||
root.append(mk_array("integer-array", "layout_ids", ids_items))
|
|
||||||
XML.indent(root)
|
|
||||||
XML.ElementTree(element=root).write(out, encoding="unicode", xml_declaration=True)
|
|
||||||
|
|
||||||
layouts = sort_layouts(read_layouts(glob.glob("srcs/layouts/*.xml")))
|
|
||||||
with open("res/values/layouts.xml", "w") as out:
|
|
||||||
generate_arrays(out, layouts)
|
|
@@ -1,3 +0,0 @@
|
|||||||
org.gradle.jvmargs=-Dfile.encoding=UTF-8
|
|
||||||
android.useAndroidX=false
|
|
||||||
android.nonTransitiveRClass=true
|
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
6
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +0,0 @@
|
|||||||
#Mon Aug 21 18:13:41 CEST 2023
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
|
||||||
distributionPath=wrapper/dists
|
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
|
||||||
zipStorePath=wrapper/dists
|
|
185
gradlew
vendored
@@ -1,185 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
#
|
|
||||||
# Copyright 2015 the original author or authors.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
##
|
|
||||||
## Gradle start up script for UN*X
|
|
||||||
##
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
|
||||||
# Resolve links: $0 may be a link
|
|
||||||
PRG="$0"
|
|
||||||
# Need this for relative symlinks.
|
|
||||||
while [ -h "$PRG" ] ; do
|
|
||||||
ls=`ls -ld "$PRG"`
|
|
||||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
|
||||||
if expr "$link" : '/.*' > /dev/null; then
|
|
||||||
PRG="$link"
|
|
||||||
else
|
|
||||||
PRG=`dirname "$PRG"`"/$link"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
SAVED="`pwd`"
|
|
||||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
|
||||||
APP_HOME="`pwd -P`"
|
|
||||||
cd "$SAVED" >/dev/null
|
|
||||||
|
|
||||||
APP_NAME="Gradle"
|
|
||||||
APP_BASE_NAME=`basename "$0"`
|
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
|
||||||
MAX_FD="maximum"
|
|
||||||
|
|
||||||
warn () {
|
|
||||||
echo "$*"
|
|
||||||
}
|
|
||||||
|
|
||||||
die () {
|
|
||||||
echo
|
|
||||||
echo "$*"
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
|
||||||
cygwin=false
|
|
||||||
msys=false
|
|
||||||
darwin=false
|
|
||||||
nonstop=false
|
|
||||||
case "`uname`" in
|
|
||||||
CYGWIN* )
|
|
||||||
cygwin=true
|
|
||||||
;;
|
|
||||||
Darwin* )
|
|
||||||
darwin=true
|
|
||||||
;;
|
|
||||||
MINGW* )
|
|
||||||
msys=true
|
|
||||||
;;
|
|
||||||
NONSTOP* )
|
|
||||||
nonstop=true
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
|
||||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
|
||||||
else
|
|
||||||
JAVACMD="$JAVA_HOME/bin/java"
|
|
||||||
fi
|
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
JAVACMD="java"
|
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
|
||||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
|
||||||
MAX_FD_LIMIT=`ulimit -H -n`
|
|
||||||
if [ $? -eq 0 ] ; then
|
|
||||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
|
||||||
MAX_FD="$MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
ulimit -n $MAX_FD
|
|
||||||
if [ $? -ne 0 ] ; then
|
|
||||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Darwin, add options to specify how the application appears in the dock
|
|
||||||
if $darwin; then
|
|
||||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
|
||||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
|
||||||
|
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
|
||||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
|
||||||
SEP=""
|
|
||||||
for dir in $ROOTDIRSRAW ; do
|
|
||||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
|
||||||
SEP="|"
|
|
||||||
done
|
|
||||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
|
||||||
# Add a user-defined pattern to the cygpath arguments
|
|
||||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
|
||||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
|
||||||
fi
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
||||||
i=0
|
|
||||||
for arg in "$@" ; do
|
|
||||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
|
||||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
|
||||||
|
|
||||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
|
||||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
|
||||||
else
|
|
||||||
eval `echo args$i`="\"$arg\""
|
|
||||||
fi
|
|
||||||
i=`expr $i + 1`
|
|
||||||
done
|
|
||||||
case $i in
|
|
||||||
0) set -- ;;
|
|
||||||
1) set -- "$args0" ;;
|
|
||||||
2) set -- "$args0" "$args1" ;;
|
|
||||||
3) set -- "$args0" "$args1" "$args2" ;;
|
|
||||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
|
||||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
|
||||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
|
||||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
|
||||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
|
||||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Escape application args
|
|
||||||
save () {
|
|
||||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
|
||||||
echo " "
|
|
||||||
}
|
|
||||||
APP_ARGS=`save "$@"`
|
|
||||||
|
|
||||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
|
||||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
|
||||||
|
|
||||||
exec "$JAVACMD" "$@"
|
|
89
gradlew.bat
vendored
@@ -1,89 +0,0 @@
|
|||||||
@rem
|
|
||||||
@rem Copyright 2015 the original author or authors.
|
|
||||||
@rem
|
|
||||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
@rem you may not use this file except in compliance with the License.
|
|
||||||
@rem You may obtain a copy of the License at
|
|
||||||
@rem
|
|
||||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
@rem
|
|
||||||
@rem Unless required by applicable law or agreed to in writing, software
|
|
||||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
@rem See the License for the specific language governing permissions and
|
|
||||||
@rem limitations under the License.
|
|
||||||
@rem
|
|
||||||
|
|
||||||
@if "%DEBUG%" == "" @echo off
|
|
||||||
@rem ##########################################################################
|
|
||||||
@rem
|
|
||||||
@rem Gradle startup script for Windows
|
|
||||||
@rem
|
|
||||||
@rem ##########################################################################
|
|
||||||
|
|
||||||
@rem Set local scope for the variables with windows NT shell
|
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
|
||||||
if "%DIRNAME%" == "" set DIRNAME=.
|
|
||||||
set APP_BASE_NAME=%~n0
|
|
||||||
set APP_HOME=%DIRNAME%
|
|
||||||
|
|
||||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
|
||||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
|
||||||
|
|
||||||
@rem Find java.exe
|
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
|
||||||
|
|
||||||
set JAVA_EXE=java.exe
|
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
|
||||||
if "%ERRORLEVEL%" == "0" goto execute
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
echo.
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
echo location of your Java installation.
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
|
||||||
echo.
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
echo location of your Java installation.
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:execute
|
|
||||||
@rem Setup the command line
|
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
|
||||||
|
|
||||||
:end
|
|
||||||
@rem End local scope for the variables with windows NT shell
|
|
||||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
|
||||||
|
|
||||||
:fail
|
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
|
||||||
rem the _cmd.exe /c_ return code!
|
|
||||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
|
||||||
exit /b 1
|
|
||||||
|
|
||||||
:mainEnd
|
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
|
||||||
|
|
||||||
:omega
|
|
18
metadata/android/de-DE/full_description.txt
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
Diese App ist eine virtuelle Tastatur für Android. Hauptfunktionen sind das einfache Tippen eines jeden ASCII-Zeichens durch Wischgesten, Hilfstasten, Tottasten für Akzente, sowie das Vorhandensein spezieller Tasten (Tabulator, Esc, Pfeiltasten etc.).
|
||||||
|
|
||||||
|
Die Tastatur hat bis zu vier Extrazeichen in den Ecken jeder Taste. Diese Extrazeichen werden durch das Wischen mit dem Finger auf der Taste ausgewählt.
|
||||||
|
|
||||||
|
Highlights mancher Funktionen:
|
||||||
|
|
||||||
|
- Jedes Zeichen und jede spezielle Taste gibt es auch auf einer PC-Tastatur. Das ist perfekt für die Nutzung von Anwendungen wie Termux.
|
||||||
|
|
||||||
|
- Dies schließt auch Tab, Esc und die Pfeil- und Funktionstasten sowie Strg und Alt mit ein!
|
||||||
|
|
||||||
|
- Akzenttasten sind über Tottasten verfügbar. Nach Aktivieren des Akzents kan der akzentuierte Buchstabe getippt werden.
|
||||||
|
|
||||||
|
- Sehr schlank und schnell. Braucht 500x weniger Speicherplatz als Googles Tastatur und 15x weniger als die Standardtastatur. Keine Werbung, kein Tracking.
|
||||||
|
|
||||||
|
- Verschiedene Layouts: QWERTY, QWERTZ, AZERTY. Themes: Weiß, Dunkel, OLED Schwarz. Und viele weitere Optionen.
|
||||||
|
|
||||||
|
Wie jede andere virtuelle Tastatur muss diese Tastatur in den Systemeinstellungen aktiviert werden. Dazu Systemeinstellungen öffnen und wie folgt vorgehen:
|
||||||
|
System > Sprachen und Eingabe > Bildschirmtastatur > Bildschirmtastaturen verwalten.
|
1
metadata/android/de-DE/short_description.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Eine schlanke Bildschirmtastatur für Entwickler
|