Compare commits

...

286 Commits

Author SHA1 Message Date
Patrick Goldinger
2b47d4a811 Release v0.3.13 2021-08-26 17:47:16 +02:00
Patrick Goldinger
e977c512a7 Fix increment step for vibration duration preference 2021-08-26 12:57:43 +02:00
Patrick Goldinger
0828c0a4db Update issue template chooser and contributing for new discussions 2021-08-25 22:47:19 +02:00
Patrick Goldinger
ecee7bfa56 Update README.md for 0.3.13 2021-08-25 17:41:35 +02:00
Patrick Goldinger
7a0485c0dc Release v0.3.13-beta12 2021-08-24 15:44:12 +02:00
Patrick Goldinger
d4ff6143f4 Add heap size restriction note to description of suggestion pref 2021-08-24 15:37:13 +02:00
Patrick Goldinger
8aa8b30a43 Lower minimum heap size requirement for word suggestions to 256 MB 2021-08-24 15:33:27 +02:00
Patrick Goldinger
019bdcae6f Add devtool override toggle for heap size restriction (#1178) 2021-08-24 15:31:14 +02:00
Patrick Goldinger
edfea2dbf2 Release v0.3.13-beta11 2021-08-23 22:25:00 +02:00
Waelwindows
eeec8e0d17 Add katakan middle dot to popups (#1177) 2021-08-23 22:15:14 +02:00
Patrick Goldinger
e79ab3c2e3 Add min memory size restriction for word suggestions (#1176) 2021-08-23 17:33:54 +02:00
Patrick Goldinger
2719cf4930 Release v0.3.13-beta10 2021-08-22 22:10:48 +02:00
Patrick Goldinger
d6d89aac43 Update translations from Crowdin 2021-08-22 21:53:37 +02:00
Patrick Goldinger
973c738059 Adapt Settings home screen for 0.3.13 2021-08-22 21:51:22 +02:00
Waelwindows
2345192728 Add Japanese JIS layout (#140)
* feat: Add Japanaese JIS layout

* feat: Add KanaSelector and KanaSizeSelector

* test: Try out new selectors

* fix: Add new selectors to polymorphic key data list

This should help make florisboard recognize the new selectors
when used in layouts.

* fix: Implement `evaluteKana` for ComputingEvaluator

This should fix the crashes, hopefully

* feat: Rework the JIS layout

* fix: Implement basic logic for kana state

* feat: Add popups for JIS

* chore: Rename JIS specific layouts

For some reason this change broke the pop-ups

* feat: Add Kana Unicode compositor

* feat: Implement flipping small state and refactor

This should allow small kana characters to be switched over to their
normal counterparts. Also clean up and refactor `KanaUnicode` and make
the filename more appropriate

* Merge `master` to `japanese`

* chore: Add internal codes for Kana switching

This should be the starting point for getting actual keys
to switch between the kana types

* feat: Add initial modifer layout for JIS

* chore: Add keycode for ideographic CJK space

* feat: Add logic for kana switching

* chore: Update layout modifer to use kana switch

* feat: Add icon for kana switcher button

* fix: Scale the icon and update relevant entries

* feat: Begin work on kana selector popup

* Add kana attributes to keyboard state

* Add workaround for Japanese popups

* chore: Remove URL popups for JIS layout

* chore: Add codes and groups for kana switching

This commit adds the "~kana" group with groupId 4.

* feat: Use "~kana" in JIS layout.

* feat: Remove `KanaSizeSelector`.

It will be redundant when compositor handles it instead.

* feat: Add alpha code for making kana small.

This code currently uses a sentinel character to trigger
the transformation. This is not ideal as that means that users
won't be able to use that character in the keyboard. This won't
be a problem if the sentinel character is a Unicode codepoint
that cannot or would not be used normally. As such, this is just
a demonstration of the how the feature should function not it's
final implementation.

* test: Add kana small key in JIS for testing.

This is to preview changes to the kana small algorithm,
This commit should be removed from history later on.

* fix: Add `KANA_SWITCHER` to exceptionsForKeyCodes

* chore: Change "~kana" groupId to avoid conflicts

* fix: Change Kana small behaviour

* chore: Change internal kana small key code

* test: Remove kana small button from JIS layout

* feat: Add iteration marks to daku list

* feat: Allow swtiching between kana modifiers

This allows users to add/remove dakuten/handakuten/small
from kana and swtiching between the three. This is helpful
as it allows users to quickly rectify mistakes. It also lays
the groundwork for the future 12 flick layout

* feat: Change Kana swticher behaviour on katakana

Makes katakana switch over to hiragana immediately. As half-width
katakana is not usually used. The kana-switcher pop-up suffices
switching over to it when needed.

A potential downside to doing it like this making the half-width
katakana more hidden and less likely to be used.

* Add CJK_SPACE special behavior to input logic

* feat: Add CJK punctuation to popups and JIS layout

* feat: Add CJK punctuation symbols

* feat: Add CJK row numbers

* feat: Add postal mark symbol in CJK symbols

And change kana small internal code. Used to be set to
postal mark with face. Now set to geta mark.

* chore: Set default numeric row to CJK for JIS

* feat: Add modifiers layouts for CJK punctuation

* chore: Add latin half-width braces to CJK layout

* fix: Change composer behaviour on empty string

* chore: Add non-composing (han)daku to JIS popups

* fix: Change composer behaviour to be consistent

Also clean up the code a little.

* fix: Change composer empty string behaviour

* feat: Add WidthSelector and migrate half_kata Kana

This adds width selector for all languages instead of tying it down
to only `KanaSelector`. As such `KanaSelector`'s `half_kata`' field
is obsolete.

* fix: Fix bug in composing logic

* fix: Implement width properly and remove half_kata

* refactor: Clean up JIS layout JSON

* fix: Change JIS punctuation to use width_selector

* Improve half width implementation / Clean-up code base

* fix: Remove Half-kata from kana switcher cycle.

* feat: Add char width keycodes and implementation

* feat: Add half-width forms to symbols/cjk layouts

* feat: Add char width switcher to CJK mod layouts

Icons are yet to be added, so the labels will be strings for now

* feat: Add half-width forms for symbols2/cjk layout

* chore: Add more appropriate CJK chars to symbols2

* feat: Add icons for character width switching.

Note that `ic_keyboard_char_width_full` and `ic_keyboard_char_width_half`
are just copies of `ic_keyboard_char_width_switcher` for now.

* feat: Add relevant entries to show char width icons

* chore: Update the character width pop up icons.

And rename the internal names so that they match up with kana_switcher.

* fix: Make char width swticher icon toggle instead

* fix: Make character width icons more consistent.

* chore: Remove reference to char_width_switcher icon

* test: Iest code for why the composer is not working

* test: Remove test code for KanaUnicode

This reverts commit f6ae545183.

* fix: Correct small kana association for E and U

* test: Remove test code for KanaUnicode

This reverts commit f6ae545183.

* fix: Don't add small sentinel on non small char.

* fix: Correct small ya entry in KanaUnicode

* feat: Make kana switcher icon toggle between modes

* fix: Update svg colors to fit with other vectors

* Update app/src/main/java/dev/patrickgold/florisboard/ime/text/TextInputManager.kt

Co-authored-by: Patrick Goldinger <patrick.goldinger@pm.me>

* chore: Fix author name

* chore: Fix author name in CJK numbers

* chore: Fix indentation on author field

Co-authored-by: Waelwindows <waelwindows@hotmail.com>
Co-authored-by: Patrick Goldinger <patrick@patrickgold.dev>
2021-08-22 21:02:55 +02:00
Patrick Goldinger
dc1c71a01d Vastly improve spell checker performance and caching
Additionally add support for multiple locales caching
2021-08-22 17:50:07 +02:00
Patrick Goldinger
b93b646d41 Improve spell checker internals, reduce setup calls 2021-08-22 17:50:07 +02:00
Patrick Goldinger
75354703ce Improve keyboard subtypes locale match for spell checker 2021-08-22 17:50:07 +02:00
Patrick Goldinger
7123f004e9 Fix candidates view showing for raw editors
Raw editors don't support composing input and suggestions hardly
make any sense, so the clipboard cursor row is shown instead.
2021-08-21 00:02:03 +02:00
Patrick Goldinger
3dac44d326 Re-add old suggestions implementation for stable track 2021-08-21 00:02:03 +02:00
Patrick Goldinger
76de7e5db9 Add Flictionary for en_US 2021-08-21 00:02:03 +02:00
Patrick Goldinger
95e0b3408d Fix delete word swipe for browser inputs 2021-08-20 21:42:53 +02:00
Patrick Goldinger
358440779f Fix crash when using delete swipe for raw input editors (#1014) 2021-08-20 21:42:53 +02:00
Patrick Goldinger
6518eebce7 Fix word alignment for delete_words_precisely swipe 2021-08-20 21:42:53 +02:00
Patrick Goldinger
e19df82147 Fix performance issues for large text areas 2021-08-20 21:42:53 +02:00
Patrick Goldinger
3ec3f90d9f Fix selection and composing state bugs in EditorInstance 2021-08-20 21:42:53 +02:00
Patrick Goldinger
85452eeb10 Fix UserDictionary locale string bug 2021-08-20 21:42:53 +02:00
Patrick Goldinger
e4520007ea Rework EditorInstance cached input and word detection logic 2021-08-20 21:42:53 +02:00
Patrick Goldinger
63b55a9560 Update ICU build repo status 2021-08-17 20:01:42 +02:00
Patrick Goldinger
4dbc1ca740 Update GitHub workflows to fetch submodules 2021-08-16 21:08:29 +02:00
Patrick Goldinger
06c585885e Move icu4c to separate repository
Preparation step to build ICU separately for F-Droid builds. Also the
main repo's stats are now not polluted again from the sheer massive
size of ICU.
2021-08-16 21:08:29 +02:00
Patrick Goldinger
5bede68a82 Release v0.3.13-beta09 2021-08-15 21:34:45 +02:00
Patrick Goldinger
1a83456d77 Update feature roadmap of FlorisBoard 2021-08-15 21:26:14 +02:00
Patrick Goldinger
58d8ce96d9 Update translations from Crowdin 2021-08-15 12:15:32 +02:00
Patrick Goldinger
5aec281e87 Fix Smartbar Cut/Copy buttons limited to few characters (#1146) 2021-08-15 12:01:52 +02:00
Patrick Goldinger
bcbf561887 Fix popup merge bug for group assigned keys (#1028) 2021-08-14 18:43:11 +02:00
Waelwindows
813f300a15 Adjust Arabic popups for main forms and remove nums (#1087)
This commit makes the most common popups the main ones which should
allow Arabic sub-layout users to use FlorisBoard's smart popup feature.
2021-08-14 11:49:56 +02:00
Patrick Goldinger
a356585cf8 Fix 5+1 keyboard layout bug (#1100) 2021-08-14 01:32:52 +02:00
dvrnynr
689881f981 Remove popups not related to Turkish 2021-08-13 23:01:31 +02:00
Patrick Goldinger
d473369f37 Improve haptic feedback UI and internal logic 2021-08-13 22:59:43 +02:00
Patrick Goldinger
5fcd605b7d Possibly fix repeating delete key 2021-08-13 20:04:25 +02:00
Patrick Goldinger
2ea9dfee60 Fix theme editor preview looking distorted (#1136) 2021-08-13 18:56:40 +02:00
Patrick Goldinger
07ad6820cc Merge pull request #1142 from florisboard/input-feedback-manager
Rework audio and haptic feedback of FlorisBoard
2021-08-12 12:31:32 +02:00
Patrick Goldinger
1c8523c6dd Adjust input feedback feature toggle internals 2021-08-12 12:14:07 +02:00
Patrick Goldinger
84f682aaa7 Add new InputFeedbackManager 2021-08-08 11:57:05 +02:00
Patrick Goldinger
efc03a90b5 Remove jcenter repository / Remove dependency update task 2021-08-08 11:43:02 +02:00
Patrick Goldinger
8f3562a0c8 Add alternative numpad with PC arrangement of digits (#1132) 2021-08-06 10:04:49 +02:00
Patrick Goldinger
b15f7f68ae Remove AssetRef and AssetSource 2021-08-06 00:22:24 +02:00
Patrick Goldinger
b646b3095b Rework code base to use FlorisRef instead of AssetRef 2021-08-06 00:22:24 +02:00
Patrick Goldinger
261ea5db2e Rename v0.4.0 milestone to v0.3.x 2021-08-04 23:32:56 +02:00
Patrick Goldinger
ff93377459 Release v0.3.13-beta08 2021-08-04 00:34:40 +02:00
Patrick Goldinger
f90befdfbe Fix crash after rebooting in clipboard manager (#1097) 2021-08-04 00:21:03 +02:00
Patrick Goldinger
d490d6d457 Update translations from Crowdin 2021-08-03 23:36:22 +02:00
Patrick Goldinger
3fdaa448af Merge pull request #1128 from Glitchy-Tozier/patch-2
Update question.md
2021-08-03 21:29:26 +02:00
Patrick Goldinger
7f88643361 Merge pull request #1127 from Glitchy-Tozier/patch-1
Update feature_request.md
2021-08-03 21:28:44 +02:00
Glitchy-Tozier
55dc817843 Update question.md 2021-08-03 21:07:18 +02:00
Glitchy-Tozier
6e2969d8a6 Update feature_request.md 2021-08-03 21:04:10 +02:00
Patrick Goldinger
9a146ba2f0 Fix crash in Settings when layout is selected but not installed 2021-08-03 21:01:06 +02:00
Patrick Goldinger
5f224806e2 Merge pull request #1126 from X-yl/master
Make sure to clone images in clipboard history
2021-08-03 20:22:33 +02:00
x-yl
77f048abda Make sure to clone images in clipboard history
Looks like I forgot to clone images when the internal clipboard is off
but the clipboard history is still on. We have to own the items in the
clipboard history since authorization to read them is temporary.
2021-08-03 11:50:43 +04:00
Patrick Goldinger
e45efc08a5 Fix gesture velocity threshold (#1086) 2021-08-01 20:41:54 +02:00
Patrick Goldinger
d1dd91d5c4 Update GitHub workflow to use Java 11
Required by Gradle 7.0.0
2021-07-31 20:01:37 +02:00
Patrick Goldinger
106ef0c417 Upgrade Gradle to 7.0.0 and adapt new Gradle syntax 2021-07-30 21:01:32 +02:00
Patrick Goldinger
8989b7130a Fix View invalidation from incorrect thread (#1118) 2021-07-30 09:25:03 +02:00
Patrick Goldinger
0663708afb Possible fix for NaN crash (#1018) 2021-07-30 09:09:41 +02:00
Patrick Goldinger
d58aba71b8 Add FLorisLocale and String utility functions 2021-07-30 09:07:19 +02:00
Patrick Goldinger
9d364f99e2 Fix glide typing which was broken in beta07 2021-07-25 19:31:50 +02:00
Patrick Goldinger
edb62f0f38 Release v0.3.13-beta07 2021-07-25 10:20:51 +02:00
Patrick Goldinger
e771eaf0a4 Merge pull request #1101 from florisboard/lithuanian-layout-support
Add support for Lithuanian layout / popup mapping
2021-07-25 09:55:32 +02:00
Patrick Goldinger
199b5c9e67 Add support for Lithuanian layout / popup mapping (#1092) 2021-07-25 09:50:26 +02:00
Patrick Goldinger
5d121935d2 Merge pull request #1091 from florisboard/keyboard-data-rework
Keyboard data logic rework
2021-07-25 08:24:32 +02:00
Patrick Goldinger
ee0677b6e5 Fix double dotted circle for combining diacritical marks (#1089) 2021-07-24 00:12:08 +02:00
Patrick Goldinger
11325e99c4 Update turkish layout and popups to fix the capital I with dot bug 2021-07-23 23:54:55 +02:00
Patrick Goldinger
fc5a6b5af3 Rework internal key data logic
This allows for selectors to be used within popups as well. Is also the solid foundation for further development with emojis and other keyboards than the text keyboard.
2021-07-23 23:54:14 +02:00
Patrick Goldinger
65d17ceea3 Fix feature roadmap text in README (#1081) 2021-07-22 09:12:17 +02:00
Patrick Goldinger
8a57ada148 Merge pull request #1082 from florisboard/spelling3
Spell checker Part 3: APK size reduction
2021-07-22 08:56:42 +02:00
Patrick Goldinger
82e07b4de3 Re-packagae ICU data file as arch-independent data archive
Re-add break iteration because it is needed for spelling corrections
2021-07-21 00:46:17 +02:00
Patrick Goldinger
6ca5645656 Remove Nuspell Dictionary Finder / Remove glob.h port 2021-07-19 23:05:30 +02:00
Patrick Goldinger
a75ff21305 Optimize ICU data feature filter and reduce used ICU headers
APK size is now at ~26MB, further improvements with .dat file possible
2021-07-18 23:33:53 +02:00
Patrick Goldinger
a7b00494e5 Fix Nuspell license / Remove Nuspell main.cxx (unused) 2021-07-18 23:32:04 +02:00
Patrick Goldinger
a0de409878 Release v0.3.13-beta06 2021-07-15 21:29:13 +02:00
Patrick Goldinger
3f0944906d Merge pull request #1069 from florisboard/spelling2
Spell checker Part 2: Bug fixes, feedback incorporation etc.
2021-07-15 20:22:44 +02:00
Patrick Goldinger
79ef5445a1 Fix dictionaries with legacy encodings crashing the app (#1064)
Especially Cyrillic (ISO8859-7)
2021-07-15 18:10:58 +02:00
Patrick Goldinger
dea2795499 Fix Czech dictionary import failing for XPI archives (#1064) 2021-07-15 17:31:17 +02:00
Patrick Goldinger
650e4fb3a9 Fix FreeOffice link not working for some locales (#1064) 2021-07-14 21:14:22 +02:00
Patrick Goldinger
29a630dcd1 Fix importer not detecting license for some Mozilla XPI files (#1064) 2021-07-14 20:47:02 +02:00
Patrick Goldinger
7733ea0c02 Merge pull request #1021 from empratyush/master
added support for direct boot
2021-07-14 20:34:29 +02:00
Pratyush
3d13d65c52 added support for direct boot 2021-07-14 22:34:07 +05:30
Patrick Goldinger
575058550a Fix auto capitalization pref incorrectly labeled (#1064) 2021-07-14 18:55:55 +02:00
Patrick Goldinger
ad3e3cb7ec Release v0.3.13-beta05 2021-07-12 20:01:19 +02:00
Patrick Goldinger
e24ca7ca4a Update translations from Crowdin 2021-07-12 19:33:49 +02:00
Patrick Goldinger
1b6d8c8f6d Merge pull request #1061 from GoRaN909/patch-6
Update kurdish_kurmanci.json
2021-07-12 19:22:25 +02:00
Patrick Goldinger
27e172cbe3 Merge pull request #1063 from florisboard/icu-header-fix
Extend build script to remove unused ICU header files
2021-07-12 19:03:19 +02:00
Patrick Goldinger
e40c720f99 Extend build script to remove unused ICU header files
Realized they are quite a lot lol
2021-07-12 18:48:48 +02:00
GoRaN
c8d7071741 Update kurdish_kurmanci.json
Replaecd none Kurmanci character "ı" by the correct one latin letter "i"
2021-07-10 22:22:58 +03:00
Patrick Goldinger
5c2154253d Merge pull request #1015 from jeremiah-miller/optimized-swype-layouts
Add keyboard layouts optimized for swype input
2021-07-10 20:46:00 +02:00
Patrick Goldinger
3c79cca77c Fix cut off hints in borderless themes (#1049) 2021-07-10 19:53:54 +02:00
Patrick Goldinger
65c0ab724f Merge pull request #1011 from X-yl/improvements
Code cleanup + some polish
2021-07-10 19:17:49 +02:00
Patrick Goldinger
d5d259e13e Merge pull request #1052 from florisboard/spelling
Add experimental spell checker & extension support
2021-07-10 19:06:55 +02:00
Patrick Goldinger
691d3929eb Prepare spell checker for experimental release on beta 2021-07-10 19:03:36 +02:00
Patrick Goldinger
57b3b7b5d7 Add spelling correction cache 2021-07-10 17:55:07 +02:00
Patrick Goldinger
1582c1a3cf Re-package ICU lib to reduce APK size a bit 2021-07-10 16:52:55 +02:00
Patrick Goldinger
e22fe940c1 Merge pull request #1057 from Luensche/patch-1
Link files in CONTRIBUTING.md
2021-07-10 02:53:44 +02:00
Björn Engel
7f19892444 Link files in CONTRIBUTING.md 2021-07-09 08:44:46 +02:00
Patrick Goldinger
123a016ec0 Raise import limit from 20 to 24 MiB 2021-07-08 01:27:41 +02:00
Patrick Goldinger
5b6dcb3bc4 Fix some issues with manual import 2021-07-08 01:15:45 +02:00
Patrick Goldinger
8d71200b66 Add manual aff/dic import 2021-07-07 21:10:03 +02:00
Patrick Goldinger
6d333d2b40 Remove language debug output code 2021-07-07 03:47:42 +02:00
Patrick Goldinger
baacfd4469 Rework data filters, add more debug logging
(For investigating crashes for some dictionary files)
2021-07-07 03:44:53 +02:00
Patrick Goldinger
e8925ce697 Add ICU data filter (reduce data library size by 10MB / arch) 2021-07-06 03:18:25 +02:00
Patrick Goldinger
e40c2a6736 Re-add ICU as git submodule
No more 2.5mil LOC added lol
2021-07-05 19:36:18 +02:00
x-yl
b9518dc92b Cache ideal gesture lengths 2021-07-05 11:24:47 +04:00
x-yl
47f26f2336 Make gesture trail time based 2021-07-05 11:24:47 +04:00
Patrick Goldinger
fbc8d98209 Add user dictionary lookup for spell checking 2021-07-03 20:52:15 +02:00
Patrick Goldinger
27aeda8921 Implement suggestions limit / Fix initial indexing bug 2021-07-03 12:29:38 +02:00
Patrick Goldinger
4c2e642a85 Temporarily disable x86/x86_64 support to reduce APK size 2021-07-01 21:33:18 +02:00
Patrick Goldinger
f8995827f6 Raise max spelling dict size limit from 6MiB to 16MiB 2021-07-01 20:40:34 +02:00
Patrick Goldinger
d7593d12f2 Remove Home tab current-word paragraph 2021-07-01 20:38:24 +02:00
Patrick Goldinger
cd471a8323 Update README.md and open source licenses 2021-07-01 19:26:42 +02:00
Patrick Goldinger
9ad962c7d0 Remove unused flict binary files 2021-07-01 19:18:01 +02:00
Patrick Goldinger
b4e16ca445 Remove hunspell library 2021-07-01 19:06:46 +02:00
Patrick Goldinger
c2269fe23d Fix nuspell initialization error 2021-07-01 19:04:55 +02:00
Patrick Goldinger
d720435945 Add nuspell library 2021-07-01 18:47:30 +02:00
Patrick Goldinger
e33b0d39f9 Add external glob implementation 2021-07-01 18:45:43 +02:00
Patrick Goldinger
bbf3fb96be Add pre-compiled ICU library files 2021-07-01 18:44:59 +02:00
Patrick Goldinger
09567234cd Add ICU4C library
Frickin finally, took me waaaay to long to add.
If there just was an NDK ICU library wrapper, this could have saved
me 4 days of work...
2021-07-01 17:19:41 +02:00
Patrick Goldinger
1c2179fc50 Fix UI theme/state bugs in the spelling activity 2021-06-25 19:03:08 +02:00
Patrick Goldinger
c7fff5d9e4 Add support for Firefox XPI dictionaries 2021-06-25 18:19:55 +02:00
Patrick Goldinger
25badd6c2e Add dictionary delete option 2021-06-25 17:08:00 +02:00
Patrick Goldinger
97fb7b9427 Fix some bugs in the JNI side of spellchecking 2021-06-25 16:24:54 +02:00
Patrick Goldinger
f9b1aba27d Add spelling extension / Fix spelling service 2021-06-25 03:42:34 +02:00
Patrick Goldinger
aa0b9acabc Add JNI/Java direct string passing implementation 2021-06-25 03:41:54 +02:00
Patrick Goldinger
67b3ae5170 Add JNI logging utils 2021-06-25 03:41:04 +02:00
Patrick Goldinger
7d796ebdb3 Add spelling dictionary indexer 2021-06-24 18:16:38 +02:00
Patrick Goldinger
5737e68b8f Make FlorisApplication crash loop safe 2021-06-24 18:15:49 +02:00
Patrick Goldinger
211019b78b Add FlorisRef unit test 2021-06-24 16:53:55 +02:00
Patrick Goldinger
1db6676c45 Add extension load/write support, improve FlorisRef 2021-06-22 19:31:51 +02:00
Patrick Goldinger
da7ae028bf Add interface for extension packages 2021-06-18 03:40:47 +02:00
Patrick Goldinger
f3aa739e72 Introduce new 'FlorisRef' class as replacement for 'AssetRef' 2021-06-17 16:40:06 +02:00
Patrick Goldinger
7f09d1a1d1 Rename package 'extension' to 'res' and move out of 'ime' 2021-06-17 14:52:27 +02:00
Patrick Goldinger
5a8483e78d Add import dictionary basic implementation 2021-06-16 21:32:49 +02:00
Jeremiah Miller
841d15056d Rename DGHP to Sangaline 2021-06-14 08:32:02 -07:00
Patrick Goldinger
09cdd0fff0 Add basic import dictionary UI sheet 2021-06-12 19:52:48 +02:00
Patrick Goldinger
ebb677d203 Add overview page for spell checker prefs 2021-06-12 12:28:21 +02:00
Patrick Goldinger
cf3236f57f Remove preferences cache
SharedPreferences already caches the preference values + the cache causes
state bugs.
2021-06-11 16:27:31 +02:00
bbgun7
3bd8169600 Add keyboard layouts optimized for swipe input 2021-06-10 10:11:56 -07:00
Patrick Goldinger
f9aaec6020 Add initial spelling manager activity 2021-06-10 16:29:44 +02:00
Patrick Goldinger
bb2cc995d6 Add JNI string utils 2021-06-10 16:29:11 +02:00
Patrick Goldinger
a65aaa5f95 Add spelling manager / config 2021-06-10 16:28:50 +02:00
Patrick Goldinger
92b9a978dc Add skeleton code for spell-checker implementation 2021-06-08 04:22:47 +02:00
Patrick Goldinger
5f2729e065 Add Hunspell ported code 2021-06-08 04:22:02 +02:00
Patrick Goldinger
37bb4cea43 Release v0.3.13-beta04 2021-06-08 00:05:36 +02:00
Patrick Goldinger
79d608feea Update translations from Crowdin 2021-06-07 23:53:37 +02:00
Patrick Goldinger
54573de3e3 Merge pull request #1006 from Luensche/move_clipboard_item_to_begin
Move new clipboard items with the same content to the beginning
2021-06-07 23:51:35 +02:00
x-yl
a2243b8825 Use coroutines and improve image loading for clipboard
Sorry, didn't know we were using coroutines when I first wrote this
code!
2021-06-07 17:50:21 +04:00
Björn Engel
2fba2d3b4a Do not compare images 2021-06-07 15:49:05 +02:00
Björn Engel
fd0cbbdcb1 Move new clipboard items with the same content to the beginning, closes #991 2021-06-07 14:08:39 +02:00
Patrick Goldinger
b6e3deedf4 Add default system subtype for proper display in system settings 2021-06-04 19:39:02 +02:00
Patrick Goldinger
4c74bf1b4a Fix glide typing not working for caps/caps-lock 2021-06-04 19:19:53 +02:00
Patrick Goldinger
2a4e3c8c58 Merge pull request #982 from dessalines/halmak
Add the Halmak keyboard layout
2021-06-04 18:56:48 +02:00
Patrick Goldinger
e34e5b4260 Merge pull request #992 from florisboard/rework-textkeyboard-rendering
Rework TextKeyboard rendering
2021-06-04 18:53:42 +02:00
Patrick Goldinger
ae2df7dfe4 Fix Smartbar incorrectly not updating selection-specific keys 2021-06-04 18:49:48 +02:00
Patrick Goldinger
1b3d0a5cf2 Fix touch logic incorrect pointer and capacity issues 2021-06-04 18:31:05 +02:00
Patrick Goldinger
4c94329071 Fix glide typing not correctly initialized at startup 2021-06-04 17:13:16 +02:00
Patrick Goldinger
6ffcf2f865 Fix keyboard preview in Settings 2021-06-04 05:43:42 +02:00
Patrick Goldinger
e2c9a66880 Fix further state bugs 2021-06-04 05:12:38 +02:00
Patrick Goldinger
e9bc25ebc7 Improve extended popup rendering performance 2021-06-04 03:53:03 +02:00
Patrick Goldinger
6379e63669 Rework TextKeyboard rendering 2021-06-04 03:31:46 +02:00
Patrick Goldinger
70a0763e7f Merge pull request #981 from florisboard/fix-keyboard-state-bug
Fix keyboard state bug for the active mode
2021-06-04 03:29:47 +02:00
Dessalines
863080e6ce Remove slash from bottom row. 2021-06-03 14:46:55 -04:00
Patrick Goldinger
3ef454b8bd Fix Smartbar not showing sometimes (#987) 2021-06-03 17:43:23 +02:00
Patrick Goldinger
2bbdfc71d0 Rework UI initialization and reduce duplicate state changes 2021-06-03 15:42:28 +02:00
Patrick Goldinger
d1c783dde1 Fix keyboard state bug for the active mode 2021-06-02 17:51:18 +02:00
Dessalines
644da67601 Add the Halmak keyboard layout 2021-06-01 21:39:26 -04:00
Patrick Goldinger
b8d99efd29 Merge pull request #977 from GoRaN909/patch-5
Update kurdish.json
2021-06-01 01:15:58 +02:00
GoRaN
4067d92a44 Update kurdish.json
Added stretched button (Kashida) to support all Kurdish layouts.
2021-06-01 01:06:00 +03:00
Patrick Goldinger
13a17f3a6b Merge pull request #974 from GoRaN909/patch-2
Update ckb.json
2021-05-31 23:50:01 +02:00
Patrick Goldinger
57c679e500 Merge pull request #975 from GoRaN909/patch-3
Update kurdish_standard.json
2021-05-31 23:41:42 +02:00
Patrick Goldinger
f70f45dab6 Merge pull request #973 from GoRaN909/patch-1
Update kurdish.json
2021-05-31 23:37:41 +02:00
GoRaN
8d8f723d66 Update kurdish_standard.json
popup characters added
2021-06-01 00:29:23 +03:00
GoRaN
7c3c6a7ad7 Update ckb.json
Added popup characters for letter (ح)
2021-06-01 00:24:18 +03:00
GoRaN
d7a1c9377a Update kurdish.json
Some changes of words position and corrections codes
2021-06-01 00:19:19 +03:00
Patrick Goldinger
2a317372b2 Release v0.3.13-beta03 2021-05-31 20:18:43 +02:00
Patrick Goldinger
402f7bd267 Update translations from Crowdin 2021-05-31 20:02:33 +02:00
Patrick Goldinger
e8eb6e3068 Fix emoticon layout missing (#950) 2021-05-31 19:17:38 +02:00
Patrick Goldinger
3dd9c45777 Fix crash when using delete left swipe in raw editors (#967) 2021-05-31 18:30:24 +02:00
Patrick Goldinger
7255229361 Merge pull request #966 from florisboard/major-input-logic-overhaul
Major input logic overhaul
2021-05-31 17:52:19 +02:00
Patrick Goldinger
4d2fa29886 Fix IME checking utility not using new ID 2021-05-31 12:46:14 +02:00
Patrick Goldinger
ef90faf98b Merge pull request #963 from Hayleia/composingFix
Fix getting composer from name
2021-05-31 06:11:38 +02:00
Patrick Goldinger
82caa8365e Fix glide trail stuck after initial touch down 2021-05-31 05:16:20 +02:00
Patrick Goldinger
391257e9e9 Re-add simple key shadows 2021-05-31 05:04:02 +02:00
Patrick Goldinger
b082253167 Fix keys not registered correctly (#953) 2021-05-31 03:59:31 +02:00
Patrick Goldinger
8df701e3fe Adapt input view to new keyboard state register 2021-05-31 03:56:08 +02:00
Patrick Goldinger
9f232f5dbf Add new keyboard state register 2021-05-31 03:55:05 +02:00
Hayleia
7017726dcb Fix getting composer from name
also use an available constant when possible rather than a hardcoded string
2021-05-30 11:05:28 +02:00
Patrick Goldinger
b48ca8fd1e Restructure the package structure 2021-05-28 21:04:27 +02:00
Patrick Goldinger
88d5e15a5e Introduce TextKeyboardState 2021-05-28 03:36:54 +02:00
Patrick Goldinger
e9537cbd1d Merge pull request #947 from yashpalgoyal1304/devanagari-fix
Fixed Devanagari Codes
2021-05-26 23:32:10 +02:00
yashpalgoyal1304
8e216bf3ac Fixed Devanagari Codes 2021-05-27 02:37:14 +05:30
Patrick Goldinger
63352cc615 Improve logic and rendering performance a bit 2021-05-26 17:12:28 +02:00
Patrick Goldinger
e9e2563739 Release v0.3.13-beta02 2021-05-26 01:26:33 +02:00
Patrick Goldinger
87bb098445 Fix batch level preventing cached input from updating 2021-05-26 01:26:17 +02:00
Patrick Goldinger
da1944bedf Temporarily remove key shadow support (#943) 2021-05-26 01:09:50 +02:00
Patrick Goldinger
d4a92e0d46 Merge pull request #942 from florisboard/new-touch-logic
Introduce new touch logic to TextKeyboardView
2021-05-26 00:46:31 +02:00
yashpalgoyal1304
0fa6c1f235 Added Indic Numerals (#940)
* Indic Devanagari Numeric

* Fixed name and label

* Fixed file name

* Added indic scripts numerals
2021-05-26 00:43:21 +02:00
Patrick Goldinger
260b1ba5ca Improve touch logic 2021-05-26 00:19:35 +02:00
Patrick Goldinger
f0799a6a0e Rework text keyboard view touch logic 2021-05-25 20:48:17 +02:00
Patrick Goldinger
155238946a Merge pull request #866 from Hayleia/composing1
Composing input method (and Korean as the first subject)
2021-05-24 15:30:06 +02:00
Patrick Goldinger
45f91cf40c Merge pull request #928 from ostrya/fix-hint-merge
fix hint merge logic (#872)
2021-05-23 16:27:22 +02:00
Patrick Goldinger
94f5b56b6a Possibly fix key shadow performance 2021-05-23 16:19:28 +02:00
Kai Helbig
46db467073 fix hint merge logic (#872)
The merge of the hints depends on the underlying main key. Especially,
hints should only be shown for character keys, and if the hint is
identical to the main key, it should not be added at all. Since the
actual main key is only evaluated on demand with TextKey#compute, all
corresponding hint merge logic needs to be moved there too.
2021-05-23 12:16:33 +02:00
Patrick Goldinger
17dde536d9 Fix one-handed panel not correctly measuring sometimes (#896) 2021-05-23 03:50:17 +02:00
Patrick Goldinger
be67bf4b84 Fix Smartbar number row bugs in password fields (#905) 2021-05-23 03:19:17 +02:00
Patrick Goldinger
8f142548fe Merge pull request #920 from tsiflimagas/default-popup-fix-greek
Fix the default popup for some letters
2021-05-23 02:49:28 +02:00
Kostas Giapis
a68f439f39 Enforce the main popup character 2021-05-22 23:01:04 +03:00
Patrick Goldinger
7a0892bb36 Fix space bar text too large (#862) 2021-05-22 20:16:55 +02:00
Patrick Goldinger
8457390156 Fix keys not showing a shadow (#901, #921) 2021-05-22 19:54:12 +02:00
Hayleia
72be3898c1 move local function out, and fix firefox url bar? 2021-05-22 19:47:30 +02:00
Kostas Giapis
d35bf5af63 Fix the default popup for some letters 2021-05-22 16:23:13 +03:00
Patrick Goldinger
04d3af6484 Merge pull request #908 from Luensche/copy-versionstring
Copy version string to clipboard on click on the version
2021-05-22 12:59:46 +02:00
Björn Engel
26920e4a98 Move the toast outside of if 2021-05-20 14:44:23 +02:00
Björn Engel
7419966b51 Create ripple for click on head_area 2021-05-20 14:37:17 +02:00
Björn Engel
58b832c6c3 Add new area for long pressing and change to onLongClickListener 2021-05-20 10:20:49 +02:00
Hayleia
99f2ec1879 deprecated methods 2021-05-19 11:47:28 +02:00
Hayleia
4249f9ef86 add author 2021-05-19 11:39:13 +02:00
Hayleia
60107ae299 useless "public" keyword 2021-05-19 09:11:07 +02:00
Hayleia
6a95a865fa one spinner per linear layout 2021-05-19 09:09:14 +02:00
Hayleia
9e32589af5 style: space before colon 2021-05-19 09:04:30 +02:00
Hayleia
6133e225e1 add author 2021-05-19 09:03:34 +02:00
Hayleia
348c143d92 use case_selector to specify shift/non-shift characters 2021-05-19 08:59:52 +02:00
Hayleia
ce00785ffe Revert "support specifying uppercase and lowercase separately in json"
This reverts commit 1715e5ddfa.

Conflicts:
	app/src/main/java/dev/patrickgold/florisboard/ime/extension/AssetManager.kt
2021-05-19 08:24:51 +02:00
Hayleia
78cdce750d style in json 2021-05-19 08:22:25 +02:00
Patrick Goldinger
f3f95ae282 Fix crash loops from occurring after a crash (#910) 2021-05-19 01:33:53 +02:00
Björn Engel
018885eb30 Copy version string to clipboard on click on the version 2021-05-18 15:18:01 +02:00
Patrick Goldinger
c6c8a76dd6 Fix user dictionary max size (#898) 2021-05-18 01:51:49 +02:00
Patrick Goldinger
3cae8b7230 Release v0.3.13-beta01 2021-05-17 20:40:39 +02:00
Patrick Goldinger
814c8de0c2 Update translations from Crowdin 2021-05-17 20:30:37 +02:00
Patrick Goldinger
32fe175b48 Small code base improvements 2021-05-17 20:27:32 +02:00
Patrick Goldinger
b901f6de8d Fix space bar gestures for non-repeating actions (#886) 2021-05-17 20:13:50 +02:00
Patrick Goldinger
fe9ba3246c Merge pull request #884 from debnone/patch-1
Fix hebrew characters
2021-05-17 19:52:32 +02:00
Patrick Goldinger
71a39f0fc1 Merge pull request #876 from florisboard/android11-autofill-api
Add support for Android 11's Autofill API
2021-05-17 10:56:31 +02:00
Patrick Goldinger
f7556898e1 Document inline suggestions code / Fix some inconsistencies 2021-05-17 03:01:46 +02:00
Patrick Goldinger
578539f5d0 Add inline suggestions theme support 2021-05-17 02:04:52 +02:00
debnone
7c28c7fbea Fix hebrew characters
fixed bottom half layout its was reversed and incorrect.
2021-05-15 23:17:28 +03:00
Patrick Goldinger
88bcadff81 Fix inline suggestions state bugs and improve logic 2021-05-15 04:50:49 +02:00
Patrick Goldinger
25e25dfbf0 Add support for Android 11's Autofill API 2021-05-15 03:23:51 +02:00
Patrick Goldinger
ba3dc0178d Merge pull request #875 from X-yl/glide-number-row
Reinitialize pruner when layout changes
2021-05-15 03:20:23 +02:00
x-yl
91e7f424bb Reinitialize pruner when layout changes
Closes #854
2021-05-14 22:16:10 +04:00
Hayleia
b89f791eb0 rename south korean layout 2021-05-14 07:51:51 +02:00
Hayleia
ad3a0425ab fix config.json after merge 2021-05-14 07:51:40 +02:00
Hayleia
7cf52ecf3e Merge branch 'master' of https://github.com/florisboard/florisboard into composing1 2021-05-14 07:35:56 +02:00
Patrick Goldinger
b1ef18f4fd Improve C++ code base 2021-05-14 00:30:19 +02:00
Hayleia
b74af5bbe9 manage old subtype configurations 2021-05-13 20:48:00 +02:00
Hayleia
b8aa4bbfc4 fix subtype equals and hashcode (and javadoc) 2021-05-13 20:16:50 +02:00
Hayleia
e024ac9272 fix default subtype crash with no subtype declared 2021-05-13 20:03:47 +02:00
Hayleia
c5fa027a8e move composer dropdown in add/edit subtype dialog 2021-05-13 16:39:32 +02:00
Hayleia
b6ec2b25be Merge branch 'master' of https://github.com/florisboard/florisboard into composing1 2021-05-13 16:25:13 +02:00
Patrick Goldinger
a756b59c60 Merge pull request #606 from ostrya/improved-hints
Merge hints more flexibly
2021-05-13 14:04:08 +02:00
Patrick Goldinger
8687ce55ed Merge pull request #527 from ostrya/neo2-layout
Neo2 layout
2021-05-13 14:04:01 +02:00
ostrya
1ac6985dd0 Allow merging popups of hints #618
A new configuration was introduced to allow showing the popup keys of
the hint keys of a given character key in addition the character key's
normal popup keys.

The previous change allowed both number and symbol hint to be merged at
the same time, with the number hint being shown as popup only.
Therefore, when allowing the popups of the hint key to be shown as
popups, both hint keys need to be taken into account.

To ensure this and also take into account the separate key hint
settings for number and symbol hints, the MutablePopupSet was extended
to contain both hint keys as well as both lists of popup keys in
addition to the existing main key and relevant list. The logic that
chooses the key prioritization when rendering the popup has now also
been moved from the PopupManager to the PopupSet.

For performance, the prioritized collection of popup keys is generated
once and then cached for a given configuration in a new PopupKeys
object. This class now has the collection semantics previously present
in the PopupSet class. Different from before, the PopupKeys object now
explicitly contains the prioritized keys (those that should be shown
directly above the original key for easier reach) in order of priority.

The PopupManager now only needs to take the number of prioritized keys
(maximum 3: main key, number hint, symbol hint) when calculating the
key positions in the popup.
2021-05-13 11:52:53 +02:00
Patrick Goldinger
986b4a878f Merge pull request #858 from florisboard/java-jni-basics
Set up base for Kotlin/C++ interoperability
2021-05-13 00:33:10 +02:00
Patrick Goldinger
1ef38fe7f3 Fix GitHub workflows not setting up cmake 2021-05-12 20:31:34 +02:00
Patrick Goldinger
bcad0af35e Finalize base implementation for SuggestionList 2021-05-12 19:29:21 +02:00
Patrick Goldinger
b5b89fde4f Add native instance wrapper interface / Clean up code 2021-05-12 02:25:41 +02:00
Patrick Goldinger
be1fc710ed Set up base for Kotlin/C++ interoperability 2021-05-12 00:40:53 +02:00
Kai Helbig
aa55fd3070 Directly merge numeric and symbolic hints
Co-authored-by: Patrick Goldinger <patrick.goldinger@pm.me>
2021-05-11 23:58:31 +02:00
ostrya
a132462466 Merge hints more flexibly
To allow symbol layouts with the same or more rows as the character
layout to be hinted more consistently, the hinting of the numeric row
is split from the rest of the symbol layout.

If enabled, the numeric row hinting is always done in the first row.
If an actual numeric row is enabled as well, no additional numeric
hints will be shown (as they are only added to CHARACTER type keys).

The symbol hinting is now bottom-aligned: hints from the last symbol
row are shown in the last character row.

If the symbol layout (excluding numeric row) has at least the same
number of rows as the character layout, the numerical row is disabled
and numerical hinting is enabled, the symbol keys take precedence. The
numeric hints are instead added as additional popup characters.
2021-05-11 23:58:25 +02:00
Hayleia
df393ff607 composers can be specified in config.json
no compatibility with previous settings, need to update the regex
2021-05-11 19:03:30 +02:00
Hayleia
88a6f436ef Merge branch 'master' of https://github.com/florisboard/florisboard into composing1 2021-05-05 10:02:17 +02:00
ostrya
ee8f44d816 Use new currency set mechanism 2021-05-04 20:52:53 +02:00
ostrya
0308ec355f Adapt to new layout rework 2021-05-04 20:44:57 +02:00
Hayleia
3ac14f8a2a remove pointless reflection (going to use serialization anyways) 2021-05-04 20:16:23 +02:00
Hayleia
2b087b76dc korean double consonants and two vowels on shift key 2021-05-04 20:12:03 +02:00
Hayleia
1715e5ddfa support specifying uppercase and lowercase separately in json 2021-05-04 20:11:27 +02:00
Hayleia
6cc17161a5 factor stuff 2021-05-03 21:00:04 +02:00
Hayleia
5d1c20617b Merge branch 'master' of https://github.com/florisboard/florisboard into composing1 2021-05-03 19:22:23 +02:00
Hayleia
d9efa48c9c copy pasted code to compose texte with suggestions enabled too 2021-05-03 19:15:03 +02:00
ostrya
dedd4cb7f0 Use custom modifier for symbol layer
To make the switch from character to symbol layer more consistent,
a neo specific symbol modifier layout was added. This also allows
overriding the comma and full stop with their layer 3 equivalents.
2021-05-02 17:06:07 +02:00
ostrya
42b147b656 Add neo/bone locale variant for better compatibility
The default de locale already defines a lot of extended popups which
do not match the Neo2 / Bone layout logic. Adding a locale variant
allows overriding those defaults.

As the Locale class does not support arbitrary country keys, the new
locale was chosen as a variant of de_DE with variant name "neobone".
There is no deep meaning in the name, it is only the concatenation of
neo and bone, and according to the Javadoc of Locale, a valid variant
must have either 5 to 8 characters or start with a number.
2021-05-02 17:06:06 +02:00
ostrya
47ce490d6c Initial attempt at Neo2 / Bone layout (#498)
* For now, only layers 1, 2 and 3 are supported.
* Layer 2 is reachable via caps, apart from number row, comma and full
  stop (which I think are easier to use if not affected by caps).
  Instead, the relevant characters are added as popups.
* Layer 3 is set up as a separate neo2 symbol / number row layer

The overall layout is kept as much as possible, with the following
exceptions:
* The number row contains only numbers and minus sign, while circumflex
  and grave accents are not included.
* To not overcrowd the layout and have the same number of keys for
  first and second row, the acute accent is not included as separate
  key but can be reached as additional popup to sharp s.
* Comma and full stop are not put between m and j (or z and k
  respectively), because the backspace takes up too much space for both
  keys to be put in this row.
* Also, having comma and full stop on the same height with the space
  key makes the layout more consistent with the existing layouts and
  the special usage as ~left and ~right keys.
2021-05-02 17:05:59 +02:00
Hayleia
5563a1cadd merge compatibility 2021-05-01 20:30:24 +02:00
Hayleia
7beb2e5ef6 Merge branch 'master' of https://github.com/florisboard/florisboard into composing1 2021-05-01 19:22:19 +02:00
Hayleia
f00da13cba less kotlin warnings and slightly more usable code
still hardcoded korean composer for all layouts
but at least it's not instanciated at every keypress
2021-05-01 09:34:40 +02:00
Hayleia
bfed1747f7 better korean jsons 2021-05-01 09:19:59 +02:00
Hayleia
abb4b104fa fix input being ignored sometimes? 2021-04-30 13:12:28 +02:00
Hayleia
b69b1caa72 Test Korean composition
currency is wrong
code is plugged at the wrong place
input is ignored sometimes
there is reflection for what seems to be no reason
I know, this is just a test and this will either be done again (properly) on another branch or discarded altogether
2021-04-30 07:31:32 +02:00
307 changed files with 26243 additions and 5286 deletions

View File

@@ -9,7 +9,7 @@ insert_final_newline = true
max_line_length = 120
trim_trailing_whitespace = true
[{*.har,*.json}]
[{*.har,*.json,*yml}]
indent_size = 2
[*.kt]

View File

@@ -1,5 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Ask a question
url: https://github.com/florisboard/florisboard/discussions/new?category=q-a
about: Ask here if you have a question about FlorisBoard or need assistance
- name: General feedback
url: https://github.com/florisboard/florisboard/blob/master/CONTRIBUTING.md
url: https://github.com/florisboard/florisboard/discussions/new?category=feedback
about: Give general feedback about this project

View File

@@ -8,12 +8,11 @@ assignees: ''
---
<!--
- Describe your idea in a short but concise way.
- If you have multiple ideas which are not directly connected to each
other, file an issue per idea. This makes it easy to implement one
feature proposal at a time.
- If you have any examples, e.g. screenshots or other keyboards which
have the proposed feature implemented, link them here.
- Please search existing proposals to avoid creating duplicates.
- Thank you for your help in making FlorisBoard better!
Thank you for your help in making FlorisBoard better!
Guide to a good feature-request:
• Please search existing proposals to avoid creating duplicates.
If you have multiple ideas which are not directly connected to other, file a new issue for each idea. This makes it easier to implement your proposals.
• Describe your idea in a short but concise way.
• If you have any examples, e.g. screenshots or other keyboards have the proposed feature implemented, feel free to post them after your description.
-->

View File

@@ -1,16 +0,0 @@
---
name: Question
about: Ask here if you have a question about FlorisBoard
title: ''
labels: question
assignees: ''
---
<!--
- If you need assistance in using FlorisBoard, ask it here!
- If you want to suggest an idea for this project, please use the
Feature request template instead.
- Please search existing questions to avoid creating duplicates.
- Thank you for your help in making FlorisBoard better!
-->

View File

@@ -11,11 +11,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: set up JDK 1.8
- uses: actions/checkout@v2
- name: Checkout submodules
run: git submodule update --init --recursive
- name: set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 1.8
java-version: 11
- name: Setup CMake and Ninja
uses: lukka/get-cmake@v3.20.1
- uses: actions/cache@v2
with:
path: |
@@ -25,7 +29,7 @@ jobs:
restore-keys: |
${{ runner.os }}-gradle-
- name: Build with Gradle
run: ./gradlew clean assemble
run: ./gradlew clean assembleDebug
- uses: actions/upload-artifact@v2
with:
name: app-debug.apk

3
.gitignore vendored
View File

@@ -41,5 +41,8 @@ captures/
*.jks
crowdin.properties
# C++
.cxx/
# AndroidX Room schema JSONs
/app/schemas/

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "app/src/main/icu4c"]
path = app/src/main/icu4c
url = https://github.com/florisboard/icu4c

View File

@@ -7,8 +7,13 @@ provides some general guidelines for each type of contribution.
## Giving general feedback
Either use the review function within Google Play or email me at
[florisboard@patrickgold.dev](mailto:florisboard@patrickgold.dev). I
NEW! You can now [give general feedback](https://github.com/florisboard/florisboard/discussions/new?category=feedback)
directly here on GitHub. This is the preferred way to give feedback, as
it allows not only for me to read and respond to feedback, but for everyone
in this community.
Optionally you can also use the review function within Google Play or email me
at [florisboard@patrickgold.dev](mailto:florisboard@patrickgold.dev). I
love to hear from you! Note, that the amount of feedback emails I get
is overwhelmingly high - so if I don't answer or answer really late, I
apologize - I guarantee though that I read through every email and that
@@ -41,7 +46,7 @@ syntax (it is very easy though by just looking at some other layout files).
There are two main steps in adding new layouts, though the config step can
be skipped if you only add a layout without a new default language support.
### The config file (`app/src/main/assets/ime/config.json`)
### The config file ([`app/src/main/assets/ime/config.json`](app/src/main/assets/ime/config.json))
This file is very important, as it defines all default currency sets as
well as all default subtypes available in the Settings Subtype UI. Note
@@ -66,7 +71,7 @@ pre-configured language.
Since v0.3.10-beta05 it is possible to add custom layouts for all types.
To add a new layout, head to `app/src/main/assets/ime/text` and then select
To add a new layout, head to [`app/src/main/assets/ime/text`](app/src/main/assets/ime/text) and then select
the correct sub-directory for the type of layout you want to add. In most cases
this will be `characters` to add a layout like QWERTY etc.
@@ -74,14 +79,14 @@ For the `code` field of each key, make sure to use the UTF-8 code. An
useful tool for finding the correct code is [unicode-table.com](https://unicode-table.com/en/).
From there, you search for your letter and then use the HTML code, but without the `&#;`
For internal codes of functional or UI keys, see
`app/src/main/java/dev/patrickgold/florisboard/ime/text/key/KeyCode.kt`.
[`app/src/main/java/dev/patrickgold/florisboard/ime/text/key/KeyCode.kt`](app/src/main/java/dev/patrickgold/florisboard/ime/text/key/KeyCode.kt).
The label is equally important and should always match up with the defined
code. If `code` and `label` don't match up, FlorisBoard won't crash but
it will most likely lead to confusion in the key processing logic.
Any accents or diacritics that should be exposed via long press can be
added at `assets/ime/text/characters/extended_popups/<languageTag_name_here>.json`.
added at [`app/src/main/assets/ime/text/characters/extended_popups/<languageTag_name_here>.json`](app/src/main/assets/ime/text/characters/extended_popups).
For each key, you can add 1 main and several relevant accents. The main
accent should be used for accents which are important for the language
you add. The main field is used for determining if a hint or an accent

View File

@@ -45,7 +45,11 @@ _A. IzzySoft's repo for F-Droid_:
[<img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png" height="64" alt="IzzySoft repo badge">](https://apt.izzysoft.de/fdroid/index/apk/dev.patrickgold.florisboard.beta)
_B. Use the APK provided in the release section of this repo_
_B. Google Play_:
Follow the same steps as for the stable track, the app can then be accessed [here](https://play.google.com/store/apps/details?id=dev.patrickgold.florisboard.beta).
_C. Use the APK provided in the release section of this repo_
### Giving feedback
If you want to give feedback to FlorisBoard, there are several ways to
@@ -60,7 +64,7 @@ alt="Preview image">
## Implemented features
This list contains all implemented and fully functional features
FlorisBoard currently has to offer. For planned features and its
milestones, please refer to the [Feature roadmap](#feature-roadmap).
milestones, please refer to the [Feature roadmap](ROADMAP.md).
### Basics
* [x] Implementation of the keyboard core (InputMethodService)
@@ -68,14 +72,14 @@ milestones, please refer to the [Feature roadmap](#feature-roadmap).
* [x] Caps + Caps Lock
* [x] Key popups
* [x] Extended key popups (e.g. a -> á, à, ä, ...)
* [x] Key press sound/vibration
* [x] Audio/haptic feedback for keyboard touch interaction
* [x] Portrait orientation support
* [x] Landscape orientation support (needs tweaks)
### Layouts
* [x] Latin character layouts (QWERTY, QWERTZ, AZERTY, Swiss, Spanish, Norwegian, Swedish/Finnish, Icelandic, Danish,
Hungarian, Croatian, Polish, Romanian, Colemak, Dvorak, Turkish-Q, Turkish-F, and more...)
* [x] Non-latin character layouts (Arabic, Persian, Kurdish, Greek, Russian (JCUKEN), and more...)
* [x] Non-latin character layouts (Arabic, Persian, Kurdish, Greek, Russian (JCUKEN), Japanese JIS, and more...)
* [x] Adapt to situation in app (password, url, text, etc. )
* [x] Special character layout(s)
* [x] Numeric layout
@@ -96,84 +100,23 @@ milestones, please refer to the [Feature roadmap](#feature-roadmap).
* [x] User dictionary manager (system and internal)
### Other useful features
* [x] Support for Android 11+ inline autofill API
* [x] One-handed mode
* [x] Clipboard/cursor tools
* [x] Clipboard manager/history
* [x] Integrated number row / symbols in character layouts
* [x] Gesture support
* [x] System-wide spell checker with spell results from FlorisBoard
* [x] Full support for the system user dictionary (shared dictionary
between all keyboards) and a private, internal user dictionary
* [x] Full integration in IME service list of Android (xml/method)
(integration is internal-only, because Android's default subtype
implementation not really allows for dynamic language/layout
pairs, only compile-time defined ones)
* [ ] Description and settings reference in System Language & Input
* [x] Description and settings reference in System Language & Input
* [ ] (dev only) Generate well-structured documentation of code
* [ ] ...
## Feature roadmap
This section describes the features which are planned to be implemented
in FlorisBoard for the next major versions, modularized into sections.
Please note that the milestone due dates are only raw estimates and will
most likely be delayed back, even though I'm eager to stick to these as
close as possible.
### [v0.4.0](https://github.com/florisboard/florisboard/milestone/4)
- Module A: Smartbar rework (Implemented with [#91])
- Ability to enable/disable Smartbar (features below thus only work if
Smartbar is enabled)
- Dynamic switching between clipboard tools and word suggestions
- Ability to show both the number row and word suggestions at once
- Better icons in quick actions
- Complete rework of the Smartbar code base and the Smartbar layout
definition in XML
- Module B: Composing suggestions (Phase 1: [#329])
- Auto-suggestion of words based of precompiled dictionaries
- Management of custom dictionary entries
- Next-word suggestions by training language models. Data collected here is stored locally and never leaves
the user's device.
- Module C: Extension packs (Implemented with [#162], reworked several times and still not stable)
- Ability to load dictionaries (and later potentially other cool
features too) only if needed to keep the core APK size small
- Currently unclear how exactly this will work, but this is definitely
a must-have feature
- A full implementation may come only in v0.5.0
- Module D: Glide typing (Implemented with [#544])
- Swiping over the characters will automatically convert this to a word
- Possibly also add improvements based on the Flow keyboard
- Module E: Theme rework (Implemented with [#162])
- Themes are now based on the Asset schema
- Dynamic theme creation
- Different theme modes (`Always day`, `Always night`, `Follow system`
and `Follow time`)
- Define a separate theme both for day and night theme
- Adapt to app theme if possible
- Theme import/export
### [v0.5.0](https://github.com/florisboard/florisboard/milestone/5)
There's no exact roadmap yet, but these are the most important points:
- Full layout customization in runtime
- Extensive rework and customization of the media input (emojis, emoticons, kaomoji)
- Better Smartbar customization
- As an extension GIF support
### > v0.5.0
This is completely open as of now and will gather planned features as time
passes...
Backlog (currently not assigned to any milestone):
- Floating keyboard
[#91]: https://github.com/florisboard/florisboard/pull/91
[#162]: https://github.com/florisboard/florisboard/pull/162
[#329]: https://github.com/florisboard/florisboard/pull/329
[#544]: https://github.com/florisboard/florisboard/pull/544
## Contributing
Wanna contribute to FlorisBoard? That's great to hear! There are lots of
different ways to help out. Bug reporting, making pull requests,
@@ -198,21 +141,10 @@ to get more information on this topic.
[JakeWharton](https://github.com/JakeWharton)
* [expandable-fab](https://github.com/nambicompany/expandable-fab) by
[Nambi](https://github.com/nambicompany)
## Usage notes for included binary dictionary files
All binary dictionaries included within this project in
(this)[app/src/main/assets/ime/dict] asset folder are built from various
sources, as stated below.
### Source 1: [wordfreq library by LuminosoInsight](https://github.com/LuminosoInsight/wordfreq):
`wordfreq` is a repository which provides both a Python library and raw
data (the wordlists). Only the data has been extracted in order to build
binary dictionary files from it. `wordfreq`'s data is licensed under the
Creative Commons Attribution-ShareAlike 4.0 license
(https://creativecommons.org/licenses/by-sa/4.0/).
For further information on what wordfreq's data depends on, see
(https://github.com/LuminosoInsight/wordfreq#license).
* [ICU4C](https://github.com/unicode-org/icu) by
[The Unicode Consortium](https://github.com/unicode-org)
* [Nuspell](https://github.com/nuspell/nuspell) by
[Nuspell](https://github.com/nuspell)
## License
```

106
ROADMAP.md Normal file
View File

@@ -0,0 +1,106 @@
# FlorisBoard's feature roadmap & milestones
This feature roadmap intents to provide transparency to what I want to add
to FlorisBoard in the foreseeable future. Note that there are no ETAs for any
version milestones down below, experience says these won't hold anyways.
I try my best to release regularly, though some features take a lot longer
than others and thus releases can be spaced out a bit on the stable track.
If you are interested in following the development more closely, make sure to
follow along the beta track releases! These are generally more unstable but
you get new stuff faster and can provide early feedback, which helps a lot!
## 0.3.x and 0.4.0
Releases in this section still follow the old versioning scheme, meaning the
patch number is a feature upgrade. As this naming convention is more confusing
than useful, after the v0.4.0 release a new release/development cycle will be
introduced.
### 0.3.13 (currently in development and soon done)
- Spell checking (mainly completed and relatively well working, Smartbar integration still missing)
- Performance improvements in keyboard rendering
- Audio/haptic feedback rework
- Lots and lots of bug fixing in all areas, really fix some annoying bugs
- New layouts added by contributors
### 0.3.14
- Re-write of the Preference core
- Reduce redundancy in key/default value definitions
- Avoid having to manually add redundant code for adding a new pref
- Goes hand-in-hand with the Settings UI re-write
- Re-write of the Settings UI with Jetpack Compose
- Also re-structure UI into a more list-like panel
- Adjust theme colors of Settings a bit to make it more modern
- Preview the keyboard at any time from within the Settings
- Settings language different than device language
- Re-write the Setup UI in Jetpack Compose
- Simplify screen based on previously discussed ideas and mock-ups
- Improve backend setup logic
- Implement base-UI for extensions and further continue development
of existing Flex (FlorisBoard extension) format
- Allows for a continuous experience of customizing FlorisBoard in different areas
- Planned in the future (not in this version though) what will use Flex:
- Themes
- Layouts (Characters, symbols, numeric, ...)
- Composers for non-Latin script languages
- Word suggestion dictionaries
- Spell check dictionaries
- User dictionaries
- Other features that require only data and no logic
- Maybe full backup of preferences? Not 100% confirmed though and may be pushed back
### 0.3.15
- Re-adding word suggestions (at least for Latin-based languages at first)
- Importing the dictionaries as well as management relies on the Flex extension core and UI in Kotlin
- Actually parsing and generating suggestions happens in C++ to avoid another OOM catastrophe like in 0.3.9/10
- The actual format of the dictionary and word list source is not decided yet
- Improvement of the candidate view in Smartbar (for word suggestions)
- Theme rework part I:
- Custom key corner radius
- Custom key border color (not shadow!!)
- Re-work theme internals so they use Flex format
- Community repository on GitHub for theme sharing across users (when Theme Flex format is ready)
### 0.4.0
- Prepare FlorisBoard repository and app store presence for public beta release
on Google Play
- Rework branding images and texts of FlorisBoard for the app stores
- Focus on polishing the app and fixing bugs/crashes
With this release the versioning scheme changes: the second number now indicates new features,
changes in the third "patch" number now indicates bug fixes for the stable track. The development
cycle for each 0.x release will have -betaXX and -rcXX (release candidate) releases on the beta
track for interested people to follow along the development.
## 0.5.0
- Complete rework of the Emoji panel
- Recently used / Emoji history
- Emoji search
- Emoji suggestions when using :emoji_name: syntax
- Kaomoji panel implementation (the third tab which currently has "not yet implemented")
- Full Smartbar customization
- Includes internal rework how Smartbar is build and assembled
- Allow for more than one Smartbar / Stackable and Collapsible Smartbars
- Customizable quick actions, clipboard row
## 0.6.0
- Full on-board layout editor which allows users to create their own layouts
without writing a JSON file
- Import/Export of custom layout files packed in Flex extensions
## Backlog / Features that MAY be added
- Theme rework part II
- Adaptive themes v2
- Voice-to-text with Mozilla's open-source voice service
- Text translation
- Glide typing better word detection
- Proximity-based key typo detection
- Floating keyboard
- Tablet mode / Optimizations for landscape input
- Stickers/GIFs
- FlorisBoard landing web page for presentation
- Implementing additional layouts
- Support for Tasker/Automate/MacroDroid plugins
- Support for WearOS/Smartwatches
- Handwriting
- ...

View File

@@ -1,14 +1,14 @@
plugins {
id("com.android.application") version "4.2.0"
kotlin("android") version "1.5.0"
kotlin("kapt") version "1.5.0"
kotlin("plugin.serialization") version "1.5.0"
id("com.android.application") version "7.0.1"
kotlin("android") version "1.5.20"
kotlin("kapt") version "1.5.20"
kotlin("plugin.serialization") version "1.5.20"
}
android {
compileSdkVersion(30)
buildToolsVersion("30.0.3")
compileSdk = 30
buildToolsVersion = "30.0.3"
ndkVersion = "22.1.7171670"
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
@@ -17,15 +17,15 @@ android {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
freeCompilerArgs = listOf("-Xallow-result-return-type", "-Xopt-in=kotlin.RequiresOptIn")
freeCompilerArgs = listOf("-Xallow-result-return-type", "-Xopt-in=kotlin.RequiresOptIn", "-Xopt-in=kotlin.contracts.ExperimentalContracts")
}
defaultConfig {
applicationId = "dev.patrickgold.florisboard"
minSdkVersion(23)
targetSdkVersion(30)
versionCode(43)
versionName("0.3.12")
minSdk = 23
targetSdk = 30
versionCode = 56
versionName = "0.3.13"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
@@ -38,17 +38,50 @@ android {
)
}
}
externalNativeBuild {
cmake {
cFlags("-fvisibility=hidden", "-DU_STATIC_IMPLEMENTATION=1")
cppFlags("-fvisibility=hidden", "-std=c++17", "-fexceptions", "-ffunction-sections", "-fdata-sections", "-DU_DISABLE_RENAMING=1", "-DU_STATIC_IMPLEMENTATION=1")
arguments("-DANDROID_STL=c++_static")
}
}
ndk {
//abiFilters += listOf("x86", "x86_64", "armeabi-v7a", "arm64-v8a")
abiFilters += listOf("armeabi-v7a", "arm64-v8a")
}
sourceSets {
maybeCreate("main").apply {
assets {
srcDirs("src/main/assets", "src/main/icu4c/prebuilt/assets")
}
jniLibs {
srcDirs("src/main/icu4c/prebuilt/jniLibs")
}
}
}
}
buildFeatures {
viewBinding = true
}
externalNativeBuild {
cmake {
path("src/main/cpp/CMakeLists.txt")
}
}
buildTypes {
named("debug").configure {
applicationIdSuffix = ".debug"
versionNameSuffix = "-debug"
isDebuggable = true
isJniDebuggable = true
resValue("mipmap", "floris_app_icon", "@mipmap/ic_app_icon_debug")
resValue("mipmap", "floris_app_icon_round", "@mipmap/ic_app_icon_debug_round")
resValue("string", "floris_app_name", "FlorisBoard Debug")
@@ -57,7 +90,7 @@ android {
create("beta") // Needed because by default the "beta" BuildType does not exist
named("beta").configure {
applicationIdSuffix = ".beta"
versionNameSuffix = "-beta06"
versionNameSuffix = "-beta12"
proguardFiles.add(getDefaultProguardFile("proguard-android-optimize.txt"))
resValue("mipmap", "floris_app_icon", "@mipmap/ic_app_icon_beta")
@@ -80,21 +113,21 @@ android {
}
}
lintOptions {
lint {
isAbortOnError = false
}
}
dependencies {
implementation("androidx.activity", "activity-ktx", "1.2.1")
implementation("androidx.appcompat", "appcompat", "1.2.0")
implementation("androidx.autofill", "autofill", "1.1.0")
implementation("androidx.core", "core-ktx", "1.3.2")
implementation("androidx.fragment", "fragment-ktx", "1.3.0")
implementation("androidx.preference", "preference-ktx", "1.1.1")
implementation("androidx.constraintlayout", "constraintlayout", "2.0.4")
implementation("androidx.lifecycle", "lifecycle-service", "2.2.0")
implementation("com.google.android", "flexbox", "2.0.1")
implementation("com.google.android.flexbox", "flexbox", "3.0.0")
implementation("com.google.android.material", "material", "1.3.0")
implementation("org.jetbrains.kotlinx", "kotlinx-coroutines-android", "1.4.2")
implementation("org.jetbrains.kotlinx", "kotlinx-serialization-json", "1.1.0")
@@ -104,9 +137,11 @@ dependencies {
implementation("androidx.room", "room-runtime", "2.2.6")
kapt("androidx.room", "room-compiler","2.2.6")
testImplementation("junit", "junit", "4.13.1")
testImplementation(kotlin("test"))
testImplementation("androidx.test", "core", "1.3.0")
testImplementation("org.mockito", "mockito-inline", "3.7.7")
testImplementation("org.robolectric", "robolectric", "4.5.1")
androidTestImplementation("androidx.test.ext", "junit", "1.1.2")
androidTestImplementation("androidx.test.espresso", "espresso-core", "3.3.0")
}

View File

@@ -21,7 +21,7 @@
<uses-permission android:name="android.permission.VIBRATE"/>
<application
android:name=".ime.core.FlorisApplication"
android:name="dev.patrickgold.florisboard.FlorisApplication"
android:allowBackup="false"
android:icon="@mipmap/floris_app_icon"
android:label="@string/floris_app_name"
@@ -31,16 +31,27 @@
<!-- IME service -->
<service
android:name="dev.patrickgold.florisboard.ime.core.FlorisBoard"
android:name="dev.patrickgold.florisboard.FlorisImeService"
android:label="@string/floris_app_name"
android:permission="android.permission.BIND_INPUT_METHOD">
<meta-data
android:name="android.view.im"
android:resource="@xml/method"/>
android:permission="android.permission.BIND_INPUT_METHOD"
android:directBootAware="true"
android:exported="true">
<intent-filter>
<action android:name="android.view.InputMethod"/>
</intent-filter>
<meta-data android:name="android.view.im" android:resource="@xml/method"/>
</service>
<!-- Spellchecker service -->
<service
android:name="dev.patrickgold.florisboard.FlorisSpellCheckerService"
android:label="@string/floris_app_name"
android:permission="android.permission.BIND_TEXT_SERVICE"
android:exported="true">
<intent-filter>
<action android:name="android.service.textservice.SpellCheckerService"/>
</intent-filter>
<meta-data android:name="android.view.textservice.scs" android:resource="@xml/spellchecker"/>
</service>
<!-- Settings Activity -->
@@ -59,7 +70,8 @@
android:label="@string/floris_app_name"
android:launchMode="singleTask"
android:roundIcon="@mipmap/floris_app_icon_round"
android:targetActivity="dev.patrickgold.florisboard.setup.SetupActivity">
android:targetActivity="dev.patrickgold.florisboard.setup.SetupActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
@@ -87,6 +99,14 @@
android:label="@string/settings__theme_editor__title"
android:theme="@style/SettingsTheme"/>
<!-- Spelling Activity -->
<activity
android:name="dev.patrickgold.florisboard.settings.spelling.SpellingActivity"
android:icon="@mipmap/floris_app_icon"
android:label="@string/settings__spelling__title_overview"
android:roundIcon="@mipmap/floris_app_icon_round"
android:theme="@style/SettingsTheme"/>
<!-- About Activity -->
<activity
android:name="dev.patrickgold.florisboard.settings.AboutActivity"

View File

@@ -1,5 +1,10 @@
{
"package": "dev.patrickgold.florisboard",
"composers": [
{ "$": "appender" },
{ "$": "hangul-unicode" },
{ "$": "kana-unicode" }
],
"currencySets": [
{
"name": "azerbaijani_manat",
@@ -246,6 +251,7 @@
{
"id": 101,
"languageTag": "en-US",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "qwerty"
@@ -254,6 +260,7 @@
{
"id": 102,
"languageTag": "en-UK",
"composer": "appender",
"currencySet": "pound",
"preferred": {
"characters": "qwerty"
@@ -262,6 +269,7 @@
{
"id": 103,
"languageTag": "en-CA",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "qwerty"
@@ -270,6 +278,7 @@
{
"id": 104,
"languageTag": "en-AU",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "qwerty"
@@ -278,6 +287,7 @@
{
"id": 201,
"languageTag": "de-DE",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "qwertz"
@@ -286,6 +296,7 @@
{
"id": 202,
"languageTag": "de-AT",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "qwertz"
@@ -294,14 +305,27 @@
{
"id": 203,
"languageTag": "de-CH",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "swiss_german"
}
},
{
"id": 204,
"languageTag": "de-DE-neobone",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "neo2",
"symbols": "neo2",
"numericRow": "neo2"
}
},
{
"id": 301,
"languageTag": "fr-FR",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "azerty"
@@ -310,6 +334,7 @@
{
"id": 302,
"languageTag": "fr-CA",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "canadian_french"
@@ -318,6 +343,7 @@
{
"id": 303,
"languageTag": "fr-CH",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "swiss_french"
@@ -326,6 +352,7 @@
{
"id": 401,
"languageTag": "it-IT",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "qwerty"
@@ -334,6 +361,7 @@
{
"id": 402,
"languageTag": "it-CH",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "swiss_italian"
@@ -342,6 +370,7 @@
{
"id": 501,
"languageTag": "es-ES",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "spanish"
@@ -350,6 +379,7 @@
{
"id": 502,
"languageTag": "es-US",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "spanish"
@@ -358,6 +388,7 @@
{
"id": 503,
"languageTag": "es-419",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "spanish"
@@ -366,6 +397,7 @@
{
"id": 601,
"languageTag": "pt-PT",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "qwerty"
@@ -374,6 +406,7 @@
{
"id": 602,
"languageTag": "pt-BR",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "qwerty"
@@ -382,6 +415,7 @@
{
"id": 701,
"languageTag": "nb-NO",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "norwegian"
@@ -390,6 +424,7 @@
{
"id": 702,
"languageTag": "nn-NO",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "norwegian"
@@ -398,6 +433,7 @@
{
"id": 711,
"languageTag": "sv-SE",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "swedish_finnish"
@@ -406,6 +442,7 @@
{
"id": 721,
"languageTag": "fi-FI",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "swedish_finnish"
@@ -414,6 +451,7 @@
{
"id": 731,
"languageTag": "da-DK",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "danish"
@@ -422,6 +460,7 @@
{
"id": 741,
"languageTag": "is-IS",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "icelandic"
@@ -430,6 +469,7 @@
{
"id": 751,
"languageTag": "fo",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "faroese"
@@ -438,6 +478,7 @@
{
"id": 801,
"languageTag": "fa-FA",
"composer": "appender",
"currencySet": "iranian_rial",
"preferred": {
"characters": "persian",
@@ -449,6 +490,7 @@
{
"id": 901,
"languageTag": "ar",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "arabic",
@@ -460,6 +502,7 @@
{
"id": 1001,
"languageTag": "hu",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "hungarian"
@@ -468,6 +511,7 @@
{
"id": 1101,
"languageTag": "eo",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "esperanto"
@@ -476,6 +520,7 @@
{
"id": 1201,
"languageTag": "hr",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "qwertz"
@@ -484,6 +529,7 @@
{
"id": 1301,
"languageTag": "ru",
"composer": "appender",
"currencySet": "russian_ruble",
"preferred": {
"characters": "jcuken_russian"
@@ -492,6 +538,7 @@
{
"id": 1351,
"languageTag": "uk",
"composer": "appender",
"currencySet": "ukrainian_hryvnia",
"preferred": {
"characters": "jcuken_ukrainian"
@@ -500,6 +547,7 @@
{
"id": 1401,
"languageTag": "el",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "greek"
@@ -508,6 +556,7 @@
{
"id": 1501,
"languageTag": "ro",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "qwerty"
@@ -516,6 +565,7 @@
{
"id": 1601,
"languageTag": "pl",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "qwerty"
@@ -524,6 +574,7 @@
{
"id": 1701,
"languageTag": "bg-bg",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "bulgarian_phonetic"
@@ -532,6 +583,7 @@
{
"id": 1801,
"languageTag": "tr",
"composer": "appender",
"currencySet": "turkish_lira",
"preferred": {
"characters": "qwerty"
@@ -540,6 +592,7 @@
{
"id": 1901,
"languageTag": "iw-IL",
"composer": "appender",
"currencySet": "israeli_new_shekel",
"preferred": {
"characters": "hebrew"
@@ -548,6 +601,7 @@
{
"id": 2001,
"languageTag": "ckb",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "kurdish",
@@ -559,6 +613,7 @@
{
"id": 2101,
"languageTag": "sr-RS",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "serbian_cyrillic"
@@ -567,6 +622,7 @@
{
"id": 2201,
"languageTag": "lv-LV",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "qwerty"
@@ -575,6 +631,7 @@
{
"id": 2301,
"languageTag": "ku",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "kurdish_kurmanci"
@@ -583,6 +640,7 @@
{
"id": 2501,
"languageTag": "ca",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "catalan"
@@ -591,6 +649,7 @@
{
"id": 2601,
"languageTag": "IPA-IPA",
"composer": "appender",
"currencySet": "dollar",
"preferred": {
"characters": "ipa",
@@ -601,6 +660,7 @@
{
"id": 2701,
"languageTag": "sk",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "qwertz"
@@ -609,10 +669,41 @@
{
"id": 2801,
"languageTag": "cs",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "qwertz"
}
},
{
"id": 2900,
"languageTag": "ko",
"composer": "hangul-unicode",
"currencySet": "south_korean_won",
"preferred": {
"characters": "korean"
}
},
{
"id": 3000,
"languageTag": "lt-LT",
"composer": "appender",
"currencySet": "euro",
"preferred": {
"characters": "qwerty"
}
},
{
"id": 3100,
"languageTag": "ja-JP-jis",
"composer": "kana-unicode",
"currencySet": "yen",
"preferred": {
"characters": "jis",
"symbols": "cjk",
"symbols2": "cjk",
"numericRow": "cjk"
}
}
]
}

View File

@@ -0,0 +1,69 @@
{
"basePath": "ime/spelling",
"importSources": [
{
"id": "mozilla_firefox",
"label": "Mozilla Firefox Add-ons",
"url": "https://addons.mozilla.org/firefox/language-tools/",
"format": {
"$": "archive",
"file": {
"name": "^.+\\.xpi$",
"isRequired": true
}
}
},
{
"id": "libre_office",
"label": "LibreOffice [CURRENTLY UNSUPPORTED]",
"url": "https://extensions.libreoffice.org/?Tags%5B%5D=50",
"format": {
"$": "archive",
"file": {
"name": "^.+\\.oxt$",
"isRequired": true
}
}
},
{
"id": "open_office",
"label": "Apache OpenOffice [CURRENTLY UNSUPPORTED]",
"url": "https://extensions.openoffice.org/en/search?f%5B0%5D=field_project_tags%3A157",
"format": {
"$": "archive",
"file": {
"name": "^.+\\.oxt$",
"isRequired": true
}
}
},
{
"id": "free_office",
"label": "SoftMaker FreeOffice",
"url": "https://www.freeoffice.com/en/download/dictionaries",
"format": {
"$": "archive",
"file": {
"name": "^.+\\.sox$",
"isRequired": true
}
}
},
{
"id": "gh_wooorm",
"label": "GitHub collection by Titus Wormer",
"url": "https://github.com/wooorm/dictionaries",
"format": {
"$": "raw",
"affFile": {
"name": "^.+\\.aff$",
"isRequired": true
},
"dicFile": {
"name": "^.+\\.dic$",
"isRequired": true
}
}
}
]
}

View File

@@ -0,0 +1,61 @@
{
"type": "characters",
"name": "bone",
"label": "Bone",
"authors": [ "ostrya" ],
"direction": "ltr",
"modifier": "neo2",
"arrangement": [
[
{ "$": "auto_text_key", "code": 106, "label": "j" },
{ "$": "auto_text_key", "code": 100, "label": "d" },
{ "$": "auto_text_key", "code": 117, "label": "u" },
{ "$": "auto_text_key", "code": 97, "label": "a" },
{ "$": "auto_text_key", "code": 120, "label": "x" },
{ "$": "auto_text_key", "code": 112, "label": "p" },
{ "$": "auto_text_key", "code": 104, "label": "h" },
{ "$": "auto_text_key", "code": 108, "label": "l" },
{ "$": "auto_text_key", "code": 109, "label": "m" },
{ "$": "auto_text_key", "code": 119, "label": "w" },
{ "$": "case_selector",
"lower": {
"code": 223, "label": "ß", "popup": {
"relevant": [
{ "code": 180, "label": "´" }
]
}
},
"upper": {
"code": 7838, "label": "ẞ", "popup": {
"relevant": [
{ "code": 180, "label": "´" }
]
}
}
}
],
[
{ "$": "auto_text_key", "code": 99, "label": "c" },
{ "$": "auto_text_key", "code": 116, "label": "t" },
{ "$": "auto_text_key", "code": 105, "label": "i" },
{ "$": "auto_text_key", "code": 101, "label": "e" },
{ "$": "auto_text_key", "code": 111, "label": "o" },
{ "$": "auto_text_key", "code": 98, "label": "b" },
{ "$": "auto_text_key", "code": 110, "label": "n" },
{ "$": "auto_text_key", "code": 114, "label": "r" },
{ "$": "auto_text_key", "code": 115, "label": "s" },
{ "$": "auto_text_key", "code": 103, "label": "g" },
{ "$": "auto_text_key", "code": 113, "label": "q" }
],
[
{ "$": "auto_text_key", "code": 102, "label": "f" },
{ "$": "auto_text_key", "code": 118, "label": "v" },
{ "$": "auto_text_key", "code": 252, "label": "ü" },
{ "$": "auto_text_key", "code": 228, "label": "ä" },
{ "$": "auto_text_key", "code": 246, "label": "ö" },
{ "$": "auto_text_key", "code": 121, "label": "y" },
{ "$": "auto_text_key", "code": 122, "label": "z" },
{ "$": "auto_text_key", "code": 107, "label": "k" }
]
]
}

View File

@@ -4,59 +4,21 @@
"authors": [ "HeiWiper" ],
"mapping": {
"all": {
"ض": {
"relevant": [
{ "code": 1633, "label": "١" }
]
},
"ص": {
"relevant": [
{ "code": 1634, "label": "٢" }
]
},
"ث": {
"relevant": [
{ "code": 1635, "label": "٣" }
]
},
"ق": {
"relevant": [
{ "code": 1704, "label": "ڨ" },
{ "code": 1636, "label": "٤" }
{ "code": 1704, "label": "ڨ" }
]
},
"ف": {
"relevant": [
{ "code": 1701, "label": "ڥ" },
{ "code": 1700, "label": "ڤ" },
{ "code": 1698, "label": "ڢ" },
{ "code": 1637, "label": "٥" }
]
},
"غ": {
"relevant": [
{ "code": 1638, "label": "٦" }
]
},
"ع": {
"relevant": [
{ "code": 1639, "label": "٧" }
{ "code": 1698, "label": "ڢ" }
]
},
"ه": {
"relevant": [
{ "code": 1726, "label": "ھ" },
{ "code": 1640, "label": "٨" }
]
},
"خ": {
"relevant": [
{ "code": 1641, "label": "٩" }
]
},
"ح": {
"relevant": [
{ "code": 1632, "label": "٠" }
{ "code": 1726, "label": "ھ" }
]
},
"ج": {
@@ -70,8 +32,8 @@
]
},
"ي": {
"main": { "code": 1574, "label": "ئ" },
"relevant": [
{ "code": 1574, "label": "ئ" },
{ "code": 1609, "label": "ى" }
]
},
@@ -89,10 +51,10 @@
]
},
"ا": {
"main": { "code": 1571, "label": "أ" },
"relevant": [
{ "code": 1570, "label": "آ" },
{ "code": 1569, "label": "ء" },
{ "code": 1571, "label": "أ" },
{ "code": 1573, "label": "إ" },
{ "code": 1649, "label": "ٱ" }
]
@@ -104,9 +66,7 @@
]
},
"ى": {
"relevant": [
{ "code": 1574, "label": "ئ" }
]
"main": { "code": 1574, "label": "ئ" }
},
"ز": {
"relevant": [

View File

@@ -4,28 +4,22 @@
"authors": [ "GoRaN" ],
"mapping": {
"all": {
"": {
"relevant": [
{ "code": 1577, "label": "ة" },
{ "code": 1729, "label": "ـہ" }
]
},
"ر": {
"relevant": [
{ "code": 1685, "label": "ڕ" },
{ "code": 1682, "label": "ڒ" }
]
},
"ی": {
"relevant": [
{ "code": 1746, "label": "ے" },
{ "code": 1610, "label": "ي" },
{ "code": 1744, "label": "ې" },
{ "code": 1741, "label": "ۍ" },
{ "code": 1742, "label": "ێ" },
{ "code": 1744, "label": "ې" },
{ "code": 1610, "label": "ي" },
{ "code": 1597, "label": "ؽ" }
]
},
@@ -34,10 +28,15 @@
"ﺋ": {
"relevant": [
{ "code": 65163, "label": "ﺋ" },
{ "code": 1569, "label": "ء" },
{ "code": 65139, "label": "ﹳ" }
]
},
"ح": {
"relevant": [
{ "code": 65010, "label": "ﷲ" },
{ "code": 65019, "label": "ﷻ" }
]
},
"ع": {
"relevant": [
@@ -56,12 +55,9 @@
]
},
"ف": {
"relevant": [
{ "code": 1701, "label": "ڥ" },
{ "code": 1700, "label": "ڤ" },
{ "code": 1698, "label": "ڢ" },
{ "code": 1697, "label": "ڡ" }
]
@@ -70,7 +66,6 @@
"د": {
"relevant": [
{ "code": 1676, "label": "ڌ" },
{ "code": 1584, "label": "ذ" },
{ "code": 64390, "label": "ﮆ" },
{ "code": 1774, "label": "ۮ" }
]
@@ -93,9 +88,7 @@
},
"ب": {
"relevant": [
{ "code": 65010, "label": "" },
{ "code": 65021, "label": "﷽" },
{ "code": 65019, "label": "ﷻ" }
{ "code": 65021, "label": "" }
]
},
"م": {
@@ -108,7 +101,6 @@
"relevant": [
{ "code": 1718, "label": "ڶ" },
{ "code": 1719, "label": "ڷ" },
{ "code": 1717, "label": "ڵ" },
{ "code": 1720, "label": "ڸ" }
]
},

View File

@@ -0,0 +1,19 @@
{
"type": "characters/extended_popups",
"name": "de-DE-neobone",
"authors": [ "ostrya" ],
"mapping": {
"uri": {
"~right": {
"main": { "code": -255, "label": ".com" },
"relevant": [
{ "code": -255, "label": ".ch" },
{ "code": -255, "label": ".de" },
{ "code": -255, "label": ".at" },
{ "code": -255, "label": ".net" }
]
}
}
}
}

View File

@@ -20,10 +20,10 @@
]
},
"ι": {
"main": { "$": "auto_text_key", "code": 943, "label": "ί" },
"relevant": [
{ "$": "auto_text_key", "code": 912, "label": "ΐ" },
{ "$": "auto_text_key", "code": 970, "label": "ϊ" },
{ "$": "auto_text_key", "code": 943, "label": "ί" }
{ "$": "auto_text_key", "code": 970, "label": "ϊ" }
]
},
"ο": {
@@ -32,10 +32,10 @@
]
},
"υ": {
"main": { "$": "auto_text_key", "code": 973, "label": "ύ" },
"relevant": [
{ "$": "auto_text_key", "code": 944, "label": "ΰ" },
{ "$": "auto_text_key", "code": 971, "label": "ϋ" },
{ "$": "auto_text_key", "code": 973, "label": "ύ" }
{ "$": "auto_text_key", "code": 971, "label": "ϋ" }
]
},
"ω": {

View File

@@ -0,0 +1,292 @@
{
"type": "characters/extended_popups",
"name": "ja-JP-jis",
"authors": [ "waelwindows" ],
"mapping": {
"all": {
"あ": {
"main": { "code": 12353, "label": "ぁ" }
},
"ア": {
"main": { "code": 12449, "label": "ァ" }
},
"ア": {
"main": { "code": 65383, "label": "ァ" }
},
"い": {
"main": { "code": 12355, "label": "ぃ" },
"relevant": [
{ "code": 12432, "label": "ゐ" },
{ "code": 110928, "label": "𛅐" }
]
},
"イ": {
"main": { "code": 12451, "label": "ィ" },
"relevant": [
{ "code": 12528, "label": "ヰ" },
{ "code": 110948, "label": "𛅤" }
]
},
"イ": {
"main": { "code": 65384, "label": "ィ" }
},
"う": {
"main": { "code": 12357, "label": "ぅ" }
},
"ウ": {
"main": { "code": 12453, "label": "ゥ" }
},
"ウ": {
"main": { "code": 65385, "label": "ゥ" }
},
"え": {
"main": { "code": 12359, "label": "ぇ" },
"relevant": [
{ "code": 12433, "label": "ゑ" },
{ "code": 110929, "label": "𛅑" }
]
},
"エ": {
"main": { "code": 12455, "label": "ェ" },
"relevant": [
{ "code": 12529, "label": "ヱ" },
{ "code": 110949, "label": "𛅥" }
]
},
"エ": {
"main": { "code": 65386, "label": "ェ" }
},
"お": {
"main": { "code": 12361, "label": "ぉ" }
},
"オ": {
"main": { "code": 12457, "label": "ォ" }
},
"オ": {
"main": { "code": 65387, "label": "ォ" }
},
"や": {
"main": { "code": 12419, "label": "ゃ" }
},
"ヤ": {
"main": { "code": 12515, "label": "ャ" }
},
"ヤ": {
"main": { "code": 65388, "label": "ャ" }
},
"ゆ": {
"main": { "code": 12421, "label": "ゅ" }
},
"ユ": {
"main": { "code": 12517, "label": "ュ" }
},
"ユ": {
"main": { "code": 65389, "label": "ュ" }
},
"よ": {
"main": { "code": 12423, "label": "ょ" }
},
"ヨ": {
"main": { "code": 12519, "label": "ョ" }
},
"ヨ": {
"main": { "code": 65390, "label": "ョ" }
},
"わ": {
"main": { "code": 12434, "label": "を" },
"relevant": [
{ "code": 12430, "label": "ゎ" },
{ "code": 110930, "label": "𛅒" }
]
},
"ワ": {
"main": { "code": 12530, "label": "ヲ" },
"relevant": [
{ "code": 12526, "label": "ヮ" },
{ "code": 110950, "label": "𛅦" }
]
},
"ワ": {
"main": { "code": 65382, "label": "ヲ" }
},
"つ": {
"main": { "code": 12387, "label": "っ" }
},
"ツ": {
"main": { "code": 12483, "label": "ッ" }
},
"ツ": {
"main": { "code": 65391, "label": "ッ" }
},
"ト": {
"relevant": [
{ "code": 12787, "label": "ㇳ" }
]
},
"シ": {
"relevant": [
{ "code": 12785, "label": "ㇱ" }
]
},
"ス": {
"main": { "code": 12786, "label": "ㇲ" }
},
"か": {
"main": { "code": 12437, "label": "ゕ" }
},
"カ": {
"main": { "code": 12533, "label": "ヵ" }
},
"ク": {
"main": { "code": 12784, "label": "ㇰ" }
},
"け": {
"main": { "code": 12438, "label": "ゖ" }
},
"ケ": {
"main": { "code": 12534, "label": "ヶ" }
},
"ヌ": {
"relevant": [
{ "code": 12788, "label": "ㇴ" }
]
},
"ハ": {
"relevant": [
{ "code": 12789, "label": "ㇵ" }
]
},
"ヒ": {
"relevant": [
{ "code": 12790, "label": "ㇶ" }
]
},
"フ": {
"relevant": [
{ "code": 12791, "label": "ㇷ" }
]
},
"ヘ": {
"relevant": [
{ "code": 12792, "label": "ㇸ" }
]
},
"ホ": {
"relevant": [
{ "code": 12793, "label": "ㇹ" }
]
},
"ム": {
"relevant": [
{ "code": 12794, "label": "ㇺ" }
]
},
"ラ": {
"relevant": [
{ "code": 12795, "label": "ㇻ" }
]
},
"リ": {
"relevant": [
{ "code": 12796, "label": "ㇼ" }
]
},
"ル": {
"relevant": [
{ "code": 12797, "label": "ㇽ" }
]
},
"レ": {
"relevant": [
{ "code": 12798, "label": "ㇾ" }
]
},
"ロ": {
"relevant": [
{ "code": 12799, "label": "ㇿ" }
]
},
"゛": {
"main": { "code": 12443, "label": "゛" }
},
"゜": {
"main": { "code": 12444, "label": "゜" }
},
"~kana": {
"relevant": [
{ "code": -9711, "label": "あ" },
{ "code": -9712, "label": "ア" },
{ "code": -9713, "label": "ア" }
]
},
"~right": {
"main": { "$": "char_width_selector",
"full": { "code": 12539, "label": "・" },
"half": { "code": 9834, "label": "♪" }
},
"relevant": [
{ "$": "char_width_selector",
"full": { "code": 65286, "label": "" },
"half": { "code": 38, "label": "&" }
},
{ "$": "char_width_selector",
"full": { "code": 65285, "label": "" },
"half": { "code": 37, "label": "%" }
},
{ "$": "char_width_selector",
"full": { "code": 65291, "label": "" },
"half": { "code": 43, "label": "+" }
},
{ "$": "char_width_selector",
"full": { "code": 65340, "label": "" },
"half": { "code": 92, "label": "\\" }
},
{ "$": "char_width_selector",
"full": { "code": 65293, "label": "" },
"half": { "code": 45, "label": "-" }
},
{ "$": "char_width_selector",
"full": { "code": 65306, "label": "" },
"half": { "code": 58, "label": ":" }
},
{ "$": "char_width_selector",
"full": { "code": 65287, "label": "" },
"half": { "code": 39, "label": "'" }
},
{ "$": "char_width_selector",
"full": { "code": 65312, "label": "" },
"half": { "code": 64, "label": "@" }
},
{ "$": "char_width_selector",
"full": { "code": 65307, "label": "" },
"half": { "code": 59, "label": ";" }
},
{ "$": "char_width_selector",
"full": { "code": 65295, "label": "" },
"half": { "code": 47, "label": "/" }
},
{ "$": "char_width_selector",
"full": { "code": 65288, "label": "" },
"half": { "code": 40, "label": "(" }
},
{ "$": "char_width_selector",
"full": { "code": 65289, "label": "" },
"half": { "code": 41, "label": ")" }
},
{ "$": "char_width_selector",
"full": { "code": 65283, "label": "" },
"half": { "code": 35, "label": "#" }
},
{ "$": "char_width_selector",
"full": { "code": 65281, "label": "" },
"half": { "code": 33, "label": "!" }
},
{ "$": "char_width_selector",
"full": { "code": 65311, "label": "" },
"half": { "code": 63, "label": "?" }
}
]
}
}
}
}

View File

@@ -0,0 +1,75 @@
{
"type": "characters/extended_popups",
"name": "ko",
"authors": [ "patrickgold", "Hayleia" ],
"mapping": {
"all": {
"ㅂ": {
"relevant": [
{ "$": "auto_text_key", "code": 12611, "label": "ㅃ" }
]
},
"ㅈ": {
"relevant": [
{ "$": "auto_text_key", "code": 12617, "label": "ㅉ" }
]
},
"ㄷ": {
"relevant": [
{ "$": "auto_text_key", "code": 12600, "label": "ㄸ" }
]
},
"ㄱ": {
"relevant": [
{ "$": "auto_text_key", "code": 12594, "label": "ㄲ" }
]
},
"ㅅ": {
"relevant": [
{ "$": "auto_text_key", "code": 12614, "label": "ㅆ" }
]
},
"ㅐ": {
"relevant": [
{ "$": "auto_text_key", "code": 12626, "label": "ㅒ" }
]
},
"ㅔ": {
"relevant": [
{ "$": "auto_text_key", "code": 12630, "label": "ㅖ" }
]
},
"~right": {
"main": { "code": 44, "label": "," },
"relevant": [
{ "code": 38, "label": "&" },
{ "code": 37, "label": "%" },
{ "code": 43, "label": "+" },
{ "code": 34, "label": "\"" },
{ "code": 45, "label": "-" },
{ "code": 58, "label": ":" },
{ "code": 39, "label": "'" },
{ "code": 64, "label": "@" },
{ "code": 59, "label": ";" },
{ "code": 47, "label": "/" },
{ "code": 40, "label": "(" },
{ "code": 41, "label": ")" },
{ "code": 35, "label": "#" },
{ "code": 33, "label": "!" },
{ "code": 63, "label": "?" }
]
}
},
"uri": {
"~right": {
"main": { "code": -255, "label": ".com" },
"relevant": [
{ "code": -255, "label": ".gov" },
{ "code": -255, "label": ".edu" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".net" }
]
}
}
}
}

View File

@@ -0,0 +1,167 @@
{
"type": "characters/extended_popups",
"name": "lv",
"authors": [ "patrickgold" ],
"mapping": {
"all": {
"a": {
"main": { "$": "auto_text_key", "code": 261, "label": "ą" },
"relevant": [
{ "$": "auto_text_key", "code": 226, "label": "â" },
{ "$": "auto_text_key", "code": 227, "label": "ã" },
{ "$": "auto_text_key", "code": 229, "label": "å" },
{ "$": "auto_text_key", "code": 230, "label": "æ" },
{ "$": "auto_text_key", "code": 228, "label": "ä" },
{ "$": "auto_text_key", "code": 257, "label": "ā" },
{ "$": "auto_text_key", "code": 224, "label": "à" },
{ "$": "auto_text_key", "code": 225, "label": "á" }
]
},
"c": {
"main": { "$": "auto_text_key", "code": 269, "label": "č" },
"relevant": [
{ "$": "auto_text_key", "code": 263, "label": "ć" },
{ "$": "auto_text_key", "code": 231, "label": "ç" }
]
},
"d": {
"main": { "$": "auto_text_key", "code": 271, "label": "ď" }
},
"e": {
"main": { "$": "auto_text_key", "code": 279, "label": "ė" },
"relevant": [
{ "$": "auto_text_key", "code": 235, "label": "ë" },
{ "$": "auto_text_key", "code": 233, "label": "é" },
{ "$": "auto_text_key", "code": 234, "label": "ê" },
{ "$": "auto_text_key", "code": 283, "label": "ě" },
{ "$": "auto_text_key", "code": 275, "label": "ē" },
{ "$": "auto_text_key", "code": 281, "label": "ę" },
{ "$": "auto_text_key", "code": 232, "label": "è" }
]
},
"g": {
"main": { "$": "auto_text_key", "code": 291, "label": "ģ" },
"relevant": [
{ "$": "auto_text_key", "code": 287, "label": "ğ" }
]
},
"i": {
"main": { "$": "auto_text_key", "code": 303, "label": "į" },
"relevant": [
{ "$": "auto_text_key", "code": 238, "label": "î" },
{ "$": "auto_text_key", "code": 239, "label": "ï" },
{ "$": "auto_text_key", "code": 236, "label": "ì" },
{ "$": "auto_text_key", "code": 299, "label": "ī" },
{ "$": "auto_text_key", "code": 237, "label": "í" }
]
},
"k": {
"main": { "$": "auto_text_key", "code": 311, "label": "ķ" }
},
"l": {
"main": { "$": "auto_text_key", "code": 316, "label": "ļ" },
"relevant": [
{ "$": "auto_text_key", "code": 318, "label": "ľ" },
{ "$": "auto_text_key", "code": 314, "label": "ĺ" },
{ "$": "auto_text_key", "code": 322, "label": "ł" }
]
},
"n": {
"main": { "$": "auto_text_key", "code": 326, "label": "ņ" },
"relevant": [
{ "$": "auto_text_key", "code": 324, "label": "ń" },
{ "$": "auto_text_key", "code": 241, "label": "ñ" }
]
},
"o": {
"main": { "$": "auto_text_key", "code": 246, "label": "ö" },
"relevant": [
{ "$": "auto_text_key", "code": 248, "label": "ø" },
{ "$": "auto_text_key", "code": 337, "label": "ő" },
{ "$": "auto_text_key", "code": 244, "label": "ô" },
{ "$": "auto_text_key", "code": 339, "label": "œ" },
{ "$": "auto_text_key", "code": 243, "label": "ó" },
{ "$": "auto_text_key", "code": 242, "label": "ò" },
{ "$": "auto_text_key", "code": 245, "label": "õ" }
]
},
"r": {
"main": { "$": "auto_text_key", "code": 343, "label": "ŗ" },
"relevant": [
{ "$": "auto_text_key", "code": 341, "label": "ŕ" },
{ "$": "auto_text_key", "code": 345, "label": "ř" }
]
},
"s": {
"main": { "$": "auto_text_key", "code": 353, "label": "š" },
"relevant": [
{ "$": "auto_text_key", "code": 347, "label": "ś" },
{ "$": "auto_text_key", "code": 223, "label": "ß" },
{ "$": "auto_text_key", "code": 351, "label": "ş" }
]
},
"t": {
"main": { "$": "auto_text_key", "code": 355, "label": "ţ" },
"relevant": [
{ "$": "auto_text_key", "code": 357, "label": "ť" }
]
},
"u": {
"main": { "$": "auto_text_key", "code": 363, "label": "ū" },
"relevant": [
{ "$": "auto_text_key", "code": 367, "label": "ů" },
{ "$": "auto_text_key", "code": 250, "label": "ú" },
{ "$": "auto_text_key", "code": 251, "label": "û" },
{ "$": "auto_text_key", "code": 369, "label": "ű" },
{ "$": "auto_text_key", "code": 249, "label": "ù" },
{ "$": "auto_text_key", "code": 252, "label": "ü" },
{ "$": "auto_text_key", "code": 371, "label": "ų" }
]
},
"y": {
"main": { "$": "auto_text_key", "code": 253, "label": "ý" },
"relevant": [
{ "$": "auto_text_key", "code": 255, "label": "ÿ" }
]
},
"z": {
"main": { "$": "auto_text_key", "code": 382, "label": "ž" },
"relevant": [
{ "$": "auto_text_key", "code": 378, "label": "ź" },
{ "$": "auto_text_key", "code": 380, "label": "ż" }
]
},
"~right": {
"main": { "code": 44, "label": "," },
"relevant": [
{ "code": 38, "label": "&" },
{ "code": 37, "label": "%" },
{ "code": 43, "label": "+" },
{ "code": 34, "label": "\"" },
{ "code": 45, "label": "-" },
{ "code": 58, "label": ":" },
{ "code": 39, "label": "'" },
{ "code": 64, "label": "@" },
{ "code": 59, "label": ";" },
{ "code": 47, "label": "/" },
{ "code": 40, "label": "(" },
{ "code": 41, "label": ")" },
{ "code": 35, "label": "#" },
{ "code": 33, "label": "!" },
{ "code": 63, "label": "?" }
]
}
},
"uri": {
"~right": {
"main": { "code": -255, "label": ".lv" },
"relevant": [
{ "code": -255, "label": ".gov" },
{ "code": -255, "label": ".edu" },
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".net" }
]
}
}
}
}

View File

@@ -1,99 +1,35 @@
{
"type": "characters/extended_popups",
"name": "tr",
"authors": [ "kisekinopureya", "patrickgold" ],
"authors": [ "kisekinopureya", "patrickgold", "dvrnynr" ],
"mapping": {
"all": {
"a": {
"relevant": [
{ "$": "auto_text_key", "code": 226, "label": "â" },
{ "$": "auto_text_key", "code": 228, "label": "ä" },
{ "$": "auto_text_key", "code": 225, "label": "á" }
]
},
"c": {
"main": { "$": "auto_text_key", "code": 231, "label": "ç" },
"relevant": [
{ "$": "auto_text_key", "code": 269, "label": "č" },
{ "$": "auto_text_key", "code": 263, "label": "ć" }
]
},
"e": {
"relevant": [
{ "$": "auto_text_key", "code": 233, "label": "é" },
{ "$": "auto_text_key", "code": 601, "label": "ə" },
{ "$": "auto_text_key", "code": 234, "label": "ê" }
]
"main": { "$": "auto_text_key", "code": 231, "label": "ç" }
},
"g": {
"main": { "$": "auto_text_key", "code": 287, "label": "ğ" }
},
"i": {
"main": { "$": "auto_text_key", "code": 305, "label": "ı" },
"relevant": [
{ "$": "auto_text_key", "code": 303, "label": "į" },
{ "$": "auto_text_key", "code": 236, "label": "ì" },
{ "$": "auto_text_key", "code": 237, "label": "í" },
{ "$": "auto_text_key", "code": 299, "label": "ī" },
{ "$": "auto_text_key", "code": 238, "label": "î" },
{ "$": "auto_text_key", "code": 239, "label": "ï" }
]
"main": { "$": "case_selector",
"lower": { "code": 305, "label": "ı" },
"upper": { "code": 73, "label": "I" }
}
},
"ı": {
"main": { "$": "auto_text_key", "code": 105, "label": "i" },
"relevant": [
{ "$": "auto_text_key", "code": 303, "label": "į" },
{ "$": "auto_text_key", "code": 236, "label": "ì" },
{ "$": "auto_text_key", "code": 237, "label": "í" },
{ "$": "auto_text_key", "code": 299, "label": "ī" },
{ "$": "auto_text_key", "code": 238, "label": "î" },
{ "$": "auto_text_key", "code": 239, "label": "ï" }
]
},
"n": {
"relevant": [
{ "$": "auto_text_key", "code": 328, "label": "ň" },
{ "$": "auto_text_key", "code": 241, "label": "ñ" }
]
"main": { "$": "case_selector",
"lower": { "code": 105, "label": "i" },
"upper": { "code": 304, "label": "İ" }
}
},
"o": {
"main": { "$": "auto_text_key", "code": 246, "label": "ö" },
"relevant": [
{ "$": "auto_text_key", "code": 333, "label": "ō" },
{ "$": "auto_text_key", "code": 248, "label": "ø" },
{ "$": "auto_text_key", "code": 243, "label": "ó" },
{ "$": "auto_text_key", "code": 245, "label": "õ" },
{ "$": "auto_text_key", "code": 242, "label": "ò" },
{ "$": "auto_text_key", "code": 339, "label": "œ" },
{ "$": "auto_text_key", "code": 244, "label": "ô" }
]
"main": { "$": "auto_text_key", "code": 246, "label": "ö" }
},
"s": {
"main": { "$": "auto_text_key", "code": 351, "label": "ş" },
"relevant": [
{ "$": "auto_text_key", "code": 347, "label": "ś" },
{ "$": "auto_text_key", "code": 223, "label": "ß" },
{ "$": "auto_text_key", "code": 353, "label": "š" }
]
"main": { "$": "auto_text_key", "code": 351, "label": "ş" }
},
"u": {
"main": { "$": "auto_text_key", "code": 252, "label": "ü" },
"relevant": [
{ "$": "auto_text_key", "code": 363, "label": "ū" },
{ "$": "auto_text_key", "code": 249, "label": "ù" },
{ "$": "auto_text_key", "code": 250, "label": "ú" },
{ "$": "auto_text_key", "code": 251, "label": "û" }
]
},
"y": {
"relevant": [
{ "$": "auto_text_key", "code": 253, "label": "ý" }
]
},
"z": {
"relevant": [
{ "$": "auto_text_key", "code": 382, "label": "ž" }
]
"main": { "$": "auto_text_key", "code": 252, "label": "ü" }
},
"~right": {
"main": { "code": 44, "label": "," },
@@ -120,10 +56,10 @@
"~right": {
"main": { "code": -255, "label": ".com" },
"relevant": [
{ "code": -255, "label": ".gov" },
{ "code": -255, "label": ".gov.tr" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".edu" },
{ "code": -255, "label": ".tr" },
{ "code": -255, "label": ".edu.tr" },
{ "code": -255, "label": ".com.tr" },
{ "code": -255, "label": ".net" }
]
}

View File

@@ -0,0 +1,77 @@
{
"type": "characters",
"name": "halmak",
"label": "Halmak",
"authors": [ "dessalines" ],
"direction": "ltr",
"arrangement": [
[
{ "$": "auto_text_key", "code": 119, "label": "w" },
{ "$": "auto_text_key", "code": 108, "label": "l" },
{ "$": "auto_text_key", "code": 114, "label": "r" },
{ "$": "auto_text_key", "code": 98, "label": "b" },
{ "$": "auto_text_key", "code": 122, "label": "z" },
{ "$": "case_selector",
"lower": { "code": 59, "label": ";", "popup": {
"relevant": [
{ "code": 58, "label": ":" }
]
} },
"upper": { "code": 58, "label": ":", "popup": {
"relevant": [
{ "code": 59, "label": ";" }
]
} }
},
{ "$": "auto_text_key", "code": 113, "label": "q" },
{ "$": "auto_text_key", "code": 117, "label": "u" },
{ "$": "auto_text_key", "code": 100, "label": "d" },
{ "$": "auto_text_key", "code": 106, "label": "j" }
],
[
{ "$": "auto_text_key", "code": 115, "label": "s" },
{ "$": "auto_text_key", "code": 104, "label": "h" },
{ "$": "auto_text_key", "code": 110, "label": "n" },
{ "$": "auto_text_key", "code": 116, "label": "t" },
{ "$": "case_selector",
"lower": { "code": 44, "label": ",", "popup": {
"relevant": [
{ "code": 40, "label": "(" }
]
} },
"upper": { "code": 40, "label": "(", "popup": {
"relevant": [
{ "code": 44, "label": "," }
]
} }
},
{ "$": "case_selector",
"lower": { "code": 46, "label": ".", "popup": {
"relevant": [
{ "code": 41, "label": ")" }
]
} },
"upper": { "code": 41, "label": ")", "popup": {
"relevant": [
{ "code": 46, "label": "." }
]
} }
},
{ "$": "auto_text_key", "code": 97, "label": "a" },
{ "$": "auto_text_key", "code": 101, "label": "e" },
{ "$": "auto_text_key", "code": 111, "label": "o" },
{ "$": "auto_text_key", "code": 105, "label": "i" }
],
[
{ "$": "auto_text_key", "code": 102, "label": "f" },
{ "$": "auto_text_key", "code": 109, "label": "m" },
{ "$": "auto_text_key", "code": 118, "label": "v" },
{ "$": "auto_text_key", "code": 99, "label": "c" },
{ "$": "auto_text_key", "code": 103, "label": "g" },
{ "$": "auto_text_key", "code": 112, "label": "p" },
{ "$": "auto_text_key", "code": 120, "label": "x" },
{ "$": "auto_text_key", "code": 107, "label": "k" },
{ "$": "auto_text_key", "code": 121, "label": "y" }
]
]
}

View File

@@ -28,27 +28,27 @@
{ "code": 1508, "label": "פ" }
],
[
{ "code": 1513, "label": "ף" },
{ "code": 1491, "label": "ך" },
{ "code": 1490, "label": "ל" },
{ "code": 1499, "label": "ח" },
{ "code": 1506, "label": "י" },
{ "code": 1497, "label": "ע" },
{ "code": 1495, "label": "כ" },
{ "code": 1500, "label": "ג" },
{ "code": 1498, "label": "ד" },
{ "code": 1507, "label": "ש" }
{ "code": 1513, "label": "ש" },
{ "code": 1491, "label": "ד" },
{ "code": 1490, "label": "ג" },
{ "code": 1499, "label": "כ" },
{ "code": 1506, "label": "ע" },
{ "code": 1497, "label": "י" },
{ "code": 1495, "label": "ח" },
{ "code": 1500, "label": "ל" },
{ "code": 1498, "label": "ך" },
{ "code": 1507, "label": "ף" }
],
[
{ "code": 1494, "label": "ץ" },
{ "code": 1505, "label": "ת" },
{ "code": 1489, "label": "צ" },
{ "code": 1492, "label": "מ" },
{ "code": 1494, "label": "ז" },
{ "code": 1505, "label": "ס" },
{ "code": 1489, "label": "ב" },
{ "code": 1492, "label": "ה" },
{ "code": 1504, "label": "נ" },
{ "code": 1502, "label": "ה" },
{ "code": 1510, "label": "ב" },
{ "code": 1514, "label": "ס" },
{ "code": 1509, "label": "ז" }
{ "code": 1502, "label": "מ" },
{ "code": 1510, "label": "צ" },
{ "code": 1514, "label": "ת" },
{ "code": 1509, "label": "ץ" }
]
]
}

View File

@@ -0,0 +1,354 @@
{
"type": "characters",
"name": "jis",
"label": "JIS",
"authors": [ "waelwindows" ],
"direction": "ltr",
"modifier": "jis",
"arrangement": [
[
{ "$": "kana_selector",
"hira": { "code": 12396, "label": "ぬ" },
"kata": { "$": "char_width_selector",
"full": { "code": 12492, "label": "ヌ" },
"half": { "code": 65415, "label": "ヌ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12405, "label": "ふ" },
"kata": { "$": "char_width_selector",
"full": { "code": 12501, "label": "フ" },
"half": { "code": 65420, "label": "フ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12354, "label": "あ" },
"kata": { "$": "char_width_selector",
"full": { "code": 12450, "label": "ア" },
"half": { "code": 65393, "label": "ア" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12358, "label": "う" },
"kata": { "$": "char_width_selector",
"full": { "code": 12454, "label": "ウ" },
"half": { "code": 65395, "label": "ウ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12360, "label": "え" },
"kata": { "$": "char_width_selector",
"full": { "code": 12456, "label": "エ" },
"half": { "code": 65396, "label": "エ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12362, "label": "お" },
"kata": { "$": "char_width_selector",
"full": { "code": 12458, "label": "オ" },
"half": { "code": 65397, "label": "オ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12420, "label": "や" },
"kata": { "$": "char_width_selector",
"full": { "code": 12516, "label": "ヤ" },
"half": { "code": 65428, "label": "ヤ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12422, "label": "ゆ" },
"kata": { "$": "char_width_selector",
"full": { "code": 12518, "label": "ユ" },
"half": { "code": 65429, "label": "ユ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12424, "label": "よ" },
"kata": { "$": "char_width_selector",
"full": { "code": 12520, "label": "ヨ" },
"half": { "code": 65430, "label": "ヨ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12431, "label": "わ" },
"kata": { "$": "char_width_selector",
"full": { "code": 12527, "label": "ワ" },
"half": { "code": 65436, "label": "ワ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12411, "label": "ほ" },
"kata": { "$": "char_width_selector",
"full": { "code": 12507, "label": "ホ" },
"half": { "code": 65422, "label": "ホ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12408, "label": "へ" },
"kata": { "$": "char_width_selector",
"full": { "code": 12504, "label": "ヘ" },
"half": { "code": 65421, "label": "ヘ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12540, "label": "ー" },
"kata": { "$": "char_width_selector",
"full": { "code": 12540, "label": "ー" },
"half": { "code": 65392, "label": "ー" }
}
}
],
[
{ "$": "kana_selector",
"hira": { "code": 12383, "label": "た" },
"kata": { "$": "char_width_selector",
"full": { "code": 12479, "label": "タ" },
"half": { "code": 65408, "label": "タ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12390, "label": "て" },
"kata": { "$": "char_width_selector",
"full": { "code": 12486, "label": "テ" },
"half": { "code": 65411, "label": "テ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12356, "label": "い" },
"kata": { "$": "char_width_selector",
"full": { "code": 12452, "label": "イ" },
"half": { "code": 65394, "label": "イ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12377, "label": "す" },
"kata": { "$": "char_width_selector",
"full": { "code": 12473, "label": "ス" },
"half": { "code": 65405, "label": "ス" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12363, "label": "か" },
"kata": { "$": "char_width_selector",
"full": { "code": 12459, "label": "カ" },
"half": { "code": 65398, "label": "カ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12435, "label": "ん" },
"kata": { "$": "char_width_selector",
"full": { "code": 12531, "label": "ン" },
"half": { "code": 65437, "label": "ン" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12394, "label": "な" },
"kata": { "$": "char_width_selector",
"full": { "code": 12490, "label": "ナ" },
"half": { "code": 65413, "label": "ナ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12395, "label": "に" },
"kata": { "$": "char_width_selector",
"full": { "code": 12491, "label": "ニ" },
"half": { "code": 65414, "label": "ニ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12425, "label": "ら" },
"kata": { "$": "char_width_selector",
"full": { "code": 12521, "label": "ラ" },
"half": { "code": 65431, "label": "ラ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12379, "label": "せ" },
"kata": { "$": "char_width_selector",
"full": { "code": 12475, "label": "セ" },
"half": { "code": 65406, "label": "セ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12441, "label": "゛" },
"kata": { "$": "char_width_selector",
"full": { "code": 12441, "label": "゛" },
"half": { "code": 65438, "label": "゙" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12442, "label": "゜" },
"kata": { "$": "char_width_selector",
"full": { "code": 12442, "label": "゜" },
"half": { "code": 65439, "label": "゚" }
}
}
],
[
{ "$": "kana_selector",
"hira": { "code": 12385, "label": "ち" },
"kata": { "$": "char_width_selector",
"full": { "code": 12481, "label": "チ" },
"half": { "code": 65409, "label": "チ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12392, "label": "と" },
"kata": { "$": "char_width_selector",
"full": { "code": 12488, "label": "ト" },
"half": { "code": 65412, "label": "ト" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12375, "label": "し" },
"kata": { "$": "char_width_selector",
"full": { "code": 12471, "label": "シ" },
"half": { "code": 65410, "label": "シ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12399, "label": "は" },
"kata": { "$": "char_width_selector",
"full": { "code": 12495, "label": "ハ" },
"half": { "code": 65418, "label": "ハ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12365, "label": "き" },
"kata": { "$": "char_width_selector",
"full": { "code": 12461, "label": "キ" },
"half": { "code": 65399, "label": "キ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12367, "label": "く" },
"kata": { "$": "char_width_selector",
"full": { "code": 12463, "label": "ク" },
"half": { "code": 65400, "label": "ク" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12414, "label": "ま" },
"kata": { "$": "char_width_selector",
"full": { "code": 12510, "label": "マ" },
"half": { "code": 65423, "label": "マ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12398, "label": "の" },
"kata": { "$": "char_width_selector",
"full": { "code": 12494, "label": "" },
"half": { "code": 65417, "label": "ノ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12426, "label": "り" },
"kata": { "$": "char_width_selector",
"full": { "code": 12522, "label": "リ" },
"half": { "code": 65432, "label": "リ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12428, "label": "れ" },
"kata": { "$": "char_width_selector",
"full": { "code": 12524, "label": "レ" },
"half": { "code": 65434, "label": "レ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12369, "label": "け" },
"kata": { "$": "char_width_selector",
"full": { "code": 12465, "label": "ケ" },
"half": { "code": 65401, "label": "ケ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12416, "label": "む" },
"kata": { "$": "char_width_selector",
"full": { "code": 12512, "label": "ム" },
"half": { "code": 65425, "label": "ム" }
}
}
],
[
{ "$": "kana_selector",
"hira": { "code": 12388, "label": "つ" },
"kata": { "$": "char_width_selector",
"full": { "code": 12484, "label": "ツ" },
"half": { "code": 65410, "label": "ツ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12373, "label": "さ" },
"kata": { "$": "char_width_selector",
"full": { "code": 12469, "label": "サ" },
"half": { "code": 65403, "label": "サ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12381, "label": "そ" },
"kata": { "$": "char_width_selector",
"full": { "code": 12477, "label": "ソ" },
"half": { "code": 65407, "label": "ソ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12402, "label": "ひ" },
"kata": { "$": "char_width_selector",
"full": { "code": 12498, "label": "ヒ" },
"half": { "code": 65419, "label": "ヒ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12371, "label": "こ" },
"kata": { "$": "char_width_selector",
"full": { "code": 12467, "label": "コ" },
"half": { "code": 65402, "label": "コ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12415, "label": "み" },
"kata": { "$": "char_width_selector",
"full": { "code": 12511, "label": "ミ" },
"half": { "code": 65424, "label": "ミ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12418, "label": "も" },
"kata": { "$": "char_width_selector",
"full": { "code": 12514, "label": "モ" },
"half": { "code": 65427, "label": "モ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12397, "label": "ね" },
"kata": { "$": "char_width_selector",
"full": { "code": 12493, "label": "ネ" },
"half": { "code": 65416, "label": "ネ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12427, "label": "る" },
"kata": { "$": "char_width_selector",
"full": { "code": 12523, "label": "ル" },
"half": { "code": 65433, "label": "ル" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12417, "label": "め" },
"kata": { "$": "char_width_selector",
"full": { "code": 12513, "label": "メ" },
"half": { "code": 65426, "label": "メ" }
}
},
{ "$": "kana_selector",
"hira": { "code": 12429, "label": "ろ" },
"kata": { "$": "char_width_selector",
"full": { "code": 12525, "label": "ロ" },
"half": { "code": 65435, "label": "ロ" }
}
}
]
]
}

View File

@@ -0,0 +1,62 @@
{
"type": "characters",
"name": "korean",
"label": "South Korean standard",
"authors": [ "patrickgold", "Hayleia" ],
"direction": "ltr",
"arrangement": [
[
{ "$": "case_selector",
"lower": { "code": 12610, "label": "ㅂ" },
"upper": { "code": 12611, "label": "ㅃ" }
},
{ "$": "case_selector",
"lower": { "code": 12616, "label": "ㅈ" },
"upper": { "code": 12617, "label": "ㅉ" }
},
{ "$": "case_selector",
"lower": { "code": 12599, "label": "ㄷ" },
"upper": { "code": 12600, "label": "ㄸ" }
},
{ "$": "case_selector",
"lower": { "code": 12593, "label": "ㄱ" },
"upper": { "code": 12594, "label": "ㄲ" }
},
{ "$": "case_selector",
"lower": { "code": 12613, "label": "ㅅ" },
"upper": { "code": 12614, "label": "ㅆ" }
},
{ "$": "auto_text_key", "code": 12635, "label": "ㅛ"},
{ "$": "auto_text_key", "code": 12629, "label": "ㅕ"},
{ "$": "auto_text_key", "code": 12625, "label": "ㅑ"},
{ "$": "case_selector",
"lower": { "code": 12624, "label": "ㅐ" },
"upper": { "code": 12626, "label": "ㅒ" }
},
{ "$": "case_selector",
"lower": { "code": 12628, "label": "ㅔ" },
"upper": { "code": 12630, "label": "ㅖ" }
}
],
[
{ "$": "auto_text_key", "code": 12609, "label": "ㅁ"},
{ "$": "auto_text_key", "code": 12596, "label": "ㄴ"},
{ "$": "auto_text_key", "code": 12615, "label": "ㅇ"},
{ "$": "auto_text_key", "code": 12601, "label": "ㄹ"},
{ "$": "auto_text_key", "code": 12622, "label": "ㅎ"},
{ "$": "auto_text_key", "code": 12631, "label": "ㅗ"},
{ "$": "auto_text_key", "code": 12627, "label": "ㅓ"},
{ "$": "auto_text_key", "code": 12623, "label": "ㅏ"},
{ "$": "auto_text_key", "code": 12643, "label": "ㅣ"}
],
[
{ "$": "auto_text_key", "code": 12619, "label": "ㅋ"},
{ "$": "auto_text_key", "code": 12620, "label": "ㅌ"},
{ "$": "auto_text_key", "code": 12618, "label": "ㅊ"},
{ "$": "auto_text_key", "code": 12621, "label": "ㅍ"},
{ "$": "auto_text_key", "code": 12640, "label": "ㅠ"},
{ "$": "auto_text_key", "code": 12636, "label": "ㅜ"},
{ "$": "auto_text_key", "code": 12641, "label": "ㅡ"}
]
]
}

View File

@@ -1,7 +1,7 @@
{
"type": "characters",
"name": "kurdish",
"label": "کوردی",
"label": "کوردی (قوەرتی نوێ)",
"authors": [ "GoRaN" ],
"direction": "rtl",
"modifier": "kurdish",
@@ -13,34 +13,46 @@
{ "code": 1608, "label": "و", "popup": {
"main": { "code": -255, "label": "وو" }
} },
{ "code": 1749, "label": "" },
{ "code": 1585, "label": "ر" },
{ "code": 1749, "label": "", "popup": {
"main": { "code": 1577, "label": "ة" }
} },
{ "code": 1585, "label": "ر", "popup": {
"main": { "code": 1685, "label": "ڕ" }
} },
{ "code": 1578, "label": "ت", "popup": {
"main": { "code": 1591, "label": "ط" }
} },
{ "code": 1740, "label": "ی" },
{ "code": 1574, "label": "ﺋ"},
{ "code": 1740, "label": "ی", "popup": {
"main": { "code": 1742, "label": "ێ" }
} },
{ "code": 1574, "label": "ﺋ", "popup": {
"main": { "code": 1569, "label": "ء" }
} },
{ "code": 1593, "label": "ع", "popup": {
"main": { "code": 1594, "label": "غ" }
} },
{ "code": 1734, "label": "ۆ" },
{ "code": 1662, "label": "پ", "popup": {
"main": { "code": 1579, "label": "ث" }
} }
],
[
{ "code": 1575, "label": "ا" },
{"code": 1575, "label": "ا"},
{ "code": 1587, "label": "س" },
{ "code": 1588, "label": "ش" },
{ "code": 1583, "label": "د" },
{ "code": 1601, "label": "ف" },
{ "code": 1583, "label": "د", "popup": {
"main": {"code": 1584, "label": "ذ" }
} },
{ "code": 1601, "label": "ف" , "popup": {
"main": {"code": 1700, "label": "ڤ" }
} },
{ "code": 1607, "label": "ھ" },
{ "code": 1688, "label": "ژ" },
{ "code": 1604, "label": "ل" },
{ "code": 1688, "label": "ژ", "popup": {
"main": { "code": 1600, "label": "" }
} },
{ "code": 1604, "label": "ل", "popup": {
"main": { "code": 1717, "label": "ڵ" }
} },
{ "code": 1705, "label": "ک" },
{ "code": 1711, "label": "گ" }
],

View File

@@ -13,7 +13,7 @@
{ "$": "auto_text_key", "code": 116, "label": "t" },
{ "$": "auto_text_key", "code": 121, "label": "y" },
{ "$": "auto_text_key", "code": 117, "label": "u" },
{ "$": "auto_text_key", "code": 305, "label": "ı" },
{ "$": "auto_text_key", "code": 105, "label": "i" },
{ "$": "auto_text_key", "code": 111, "label": "o" },
{ "$": "auto_text_key", "code": 112, "label": "p" },
{ "$": "auto_text_key", "code": 251, "label": "û" }

View File

@@ -1,7 +1,7 @@
{
"type": "characters",
"name": "kurdish_standard",
"label": "کوردی - ستاندارد",
"label": "کوردی (ق‌ڤ‌ف‌غ)",
"authors": [ "GoRaN" ],
"direction": "rtl",
"modifier": "kurdish",
@@ -10,16 +10,14 @@
{ "code": 1602, "label": "ق", "popup": {
"main": { "code": 1647, "label": "ٯ" }
} },
{ "code": 1700, "label": "ڤ", "popup": {
"main": { "code": 1701, "label": "ڥ" }
} },
{ "code": 1601, "label": "ف", "popup": {
"main": { "code": 1698, "label": "ڢ" }
} },
{ "code": 1700, "label": "ڤ" },
{ "code": 1601, "label": "ف" },
{ "code": 1594, "label": "غ" },
{ "code": 1593, "label": "ع"},
{ "code": 1607, "label": "ھ" },
{ "code": 1749, "label": "" },
{ "code": 1749, "label": "", "popup": {
"main": { "code": 1577, "label": "ة" }
} },
{ "code": 1578, "label": "ت", "popup": {
"main": { "code": 1591, "label": "ط" }
@@ -46,7 +44,9 @@
} },
{ "code": 1585, "label": "ر" },
{ "code": 1685, "label": "ڕ" },
{ "code": 1583, "label": "د" },
{ "code": 1583, "label": "د", "popup": {
"main": {"code": 1584, "label": "ذ" }
} },
{ "code": -255, "label": "وو" },
{ "code": 1608, "label": "و" },
{ "code": 1734, "label": "ۆ" },
@@ -55,8 +55,10 @@
],
[
{ "code": 1600, "label": "kashida", "variation": "normal" },
{ "code": 1574, "label": "ﺋ"},
{ "code": 1574, "label": "ﺋ", "popup": {
"main": { "code": 1569, "label": "ء" }
} },
{ "code": 1662, "label": "پ", "popup": {
"main": { "code": 1579, "label": "ث" }

View File

@@ -0,0 +1,29 @@
{
"type": "characters/mod",
"name": "jis",
"label": "JIS",
"authors": [ "waelwindows" ],
"direction": "ltr",
"arrangement": [
[
{ "code": 0, "type": "placeholder" },
{ "code": -5, "label": "delete", "type": "enter_editing" }
],
[
{ "code": -202, "label": "view_symbols", "type": "system_gui" },
{ "$": "char_width_selector",
"full": { "code": 12289, "label": "、", "groupId": 1 },
"half": { "code": 65380, "label": "、", "groupId": 1 }
},
{ "code": -210, "label": "language_switch", "type": "system_gui" },
{ "code": -213, "label": "switch_to_media_context", "type": "system_gui" },
{ "code": 12288, "label": "空白" },
{ "code": -9710, "label": "かな", "groupId": 97, "type": "system_gui" },
{ "$": "char_width_selector",
"full": { "code": 12290, "label": "。", "groupId": 2 },
"half": { "code": 65377, "label": "。", "groupId": 2 }
},
{ "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" }
]
]
}

View File

@@ -6,14 +6,17 @@
"direction": "rtl",
"arrangement": [
[
{ "code": 1600, "label": "kashida", "popup":
{ "main": { "code": 8204, "label": "half_space" }
} },
{ "code": 0, "type": "placeholder" },
{ "code": -5, "label": "delete", "type": "enter_editing" }
],
[
{ "code": -202, "label": "view_symbols", "type": "system_gui" },
{ "$": "variation_selector",
"default": { "code": 1567, "label": "؟", "groupId": 1 },
"password": { "code": 1548, "label": "،", "groupId": 1 },
"default": { "code": 1548, "label": "،", "groupId": 1 },
"password": { "code": 35, "label": "#", "groupId": 1 },
"email": { "code": 64, "label": "@", "groupId": 1 },
"uri": { "code": 47, "label": "/", "groupId": 1 }
},

View File

@@ -0,0 +1,53 @@
{
"type": "characters/mod",
"name": "neo2",
"label": "Neo2",
"authors": [ "ostrya" ],
"direction": "ltr",
"arrangement": [
[
{ "code": -1, "label": "shift", "type": "modifier" },
{ "code": 0, "type": "placeholder" },
{ "code": -5, "label": "delete", "type": "enter_editing" }
],
[
{ "code": -202, "label": "view_symbols", "type": "system_gui" },
{ "code": -210, "label": "language_switch", "type": "system_gui" },
{ "code": -213, "label": "switch_to_media_context", "type": "system_gui" },
{ "code": 32, "label": "space" },
{ "$": "variation_selector",
"default": { "code": 44, "label": ",", "groupId": 1,
"popup": {
"main": { "code": 34, "label": "\"" },
"relevant": [
{ "code": 8211, "label": "" }
]
} },
"email": { "code": 64, "label": "@", "groupId": 1,
"popup": {
"relevant": [
{ "code": 44, "label": "," }
]
} },
"uri": { "code": 47, "label": "/", "groupId": 1,
"popup": {
"relevant": [
{ "code": 44, "label": "," }
]
} }
},
{ "$": "variation_selector",
"default": { "code": 46, "label": ".", "groupId": 2,
"popup": {
"relevant": [
{ "code": 183, "label": "·" },
{ "code": 39, "label": "'" }
]
} },
"email": { "code": 46, "label": ".", "groupId": 2 },
"uri": { "code": 46, "label": ".", "groupId": 2 }
},
{ "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" }
]
]
}

View File

@@ -0,0 +1,41 @@
{
"type": "characters",
"name": "nalmy",
"label": "NALMY",
"authors": [ "jeremiah-mille", "jasmcole" ],
"direction": "ltr",
"arrangement": [
[
{ "$": "auto_text_key", "code": 122, "label": "z" },
{ "$": "auto_text_key", "code": 118, "label": "v" },
{ "$": "auto_text_key", "code": 100, "label": "d" },
{ "$": "auto_text_key", "code": 110, "label": "n" },
{ "$": "auto_text_key", "code": 97, "label": "a" },
{ "$": "auto_text_key", "code": 108, "label": "l" },
{ "$": "auto_text_key", "code": 109, "label": "m" },
{ "$": "auto_text_key", "code": 121, "label": "y" },
{ "$": "auto_text_key", "code": 120, "label": "x" },
{ "$": "auto_text_key", "code": 106, "label": "j" }
],
[
{ "$": "auto_text_key", "code": 107, "label": "k" },
{ "$": "auto_text_key", "code": 103, "label": "g" },
{ "$": "auto_text_key", "code": 105, "label": "i" },
{ "$": "auto_text_key", "code": 101, "label": "e" },
{ "$": "auto_text_key", "code": 114, "label": "r" },
{ "$": "auto_text_key", "code": 111, "label": "o" },
{ "$": "auto_text_key", "code": 112, "label": "p" },
{ "$": "auto_text_key", "code": 98, "label": "b" },
{ "$": "auto_text_key", "code": 113, "label": "q" }
],
[
{ "$": "auto_text_key", "code": 119, "label": "w" },
{ "$": "auto_text_key", "code": 104, "label": "h" },
{ "$": "auto_text_key", "code": 116, "label": "t" },
{ "$": "auto_text_key", "code": 115, "label": "s" },
{ "$": "auto_text_key", "code": 99, "label": "c" },
{ "$": "auto_text_key", "code": 117, "label": "u" },
{ "$": "auto_text_key", "code": 102, "label": "f" }
]
]
}

View File

@@ -0,0 +1,61 @@
{
"type": "characters",
"name": "neo2",
"label": "Neo2",
"authors": [ "ostrya" ],
"direction": "ltr",
"modifier": "neo2",
"arrangement": [
[
{ "$": "auto_text_key", "code": 120, "label": "x" },
{ "$": "auto_text_key", "code": 118, "label": "v" },
{ "$": "auto_text_key", "code": 108, "label": "l" },
{ "$": "auto_text_key", "code": 99, "label": "c" },
{ "$": "auto_text_key", "code": 119, "label": "w" },
{ "$": "auto_text_key", "code": 107, "label": "k" },
{ "$": "auto_text_key", "code": 104, "label": "h" },
{ "$": "auto_text_key", "code": 103, "label": "g" },
{ "$": "auto_text_key", "code": 102, "label": "f" },
{ "$": "auto_text_key", "code": 113, "label": "q" },
{ "$": "case_selector",
"lower": {
"code": 223, "label": "ß", "popup": {
"relevant": [
{ "code": 180, "label": "´" }
]
}
},
"upper": {
"code": 7838, "label": "ẞ", "popup": {
"relevant": [
{ "code": 180, "label": "´" }
]
}
}
}
],
[
{ "$": "auto_text_key", "code": 117, "label": "u" },
{ "$": "auto_text_key", "code": 105, "label": "i" },
{ "$": "auto_text_key", "code": 97, "label": "a" },
{ "$": "auto_text_key", "code": 101, "label": "e" },
{ "$": "auto_text_key", "code": 111, "label": "o" },
{ "$": "auto_text_key", "code": 115, "label": "s" },
{ "$": "auto_text_key", "code": 110, "label": "n" },
{ "$": "auto_text_key", "code": 114, "label": "r" },
{ "$": "auto_text_key", "code": 116, "label": "t" },
{ "$": "auto_text_key", "code": 100, "label": "d" },
{ "$": "auto_text_key", "code": 121, "label": "y" }
],
[
{ "$": "auto_text_key", "code": 252, "label": "ü" },
{ "$": "auto_text_key", "code": 246, "label": "ö" },
{ "$": "auto_text_key", "code": 228, "label": "ä" },
{ "$": "auto_text_key", "code": 112, "label": "p" },
{ "$": "auto_text_key", "code": 122, "label": "z" },
{ "$": "auto_text_key", "code": 98, "label": "b" },
{ "$": "auto_text_key", "code": 109, "label": "m" },
{ "$": "auto_text_key", "code": 106, "label": "j" }
]
]
}

View File

@@ -0,0 +1,41 @@
{
"type": "characters",
"name": "sangaline",
"label": "Sangaline",
"authors": [ "jeremiah-miller", "sangaline" ],
"direction": "ltr",
"arrangement": [
[
{ "$": "auto_text_key", "code": 100, "label": "d" },
{ "$": "auto_text_key", "code": 103, "label": "g" },
{ "$": "auto_text_key", "code": 104, "label": "h" },
{ "$": "auto_text_key", "code": 112, "label": "p" },
{ "$": "auto_text_key", "code": 97, "label": "a" },
{ "$": "auto_text_key", "code": 115, "label": "s" },
{ "$": "auto_text_key", "code": 106, "label": "j" },
{ "$": "auto_text_key", "code": 114, "label": "r" },
{ "$": "auto_text_key", "code": 107, "label": "k" },
{ "$": "auto_text_key", "code": 110, "label": "n" }
],
[
{ "$": "auto_text_key", "code": 105, "label": "i" },
{ "$": "auto_text_key", "code": 113, "label": "q" },
{ "$": "auto_text_key", "code": 118, "label": "v" },
{ "$": "auto_text_key", "code": 117, "label": "u" },
{ "$": "auto_text_key", "code": 119, "label": "w" },
{ "$": "auto_text_key", "code": 99, "label": "c" },
{ "$": "auto_text_key", "code": 108, "label": "l" },
{ "$": "auto_text_key", "code": 120, "label": "x" },
{ "$": "auto_text_key", "code": 109, "label": "m" }
],
[
{ "$": "auto_text_key", "code": 116, "label": "t" },
{ "$": "auto_text_key", "code": 121, "label": "y" },
{ "$": "auto_text_key", "code": 98, "label": "b" },
{ "$": "auto_text_key", "code": 101, "label": "e" },
{ "$": "auto_text_key", "code": 122, "label": "z" },
{ "$": "auto_text_key", "code": 102, "label": "f" },
{ "$": "auto_text_key", "code": 111, "label": "o" }
]
]
}

View File

@@ -9,7 +9,10 @@
{ "$": "auto_text_key", "code": 102, "label": "f" },
{ "$": "auto_text_key", "code": 103, "label": "g" },
{ "$": "auto_text_key", "code": 287, "label": "ğ" },
{ "$": "auto_text_key", "code": 305, "label": "ı" },
{ "$": "case_selector",
"lower": { "code": 305, "label": "ı" },
"upper": { "code": 73, "label": "I" }
},
{ "$": "auto_text_key", "code": 111, "label": "o" },
{ "$": "auto_text_key", "code": 100, "label": "d" },
{ "$": "auto_text_key", "code": 114, "label": "r" },
@@ -21,7 +24,10 @@
],
[
{ "$": "auto_text_key", "code": 117, "label": "u" },
{ "$": "auto_text_key", "code": 105, "label": "i" },
{ "$": "case_selector",
"lower": { "code": 105, "label": "i" },
"upper": { "code": 304, "label": "İ" }
},
{ "$": "auto_text_key", "code": 101, "label": "e" },
{ "$": "auto_text_key", "code": 97, "label": "a" },
{ "$": "auto_text_key", "code": 252, "label": "ü" },

View File

@@ -13,7 +13,10 @@
{ "$": "auto_text_key", "code": 116, "label": "t" },
{ "$": "auto_text_key", "code": 121, "label": "y" },
{ "$": "auto_text_key", "code": 117, "label": "u" },
{ "$": "auto_text_key", "code": 305, "label": "ı" },
{ "$": "case_selector",
"lower": { "code": 305, "label": "ı" },
"upper": { "code": 73, "label": "I" }
},
{ "$": "auto_text_key", "code": 111, "label": "o" },
{ "$": "auto_text_key", "code": 112, "label": "p" },
{ "$": "auto_text_key", "code": 287, "label": "ğ" },
@@ -30,7 +33,10 @@
{ "$": "auto_text_key", "code": 107, "label": "k" },
{ "$": "auto_text_key", "code": 108, "label": "l" },
{ "$": "auto_text_key", "code": 351, "label": "ş" },
{ "$": "auto_text_key", "code": 105, "label": "i" }
{ "$": "case_selector",
"lower": { "code": 105, "label": "i" },
"upper": { "code": 304, "label": "İ" }
}
],
[
{ "$": "auto_text_key", "code": 122, "label": "z" },

View File

@@ -0,0 +1,55 @@
{
"type": "numeric_advanced",
"name": "western_arabic_pc",
"label": "Western Arabic (PC)",
"authors": [ "patrickgold" ],
"direction": "ltr",
"arrangement": [
[
{ "code": 43, "label": "+", "popup": {
"relevant": [
{ "code": 45, "label": "-" },
{ "code": 42, "label": "*" },
{ "code": 47, "label": "/" }
]
} },
{ "code": 55, "label": "7", "type": "numeric" },
{ "code": 56, "label": "8", "type": "numeric" },
{ "code": 57, "label": "9", "type": "numeric" },
{ "code": 37, "label": "%" }
],
[
{ "code": 40, "label": "(", "popup": {
"relevant": [
{ "code": 91, "label": "[" },
{ "code": 123, "label": "{" }
]
} },
{ "code": 52, "label": "4", "type": "numeric" },
{ "code": 53, "label": "5", "type": "numeric" },
{ "code": 54, "label": "6", "type": "numeric" },
{ "code": 32, "label": "space" }
],
[
{ "code": 41, "label": ")", "popup": {
"relevant": [
{ "code": 93, "label": "]" },
{ "code": 125, "label": "}" }
]
} },
{ "code": 49, "label": "1", "type": "numeric" },
{ "code": 50, "label": "2", "type": "numeric" },
{ "code": 51, "label": "3", "type": "numeric" },
{ "code": -5, "label": "delete", "type": "enter_editing" }
],
[
{ "code": -201, "label": "view_characters", "type": "system_gui" },
{ "code": 44, "label": "," },
{ "code": -202, "label": "view_symbols", "type": "system_gui" },
{ "code": 48, "label": "0", "type": "numeric" },
{ "code": 61, "label": "=" },
{ "code": 46, "label": "." },
{ "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" }
]
]
}

View File

@@ -0,0 +1,91 @@
{
"type": "numeric_row",
"name": "bengali",
"label": "Bengali",
"authors": [ "yashpalgoyal1304" ],
"direction": "ltr",
"arrangement": [
[
{ "code": 2535, "label": "১", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "⅙" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
]
} },
{ "code": 2536, "label": "২", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "⅔" },
{ "code": 178, "label": "²" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 2537, "label": "৩", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
]
} },
{ "code": 2538, "label": "", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "⅘" },
{ "code": 8308, "label": "⁴" }
]
} },
{ "code": 2539, "label": "৫", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
} },
{ "code": 2540, "label": "৬", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8310, "label": "⁶" }
]
} },
{ "code": 2541, "label": "", "type": "numeric", "popup": {
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 2542, "label": "৮", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 2543, "label": "৯", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 2534, "label": "", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "⁰" }
]
} }
]
]
}

View File

@@ -0,0 +1,108 @@
{
"type": "numeric_row",
"name": "cjk",
"label": "CJK",
"authors": [ "waelwindows" ],
"direction": "ltr",
"arrangement": [
[
{ "code": 19968, "label": "一", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 22769, "label": "壱" },
{ "code": 22777, "label": "壹" },
{ "code": 24332, "label": "弌" },
{ "code": 65297, "label": "" }
]
} },
{ "code": 20108, "label": "二", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 24336, "label": "弐" },
{ "code": 36019, "label": "貳" },
{ "code": 36014, "label": "貮" },
{ "code": 65298, "label": "" }
]
} },
{ "code": 19977, "label": "三", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 21442, "label": "参" },
{ "code": 21443, "label": "參" },
{ "code": 24334, "label": "弎" },
{ "code": 65299, "label": "" }
]
} },
{ "code": 22235, "label": "四", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 32902, "label": "肆" },
{ "code": 18825, "label": "䦉" },
{ "code": 20118, "label": "亖" },
{ "code": 65300, "label": "" }
]
} },
{ "code": 20116, "label": "五", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 20237, "label": "伍" },
{ "code": 65301, "label": "" }
]
} },
{ "code": 20845, "label": "六", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 38520, "label": "陸" },
{ "code": 65302, "label": "" }
]
} },
{ "code": 19971, "label": "七", "type": "numeric", "popup": {
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 28422, "label": "漆" },
{ "code": 26578, "label": "柒" },
{ "code": 65303, "label": "" }
]
} },
{ "code": 20843, "label": "八", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 25420, "label": "捌" },
{ "code": 65304, "label": "" }
]
} },
{ "code": 20061, "label": "九", "type": "numeric", "popup": {
"main": {"code": 57, "label": "9" },
"relevant": [
{ "code": 29590, "label": "玖" },
{ "code": 65305, "label": "" }
]
} },
{ "code": 38646, "label": "零", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 12295, "label": "" },
{ "code": 65296, "label": "" }
]
} },
{ "code": 21313, "label": "十", "type": "numeric", "popup": {
"main": { "code": 25342, "label": "拾" },
"relevant": [
{ "code": 20160, "label": "什" }
]
} },
{ "code": 30334, "label": "百", "type": "numeric", "popup": {
"main": { "code": 20336, "label": "佰" },
"relevant": [
{ "code": 38476, "label": "陌" }
]
} },
{ "code": 21315, "label": "千", "type": "numeric", "popup": {
"main": { "code": 20191, "label": "仟" },
"relevant": [
{ "code": 38433, "label": "阡" }
]
} }
]
]
}

View File

@@ -0,0 +1,91 @@
{
"type": "numeric_row",
"name": "devanagari",
"label": "Devanagari",
"authors": [ "yashpalgoyal1304" ],
"direction": "ltr",
"arrangement": [
[
{ "code": 2407, "label": "१", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "⅙" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
]
} },
{ "code": 2408, "label": "२", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "⅔" },
{ "code": 178, "label": "²" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 2409, "label": "३", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
]
} },
{ "code": 2410, "label": "४", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "⅘" },
{ "code": 8308, "label": "⁴" }
]
} },
{ "code": 2411, "label": "५", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
} },
{ "code": 2412, "label": "६", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8310, "label": "⁶" }
]
} },
{ "code": 2413, "label": "७", "type": "numeric", "popup": {
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 2414, "label": "८", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 2415, "label": "९", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 2406, "label": "", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "⁰" }
]
} }
]
]
}

View File

@@ -0,0 +1,91 @@
{
"type": "numeric_row",
"name": "gujarati",
"label": "Gujarati",
"authors": [ "yashpalgoyal1304" ],
"direction": "ltr",
"arrangement": [
[
{ "code": 2791, "label": "૧", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "⅙" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
]
} },
{ "code": 2792, "label": "૨", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "⅔" },
{ "code": 178, "label": "²" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 2793, "label": "૩", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
]
} },
{ "code": 2794, "label": "૪", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "⅘" },
{ "code": 8308, "label": "⁴" }
]
} },
{ "code": 2795, "label": "૫", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
} },
{ "code": 2796, "label": "૬", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8310, "label": "⁶" }
]
} },
{ "code": 2797, "label": "૭", "type": "numeric", "popup": {
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 2798, "label": "૮", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 2799, "label": "૯", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 2790, "label": "", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "⁰" }
]
} }
]
]
}

View File

@@ -0,0 +1,91 @@
{
"type": "numeric_row",
"name": "gurmukhi",
"label": "Gurmukhi",
"authors": [ "yashpalgoyal1304" ],
"direction": "ltr",
"arrangement": [
[
{ "code": 2663, "label": "", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "⅙" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
]
} },
{ "code": 2664, "label": "੨", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "⅔" },
{ "code": 178, "label": "²" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 2665, "label": "੩", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
]
} },
{ "code": 2666, "label": "", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "⅘" },
{ "code": 8308, "label": "⁴" }
]
} },
{ "code": 2667, "label": "੫", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
} },
{ "code": 2668, "label": "੬", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8310, "label": "⁶" }
]
} },
{ "code": 2669, "label": "੭", "type": "numeric", "popup": {
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 2670, "label": "੮", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 2671, "label": "੯", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 2662, "label": "", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "⁰" }
]
} }
]
]
}

View File

@@ -0,0 +1,91 @@
{
"type": "numeric_row",
"name": "kannada",
"label": "Kannada",
"authors": [ "yashpalgoyal1304" ],
"direction": "ltr",
"arrangement": [
[
{ "code": 3303, "label": "೧", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "⅙" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
]
} },
{ "code": 3304, "label": "೨", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "⅔" },
{ "code": 178, "label": "²" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 3305, "label": "೩", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
]
} },
{ "code": 3306, "label": "೪", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "⅘" },
{ "code": 8308, "label": "⁴" }
]
} },
{ "code": 3307, "label": "೫", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
} },
{ "code": 3308, "label": "೬", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8310, "label": "⁶" }
]
} },
{ "code": 3309, "label": "೭", "type": "numeric", "popup": {
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 3310, "label": "೮", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 3311, "label": "೯", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 3302, "label": "", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "⁰" }
]
} }
]
]
}

View File

@@ -0,0 +1,91 @@
{
"type": "numeric_row",
"name": "malayalam",
"label": "Malayalam",
"authors": [ "yashpalgoyal1304" ],
"direction": "ltr",
"arrangement": [
[
{ "code": 3431, "label": "൧", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "⅙" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
]
} },
{ "code": 3432, "label": "൨", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "⅔" },
{ "code": 178, "label": "²" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 3433, "label": "൩", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
]
} },
{ "code": 3434, "label": "൪", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "⅘" },
{ "code": 8308, "label": "⁴" }
]
} },
{ "code": 3435, "label": "൫", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
} },
{ "code": 3436, "label": "൬", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8310, "label": "⁶" }
]
} },
{ "code": 3437, "label": "", "type": "numeric", "popup": {
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 3438, "label": "൮", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 3439, "label": "൯", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 3430, "label": "", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "⁰" }
]
} }
]
]
}

View File

@@ -0,0 +1,80 @@
{
"type": "numeric_row",
"name": "neo2",
"label": "Neo2",
"authors": [ "ostrya" ],
"direction": "ltr",
"arrangement": [
[
{ "code": 49, "label": "1", "type": "numeric", "popup": {
"relevant": [
{ "code": 176, "label": "°" },
{ "code": 185, "label": "¹" }
]
} },
{ "code": 50, "label": "2", "type": "numeric", "popup": {
"relevant": [
{ "code": 167, "label": "§" },
{ "code": 178, "label": "²" }
]
} },
{ "code": 51, "label": "3", "type": "numeric", "popup": {
"relevant": [
{ "code": 8467, "label": "" },
{ "code": 179, "label": "³" }
]
} },
{ "code": 52, "label": "4", "type": "numeric", "popup": {
"relevant": [
{ "code": 187, "label": "»" },
{ "code": 8250, "label": "" }
]
} },
{ "code": 53, "label": "5", "type": "numeric", "popup": {
"relevant": [
{ "code": 171, "label": "«" },
{ "code": 8249, "label": "" }
]
} },
{ "code": 54, "label": "6", "type": "numeric", "popup": {
"relevant": [
{ "code": 36, "label": "$" },
{ "code": 162, "label": "¢" }
]
} },
{ "code": 55, "label": "7", "type": "numeric", "popup": {
"main": { "code": -801, "label": "currency_slot_1" },
"relevant": [
{ "code": -802, "label": "currency_slot_2" },
{ "code": -803, "label": "currency_slot_3" },
{ "code": -804, "label": "currency_slot_4" },
{ "code": -805, "label": "currency_slot_5" },
{ "code": -806, "label": "currency_slot_6" }
]
} },
{ "code": 56, "label": "8", "type": "numeric", "popup": {
"relevant": [
{ "code": 8222, "label": "„" },
{ "code": 8218, "label": "" }
]
} },
{ "code": 57, "label": "9", "type": "numeric", "popup": {
"relevant": [
{ "code": 8220, "label": "“" },
{ "code": 8216, "label": "" }
]
} },
{ "code": 48, "label": "0", "type": "numeric", "popup": {
"relevant": [
{ "code": 8221, "label": "”" },
{ "code": 8217, "label": "" }
]
} },
{ "code": 45, "label": "-", "type": "numeric", "popup": {
"relevant": [
{ "code": 8212, "label": "—" }
]
} }
]
]
}

View File

@@ -0,0 +1,91 @@
{
"type": "numeric_row",
"name": "oriya",
"label": "Odia",
"authors": [ "yashpalgoyal1304" ],
"direction": "ltr",
"arrangement": [
[
{ "code": 2919, "label": "୧", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "⅙" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
]
} },
{ "code": 2920, "label": "", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "⅔" },
{ "code": 178, "label": "²" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 2921, "label": "୩", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
]
} },
{ "code": 2922, "label": "୪", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "⅘" },
{ "code": 8308, "label": "⁴" }
]
} },
{ "code": 2923, "label": "୫", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
} },
{ "code": 2924, "label": "୬", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8310, "label": "⁶" }
]
} },
{ "code": 2925, "label": "୭", "type": "numeric", "popup": {
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 2926, "label": "୮", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 2927, "label": "୯", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 2918, "label": "", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "⁰" }
]
} }
]
]
}

View File

@@ -0,0 +1,91 @@
{
"type": "numeric_row",
"name": "tamil",
"label": "Tamil",
"authors": [ "yashpalgoyal1304" ],
"direction": "ltr",
"arrangement": [
[
{ "code": 3047, "label": "௧", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "⅙" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
]
} },
{ "code": 3048, "label": "௨", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "⅔" },
{ "code": 178, "label": "²" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 3049, "label": "௩", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
]
} },
{ "code": 3050, "label": "௪", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "⅘" },
{ "code": 8308, "label": "⁴" }
]
} },
{ "code": 3051, "label": "௫", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
} },
{ "code": 3052, "label": "௬", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8310, "label": "⁶" }
]
} },
{ "code": 3053, "label": "௭", "type": "numeric", "popup": {
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 3054, "label": "௮", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 3055, "label": "௯", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 3046, "label": "", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "⁰" }
]
} }
]
]
}

View File

@@ -0,0 +1,91 @@
{
"type": "numeric_row",
"name": "telugu",
"label": "Telugu",
"authors": [ "yashpalgoyal1304" ],
"direction": "ltr",
"arrangement": [
[
{ "code": 3175, "label": "౧", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "⅙" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
]
} },
{ "code": 3176, "label": "౨", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "⅔" },
{ "code": 178, "label": "²" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 3177, "label": "౩", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
]
} },
{ "code": 3178, "label": "౪", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "⅘" },
{ "code": 8308, "label": "⁴" }
]
} },
{ "code": 3179, "label": "౫", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
} },
{ "code": 3180, "label": "౬", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8310, "label": "⁶" }
]
} },
{ "code": 3181, "label": "౭", "type": "numeric", "popup": {
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 3182, "label": "౮", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 3183, "label": "౯", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 3174, "label": "", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "⁰" }
]
} }
]
]
}

View File

@@ -0,0 +1,35 @@
{
"type": "numeric",
"name": "western_arabic_pc",
"label": "Western Arabic (PC)",
"authors": [ "patrickgold" ],
"direction": "ltr",
"arrangement": [
[
{ "code": 55, "label": "7", "type": "numeric" },
{ "code": 56, "label": "8", "type": "numeric" },
{ "code": 57, "label": "9", "type": "numeric" },
{ "code": 45, "label": "-" }
],
[
{ "code": 52, "label": "4", "type": "numeric" },
{ "code": 53, "label": "5", "type": "numeric" },
{ "code": 54, "label": "6", "type": "numeric" },
{ "code": 32, "label": "space" }
],
[
{ "code": 49, "label": "1", "type": "numeric" },
{ "code": 50, "label": "2", "type": "numeric" },
{ "code": 51, "label": "3", "type": "numeric" },
{ "code": -5, "label": "delete", "type": "enter_editing" }
],
[
{ "code": 44, "label": "," },
{ "code": 48, "label": "0", "type": "numeric", "popup": {
"main": { "code": 43, "label": "+" }
} },
{ "code": 46, "label": "." },
{ "code": 10, "label": "enter", "type": "enter_editing" }
]
]
}

View File

@@ -0,0 +1,283 @@
{
"type": "symbols",
"name": "cjk",
"label": "CJK",
"authors": [ "waelwindows" ],
"direction": "ltr",
"modifier": "cjk",
"arrangement": [
[
{
"$": "char_width_selector",
"full": { "code": 65312, "label": "", "popup": {
"main": { "code": 64, "label": "@" }
}
},
"half": { "code": 64, "label": "@" }
},
{ "code": 12306, "label": "〒", "popup": {
"main": { "code": 12320, "label": "〠" }
}
},
{
"$": "char_width_selector",
"full": { "code": 65283, "label": "", "popup": {
"main": { "code": 35, "label": "#" },
"relevant": [
{ "code": 8470, "label": "№" }
]
}
},
"half": { "code": 35, "label": "#", "popup": {
"main": { "code": 65283, "label": "" },
"relevant": [
{ "code": 8470, "label": "№" }
]
}
}
},
{ "code": -801, "label": "currency_slot_1", "popup": {
"main": { "code": -802, "label": "currency_slot_2" },
"relevant": [
{ "code": -806, "label": "currency_slot_6" },
{ "code": -803, "label": "currency_slot_3" },
{ "code": -804, "label": "currency_slot_4" },
{ "code": -805, "label": "currency_slot_5" }
]
}
},
{
"$": "char_width_selector",
"full": { "code": 65285, "label": "", "popup": {
"main": { "code": 37, "label": "%" },
"relevant": [
{ "code": 8240, "label": "‰" },
{ "code": 8453, "label": "℅" }
]
}
},
"half": { "code": 37, "label": "%", "popup": {
"main": { "code": 65285, "label": "" },
"relevant": [
{ "code": 8240, "label": "‰" },
{ "code": 8453, "label": "℅" }
]
}
}
},
{
"$": "char_width_selector",
"full": { "code": 65286, "label": "", "popup": {
"main": { "code": 38, "label": "&" }
}
},
"half": { "code": 38, "label": "&", "popup": {
"main": { "code": 65286, "label": "" }
}
}
},
{
"$": "char_width_selector",
"full": { "code": 65293, "label": "", "popup": {
"main": { "code": 65343, "label": "_" },
"relevant": [
{ "code": 45, "label": "-" },
{ "code": 95, "label": "_" },
{ "code": 8212, "label": "—" },
{ "code": 8211, "label": "" },
{ "code": 183, "label": "·" }
]
}
},
"half": { "code": 45, "label": "-", "popup": {
"main": { "code": 95, "label": "_" },
"relevant": [
{ "code": 65293, "label": "" },
{ "code": 65343, "label": "_" },
{ "code": 8212, "label": "—" },
{ "code": 8211, "label": "" },
{ "code": 183, "label": "·" }
]
}
}
},
{
"$": "char_width_selector",
"full": { "code": 65291, "label": "", "popup": {
"main": { "code": 43, "label": "+" },
"relevant": [
{ "code": 177, "label": "±" }
]
}
},
"half": { "code": 43, "label": "+", "popup": {
"main": { "code": 65291, "label": "" },
"relevant": [
{ "code": 177, "label": "±" }
]
}
}
},
{
"$": "char_width_selector",
"full": { "code": 12300, "label": "「", "popup": {
"main": { "code": 12302, "label": "『" },
"relevant": [
{ "code": 12304, "label": "【" },
{ "code": 12310, "label": "〖" }
]
}
},
"half": { "code": 65378, "label": "「", "popup": {
"main": { "code": 12301, "label": "」" },
"relevant": [
{ "code": 12303, "label": "』" },
{ "code": 12304, "label": "【" },
{ "code": 12310, "label": "〖" }
]
}
}
},
{
"$": "char_width_selector",
"full": { "code": 12301, "label": "」", "popup": {
"main": { "code": 12303, "label": "』" },
"relevant": [
{ "code": 12305, "label": "】" },
{ "code": 12311, "label": "〗" }
]
}
},
"half": { "code": 65379, "label": "」", "popup": {
"main": { "code": 12301, "label": "」" },
"relevant": [
{ "code": 12303, "label": "』" },
{ "code": 12305, "label": "】" },
{ "code": 12311, "label": "〗" }
]
}
}
},
{
"$": "char_width_selector",
"full": { "code": 65295, "label": "", "popup": {
"main": { "code": 47, "label": "/" }
}
},
"half": { "code": 47, "label": "/", "popup": {
"main": { "code": 65295, "label": "" }
}
}
}
],
[
{
"$": "char_width_selector",
"full": { "code": 65290, "label": "", "popup": {
"main": { "code": 8251, "label": "※" },
"relevant": [
{ "code": 42, "label": "*" },
{ "code": 8224, "label": "†" },
{ "code": 9733, "label": "★" },
{ "code": 8225, "label": "‡" }
]
}
},
"half": { "code": 42, "label": "*", "popup": {
"main": { "code": 65290, "label": "" },
"relevant": [
{ "code": 8251, "label": "※" },
{ "code": 8224, "label": "†" },
{ "code": 9733, "label": "★" },
{ "code": 8225, "label": "‡" }
]
}
}
},
{ "code": 34, "label": "\"", "popup": {
"main": { "code": 8221, "label": "”" },
"relevant": [
{ "code": 8222, "label": "„" },
{ "code": 8220, "label": "“" },
{ "code": 171, "label": "«" },
{ "code": 187, "label": "»" }
]
}
},
{ "code": 39, "label": "'", "popup": {
"main": { "code": 8217, "label": "" },
"relevant": [
{ "code": 8218, "label": "" },
{ "code": 8216, "label": "" },
{ "code": 8249, "label": "" },
{ "code": 8250, "label": "" }
]
}
},
{
"$": "char_width_selector",
"full": { "code": 65306, "label": "", "popup": {
"main": { "code": 58, "label": ":" },
"relevant": [
{ "code": 8942, "label": "⋮" }
]
}
},
"half": { "code": 58, "label": ":", "popup": {
"main": { "code": 65306, "label": "" },
"relevant": [
{ "code": 8942, "label": "⋮" }
]
}
}
},
{
"$": "char_width_selector",
"full": { "code": 65307, "label": "", "popup": {
"main": { "code": 59, "label": ";" }
}
},
"half": { "code": 59, "label": ";", "popup": {
"main": { "code": 65307, "label": "" }
}
}
},
{
"$": "char_width_selector",
"full": { "code": 65281, "label": "", "popup": {
"main": { "code": 33, "label": "!" },
"relevant": [
{ "code": 161, "label": "¡" }
]
}
},
"half": { "code": 33, "label": "!", "popup": {
"main": { "code": 65281, "label": "" },
"relevant": [
{ "code": 161, "label": "¡" }
]
}
}
},
{
"$": "char_width_selector",
"full": { "code": 65311, "label": "", "popup": {
"main": { "code": 63, "label": "?" },
"relevant": [
{ "code": 191, "label": "¿" },
{ "code": 8253, "label": "‽" }
]
}
},
"half": { "code": 63, "label": "?", "popup": {
"main": { "code": 65311, "label": "" },
"relevant": [
{ "code": 191, "label": "¿" },
{ "code": 8253, "label": "‽" }
]
}
}
}
]
]
}

View File

@@ -0,0 +1,55 @@
{
"type": "symbols/mod",
"name": "cjk",
"label": "CJK",
"authors": [ "waelwindows" ],
"direction": "ltr",
"arrangement": [
[
{ "code": -203, "label": "view_symbols2", "type": "system_gui" },
{ "code": 0, "type": "placeholder" },
{ "code": -5, "label": "delete", "type": "enter_editing" }
],
[
{ "code": -201, "label": "view_characters", "type": "system_gui" },
{ "$": "char_width_selector",
"full": { "code": 12289, "label": "、", "popup": {
"main": { "code": 44, "label": "," }
}
},
"half": { "code": 65380, "label": "、", "popup": {
"main": { "code": 44, "label": "," }
}
}
},
{ "code": -205, "label": "view_numeric_advanced", "type": "system_gui" },
{ "code": 12288, "label": "空白" },
{ "code": -9701, "label": "char_width_switcher", "type": "system_gui", "popup": {
"relevant": [
{ "code": -9702, "label": "char_width_full", "type": "system_gui" },
{ "code": -9703, "label": "char_width_half", "type": "system_gui" }
]
}
},
{ "$": "char_width_selector",
"full": { "code": 12290, "label": "。", "popup": {
"main": { "code": 8230, "label": "…" },
"relevant": [
{ "code": 12539, "label": "・" },
{ "code": 46, "label": "." }
]
}
},
"half": { "code": 65377, "label": "。", "popup": {
"main": { "code": 8230, "label": "…" },
"relevant": [
{ "code": 65381, "label": "・" },
{ "code": 46, "label": "." }
]
}
}
},
{ "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" }
]
]
}

View File

@@ -0,0 +1,22 @@
{
"type": "symbols/mod",
"name": "neo2",
"label": "Neo2",
"authors": [ "ostrya" ],
"direction": "ltr",
"arrangement": [
[
{ "code": -203, "label": "view_symbols2", "type": "system_gui" },
{ "code": 0, "type": "placeholder" },
{ "code": -5, "label": "delete", "type": "enter_editing" }
],
[
{ "code": -201, "label": "view_characters", "type": "system_gui" },
{ "code": -205, "label": "view_numeric_advanced", "type": "system_gui" },
{ "code": 32, "label": "space" },
{ "code": 34, "label": "\"" },
{ "code": 39, "label": "'" },
{ "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" }
]
]
}

View File

@@ -0,0 +1,46 @@
{
"type": "symbols",
"name": "neo2",
"label": "Neo2",
"authors": [ "ostrya" ],
"direction": "ltr",
"modifier": "neo2",
"arrangement": [
[
{ "code": 8230, "label": "…" },
{ "code": 95, "label": "_" },
{ "code": 91, "label": "[" },
{ "code": 93, "label": "]" },
{ "code": 94, "label": "^" },
{ "code": 33, "label": "!" },
{ "code": 60, "label": "<" },
{ "code": 62, "label": ">" },
{ "code": 61, "label": "=" },
{ "code": 38, "label": "&" },
{ "code": 383, "label": "ſ" }
],
[
{ "code": 92, "label": "\\" },
{ "code": 47, "label": "/" },
{ "code": 123, "label": "{" },
{ "code": 125, "label": "}" },
{ "code": 42, "label": "*" },
{ "code": 63, "label": "?" },
{ "code": 40, "label": "(" },
{ "code": 41, "label": ")" },
{ "code": 45, "label": "-" },
{ "code": 58, "label": ":" },
{ "code": 64, "label": "@" }
],
[
{ "code": 35, "label": "#" },
{ "code": 36, "label": "$" },
{ "code": 124, "label": "|" },
{ "code": 126, "label": "~" },
{ "code": 96, "label": "`" },
{ "code": 43, "label": "+" },
{ "code": 37, "label": "%" },
{ "code": 59, "label": ";" }
]
]
}

View File

@@ -0,0 +1,225 @@
{
"type": "symbols2",
"name": "cjk",
"label": "CJK",
"authors": [ "waelwindows" ],
"direction": "ltr",
"modifier": "cjk",
"arrangement": [
[
{ "$": "char_width_selector",
"full": { "code": 12316, "label": "〜", "popup": {
"main": { "code": 126, "label": "~" }
}
},
"half": { "code": 126, "label": "~", "popup": {
"main": { "code": 12316, "label": "〜" }
}
}
},
{ "$": "char_width_selector",
"full": { "code": 65344, "label": "", "popup": {
"main": { "code": 96, "label": "`" }
}
},
"half": { "code": 96, "label": "`", "popup": {
"main": { "code": 65344, "label": "" }
}
}
},
{ "$": "char_width_selector",
"full": { "code": 65372, "label": "", "popup": {
"main": { "code": 124, "label": "|" }
}
},
"half": { "code": 124, "label": "|", "popup": {
"main": { "code": 65372, "label": "" }
}
}
},
{ "$": "char_width_selector",
"full":
{ "code": 12539, "label": "・", "popup": {
"main": { "code": 9834, "label": "♪" },
"relevant": [
{ "code": 8226, "label": "•" },
{ "code": 9827, "label": "♣" },
{ "code": 9824, "label": "♠" },
{ "code": 9829, "label": "♥" },
{ "code": 9830, "label": "♦" }
]
} },
"half":
{ "code": 8226, "label": "•", "popup": {
"main": { "code": 9834, "label": "♪" },
"relevant": [
{ "code": 12539, "label": "・" },
{ "code": 9827, "label": "♣" },
{ "code": 9824, "label": "♠" },
{ "code": 9829, "label": "♥" },
{ "code": 9830, "label": "♦" }
]
} }
},
{ "code": 8730, "label": "√" },
{ "code": 960, "label": "π", "popup": {
"main": { "code": 928, "label": "Π" },
"relevant": [
{ "code": 969, "label": "ω" },
{ "code": 945, "label": "α" },
{ "code": 946, "label": "β" },
{ "code": 937, "label": "Ω" },
{ "code": 956, "label": "μ" }
]
} },
{ "code": 247, "label": "÷" },
{ "code": 215, "label": "×" },
{ "code": 182, "label": "¶" },
{ "code": 8710, "label": "∆" }
],
[
{ "code": -805, "label": "currency_slot_5" },
{ "code": -804, "label": "currency_slot_4" },
{ "code": -803, "label": "currency_slot_3" },
{ "code": -802, "label": "currency_slot_2" },
{ "code": 94, "label": "^", "popup": {
"main": { "code": 8593, "label": "↑" },
"relevant": [
{ "code": 8592, "label": "←" },
{ "code": 8595, "label": "↓" },
{ "code": 8594, "label": "→" }
]
} },
{ "code": 176, "label": "°", "popup": {
"main": { "code": 8242, "label": "" },
"relevant": [
{ "code": 8243, "label": "″" }
]
} },
{ "$": "char_width_selector",
"full":
{ "code": 65309, "label": "", "popup": {
"main": { "code": 8800, "label": "≠" },
"relevant": [
{ "code": 61, "label": "=" },
{ "code": 8734, "label": "∞" },
{ "code": 8776, "label": "≈" }
]
}
},
"half":
{ "code": 61, "label": "=", "popup": {
"main": { "code": 8800, "label": "≠" },
"relevant": [
{ "code": 61, "label": "=" },
{ "code": 8734, "label": "∞" },
{ "code": 8776, "label": "≈" }
]
}
}
},
{ "$": "char_width_selector",
"full": { "code": 65371, "label": "", "popup": {
"main": { "code": 65288, "label": "" },
"relevant": [
{ "code": 123, "label": "{" },
{ "code": 12308, "label": "" },
{ "code": 12312, "label": "〘" },
{ "code": 65375, "label": "⦅" }
]
}
},
"half": { "code": 123, "label": "{", "popup": {
"main": { "code": 40, "label": "(" },
"relevant": [
{ "code": 65371, "label": "" }
]
}
}
},
{ "$": "char_width_selector",
"full": { "code": 65373, "label": "", "popup": {
"main": { "code": 65289, "label": "" },
"relevant": [
{ "code": 125, "label": "}" },
{ "code": 12309, "label": "" },
{ "code": 12313, "label": "〙" },
{ "code": 65376, "label": "⦆" }
]
}
},
"half": { "code": 125, "label": "}", "popup": {
"main": { "code": 41, "label": ")" },
"relevant": [
{ "code": 65373, "label": "" }
]
}
}
},
{ "$": "char_width_selector",
"full": { "code": 65340, "label": "", "popup": {
"main": { "code": 92, "label": "\\" }
}
},
"half": { "code": 92, "label": "\\", "popup": {
"main": { "code": 65340, "label": "" }
}
}
}
],
[
{ "code": 12292, "label": "〄" },
{ "code": 12293, "label": "々" },
{ "code": 12294, "label": "〆" },
{ "code": 12295, "label": "" },
{ "$": "kana_selector",
"hira": { "code": 12445, "label": "ゝ", "popup": {
"main": { "code": 12446, "label": "ゞ" },
"relevant": [
{ "code": 12541, "label": "ヽ" },
{ "code": 12542, "label": "ヾ" }
]
}
},
"kata": { "code": 12541, "label": "ヽ", "popup": {
"main": { "code": 12542, "label": "ヾ" },
"relevant": [
{ "code": 12445, "label": "ゝ" },
{ "code": 12446, "label": "ゞ" }
]
}
}
},
{ "$": "char_width_selector",
"full": { "code": 65339, "label": "", "popup": {
"main": { "code": 91, "label": "[" },
"relevant": [
{ "code": 12314, "label": "〚" },
{ "code": 12304, "label": "【" },
{ "code": 12310, "label": "〖" }
]
}
},
"half": { "code": 91, "label": "[", "popup": {
"main": { "code": 65339, "label": "" }
}
}
},
{ "$": "char_width_selector",
"full": { "code": 65341, "label": "", "popup": {
"main": { "code": 93, "label": "]" },
"relevant": [
{ "code": 12315, "label": "〛" },
{ "code": 12305, "label": "】" },
{ "code": 12311, "label": "〗" }
]
}
},
"half": { "code": 93, "label": "]", "popup": {
"main": { "code": 65341, "label": "" }
}
}
}
]
]
}

View File

@@ -0,0 +1,45 @@
{
"type": "symbols2/mod",
"name": "cjk",
"label": "CJK",
"authors": [ "waelwindows" ],
"direction": "ltr",
"arrangement": [
[
{ "code": -202, "label": "view_symbols", "type": "system_gui" },
{ "code": 0, "type": "placeholder" },
{ "code": -5, "label": "delete", "type": "enter_editing" }
],
[
{ "code": -201, "label": "view_characters", "type": "system_gui" },
{ "code": 12296, "label": "〈", "popup": {
"main": { "code": 12298, "label": "《" },
"relevant": [
{ "code": 8804, "label": "≤" },
{ "code": 8249, "label": "" },
{ "code": 10216, "label": "⟨" },
{ "code": 65308, "label": "" }
]
} },
{ "code": -205, "label": "view_numeric_advanced", "type": "system_gui" },
{ "code": 12288, "label": "空白" },
{ "code": -9701, "label": "char_width_switcher", "type": "system_gui", "popup": {
"relevant": [
{ "code": -9702, "label": "char_width_full", "type": "system_gui" },
{ "code": -9703, "label": "char_width_half", "type": "system_gui" }
]
}
},
{ "code": 12297, "label": "〉", "popup": {
"main": { "code": 12299, "label": "》" },
"relevant": [
{ "code": 62, "label": ">" },
{ "code": 8805, "label": "≥" },
{ "code": 10217, "label": "⟩" },
{ "code": 65310, "label": "" }
]
} },
{ "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" }
]
]
}

View File

@@ -294,6 +294,422 @@ SOFTWARE.
<hr>
<h3>ICU4C: International Components for Unicode</h3>
<span>Copyright © 1991-2020 Unicode, Inc. All rights reserved.</span>
<pre>
Distributed under the Terms of Use in https://www.unicode.org/copyright.html.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Unicode data files and any associated documentation
(the "Data Files") or Unicode software and any associated documentation
(the "Software") to deal in the Data Files or Software
without restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, and/or sell copies of
the Data Files or Software, and to permit persons to whom the Data Files
or Software are furnished to do so, provided that either
(a) this copyright and permission notice appear with all copies
of the Data Files or Software, or
(b) this copyright and permission notice appear in associated
Documentation.
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THE DATA FILES OR SOFTWARE.
Except as contained in this notice, the name of a copyright holder
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in these Data Files or Software without prior
written authorization of the copyright holder.
---------------------
Third-Party Software Licenses
This section contains third-party software notices and/or additional
terms for licensed third-party software components included within ICU
libraries.
1. ICU License - ICU 1.8.1 to ICU 57.1
COPYRIGHT AND PERMISSION NOTICE
Copyright (c) 1995-2016 International Business Machines Corporation and others
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, provided that the above
copyright notice(s) and this permission notice appear in all copies of
the Software and that both the above copyright notice(s) and this
permission notice appear in supporting documentation.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Except as contained in this notice, the name of a copyright holder
shall not be used in advertising or otherwise to promote the sale, use
or other dealings in this Software without prior written authorization
of the copyright holder.
All trademarks and registered trademarks mentioned herein are the
property of their respective owners.
2. Chinese/Japanese Word Break Dictionary Data (cjdict.txt)
# The Google Chrome software developed by Google is licensed under
# the BSD license. Other software included in this distribution is
# provided under other licenses, as set forth below.
#
# The BSD License
# http://opensource.org/licenses/bsd-license.php
# Copyright (C) 2006-2008, Google Inc.
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided with
# the distribution.
# Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#
# The word list in cjdict.txt are generated by combining three word lists
# listed below with further processing for compound word breaking. The
# frequency is generated with an iterative training against Google web
# corpora.
#
# * Libtabe (Chinese)
# - https://sourceforge.net/project/?group_id=1519
# - Its license terms and conditions are shown below.
#
# * IPADIC (Japanese)
# - http://chasen.aist-nara.ac.jp/chasen/distribution.html
# - Its license terms and conditions are shown below.
#
# ---------COPYING.libtabe ---- BEGIN--------------------
#
# /*
# * Copyright (c) 1999 TaBE Project.
# * Copyright (c) 1999 Pai-Hsiang Hsiao.
# * All rights reserved.
# *
# * Redistribution and use in source and binary forms, with or without
# * modification, are permitted provided that the following conditions
# * are met:
# *
# * . Redistributions of source code must retain the above copyright
# * notice, this list of conditions and the following disclaimer.
# * . Redistributions in binary form must reproduce the above copyright
# * notice, this list of conditions and the following disclaimer in
# * the documentation and/or other materials provided with the
# * distribution.
# * . Neither the name of the TaBE Project nor the names of its
# * contributors may be used to endorse or promote products derived
# * from this software without specific prior written permission.
# *
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# * OF THE POSSIBILITY OF SUCH DAMAGE.
# */
#
# /*
# * Copyright (c) 1999 Computer Systems and Communication Lab,
# * Institute of Information Science, Academia
# * Sinica. All rights reserved.
# *
# * Redistribution and use in source and binary forms, with or without
# * modification, are permitted provided that the following conditions
# * are met:
# *
# * . Redistributions of source code must retain the above copyright
# * notice, this list of conditions and the following disclaimer.
# * . Redistributions in binary form must reproduce the above copyright
# * notice, this list of conditions and the following disclaimer in
# * the documentation and/or other materials provided with the
# * distribution.
# * . Neither the name of the Computer Systems and Communication Lab
# * nor the names of its contributors may be used to endorse or
# * promote products derived from this software without specific
# * prior written permission.
# *
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# * OF THE POSSIBILITY OF SUCH DAMAGE.
# */
#
# Copyright 1996 Chih-Hao Tsai @ Beckman Institute,
# University of Illinois
# c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4
#
# ---------------COPYING.libtabe-----END--------------------------------
#
#
# ---------------COPYING.ipadic-----BEGIN-------------------------------
#
# Copyright 2000, 2001, 2002, 2003 Nara Institute of Science
# and Technology. All Rights Reserved.
#
# Use, reproduction, and distribution of this software is permitted.
# Any copy of this software, whether in its original form or modified,
# must include both the above copyright notice and the following
# paragraphs.
#
# Nara Institute of Science and Technology (NAIST),
# the copyright holders, disclaims all warranties with regard to this
# software, including all implied warranties of merchantability and
# fitness, in no event shall NAIST be liable for
# any special, indirect or consequential damages or any damages
# whatsoever resulting from loss of use, data or profits, whether in an
# action of contract, negligence or other tortuous action, arising out
# of or in connection with the use or performance of this software.
#
# A large portion of the dictionary entries
# originate from ICOT Free Software. The following conditions for ICOT
# Free Software applies to the current dictionary as well.
#
# Each User may also freely distribute the Program, whether in its
# original form or modified, to any third party or parties, PROVIDED
# that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear
# on, or be attached to, the Program, which is distributed substantially
# in the same form as set out herein and that such intended
# distribution, if actually made, will neither violate or otherwise
# contravene any of the laws and regulations of the countries having
# jurisdiction over the User or the intended distribution itself.
#
# NO WARRANTY
#
# The program was produced on an experimental basis in the course of the
# research and development conducted during the project and is provided
# to users as so produced on an experimental basis. Accordingly, the
# program is provided without any warranty whatsoever, whether express,
# implied, statutory or otherwise. The term "warranty" used herein
# includes, but is not limited to, any warranty of the quality,
# performance, merchantability and fitness for a particular purpose of
# the program and the nonexistence of any infringement or violation of
# any right of any third party.
#
# Each user of the program will agree and understand, and be deemed to
# have agreed and understood, that there is no warranty whatsoever for
# the program and, accordingly, the entire risk arising from or
# otherwise connected with the program is assumed by the user.
#
# Therefore, neither ICOT, the copyright holder, or any other
# organization that participated in or was otherwise related to the
# development of the program and their respective officials, directors,
# officers and other employees shall be held liable for any and all
# damages, including, without limitation, general, special, incidental
# and consequential damages, arising out of or otherwise in connection
# with the use or inability to use the program or any product, material
# or result produced or otherwise obtained by using the program,
# regardless of whether they have been advised of, or otherwise had
# knowledge of, the possibility of such damages at any time during the
# project or thereafter. Each user will be deemed to have agreed to the
# foregoing by his or her commencement of use of the program. The term
# "use" as used herein includes, but is not limited to, the use,
# modification, copying and distribution of the program and the
# production of secondary products from the program.
#
# In the case where the program, whether in its original form or
# modified, was distributed or delivered to or received by a user from
# any person, organization or entity other than ICOT, unless it makes or
# grants independently of ICOT any specific warranty to the user in
# writing, such person, organization or entity, will also be exempted
# from and not be held liable to the user for any such damages as noted
# above as far as the program is concerned.
#
# ---------------COPYING.ipadic-----END----------------------------------
3. Lao Word Break Dictionary Data (laodict.txt)
# Copyright (C) 2016 and later: Unicode, Inc. and others.
# License & terms of use: http://www.unicode.org/copyright.html
# Copyright (c) 2015 International Business Machines Corporation
# and others. All Rights Reserved.
#
# Project: https://github.com/rober42539/lao-dictionary
# Dictionary: https://github.com/rober42539/lao-dictionary/laodict.txt
# License: https://github.com/rober42539/lao-dictionary/LICENSE.txt
# (copied below)
#
# This file is derived from the above dictionary version of Nov 22, 2020
# ----------------------------------------------------------------------
# Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer. Redistributions in binary
# form must reproduce the above copyright notice, this list of conditions and
# the following disclaimer in the documentation and/or ther materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
# --------------------------------------------------------------------------
4. Burmese Word Break Dictionary Data (burmesedict.txt)
# Copyright (c) 2014 International Business Machines Corporation
# and others. All Rights Reserved.
#
# This list is part of a project hosted at:
# github.com/kanyawtech/myanmar-karen-word-lists
#
# --------------------------------------------------------------------------
# Copyright (c) 2013, LeRoy Benjamin Sharon
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met: Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer. Redistributions in binary form must reproduce the
# above copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
#
# Neither the name Myanmar Karen Word Lists, nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
# --------------------------------------------------------------------------
5. Time Zone Database
ICU uses the public domain data and code derived from Time Zone
Database for its time zone support. The ownership of the TZ database
is explained in BCP 175: Procedure for Maintaining the Time Zone
Database section 7.
# 7. Database Ownership
#
# The TZ database itself is not an IETF Contribution or an IETF
# document. Rather it is a pre-existing and regularly updated work
# that is in the public domain, and is intended to remain in the
# public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do
# not apply to the TZ Database or contributions that individuals make
# to it. Should any claims be made and substantiated against the TZ
# Database, the organization that is providing the IANA
# Considerations defined in this RFC, under the memorandum of
# understanding with the IETF, currently ICANN, may act in accordance
# with all competent court orders. No ownership claims will be made
# by ICANN or the IETF Trust on the database or the code. Any person
# making a contribution to the database or code waives all rights to
# future claims in that contribution or in the TZ Database.
6. Google double-conversion
Copyright 2006-2011, the V8 project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</pre>
<hr>
<h3>Kotlin & KotlinX libraries</h3>
<span>Copyright 2000-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.</span>
<pre>
@@ -711,6 +1127,176 @@ SOFTWARE.
<hr>
<h3>Nuspell</h3>
<span>Copyright (c) 2021 Nuspell</span>
<pre>
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
</pre>
<h3>Timber</h3>
<span>Copyright 2013 Jake Wharton</span>
<pre>
@@ -764,384 +1350,6 @@ shall not be used in advertising or otherwise to promote the sale,
use or other dealings in these Data Files or Software without prior
written authorization of the copyright holder.
</pre>
<hr>
<h3>Dictionary Source 1: wordfreq data</h3>
<span>Copyright (c) 2015 Luminoso Technologies, Inc.</span>
<pre>
Creative Commons Attribution-ShareAlike 4.0 International Public
License
By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution-ShareAlike 4.0 International Public License ("Public
License"). To the extent this Public License may be interpreted as a
contract, You are granted the Licensed Rights in consideration of Your
acceptance of these terms and conditions, and the Licensor grants You
such rights in consideration of benefits the Licensor receives from
making the Licensed Material available under these terms and
conditions.
Section 1 -- Definitions.
a. Adapted Material means material subject to Copyright and Similar
Rights that is derived from or based upon the Licensed Material
and in which the Licensed Material is translated, altered,
arranged, transformed, or otherwise modified in a manner requiring
permission under the Copyright and Similar Rights held by the
Licensor. For purposes of this Public License, where the Licensed
Material is a musical work, performance, or sound recording,
Adapted Material is always produced where the Licensed Material is
synched in timed relation with a moving image.
b. Adapter's License means the license You apply to Your Copyright
and Similar Rights in Your contributions to Adapted Material in
accordance with the terms and conditions of this Public License.
c. BY-SA Compatible License means a license listed at
creativecommons.org/compatiblelicenses, approved by Creative
Commons as essentially the equivalent of this Public License.
d. Copyright and Similar Rights means copyright and/or similar rights
closely related to copyright including, without limitation,
performance, broadcast, sound recording, and Sui Generis Database
Rights, without regard to how the rights are labeled or
categorized. For purposes of this Public License, the rights
specified in Section 2(b)(1)-(2) are not Copyright and Similar
Rights.
e. Effective Technological Measures means those measures that, in the
absence of proper authority, may not be circumvented under laws
fulfilling obligations under Article 11 of the WIPO Copyright
Treaty adopted on December 20, 1996, and/or similar international
agreements.
f. Exceptions and Limitations means fair use, fair dealing, and/or
any other exception or limitation to Copyright and Similar Rights
that applies to Your use of the Licensed Material.
g. License Elements means the license attributes listed in the name
of a Creative Commons Public License. The License Elements of this
Public License are Attribution and ShareAlike.
h. Licensed Material means the artistic or literary work, database,
or other material to which the Licensor applied this Public
License.
i. Licensed Rights means the rights granted to You subject to the
terms and conditions of this Public License, which are limited to
all Copyright and Similar Rights that apply to Your use of the
Licensed Material and that the Licensor has authority to license.
j. Licensor means the individual(s) or entity(ies) granting rights
under this Public License.
k. Share means to provide material to the public by any means or
process that requires permission under the Licensed Rights, such
as reproduction, public display, public performance, distribution,
dissemination, communication, or importation, and to make material
available to the public including in ways that members of the
public may access the material from a place and at a time
individually chosen by them.
l. Sui Generis Database Rights means rights other than copyright
resulting from Directive 96/9/EC of the European Parliament and of
the Council of 11 March 1996 on the legal protection of databases,
as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.
m. You means the individual or entity exercising the Licensed Rights
under this Public License. Your has a corresponding meaning.
Section 2 -- Scope.
a. License grant.
1. Subject to the terms and conditions of this Public License,
the Licensor hereby grants You a worldwide, royalty-free,
non-sublicensable, non-exclusive, irrevocable license to
exercise the Licensed Rights in the Licensed Material to:
a. reproduce and Share the Licensed Material, in whole or
in part; and
b. produce, reproduce, and Share Adapted Material.
2. Exceptions and Limitations. For the avoidance of doubt, where
Exceptions and Limitations apply to Your use, this Public
License does not apply, and You do not need to comply with
its terms and conditions.
3. Term. The term of this Public License is specified in Section
6(a).
4. Media and formats; technical modifications allowed. The
Licensor authorizes You to exercise the Licensed Rights in
all media and formats whether now known or hereafter created,
and to make technical modifications necessary to do so. The
Licensor waives and/or agrees not to assert any right or
authority to forbid You from making technical modifications
necessary to exercise the Licensed Rights, including
technical modifications necessary to circumvent Effective
Technological Measures. For purposes of this Public License,
simply making modifications authorized by this Section 2(a)
(4) never produces Adapted Material.
5. Downstream recipients.
a. Offer from the Licensor -- Licensed Material. Every
recipient of the Licensed Material automatically
receives an offer from the Licensor to exercise the
Licensed Rights under the terms and conditions of this
Public License.
b. Additional offer from the Licensor -- Adapted Material.
Every recipient of Adapted Material from You
automatically receives an offer from the Licensor to
exercise the Licensed Rights in the Adapted Material
under the conditions of the Adapter's License You apply.
c. No downstream restrictions. You may not offer or impose
any additional or different terms or conditions on, or
apply any Effective Technological Measures to, the
Licensed Material if doing so restricts exercise of the
Licensed Rights by any recipient of the Licensed
Material.
6. No endorsement. Nothing in this Public License constitutes or
may be construed as permission to assert or imply that You
are, or that Your use of the Licensed Material is, connected
with, or sponsored, endorsed, or granted official status by,
the Licensor or others designated to receive attribution as
provided in Section 3(a)(1)(A)(i).
b. Other rights.
1. Moral rights, such as the right of integrity, are not
licensed under this Public License, nor are publicity,
privacy, and/or other similar personality rights; however, to
the extent possible, the Licensor waives and/or agrees not to
assert any such rights held by the Licensor to the limited
extent necessary to allow You to exercise the Licensed
Rights, but not otherwise.
2. Patent and trademark rights are not licensed under this
Public License.
3. To the extent possible, the Licensor waives any right to
collect royalties from You for the exercise of the Licensed
Rights, whether directly or through a collecting society
under any voluntary or waivable statutory or compulsory
licensing scheme. In all other cases the Licensor expressly
reserves any right to collect such royalties.
Section 3 -- License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the
following conditions.
a. Attribution.
1. If You Share the Licensed Material (including in modified
form), You must:
a. retain the following if it is supplied by the Licensor
with the Licensed Material:
i. identification of the creator(s) of the Licensed
Material and any others designated to receive
attribution, in any reasonable manner requested by
the Licensor (including by pseudonym if
designated);
ii. a copyright notice;
iii. a notice that refers to this Public License;
iv. a notice that refers to the disclaimer of
warranties;
v. a URI or hyperlink to the Licensed Material to the
extent reasonably practicable;
b. indicate if You modified the Licensed Material and
retain an indication of any previous modifications; and
c. indicate the Licensed Material is licensed under this
Public License, and include the text of, or the URI or
hyperlink to, this Public License.
2. You may satisfy the conditions in Section 3(a)(1) in any
reasonable manner based on the medium, means, and context in
which You Share the Licensed Material. For example, it may be
reasonable to satisfy the conditions by providing a URI or
hyperlink to a resource that includes the required
information.
3. If requested by the Licensor, You must remove any of the
information required by Section 3(a)(1)(A) to the extent
reasonably practicable.
b. ShareAlike.
In addition to the conditions in Section 3(a), if You Share
Adapted Material You produce, the following conditions also apply.
1. The Adapter's License You apply must be a Creative Commons
license with the same License Elements, this version or
later, or a BY-SA Compatible License.
2. You must include the text of, or the URI or hyperlink to, the
Adapter's License You apply. You may satisfy this condition
in any reasonable manner based on the medium, means, and
context in which You Share Adapted Material.
3. You may not offer or impose any additional or different terms
or conditions on, or apply any Effective Technological
Measures to, Adapted Material that restrict exercise of the
rights granted under the Adapter's License You apply.
Section 4 -- Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
to extract, reuse, reproduce, and Share all or a substantial
portion of the contents of the database;
b. if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database
Rights, then the database in which You have Sui Generis Database
Rights (but not its individual contents) is Adapted Material,
including for purposes of Section 3(b); and
c. You must comply with the conditions in Section 3(a) if You Share
all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
c. The disclaimer of warranties and limitation of liability provided
above shall be interpreted in a manner that, to the extent
possible, most closely approximates an absolute disclaimer and
waiver of all liability.
Section 6 -- Term and Termination.
a. This Public License applies for the term of the Copyright and
Similar Rights licensed here. However, if You fail to comply with
this Public License, then Your rights under this Public License
terminate automatically.
b. Where Your right to use the Licensed Material has terminated under
Section 6(a), it reinstates:
1. automatically as of the date the violation is cured, provided
it is cured within 30 days of Your discovery of the
violation; or
2. upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any
right the Licensor may have to seek remedies for Your violations
of this Public License.
c. For the avoidance of doubt, the Licensor may also offer the
Licensed Material under separate terms or conditions or stop
distributing the Licensed Material at any time; however, doing so
will not terminate this Public License.
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
License.
Section 7 -- Other Terms and Conditions.
a. The Licensor shall not be bound by any additional or different
terms or conditions communicated by You unless expressly agreed.
b. Any arrangements, understandings, or agreements regarding the
Licensed Material not stated herein are separate from and
independent of the terms and conditions of this Public License.
Section 8 -- Interpretation.
a. For the avoidance of doubt, this Public License does not, and
shall not be interpreted to, reduce, limit, restrict, or impose
conditions on any use of the Licensed Material that could lawfully
be made without permission under this Public License.
b. To the extent possible, if any provision of this Public License is
deemed unenforceable, it shall be automatically reformed to the
minimum extent necessary to make it enforceable. If the provision
cannot be reformed, it shall be severed from this Public License
without affecting the enforceability of the remaining terms and
conditions.
c. No term or condition of this Public License will be waived and no
failure to comply consented to unless expressly agreed to by the
Licensor.
d. Nothing in this Public License constitutes or may be interpreted
as a limitation upon, or waiver of, any privileges and immunities
that apply to the Licensor or You, including from the legal
processes of any jurisdiction or authority.
=======================================================================
Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
will be considered the “Licensor.” The text of the Creative Commons
public licenses is dedicated to the public domain under the CC0 Public
Domain Dedication. Except for the limited purpose of indicating that
material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the
public licenses.
Creative Commons may be contacted at creativecommons.org.
</pre>
</body>
</html>

View File

@@ -0,0 +1,48 @@
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
cmake_minimum_required(VERSION 3.10.2)
project("florisboard")
set(CMAKE_CXX_STANDARD 17)
include_directories(.)
### ICU4C ###
include_directories(../icu4c/prebuilt/include)
set(JNI_LIBS ${CMAKE_SOURCE_DIR}/../icu4c/prebuilt/jniLibs/${ANDROID_ABI})
add_library(ICU::data STATIC IMPORTED)
set_property(TARGET ICU::data PROPERTY IMPORTED_LOCATION "${JNI_LIBS}/libicudata.a")
add_library(ICU::uc STATIC IMPORTED)
set_property(TARGET ICU::uc PROPERTY IMPORTED_LOCATION "${JNI_LIBS}/libicuuc.a")
### FlorisBoard ###
add_subdirectory(nuspell)
add_subdirectory(utils)
add_subdirectory(ime/nlp)
add_subdirectory(ime/spelling)
add_library(
florisboard-native
SHARED
dev_patrickgold_florisboard_FlorisApplication.cpp
dev_patrickgold_florisboard_ime_nlp_SuggestionList.cpp
dev_patrickgold_florisboard_ime_spelling_SpellingDict.cpp
)
target_compile_options(florisboard-native PRIVATE -ffunction-sections -fdata-sections -fexceptions)
target_link_libraries(
# Destination
florisboard-native
# Sources
android
log
ICU::uc
ICU::data
Nuspell::nuspell
utils
ime-nlp
ime-spelling
)

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
#include <fstream>
#include <vector>
#include <jni.h>
#include <unicode/udata.h>
#include "utils/jni_utils.h"
#pragma ide diagnostic ignored "UnusedLocalVariable"
extern "C"
JNIEXPORT jint JNICALL
Java_dev_patrickgold_florisboard_FlorisApplication_00024Companion_nativeInitICUData(
JNIEnv *env,
jobject thiz,
jobject path) {
auto path_str = utils::j2std_string(env, path);
std::ifstream in_file(path_str, std::ios::in | std::ios::binary);
if (!in_file) {
return U_FILE_ACCESS_ERROR;
}
in_file.seekg(0, std::ios::end);
size_t size = in_file.tellg();
if (size <= 0) {
return U_FILE_ACCESS_ERROR;
}
in_file.seekg(0, std::ios::beg);
char *icu_data = new char[size + 1];
in_file.read(icu_data, size);
if (!in_file) {
in_file.close();
return U_FILE_ACCESS_ERROR;
}
icu_data[size] = 0;
in_file.close();
UErrorCode status = U_ZERO_ERROR;
udata_setCommonData(reinterpret_cast<void *>(icu_data), &status);
return status;
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
#include <jni.h>
#include "ime/nlp/suggestion_list.h"
#pragma ide diagnostic ignored "UnusedLocalVariable"
using namespace ime::nlp;
extern "C"
JNIEXPORT jlong JNICALL
Java_dev_patrickgold_florisboard_ime_nlp_SuggestionList_00024Companion_nativeInitialize(
JNIEnv *env,
jobject thiz,
jint max_size) {
auto *suggestionList = new SuggestionList(max_size);
return reinterpret_cast<jlong>(suggestionList);
}
extern "C"
JNIEXPORT void JNICALL
Java_dev_patrickgold_florisboard_ime_nlp_SuggestionList_00024Companion_nativeDispose(
JNIEnv *env,
jobject thiz,
jlong native_ptr) {
auto *suggestionList = reinterpret_cast<SuggestionList *>(native_ptr);
suggestionList->clear();
delete suggestionList;
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_dev_patrickgold_florisboard_ime_nlp_SuggestionList_00024Companion_nativeAdd(
JNIEnv *env,
jobject thiz,
jlong native_ptr,
jstring word,
jint freq) {
const char *cWord = env->GetStringUTFChars(word, nullptr);
word_t stdWord = word_t(cWord);
env->ReleaseStringUTFChars(word, cWord);
auto *suggestionList = reinterpret_cast<SuggestionList *>(native_ptr);
return suggestionList->add(std::move(stdWord), freq);
}
extern "C"
JNIEXPORT void JNICALL
Java_dev_patrickgold_florisboard_ime_nlp_SuggestionList_00024Companion_nativeClear(
JNIEnv *env,
jobject thiz,
jlong native_ptr) {
auto *suggestionList = reinterpret_cast<SuggestionList *>(native_ptr);
suggestionList->clear();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_dev_patrickgold_florisboard_ime_nlp_SuggestionList_00024Companion_nativeContains(
JNIEnv *env,
jobject thiz,
jlong native_ptr,
jstring element) {
const char *cWord = env->GetStringUTFChars(element, nullptr);
const word_t stdWord = word_t(cWord);
env->ReleaseStringUTFChars(element, cWord);
auto *suggestionList = reinterpret_cast<SuggestionList *>(native_ptr);
return suggestionList->containsWord(stdWord);
}
extern "C"
JNIEXPORT jstring JNICALL
Java_dev_patrickgold_florisboard_ime_nlp_SuggestionList_00024Companion_nativeGetOrNull(
JNIEnv *env,
jobject thiz,
jlong native_ptr,
jint index) {
auto *suggestionList = reinterpret_cast<SuggestionList *>(native_ptr);
auto weightedToken = suggestionList->get(index);
if (weightedToken == nullptr) {
return nullptr;
}
return env->NewStringUTF(weightedToken->data.c_str());
}
extern "C"
JNIEXPORT jint JNICALL
Java_dev_patrickgold_florisboard_ime_nlp_SuggestionList_00024Companion_nativeSize(
JNIEnv *env,
jobject thiz,
jlong native_ptr) {
auto *suggestionList = reinterpret_cast<SuggestionList *>(native_ptr);
return suggestionList->size();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_dev_patrickgold_florisboard_ime_nlp_SuggestionList_00024Companion_nativeGetIsPrimaryTokenAutoInsert(
JNIEnv *env, jobject thiz, jlong native_ptr) {
auto *suggestionList = reinterpret_cast<SuggestionList *>(native_ptr);
return suggestionList->isPrimaryTokenAutoInsert;
}
extern "C"
JNIEXPORT void JNICALL
Java_dev_patrickgold_florisboard_ime_nlp_SuggestionList_00024Companion_nativeSetIsPrimaryTokenAutoInsert(
JNIEnv *env, jobject thiz, jlong native_ptr, jboolean v) {
auto *suggestionList = reinterpret_cast<SuggestionList *>(native_ptr);
suggestionList->isPrimaryTokenAutoInsert = v;
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
#include <jni.h>
#include <algorithm>
#include "ime/spelling/spellingdict.h"
#include "utils/jni_utils.h"
#pragma ide diagnostic ignored "UnusedLocalVariable"
using namespace ime::spellcheck;
extern "C"
JNIEXPORT jlong JNICALL
Java_dev_patrickgold_florisboard_ime_spelling_SpellingDict_00024Companion_nativeInitialize(
JNIEnv *env,
jobject thiz,
jobject base_path) {
auto strBasePath = utils::j2std_string(env, base_path);
auto *spellingDict = SpellingDict::load(strBasePath);
if (spellingDict == nullptr) {
return 0L;
} else {
return reinterpret_cast<jlong>(spellingDict);
}
}
extern "C"
JNIEXPORT void JNICALL
Java_dev_patrickgold_florisboard_ime_spelling_SpellingDict_00024Companion_nativeDispose(
JNIEnv *env,
jobject thiz,
jlong native_ptr) {
auto spellingDict = reinterpret_cast<SpellingDict *>(native_ptr);
delete spellingDict;
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_dev_patrickgold_florisboard_ime_spelling_SpellingDict_00024Companion_nativeSpell(
JNIEnv *env,
jobject thiz,
jlong native_ptr,
jobject word) {
auto strWord = utils::j2std_string(env, word);
auto spellingDict = reinterpret_cast<SpellingDict *>(native_ptr);
auto result = spellingDict->spell(strWord);
return result;
}
extern "C"
JNIEXPORT jobjectArray JNICALL
Java_dev_patrickgold_florisboard_ime_spelling_SpellingDict_00024Companion_nativeSuggest(
JNIEnv *env,
jobject thiz,
jlong native_ptr,
jobject word,
jint limit) {
auto strWord = utils::j2std_string(env, word);
auto spellingDict = reinterpret_cast<SpellingDict *>(native_ptr);
auto result = spellingDict->suggest(strWord);
auto retSize = std::min(result.size(), (size_t)std::max(0, limit));
jclass jByteArrayClass = env->FindClass("java/nio/ByteBuffer");
jobjectArray jSuggestions = env->NewObjectArray(retSize, jByteArrayClass, nullptr);
for (int n = 0; n < retSize; n++) {
env->SetObjectArrayElement(jSuggestions, n, utils::std2j_string(env, result[n]));
}
return jSuggestions;
}

View File

@@ -0,0 +1,13 @@
add_library(
# Name
ime-nlp
# Headers
nlp.h
token.h
suggestion_list.h
# Sources
token.cpp
suggestion_list.cpp
)

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
#ifndef FLORISBOARD_NLP_H
#define FLORISBOARD_NLP_H
#include <string>
namespace ime::nlp {
typedef std::string word_t;
typedef uint16_t freq_t;
static const freq_t FREQ_VALUE_MASK = 0xFF;
static const freq_t FREQ_POSSIBLY_OFFENSIVE = 0x01;
} // namespace ime::nlp
#endif // FLORISBOARD_NLP_H

View File

@@ -0,0 +1,98 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
#include "suggestion_list.h"
#include <utility>
using namespace ime::nlp;
SuggestionList::SuggestionList(size_t _maxSize) :
maxSize(_maxSize), internalSize(0), tokens(_maxSize), isPrimaryTokenAutoInsert(false)
{ }
SuggestionList::~SuggestionList() = default;
bool SuggestionList::add(word_t &&word, freq_t &&freq) {
auto entryIndex = indexOfWord(word);
if (entryIndex.has_value()) {
// Word exists already
auto entry = tokens[entryIndex.value()];
if (entry.freq < freq) {
// Need to update freq
entry.freq = freq;
} else {
return false;
}
} else {
if (internalSize < maxSize) {
tokens[internalSize++] = WeightedToken(std::move(word), freq);
} else {
auto last = tokens[internalSize - 1];
if (last.freq < freq) {
tokens[internalSize - 1] = WeightedToken(std::move(word), freq);
} else {
return false;
}
}
}
std::sort(tokens.begin(), tokens.begin() + internalSize, std::greater<>());
return true;
}
void SuggestionList::clear() {
internalSize = 0;
isPrimaryTokenAutoInsert = false;
}
bool SuggestionList::contains(const WeightedToken &element) const {
return indexOf(element).has_value();
}
bool SuggestionList::containsWord(const word_t &word) const {
return indexOfWord(word).has_value();
}
const WeightedToken *SuggestionList::get(size_t index) const {
if (index < 0 || index >= internalSize) return nullptr;
return &tokens[index];
}
std::optional<size_t> SuggestionList::indexOf(const WeightedToken &element) const {
for (size_t n = 0; n < internalSize; n++) {
if (element == tokens[n]) {
return n;
}
}
return std::nullopt;
}
std::optional<size_t> SuggestionList::indexOfWord(const word_t &word) const {
for (size_t n = 0; n < internalSize; n++) {
if (word == tokens[n].data) {
return n;
}
}
return std::nullopt;
}
bool SuggestionList::isEmpty() const {
return internalSize == 0;
}
size_t SuggestionList::size() const {
return internalSize;
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
#ifndef FLORISBOARD_SUGGESTION_LIST_H
#define FLORISBOARD_SUGGESTION_LIST_H
#include <optional>
#include <vector>
#include "token.h"
namespace ime::nlp {
class SuggestionList {
public:
SuggestionList(size_t _maxSize);
~SuggestionList();
bool add(word_t &&word, freq_t &&freq);
void clear();
bool contains(const WeightedToken &element) const;
bool containsWord(const word_t &word) const;
const WeightedToken *get(size_t index) const;
std::optional<size_t> indexOf(const WeightedToken &element) const;
std::optional<size_t> indexOfWord(const word_t &word) const;
bool isEmpty() const;
size_t size() const;
bool isPrimaryTokenAutoInsert;
private:
std::vector<WeightedToken> tokens;
size_t internalSize;
size_t maxSize;
};
} // namespace ime::nlp
#endif // FLORISBOARD_SUGGESTION_LIST_H

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
#include "token.h"
#include <utility>
namespace ime::nlp {
Token::Token() : data() {}
Token::Token(word_t &&_data) : data(std::move(_data)) {}
bool operator==(const Token &t1, const Token &t2) {
return t1.data == t2.data;
}
bool operator!=(const Token &t1, const Token &t2) {
return !(t1 == t2);
}
WeightedToken::WeightedToken() : Token(), freq(0) {}
WeightedToken::WeightedToken(word_t &&_data, freq_t _freq) : Token(std::move(_data)), freq(_freq) {}
bool operator==(const WeightedToken &t1, const WeightedToken &t2) {
return t1.data == t2.data && t1.freq == t2.freq;
}
bool operator!=(const WeightedToken &t1, const WeightedToken &t2) {
return !(t1 == t2);
}
bool operator<(const WeightedToken &t1, const WeightedToken &t2) {
return t1.freq < t2.freq;
}
bool operator<=(const WeightedToken &t1, const WeightedToken &t2) {
return t1.freq <= t2.freq;
}
bool operator>(const WeightedToken &t1, const WeightedToken &t2) {
return t1.freq > t2.freq;
}
bool operator>=(const WeightedToken &t1, const WeightedToken &t2) {
return t1.freq >= t2.freq;
}
} // namespace ime::nlp

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
#ifndef FLORISBOARD_TOKEN_H
#define FLORISBOARD_TOKEN_H
#include "nlp.h"
#include <string>
namespace ime::nlp {
class Token {
public:
word_t data;
Token();
Token(word_t &&_data);
friend bool operator==(const Token &t1, const Token &t2);
friend bool operator!=(const Token &t1, const Token &t2);
};
class WeightedToken : public Token {
public:
freq_t freq;
WeightedToken();
WeightedToken(word_t &&_data, freq_t _freq);
friend bool operator==(const WeightedToken &t1, const WeightedToken &t2);
friend bool operator!=(const WeightedToken &t1, const WeightedToken &t2);
friend bool operator<(const WeightedToken &t1, const WeightedToken &t2);
friend bool operator<=(const WeightedToken &t1, const WeightedToken &t2);
friend bool operator>(const WeightedToken &t1, const WeightedToken &t2);
friend bool operator>=(const WeightedToken &t1, const WeightedToken &t2);
};
} // namespace ime::nlp
#endif // FLORISBOARD_TOKEN_H

View File

@@ -0,0 +1,10 @@
add_library(
# Name
ime-spelling
# Headers
spellingdict.h
# Sources
spellingdict.cpp
)

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
#include "spellingdict.h"
#include "utils/log.h"
using namespace ime::spellcheck;
SpellingDict::SpellingDict(const nuspell::Dictionary& dict) : dictionary(std::make_unique<nuspell::Dictionary>(dict))
{ }
SpellingDict::~SpellingDict() = default;
SpellingDict* SpellingDict::load(const std::string &basePath) {
utils::start_stdout_stderr_logger("spell-floris");
try {
auto temp = nuspell::Dictionary::load_from_path(basePath);
auto spellingDict = new SpellingDict(temp);
return spellingDict;
} catch (const nuspell::Dictionary_Loading_Error& e) {
utils::log_error("SpellingDict.load()", e.what());
return nullptr;
} catch (...) {
utils::log_error("SpellingDict.load()", "An unknown error occurred!");
return nullptr;
}
}
bool SpellingDict::spell(const std::string& word) {
bool result = dictionary->spell(word);
return result;
}
std::vector<std::string> SpellingDict::suggest(const std::string &word) {
auto result = std::vector<std::string>();
dictionary->suggest(word, result);
return result;
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
#ifndef FLORISBOARD_SPELLINGDICT_H
#define FLORISBOARD_SPELLINGDICT_H
#include "nuspell/dictionary.hxx"
#include <string>
#include <vector>
namespace ime::spellcheck {
class SpellingDict {
public:
SpellingDict(const nuspell::Dictionary& dict);
~SpellingDict();
static SpellingDict* load(const std::string& basePath);
bool spell(const std::string& word);
std::vector<std::string> suggest(const std::string& word);
private:
std::unique_ptr<nuspell::Dictionary> dictionary;
};
} // namespace ime::spellcheck
#endif // FLORISBOARD_SPELLINGDICT_H

View File

@@ -0,0 +1,10 @@
add_library(nuspell
aff_data.cxx aff_data.hxx
checker.cxx checker.hxx
suggester.cxx suggester.hxx
dictionary.cxx dictionary.hxx
unicode.hxx
utils.cxx utils.hxx
structures.hxx)
add_library(Nuspell::nuspell ALIAS nuspell)

View File

@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,173 @@
/* Copyright 2016-2021 Dimitrij Mijoski
*
* This file is part of Nuspell.
*
* Nuspell is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nuspell is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Nuspell. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NUSPELL_AFF_DATA_HXX
#define NUSPELL_AFF_DATA_HXX
#include "nuspell_export.h"
#include "structures.hxx"
#include <iosfwd>
#include <unicode/locid.h>
namespace nuspell {
inline namespace v5 {
class Encoding {
std::string name;
NUSPELL_EXPORT auto normalize_name() -> void;
public:
enum Enc_Type { SINGLEBYTE = false, UTF8 = true };
Encoding() = default;
explicit Encoding(const std::string& e) : name(e) { normalize_name(); }
explicit Encoding(std::string&& e) : name(move(e)) { normalize_name(); }
explicit Encoding(const char* e) : name(e) { normalize_name(); }
auto& operator=(const std::string& e)
{
name = e;
normalize_name();
return *this;
}
auto& operator=(std::string&& e)
{
name = move(e);
normalize_name();
return *this;
}
auto& operator=(const char* e)
{
name = e;
normalize_name();
return *this;
}
auto empty() const { return name.empty(); }
auto& value() const { return name; }
auto is_utf8() const { return name == "UTF-8"; }
auto value_or_default() const -> std::string
{
if (name.empty())
return "ISO8859-1";
else
return name;
}
operator Enc_Type() const { return is_utf8() ? UTF8 : SINGLEBYTE; }
};
enum class Flag_Type { SINGLE_CHAR, DOUBLE_CHAR, NUMBER, UTF8 };
/**
* @internal
* @brief Map between words and word_flags.
*
* Flags are stored as part of the container. Maybe for the future flags should
* be stored elsewhere (flag aliases) and this should store pointers.
*
* Does not store morphological data as is low priority feature and is out of
* scope.
*/
using Word_List = Hash_Multimap<std::string, Flag_Set>;
struct Aff_Data {
static constexpr auto HIDDEN_HOMONYM_FLAG = char16_t(-1);
static constexpr auto MAX_SUGGESTIONS = size_t(16);
// spell checking options
Word_List words;
Prefix_Table prefixes;
Suffix_Table suffixes;
bool complex_prefixes;
bool fullstrip;
bool checksharps;
bool forbid_warn;
char16_t compound_onlyin_flag;
char16_t circumfix_flag;
char16_t forbiddenword_flag;
char16_t keepcase_flag;
char16_t need_affix_flag;
char16_t warn_flag;
// compounding options
char16_t compound_flag;
char16_t compound_begin_flag;
char16_t compound_last_flag;
char16_t compound_middle_flag;
Compound_Rule_Table compound_rules;
// spell checking options
Break_Table break_table;
Substr_Replacer input_substr_replacer;
std::string ignored_chars;
icu::Locale icu_locale;
Substr_Replacer output_substr_replacer;
// suggestion options
Replacement_Table replacements;
std::vector<Similarity_Group> similarities;
std::string keyboard_closeness;
std::string try_chars;
// Phonetic_Table phonetic_table;
char16_t nosuggest_flag;
char16_t substandard_flag;
unsigned short max_compound_suggestions;
unsigned short max_ngram_suggestions;
unsigned short max_diff_factor;
bool only_max_diff;
bool no_split_suggestions;
bool suggest_with_dots;
// compounding options
unsigned short compound_min_length;
unsigned short compound_max_word_count;
char16_t compound_permit_flag;
char16_t compound_forbid_flag;
char16_t compound_root_flag;
char16_t compound_force_uppercase;
bool compound_more_suffixes;
bool compound_check_duplicate;
bool compound_check_rep;
bool compound_check_case;
bool compound_check_triple;
bool compound_simplified_triple;
bool compound_syllable_num;
unsigned short compound_syllable_max;
std::string compound_syllable_vowels;
std::vector<Compound_Pattern> compound_patterns;
// data members used only while parsing
Flag_Type flag_type;
Encoding encoding;
std::vector<Flag_Set> flag_aliases;
std::string wordchars; // deprecated?
auto parse_aff(std::istream& in) -> bool;
auto parse_dic(std::istream& in) -> bool;
auto parse_aff_dic(std::istream& aff, std::istream& dic)
{
if (parse_aff(aff))
return parse_dic(dic);
return false;
}
};
} // namespace v5
} // namespace nuspell
#endif // NUSPELL_AFF_DATA_HXX

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,352 @@
/* Copyright 2016-2021 Dimitrij Mijoski
*
* This file is part of Nuspell.
*
* Nuspell is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nuspell is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Nuspell. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NUSPELL_CHECKER_HXX
#define NUSPELL_CHECKER_HXX
#include "aff_data.hxx"
namespace nuspell {
inline namespace v5 {
enum Affixing_Mode {
FULL_WORD,
AT_COMPOUND_BEGIN,
AT_COMPOUND_END,
AT_COMPOUND_MIDDLE
};
struct Affixing_Result_Base {
Word_List::const_pointer root_word = {};
operator Word_List::const_pointer() const { return root_word; }
auto& operator*() const { return *root_word; }
auto operator->() const { return root_word; }
};
template <class T1 = void, class T2 = void>
struct Affixing_Result : Affixing_Result_Base {
const T1* a = {};
const T2* b = {};
Affixing_Result() = default;
Affixing_Result(Word_List::const_reference r, const T1& a, const T2& b)
: Affixing_Result_Base{&r}, a{&a}, b{&b}
{
}
};
template <class T1>
struct Affixing_Result<T1, void> : Affixing_Result_Base {
const T1* a = {};
Affixing_Result() = default;
Affixing_Result(Word_List::const_reference r, const T1& a)
: Affixing_Result_Base{&r}, a{&a}
{
}
};
template <>
struct Affixing_Result<void, void> : Affixing_Result_Base {
Affixing_Result() = default;
Affixing_Result(Word_List::const_reference r) : Affixing_Result_Base{&r}
{
}
};
struct Compounding_Result {
Word_List::const_pointer word_entry = {};
unsigned char num_words_modifier = {};
signed char num_syllable_modifier = {};
bool affixed_and_modified = {}; /**< non-zero affix */
operator Word_List::const_pointer() const { return word_entry; }
auto& operator*() const { return *word_entry; }
auto operator->() const { return word_entry; }
};
struct Checker : public Aff_Data {
enum Forceucase : bool {
FORBID_BAD_FORCEUCASE = false,
ALLOW_BAD_FORCEUCASE = true
};
enum Hidden_Homonym : bool {
ACCEPT_HIDDEN_HOMONYM = false,
SKIP_HIDDEN_HOMONYM = true
};
Checker()
: Aff_Data() // we explicity do value init so content is zeroed
{
}
auto spell_priv(std::string& s) const -> bool;
auto spell_break(std::string& s, size_t depth = 0) const -> bool;
auto spell_casing(std::string& s) const -> const Flag_Set*;
auto spell_casing_upper(std::string& s) const -> const Flag_Set*;
auto spell_casing_title(std::string& s) const -> const Flag_Set*;
auto spell_sharps(std::string& base, size_t n_pos = 0, size_t n = 0,
size_t rep = 0) const -> const Flag_Set*;
auto check_word(std::string& s, Forceucase allow_bad_forceucase = {},
Hidden_Homonym skip_hidden_homonym = {}) const
-> const Flag_Set*;
auto check_simple_word(std::string& word,
Hidden_Homonym skip_hidden_homonym = {}) const
-> const Flag_Set*;
template <Affixing_Mode m>
auto affix_NOT_valid(const Prefix& a) const;
template <Affixing_Mode m>
auto affix_NOT_valid(const Suffix& a) const;
template <Affixing_Mode m, class AffixT>
auto outer_affix_NOT_valid(const AffixT& a) const;
template <class AffixT>
auto is_circumfix(const AffixT& a) const;
template <Affixing_Mode m>
auto is_valid_inside_compound(const Flag_Set& flags) const;
template <Affixing_Mode m = FULL_WORD>
auto strip_prefix_only(std::string& s,
Hidden_Homonym skip_hidden_homonym = {}) const
-> Affixing_Result<Prefix>;
template <Affixing_Mode m = FULL_WORD>
auto strip_suffix_only(std::string& s,
Hidden_Homonym skip_hidden_homonym = {}) const
-> Affixing_Result<Suffix>;
template <Affixing_Mode m = FULL_WORD>
auto
strip_prefix_then_suffix(std::string& s,
Hidden_Homonym skip_hidden_homonym = {}) const
-> Affixing_Result<Suffix, Prefix>;
template <Affixing_Mode m>
auto strip_pfx_then_sfx_2(const Prefix& pe, std::string& s,
Hidden_Homonym skip_hidden_homonym) const
-> Affixing_Result<Suffix, Prefix>;
template <Affixing_Mode m = FULL_WORD>
auto
strip_suffix_then_prefix(std::string& s,
Hidden_Homonym skip_hidden_homonym = {}) const
-> Affixing_Result<Prefix, Suffix>;
template <Affixing_Mode m>
auto strip_sfx_then_pfx_2(const Suffix& se, std::string& s,
Hidden_Homonym skip_hidden_homonym) const
-> Affixing_Result<Prefix, Suffix>;
template <Affixing_Mode m = FULL_WORD>
auto strip_prefix_then_suffix_commutative(
std::string& word, Hidden_Homonym skip_hidden_homonym = {}) const
-> Affixing_Result<Suffix, Prefix>;
template <Affixing_Mode m = FULL_WORD>
auto strip_pfx_then_sfx_comm_2(const Prefix& pe, std::string& word,
Hidden_Homonym skip_hidden_homonym) const
-> Affixing_Result<Suffix, Prefix>;
template <Affixing_Mode m = FULL_WORD>
auto
strip_suffix_then_suffix(std::string& s,
Hidden_Homonym skip_hidden_homonym = {}) const
-> Affixing_Result<Suffix, Suffix>;
template <Affixing_Mode m>
auto strip_sfx_then_sfx_2(const Suffix& se1, std::string& s,
Hidden_Homonym skip_hidden_homonym) const
-> Affixing_Result<Suffix, Suffix>;
template <Affixing_Mode m = FULL_WORD>
auto
strip_prefix_then_prefix(std::string& s,
Hidden_Homonym skip_hidden_homonym = {}) const
-> Affixing_Result<Prefix, Prefix>;
template <Affixing_Mode m>
auto strip_pfx_then_pfx_2(const Prefix& pe1, std::string& s,
Hidden_Homonym skip_hidden_homonym) const
-> Affixing_Result<Prefix, Prefix>;
template <Affixing_Mode m = FULL_WORD>
auto strip_prefix_then_2_suffixes(
std::string& s, Hidden_Homonym skip_hidden_homonym = {}) const
-> Affixing_Result<>;
template <Affixing_Mode m>
auto strip_pfx_2_sfx_3(const Prefix& pe1, const Suffix& se1,
std::string& s,
Hidden_Homonym skip_hidden_homonym) const
-> Affixing_Result<>;
template <Affixing_Mode m = FULL_WORD>
auto strip_suffix_prefix_suffix(
std::string& s, Hidden_Homonym skip_hidden_homonym = {}) const
-> Affixing_Result<>;
template <Affixing_Mode m>
auto strip_s_p_s_3(const Suffix& se1, const Prefix& pe1,
std::string& word,
Hidden_Homonym skip_hidden_homonym) const
-> Affixing_Result<>;
template <Affixing_Mode m = FULL_WORD>
auto strip_2_suffixes_then_prefix(
std::string& s, Hidden_Homonym skip_hidden_homonym = {}) const
-> Affixing_Result<>;
template <Affixing_Mode m>
auto strip_2_sfx_pfx_3(const Suffix& se1, const Suffix& se2,
std::string& word,
Hidden_Homonym skip_hidden_homonym) const
-> Affixing_Result<>;
template <Affixing_Mode m = FULL_WORD>
auto strip_suffix_then_2_prefixes(
std::string& s, Hidden_Homonym skip_hidden_homonym = {}) const
-> Affixing_Result<>;
template <Affixing_Mode m>
auto strip_sfx_2_pfx_3(const Suffix& se1, const Prefix& pe1,
std::string& s,
Hidden_Homonym skip_hidden_homonym) const
-> Affixing_Result<>;
template <Affixing_Mode m = FULL_WORD>
auto strip_prefix_suffix_prefix(
std::string& word, Hidden_Homonym skip_hidden_homonym = {}) const
-> Affixing_Result<>;
template <Affixing_Mode m>
auto strip_p_s_p_3(const Prefix& pe1, const Suffix& se1,
std::string& word,
Hidden_Homonym skip_hidden_homonym) const
-> Affixing_Result<>;
template <Affixing_Mode m = FULL_WORD>
auto strip_2_prefixes_then_suffix(
std::string& word, Hidden_Homonym skip_hidden_homonym = {}) const
-> Affixing_Result<>;
template <Affixing_Mode m>
auto strip_2_pfx_sfx_3(const Prefix& pe1, const Prefix& pe2,
std::string& word,
Hidden_Homonym skip_hidden_homonym) const
-> Affixing_Result<>;
auto check_compound(std::string& word,
Forceucase allow_bad_forceucase) const
-> Compounding_Result;
template <Affixing_Mode m = AT_COMPOUND_BEGIN>
auto check_compound(std::string& word, size_t start_pos,
size_t num_part, std::string& part,
Forceucase allow_bad_forceucase) const
-> Compounding_Result;
template <Affixing_Mode m = AT_COMPOUND_BEGIN>
auto check_compound_classic(std::string& word, size_t start_pos,
size_t i, size_t num_part,
std::string& part,
Forceucase allow_bad_forceucase) const
-> Compounding_Result;
template <Affixing_Mode m = AT_COMPOUND_BEGIN>
auto check_compound_with_pattern_replacements(
std::string& word, size_t start_pos, size_t i, size_t num_part,
std::string& part, Forceucase allow_bad_forceucase) const
-> Compounding_Result;
template <Affixing_Mode m>
auto check_word_in_compound(std::string& s) const -> Compounding_Result;
auto calc_num_words_modifier(const Prefix& pfx) const -> unsigned char;
template <Affixing_Mode m>
auto calc_syllable_modifier(Word_List::const_reference we) const
-> signed char;
template <Affixing_Mode m>
auto calc_syllable_modifier(Word_List::const_reference we,
const Suffix& sfx) const -> signed char;
auto count_syllables(std::string_view word) const -> size_t;
auto check_compound_with_rules(std::string& word,
std::vector<const Flag_Set*>& words_data,
size_t start_pos, std::string& part,
Forceucase allow_bad_forceucase) const
-> Compounding_Result;
auto is_rep_similar(std::string& word) const -> bool;
};
template <Affixing_Mode m>
auto Checker::affix_NOT_valid(const Prefix& e) const
{
if (m == FULL_WORD && e.cont_flags.contains(compound_onlyin_flag))
return true;
if (m == AT_COMPOUND_END &&
!e.cont_flags.contains(compound_permit_flag))
return true;
if (m != FULL_WORD && e.cont_flags.contains(compound_forbid_flag))
return true;
return false;
}
template <Affixing_Mode m>
auto Checker::affix_NOT_valid(const Suffix& e) const
{
if (m == FULL_WORD && e.cont_flags.contains(compound_onlyin_flag))
return true;
if (m == AT_COMPOUND_BEGIN &&
!e.cont_flags.contains(compound_permit_flag))
return true;
if (m != FULL_WORD && e.cont_flags.contains(compound_forbid_flag))
return true;
return false;
}
template <Affixing_Mode m, class AffixT>
auto Checker::outer_affix_NOT_valid(const AffixT& e) const
{
if (affix_NOT_valid<m>(e))
return true;
if (e.cont_flags.contains(need_affix_flag))
return true;
return false;
}
template <class AffixT>
auto Checker::is_circumfix(const AffixT& a) const
{
return a.cont_flags.contains(circumfix_flag);
}
template <class AffixInner, class AffixOuter>
auto cross_valid_inner_outer(const AffixInner& inner, const AffixOuter& outer)
{
return inner.cont_flags.contains(outer.flag);
}
template <class Affix>
auto cross_valid_inner_outer(const Flag_Set& word_flags, const Affix& afx)
{
return word_flags.contains(afx.flag);
}
} // namespace v5
} // namespace nuspell
#endif // NUSPELL_CHECKER_HXX

View File

@@ -0,0 +1 @@
clang-format -style=file -i *.[ch]xx

View File

@@ -0,0 +1,115 @@
/* Copyright 2016-2021 Dimitrij Mijoski
*
* This file is part of Nuspell.
*
* Nuspell is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nuspell is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Nuspell. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dictionary.hxx"
#include "utils.hxx"
#include <fstream>
#include <iostream>
#include <stdexcept>
using namespace std;
namespace nuspell {
inline namespace v5 {
Dictionary::Dictionary(std::istream& aff, std::istream& dic)
{
if (!parse_aff_dic(aff, dic))
throw Dictionary_Loading_Error("error parsing");
}
Dictionary::Dictionary() = default;
/**
* @brief Create a dictionary from opened files as iostreams
*
* Prefer using load_from_path(). Use this if you have a specific use case,
* like when .aff and .dic are in-memory buffers istringstream.
*
* @param aff The iostream of the .aff file
* @param dic The iostream of the .dic file
* @return Dictionary object
* @throws Dictionary_Loading_Error on error
*/
auto Dictionary::load_from_aff_dic(std::istream& aff, std::istream& dic)
-> Dictionary
{
return Dictionary(aff, dic);
}
/**
* @brief Create a dictionary from files
* @param file_path_without_extension path *without* extensions (without .dic or
* .aff)
* @return Dictionary object
* @throws Dictionary_Loading_Error on error
*/
auto Dictionary::load_from_path(const std::string& file_path_without_extension)
-> Dictionary
{
auto path = file_path_without_extension;
path += ".aff";
std::ifstream aff_file(path);
if (aff_file.fail()) {
auto err = "Aff file " + path + " not found";
throw Dictionary_Loading_Error(err);
}
path.replace(path.size() - 3, 3, "dic");
std::ifstream dic_file(path);
if (dic_file.fail()) {
auto err = "Dic file " + path + " not found";
throw Dictionary_Loading_Error(err);
}
return load_from_aff_dic(aff_file, dic_file);
}
/**
* @brief Checks if a given word is correct
* @param word any word
* @return true if correct, false otherwise
*/
auto Dictionary::spell(std::string_view word) const -> bool
{
auto ok_enc = validate_utf8(word);
if (unlikely(word.size() > 360))
return false;
if (unlikely(!ok_enc))
return false;
auto word_buf = string(word);
return spell_priv(word_buf);
}
/**
* @brief Suggests correct words for a given incorrect word
* @param[in] word incorrect word
* @param[out] out this object will be populated with the suggestions
*/
auto Dictionary::suggest(std::string_view word,
std::vector<std::string>& out) const -> void
{
out.clear();
auto ok_enc = validate_utf8(word);
if (unlikely(word.size() > 360))
return;
if (unlikely(!ok_enc))
return;
suggest_priv(word, out);
}
} // namespace v5
} // namespace nuspell

View File

@@ -0,0 +1,59 @@
/* Copyright 2016-2021 Dimitrij Mijoski
*
* This file is part of Nuspell.
*
* Nuspell is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nuspell is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Nuspell. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file
* @brief Dictionary spelling.
*/
#ifndef NUSPELL_DICTIONARY_HXX
#define NUSPELL_DICTIONARY_HXX
#include "suggester.hxx"
namespace nuspell {
inline namespace v5 {
/**
* @brief The only important public exception
*/
class Dictionary_Loading_Error : public std::runtime_error {
public:
using std::runtime_error::runtime_error;
};
/**
* @brief The only important public class
*/
class NUSPELL_EXPORT Dictionary : private Suggester {
Dictionary(std::istream& aff, std::istream& dic);
public:
Dictionary();
auto static load_from_aff_dic(std::istream& aff, std::istream& dic)
-> Dictionary;
auto static load_from_path(
const std::string& file_path_without_extension) -> Dictionary;
auto spell(std::string_view word) const -> bool;
auto suggest(std::string_view word, std::vector<std::string>& out) const
-> void;
};
} // namespace v5
} // namespace nuspell
#endif // NUSPELL_DICTIONARY_HXX

View File

@@ -0,0 +1,18 @@
#ifndef NUSPELL_EXPORT_H
#define NUSPELL_EXPORT_H
#ifdef NUSPELL_STATIC_DEFINE
# define NUSPELL_EXPORT
#elif defined(_WIN32) || defined(__CYGWIN__)
# ifdef nuspell_EXPORTS // Define this only when building Nuspell as DLL on Windows, not when using the DLL.
# define NUSPELL_EXPORT __declspec(dllexport)
# else
# define NUSPELL_EXPORT __declspec(dllimport)
# endif
#elif __GNUC__ >= 4
# define NUSPELL_EXPORT __attribute__((visibility("default")))
#else
# define NUSPELL_EXPORT
#endif
#endif /* NUSPELL_EXPORT_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,97 @@
/* Copyright 2016-2021 Dimitrij Mijoski
*
* This file is part of Nuspell.
*
* Nuspell is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nuspell is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Nuspell. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NUSPELL_SUGGESTER_HXX
#define NUSPELL_SUGGESTER_HXX
#include "checker.hxx"
namespace nuspell {
inline namespace v5 {
struct NUSPELL_EXPORT Suggester : public Checker {
enum High_Quality_Sugs : bool {
ALL_LOW_QUALITY_SUGS = false,
HAS_HIGH_QUALITY_SUGS = true
};
auto suggest_priv(std::string_view input_word, List_Strings& out) const
-> void;
auto suggest_low(std::string& word, List_Strings& out) const
-> High_Quality_Sugs;
auto add_sug_if_correct(std::string& word, List_Strings& out) const
-> bool;
auto uppercase_suggest(const std::string& word, List_Strings& out) const
-> void;
auto rep_suggest(std::string& word, List_Strings& out) const -> void;
auto try_rep_suggestion(std::string& word, List_Strings& out) const
-> void;
auto max_attempts_for_long_alogs(std::string_view word) const -> size_t;
auto map_suggest(std::string& word, List_Strings& out) const -> void;
auto map_suggest(std::string& word, List_Strings& out, size_t i,
size_t& remaining_attempts) const -> void;
auto adjacent_swap_suggest(std::string& word, List_Strings& out) const
-> void;
auto distant_swap_suggest(std::string& word, List_Strings& out) const
-> void;
auto keyboard_suggest(std::string& word, List_Strings& out) const
-> void;
auto extra_char_suggest(std::string& word, List_Strings& out) const
-> void;
auto forgotten_char_suggest(std::string& word, List_Strings& out) const
-> void;
auto move_char_suggest(std::string& word, List_Strings& out) const
-> void;
auto bad_char_suggest(std::string& word, List_Strings& out) const
-> void;
auto doubled_two_chars_suggest(std::string& word,
List_Strings& out) const -> void;
auto two_words_suggest(const std::string& word, List_Strings& out) const
-> void;
auto ngram_suggest(const std::string& word_u8, List_Strings& out) const
-> void;
auto expand_root_word_for_ngram(Word_List::const_reference root,
std::string_view wrong,
List_Strings& expanded_list,
std::vector<bool>& cross_affix) const
-> void;
};
} // namespace v5
} // namespace nuspell
#endif // NUSPELL_SUGGESTER_HXX

View File

@@ -0,0 +1,383 @@
/* Copyright 2021 Dimitrij Mijoski
*
* This file is part of Nuspell.
*
* Nuspell is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nuspell is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Nuspell. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NUSPELL_UNICODE_HXX
#define NUSPELL_UNICODE_HXX
#include <string>
#include <string_view>
#include <unicode/utf16.h>
#include <unicode/utf8.h>
namespace nuspell {
inline namespace v5 {
// UTF-8, work on malformed
inline constexpr auto u8_max_cp_length = U8_MAX_LENGTH;
auto inline u8_is_cp_error(int32_t cp) -> bool { return cp < 0; }
template <class Range>
auto u8_advance_cp(const Range& str, size_t& i, int32_t& cp) -> void
{
using std::size, std::data;
#if U_ICU_VERSION_MAJOR_NUM <= 60
auto s_ptr = data(str);
int32_t idx = i;
int32_t len = size(str);
U8_NEXT(s_ptr, idx, len, cp);
i = idx;
#else
auto len = size(str);
U8_NEXT(str, i, len, cp);
#endif
}
template <class Range>
auto u8_advance_index(const Range& str, size_t& i) -> void
{
using std::size;
auto len = size(str);
U8_FWD_1(str, i, len);
}
template <class Range>
auto u8_reverse_cp(const Range& str, size_t& i, int32_t& cp) -> void
{
using std::size, std::data;
auto ptr = data(str);
int32_t idx = i;
U8_PREV(ptr, 0, idx, cp);
i = idx;
}
template <class Range>
auto u8_reverse_index(const Range& str, size_t& i) -> void
{
using std::size, std::data;
auto ptr = data(str);
int32_t idx = i;
U8_BACK_1(ptr, 0, idx);
i = idx;
}
template <class Range>
auto u8_write_cp_and_advance(Range& buf, size_t& i, int32_t cp, bool& error)
-> void
{
using std::size, std::data;
#if U_ICU_VERSION_MAJOR_NUM <= 60
auto ptr = data(buf);
int32_t idx = i;
int32_t len = size(buf);
U8_APPEND(buf, idx, len, cp, error);
i = idx;
#else
auto len = size(buf);
U8_APPEND(buf, i, len, cp, error);
#endif
}
// UTF-8, valid
template <class Range>
auto valid_u8_advance_cp(const Range& str, size_t& i, char32_t& cp) -> void
{
U8_NEXT_UNSAFE(str, i, cp);
}
template <class Range>
auto valid_u8_advance_index(const Range& str, size_t& i) -> void
{
U8_FWD_1_UNSAFE(str, i);
}
template <class Range>
auto valid_u8_reverse_cp(const Range& str, size_t& i, char32_t& cp) -> void
{
U8_PREV_UNSAFE(str, i, cp);
}
template <class Range>
auto valid_u8_reverse_index(const Range& str, size_t& i) -> void
{
U8_BACK_1_UNSAFE(str, i);
}
template <class Range>
auto valid_u8_write_cp_and_advance(Range& buf, size_t& i, char32_t cp) -> void
{
U8_APPEND_UNSAFE(buf, i, cp);
}
// UTF-16, work on malformed
inline constexpr auto u16_max_cp_length = U16_MAX_LENGTH;
auto inline u16_is_cp_error(int32_t cp) -> bool { return U_IS_SURROGATE(cp); }
template <class Range>
auto u16_advance_cp(const Range& str, size_t& i, int32_t& cp) -> void
{
using std::size;
auto len = size(str);
U16_NEXT(str, i, len, cp);
}
template <class Range>
auto u16_advance_index(const Range& str, size_t& i) -> void
{
using std::size;
auto len = size(str);
U16_FWD_1(str, i, len);
}
template <class Range>
auto u16_reverse_cp(const Range& str, size_t& i, int32_t& cp) -> void
{
U16_PREV(str, 0, i, cp);
}
template <class Range>
auto u16_reverse_index(const Range& str, size_t& i) -> void
{
U16_BACK_1(str, 0, i);
}
template <class Range>
auto u16_write_cp_and_advance(Range& buf, size_t& i, int32_t cp, bool& error)
-> void
{
using std::size;
auto len = size(buf);
U16_APPEND(buf, i, len, cp, error);
}
// UTF-16, valid
template <class Range>
auto valid_u16_advance_cp(const Range& str, size_t& i, char32_t& cp) -> void
{
U16_NEXT_UNSAFE(str, i, cp);
}
template <class Range>
auto valid_u16_advance_index(const Range& str, size_t& i) -> void
{
U16_FWD_1_UNSAFE(str, i);
}
template <class Range>
auto valid_u16_reverse_cp(const Range& str, size_t& i, char32_t& cp) -> void
{
U16_PREV_UNSAFE(str, i, cp);
}
template <class Range>
auto valid_u16_reverse_index(const Range& str, size_t& i) -> void
{
U16_BACK_1_UNSAFE(str, i);
}
template <class Range>
auto valid_u16_write_cp_and_advance(Range& buf, size_t& i, char32_t cp) -> void
{
U16_APPEND_UNSAFE(buf, i, cp);
}
// higer level funcs
struct U8_CP_Pos {
size_t begin_i = 0;
size_t end_i = begin_i;
};
class U8_Encoded_CP {
char d[u8_max_cp_length];
int sz;
public:
explicit U8_Encoded_CP(std::string_view str, U8_CP_Pos pos)
: sz(pos.end_i - pos.begin_i)
{
auto i = sz;
auto j = pos.end_i;
auto max_len = 4;
do {
d[--i] = str[--j];
} while (i && --max_len);
}
U8_Encoded_CP(char32_t cp)
{
size_t z = 0;
valid_u8_write_cp_and_advance(d, z, cp);
sz = z;
}
auto size() const noexcept -> size_t { return sz; }
auto data() const noexcept -> const char* { return d; }
operator std::string_view() const noexcept
{
return std::string_view(data(), size());
}
auto copy_to(std::string& str, size_t j) const
{
auto i = sz;
j += sz;
auto max_len = 4;
do {
str[--j] = d[--i];
} while (i && --max_len);
}
};
auto inline u8_swap_adjacent_cp(std::string& str, size_t i1, size_t i2,
size_t i3) -> size_t
{
auto cp1 = U8_Encoded_CP(str, {i1, i2});
auto cp2 = U8_Encoded_CP(str, {i2, i3});
auto new_i2 = i1 + std::size(cp2);
cp1.copy_to(str, new_i2);
cp2.copy_to(str, i1);
return new_i2;
}
auto inline u8_swap_cp(std::string& str, U8_CP_Pos pos1, U8_CP_Pos pos2)
-> std::pair<size_t, size_t>
{
using std::size;
auto cp1 = U8_Encoded_CP(str, pos1);
auto cp2 = U8_Encoded_CP(str, pos2);
auto new_p1_end_i = pos1.begin_i + size(cp2);
auto new_p2_begin_i = pos2.end_i - size(cp1);
std::char_traits<char>::move(&str[new_p1_end_i], &str[pos1.end_i],
pos2.begin_i - pos1.end_i);
cp2.copy_to(str, pos1.begin_i);
cp1.copy_to(str, new_p2_begin_i);
return {new_p1_end_i, new_p2_begin_i};
}
// bellow go func without out-parametars
// UTF-8, can be malformed, no out-parametars
struct Idx_And_Next_CP {
size_t end_i;
int32_t cp;
};
struct Idx_And_Prev_CP {
size_t begin_i;
int32_t cp;
};
struct Write_CP_Idx_and_Error {
size_t end_i;
bool error;
};
template <class Range>
[[nodiscard]] auto u8_next_cp(const Range& str, size_t i) -> Idx_And_Next_CP
{
int32_t cp;
u8_advance_cp(str, i, cp);
return {i, cp};
}
template <class Range>
[[nodiscard]] auto u8_next_index(const Range& str, size_t i) -> size_t
{
u8_advance_index(str, i);
return i;
}
template <class Range>
[[nodiscard]] auto u8_prev_cp(const Range& str, size_t i) -> Idx_And_Prev_CP
{
int32_t cp;
u8_reverse_cp(str, i, cp);
return {i, cp};
}
template <class Range>
[[nodiscard]] auto u8_prev_index(const Range& str, size_t i) -> size_t
{
u8_reverse_index(str, i);
return i;
}
template <class Range>
[[nodiscard]] auto u8_write_cp(Range& buf, size_t i, int32_t cp)
-> Write_CP_Idx_and_Error
{
bool err;
u8_write_cp_and_advance(buf, i, cp, err);
return {i, err};
}
// UTF-8, valid, no out-parametars
struct Idx_And_Next_CP_Valid {
size_t end_i;
char32_t cp;
};
struct Idx_And_Prev_CP_Valid {
size_t begin_i;
char32_t cp;
};
template <class Range>
[[nodiscard]] auto valid_u8_next_cp(const Range& str, size_t i)
-> Idx_And_Next_CP_Valid
{
char32_t cp;
valid_u8_advance_cp(str, i, cp);
return {i, cp};
}
template <class Range>
[[nodiscard]] auto valid_u8_next_index(const Range& str, size_t i) -> size_t
{
valid_u8_advance_index(str, i);
return i;
}
template <class Range>
[[nodiscard]] auto valid_u8_prev_cp(const Range& str, size_t i)
-> Idx_And_Prev_CP_Valid
{
char32_t cp;
valid_u8_reverse_cp(str, i, cp);
return {i, cp};
}
template <class Range>
[[nodiscard]] auto valid_u8_prev_index(const Range& str, size_t i) -> size_t
{
valid_u8_reverse_index(str, i);
return i;
}
template <class Range>
[[nodiscard]] auto valid_u8_write_cp(Range& buf, size_t i, int32_t cp) -> size_t
{
valid_u8_write_cp_and_advance(buf, i, cp);
return i;
}
} // namespace v5
} // namespace nuspell
#endif // NUSPELL_UNICODE_HXX

View File

@@ -0,0 +1,465 @@
/* Copyright 2016-2021 Dimitrij Mijoski
*
* This file is part of Nuspell.
*
* Nuspell is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nuspell is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Nuspell. If not, see <http://www.gnu.org/licenses/>.
*/
#include "utils.hxx"
#include "unicode.hxx"
#include <algorithm>
#include <limits>
#include <unicode/uchar.h>
#include <unicode/ucnv.h>
#include <unicode/unistr.h>
#include <unicode/ustring.h>
#if ' ' != 32 || '.' != 46 || 'A' != 65 || 'Z' != 90 || 'a' != 97 || 'z' != 122
#error "Basic execution character set is not ASCII"
#endif
using namespace std;
namespace nuspell {
inline namespace v5 {
template <class SepT>
static auto& split_on_any_of_low(std::string_view s, const SepT& sep,
std::vector<std::string>& out)
{
size_t i1 = 0;
size_t i2;
do {
i2 = s.find_first_of(sep, i1);
out.emplace_back(s.substr(i1, i2 - i1));
i1 = i2 + 1; // we can only add +1 if separator is single char.
// i2 gets s.npos after the last separator.
// Length of i2-i1 will always go past the end. That is defined.
} while (i2 != s.npos);
return out;
}
/**
* @internal
* @brief Splits string on single char seperator.
*
* Consecutive separators are treated as separate and will emit empty strings.
*
* @param s string to split.
* @param sep char that acts as separator to split on.
* @param out vector where separated strings are appended.
* @return @p out.
*/
auto split(std::string_view s, char sep, std::vector<std::string>& out)
-> std::vector<std::string>&
{
return split_on_any_of_low(s, sep, out);
}
/**
* @internal
* @brief Splits string on set of single char seperators.
*
* Consecutive separators are treated as separate and will emit empty strings.
*
* @param s string to split.
* @param sep seperator(s) to split on.
* @param out vector where separated strings are appended.
* @return @p out.
*/
auto split_on_any_of(std::string_view s, const char* sep,
std::vector<std::string>& out) -> std::vector<std::string>&
{
return split_on_any_of_low(s, sep, out);
}
auto utf32_to_utf8(std::u32string_view in, std::string& out) -> void
{
out.clear();
for (size_t i = 0; i != size(in); ++i) {
auto cp = in[i];
auto enc_cp = U8_Encoded_CP(cp);
out += enc_cp;
}
}
auto utf32_to_utf8(std::u32string_view in) -> std::string
{
auto out = string();
utf32_to_utf8(in, out);
return out;
}
auto valid_utf8_to_32(std::string_view in, std::u32string& out) -> void
{
out.clear();
for (size_t i = 0; i != size(in);) {
char32_t cp;
valid_u8_advance_cp(in, i, cp);
out.push_back(cp);
}
}
auto valid_utf8_to_32(std::string_view in) -> std::u32string
{
auto out = u32string();
valid_utf8_to_32(in, out);
return out;
}
auto utf8_to_16(std::string_view in) -> std::u16string
{
auto out = u16string();
utf8_to_16(in, out);
return out;
}
bool utf8_to_16(std::string_view in, std::u16string& out)
{
int32_t len;
auto err = U_ZERO_ERROR;
u_strFromUTF8(data(out), size(out), &len, data(in), size(in), &err);
out.resize(len);
if (err == U_BUFFER_OVERFLOW_ERROR) {
err = U_ZERO_ERROR;
u_strFromUTF8(data(out), size(out), &len, data(in), size(in),
&err);
}
if (U_SUCCESS(err))
return true;
out.clear();
return false;
}
bool validate_utf8(string_view s)
{
auto err = U_ZERO_ERROR;
u_strFromUTF8(nullptr, 0, nullptr, data(s), size(s), &err);
if (err == U_INVALID_CHAR_FOUND)
return false;
return err == U_BUFFER_OVERFLOW_ERROR || U_SUCCESS(err);
}
auto static is_ascii(char c) -> bool
{
return static_cast<unsigned char>(c) <= 127;
}
auto is_all_ascii(std::string_view s) -> bool
{
return all_of(begin(s), end(s), is_ascii);
}
auto static widen_latin1(char c) -> char16_t
{
return static_cast<unsigned char>(c);
}
auto latin1_to_ucs2(std::string_view s) -> std::u16string
{
u16string ret;
latin1_to_ucs2(s, ret);
return ret;
}
auto latin1_to_ucs2(std::string_view s, std::u16string& out) -> void
{
out.resize(s.size());
transform(begin(s), end(s), begin(out), widen_latin1);
}
auto static is_surrogate_pair(char16_t c) -> bool
{
return 0xD800 <= c && c <= 0xDFFF;
}
auto is_all_bmp(std::u16string_view s) -> bool
{
return none_of(begin(s), end(s), is_surrogate_pair);
}
auto to_upper_ascii(std::string& s) -> void
{
auto& char_type = use_facet<ctype<char>>(locale::classic());
char_type.toupper(begin_ptr(s), end_ptr(s));
}
auto static utf32_to_icu(u32string_view in) -> icu::UnicodeString
{
static_assert(sizeof(UChar32) == sizeof(char32_t));
return icu::UnicodeString::fromUTF32(
reinterpret_cast<const UChar32*>(in.data()), in.size());
}
auto static icu_to_utf32(const icu::UnicodeString& in, std::u32string& out)
-> bool
{
out.resize(in.length());
auto err = U_ZERO_ERROR;
auto len =
in.toUTF32(reinterpret_cast<UChar32*>(out.data()), out.size(), err);
if (U_SUCCESS(err)) {
out.erase(len);
return true;
}
out.clear();
return false;
}
auto to_upper(std::string_view in, const icu::Locale& loc) -> std::string
{
auto out = std::string();
to_upper(in, loc, out);
return out;
}
auto to_title(std::string_view in, const icu::Locale& loc) -> std::string
{
auto out = std::string();
to_title(in, loc, out);
return out;
}
auto to_lower(std::string_view in, const icu::Locale& loc) -> std::string
{
auto out = std::string();
to_lower(in, loc, out);
return out;
}
auto to_upper(string_view in, const icu::Locale& loc, string& out) -> void
{
auto sp = icu::StringPiece(data(in), size(in));
auto us = icu::UnicodeString::fromUTF8(sp);
us.toUpper(loc);
out.clear();
us.toUTF8String(out);
}
auto to_title(string_view in, const icu::Locale& loc, string& out) -> void
{
auto sp = icu::StringPiece(data(in), size(in));
auto us = icu::UnicodeString::fromUTF8(sp);
us.toTitle(nullptr, loc);
out.clear();
us.toUTF8String(out);
}
auto to_lower(u32string_view in, const icu::Locale& loc, u32string& out) -> void
{
auto us = utf32_to_icu(in);
us.toLower(loc);
icu_to_utf32(us, out);
}
auto to_lower(string_view in, const icu::Locale& loc, string& out) -> void
{
auto sp = icu::StringPiece(data(in), size(in));
auto us = icu::UnicodeString::fromUTF8(sp);
us.toLower(loc);
out.clear();
us.toUTF8String(out);
}
auto to_lower_char_at(std::string& s, size_t i, const icu::Locale& loc) -> void
{
auto cp = valid_u8_next_cp(s, i);
auto us = icu::UnicodeString(UChar32(cp.cp));
us.toLower(loc);
auto u8_low = string();
us.toUTF8String(u8_low);
s.replace(i, cp.end_i - i, u8_low);
}
auto to_title_char_at(std::string& s, size_t i, const icu::Locale& loc) -> void
{
auto cp = valid_u8_next_cp(s, i);
auto us = icu::UnicodeString(UChar32(cp.cp));
us.toTitle(nullptr, loc);
auto u8_title = string();
us.toUTF8String(u8_title);
s.replace(i, cp.end_i - i, u8_title);
}
/**
* @internal
* @brief Determines casing (capitalization) type for a word.
*
* Casing is sometimes referred to as capitalization.
*
* @param s word.
* @return The casing type.
*/
auto classify_casing(string_view s) -> Casing
{
size_t upper = 0;
size_t lower = 0;
for (size_t i = 0; i != size(s);) {
char32_t c;
valid_u8_advance_cp(s, i, c);
if (u_isupper(c))
upper++;
else if (u_islower(c))
lower++;
// else neutral
}
if (upper == 0) // all lowercase, maybe with some neutral
return Casing::SMALL; // most common case
auto first_cp = valid_u8_next_cp(s, 0);
auto first_capital = u_isupper(first_cp.cp);
if (first_capital && upper == 1)
return Casing::INIT_CAPITAL; // second most common
if (lower == 0)
return Casing::ALL_CAPITAL;
if (first_capital)
return Casing::PASCAL;
else
return Casing::CAMEL;
}
/**
* @internal
* @brief Check if word[i] or word[i-1] are uppercase
*
* Check if the two chars are alphabetic and at least one of them is in
* uppercase.
*
* @return true if at least one is uppercase, false otherwise.
*/
auto has_uppercase_at_compound_word_boundary(string_view word, size_t i) -> bool
{
auto cp = valid_u8_next_cp(word, i);
auto cp_prev = valid_u8_prev_cp(word, i);
if (u_isupper(cp.cp)) {
if (u_isalpha(cp_prev.cp))
return true;
}
else if (u_isupper(cp_prev.cp) && u_isalpha(cp.cp))
return true;
return false;
}
Encoding_Converter::Encoding_Converter(const char* enc)
{
auto err = UErrorCode();
cnv = ucnv_open(enc, &err);
}
Encoding_Converter::~Encoding_Converter()
{
if (cnv)
ucnv_close(cnv);
}
Encoding_Converter::Encoding_Converter(const Encoding_Converter& other)
{
auto err = UErrorCode();
cnv = ucnv_safeClone(other.cnv, nullptr, nullptr, &err);
}
auto Encoding_Converter::operator=(const Encoding_Converter& other)
-> Encoding_Converter&
{
this->~Encoding_Converter();
auto err = UErrorCode();
cnv = ucnv_safeClone(other.cnv, nullptr, nullptr, &err);
return *this;
}
auto Encoding_Converter::to_utf8(string_view in, string& out) -> bool
{
if (ucnv_getType(cnv) == UCNV_UTF8) {
if (validate_utf8(in)) {
out = in;
return true;
}
else {
out.clear();
return false;
}
}
auto err = U_ZERO_ERROR;
auto len = ucnv_toAlgorithmic(UCNV_UTF8, cnv, out.data(), out.size(),
in.data(), in.size(), &err);
out.resize(len);
if (err == U_BUFFER_OVERFLOW_ERROR) {
err = U_ZERO_ERROR;
ucnv_toAlgorithmic(UCNV_UTF8, cnv, out.data(), out.size(),
in.data(), in.size(), &err);
}
return U_SUCCESS(err);
}
auto replace_ascii_char(string& s, char from, char to) -> void
{
for (auto i = s.find(from); i != s.npos; i = s.find(from, i + 1)) {
s[i] = to;
}
}
auto erase_chars(string& s, string_view erase_chars) -> void
{
if (erase_chars.empty())
return;
for (size_t i = 0, next_i = 0; i != size(s); i = next_i) {
valid_u8_advance_index(s, next_i);
auto enc_cp = string_view(&s[i], next_i - i);
if (erase_chars.find(enc_cp) != erase_chars.npos) {
s.erase(i, next_i - i);
next_i = i;
}
}
return;
}
/**
* @internal
* @brief Tests if word is a number.
*
* Allow numbers with dot ".", dash "-" or comma "," inbetween the digits, but
* forbids double separators such as "..", "--" and ".,".
*/
auto is_number(string_view s) -> bool
{
if (s.empty())
return false;
auto it = begin(s);
if (s[0] == '-')
++it;
while (it != end(s)) {
auto next = std::find_if(
it, end(s), [](auto c) { return c < '0' || c > '9'; });
if (next == it)
return false;
if (next == end(s))
return true;
it = next;
auto c = *it;
if (c == '.' || c == ',' || c == '-')
++it;
else
return false;
}
return false;
}
auto count_appereances_of(string_view haystack, string_view needles) -> size_t
{
auto ret = size_t(0);
for (size_t i = 0, next_i = 0; i != size(haystack); i = next_i) {
valid_u8_advance_index(haystack, next_i);
auto enc_cp = string_view(&haystack[i], next_i - i);
ret += needles.find(enc_cp) != needles.npos;
}
return ret;
}
} // namespace v5
} // namespace nuspell

View File

@@ -0,0 +1,228 @@
/* Copyright 2016-2021 Dimitrij Mijoski
*
* This file is part of Nuspell.
*
* Nuspell is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nuspell is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Nuspell. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NUSPELL_UTILS_HXX
#define NUSPELL_UTILS_HXX
#include "nuspell_export.h"
#include <clocale>
#include <locale>
#include <string>
#include <string_view>
#include <vector>
#if !defined(_WIN32) && \
(defined(__unix__) || defined(__unix) || \
(defined(__APPLE__) && defined(__MACH__)) || defined(__HAIKU__))
#include <unistd.h>
#endif
#include <unicode/locid.h>
#ifdef __GNUC__
#define likely(expr) __builtin_expect(!!(expr), 1)
#define unlikely(expr) __builtin_expect(!!(expr), 0)
#else
#define likely(expr) (expr)
#define unlikely(expr) (expr)
#endif
struct UConverter; // unicode/ucnv.h
namespace nuspell {
inline namespace v5 {
auto split(std::string_view s, char sep, std::vector<std::string>& out)
-> std::vector<std::string>&;
NUSPELL_EXPORT auto split_on_any_of(std::string_view s, const char* sep,
std::vector<std::string>& out)
-> std::vector<std::string>&;
NUSPELL_EXPORT auto utf32_to_utf8(std::u32string_view in, std::string& out)
-> void;
NUSPELL_EXPORT auto utf32_to_utf8(std::u32string_view in) -> std::string;
auto valid_utf8_to_32(std::string_view in, std::u32string& out) -> void;
auto valid_utf8_to_32(std::string_view in) -> std::u32string;
auto utf8_to_16(std::string_view in) -> std::u16string;
auto utf8_to_16(std::string_view in, std::u16string& out) -> bool;
auto validate_utf8(std::string_view s) -> bool;
NUSPELL_EXPORT auto is_all_ascii(std::string_view s) -> bool;
NUSPELL_EXPORT auto latin1_to_ucs2(std::string_view s) -> std::u16string;
auto latin1_to_ucs2(std::string_view s, std::u16string& out) -> void;
NUSPELL_EXPORT auto is_all_bmp(std::u16string_view s) -> bool;
auto to_upper_ascii(std::string& s) -> void;
[[nodiscard]] NUSPELL_EXPORT auto to_upper(std::string_view in,
const icu::Locale& loc)
-> std::string;
[[nodiscard]] NUSPELL_EXPORT auto to_title(std::string_view in,
const icu::Locale& loc)
-> std::string;
[[nodiscard]] NUSPELL_EXPORT auto to_lower(std::string_view in,
const icu::Locale& loc)
-> std::string;
auto to_upper(std::string_view in, const icu::Locale& loc, std::string& out)
-> void;
auto to_title(std::string_view in, const icu::Locale& loc, std::string& out)
-> void;
auto to_lower(std::u32string_view in, const icu::Locale& loc,
std::u32string& out) -> void;
auto to_lower(std::string_view in, const icu::Locale& loc, std::string& out)
-> void;
auto to_lower_char_at(std::string& s, size_t i, const icu::Locale& loc) -> void;
auto to_title_char_at(std::string& s, size_t i, const icu::Locale& loc) -> void;
/**
* @internal
* @brief Enum that identifies the casing type of a word.
*
* Neutral characters like numbers are ignored, so "abc" and "abc123abc" are
* both classified as small.
*/
enum class Casing : char {
SMALL,
INIT_CAPITAL,
ALL_CAPITAL,
CAMEL /**< @internal camelCase i.e. mixed case with first small */,
PASCAL /**< @internal PascalCase i.e. mixed case with first capital */
};
NUSPELL_EXPORT auto classify_casing(std::string_view s) -> Casing;
auto has_uppercase_at_compound_word_boundary(std::string_view word, size_t i)
-> bool;
class Encoding_Converter {
UConverter* cnv = nullptr;
public:
Encoding_Converter() = default;
explicit Encoding_Converter(const char* enc);
explicit Encoding_Converter(const std::string& enc)
: Encoding_Converter(enc.c_str())
{
}
~Encoding_Converter();
Encoding_Converter(const Encoding_Converter& other);
Encoding_Converter(Encoding_Converter&& other) noexcept
{
cnv = other.cnv;
cnv = nullptr;
}
auto operator=(const Encoding_Converter& other) -> Encoding_Converter&;
auto operator=(Encoding_Converter&& other) noexcept
-> Encoding_Converter&
{
std::swap(cnv, other.cnv);
return *this;
}
auto to_utf8(std::string_view in, std::string& out) -> bool;
auto valid() -> bool { return cnv != nullptr; }
};
//#if _POSIX_VERSION >= 200809L
#if defined(_POSIX_VERSION) && !defined(__NetBSD__) && !defined(__HAIKU__)
class Setlocale_To_C_In_Scope {
locale_t old_loc = nullptr;
public:
Setlocale_To_C_In_Scope()
: old_loc{uselocale(newlocale(0, "C", nullptr))}
{
}
~Setlocale_To_C_In_Scope()
{
auto new_loc = uselocale(old_loc);
if (new_loc != old_loc)
freelocale(new_loc);
}
Setlocale_To_C_In_Scope(const Setlocale_To_C_In_Scope&) = delete;
};
#else
class Setlocale_To_C_In_Scope {
std::string old_name;
#ifdef _WIN32
int old_per_thread;
#endif
public:
Setlocale_To_C_In_Scope() : old_name(setlocale(LC_ALL, nullptr))
{
#ifdef _WIN32
old_per_thread = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
#endif
auto x = setlocale(LC_ALL, "C");
if (!x)
old_name.clear();
}
~Setlocale_To_C_In_Scope()
{
#ifdef _WIN32
_configthreadlocale(old_per_thread);
if (old_per_thread == _ENABLE_PER_THREAD_LOCALE)
#endif
{
if (!old_name.empty())
setlocale(LC_ALL, old_name.c_str());
}
}
Setlocale_To_C_In_Scope(const Setlocale_To_C_In_Scope&) = delete;
};
#endif
auto replace_ascii_char(std::string& s, char from, char to) -> void;
auto erase_chars(std::string& s, std::string_view erase_chars) -> void;
NUSPELL_EXPORT auto is_number(std::string_view s) -> bool;
auto count_appereances_of(std::string_view haystack, std::string_view needles)
-> size_t;
auto inline begins_with(std::string_view haystack, std::string_view needle)
-> bool
{
return haystack.compare(0, needle.size(), needle) == 0;
}
auto inline ends_with(std::string_view haystack, std::string_view needle)
-> bool
{
return haystack.size() >= needle.size() &&
haystack.compare(haystack.size() - needle.size(), needle.size(),
needle) == 0;
}
template <class T>
auto begin_ptr(T& x)
{
return x.data();
}
template <class T>
auto end_ptr(T& x)
{
return x.data() + x.size();
}
} // namespace v5
} // namespace nuspell
#endif // NUSPELL_UTILS_HXX

View File

@@ -0,0 +1,12 @@
add_library(
# Name
utils
# Headers
jni_utils.h
log.h
# Sources
jni_utils.cpp
log.cpp
)

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
#include "jni_utils.h"
#include "log.h"
std::string utils::j2std_string(JNIEnv *env, jobject jStr) {
auto cStr = reinterpret_cast<const char *>(env->GetDirectBufferAddress(jStr));
auto size = env->GetDirectBufferCapacity(jStr);
std::string stdStr(cStr, size);
log_debug("spell j2s", stdStr);
return stdStr;
}
jobject utils::std2j_string(JNIEnv *env, const std::string& stdStr) {
log_debug("spell s2j", stdStr);
size_t byteCount = stdStr.length();
auto cStr = stdStr.c_str();
auto buffer = env->NewDirectByteBuffer((void *) cStr, byteCount);
return buffer;
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
#ifndef FLORISBOARD_JNI_UTILS_H
#define FLORISBOARD_JNI_UTILS_H
#include <jni.h>
#include <string>
namespace utils {
std::string j2std_string(JNIEnv *env, jobject jStr);
jobject std2j_string(JNIEnv *env, const std::string& in);
} // namespace utils
#endif // FLORISBOARD_JNI_UTILS_H

View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
#include <android/log.h>
#include <unistd.h>
#include "log.h"
void utils::log_debug(const std::string &tag, const std::string &msg) {
__android_log_print(ANDROID_LOG_DEBUG, tag.c_str(), "%s", msg.c_str());
}
void utils::log_info(const std::string &tag, const std::string &msg) {
__android_log_print(ANDROID_LOG_INFO, tag.c_str(), "%s", msg.c_str());
}
void utils::log_warning(const std::string &tag, const std::string &msg) {
__android_log_print(ANDROID_LOG_WARN, tag.c_str(), "%s", msg.c_str());
}
void utils::log_error(const std::string &tag, const std::string &msg) {
__android_log_print(ANDROID_LOG_ERROR, tag.c_str(), "%s", msg.c_str());
}
void utils::log_wtf(const std::string &tag, const std::string &msg) {
__android_log_print(ANDROID_LOG_FATAL, tag.c_str(), "%s", msg.c_str());
}
/**
* Code below taken from here:
* https://codelab.wordpress.com/2014/11/03/how-to-use-standard-output-streams-for-logging-in-android-apps/
*/
static int pfd[2];
static pthread_t thr;
static const char *tag = "myapp";
static bool already_started = false;
static void *thread_func(void*) {
ssize_t rdsz;
char buf[2048];
while ((rdsz = read(pfd[0], buf, sizeof buf - 1)) > 0) {
if (buf[rdsz - 1] == '\n') --rdsz;
buf[rdsz] = 0; /* add null-terminator */
__android_log_write(ANDROID_LOG_DEBUG, tag, buf);
}
return nullptr;
}
int utils::start_stdout_stderr_logger(const char *app_name) {
if (already_started) return 0;
already_started = true;
tag = app_name;
/* make stdout line-buffered and stderr unbuffered */
setvbuf(stdout, nullptr, _IOLBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
/* create the pipe and redirect stdout and stderr */
pipe(pfd);
dup2(pfd[1], 1);
dup2(pfd[1], 2);
/* spawn the logging thread */
if (pthread_create(&thr, nullptr, thread_func, nullptr) != 0) {
return -1;
}
pthread_detach(thr);
return 0;
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
#ifndef FLORISBOARD_LOG_H
#define FLORISBOARD_LOG_H
#include <string>
namespace utils {
void log_debug(const std::string& tag, const std::string& msg);
void log_info(const std::string& tag, const std::string& msg);
void log_warning(const std::string& tag, const std::string& msg);
void log_error(const std::string& tag, const std::string& msg);
void log_wtf(const std::string& tag, const std::string& msg);
int start_stdout_stderr_logger(const char *app_name);
} // namespace utils
#endif // FLORISBOARD_LOG_H

1
app/src/main/icu4c Submodule

Submodule app/src/main/icu4c added at c434a473c5

View File

@@ -0,0 +1,141 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
package dev.patrickgold.florisboard
import android.app.Application
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import androidx.core.os.UserManagerCompat
import dev.patrickgold.florisboard.common.NativeStr
import dev.patrickgold.florisboard.common.toNativeStr
import dev.patrickgold.florisboard.crashutility.CrashUtility
import dev.patrickgold.florisboard.debug.Flog
import dev.patrickgold.florisboard.debug.LogTopic
import dev.patrickgold.florisboard.debug.flogError
import dev.patrickgold.florisboard.debug.flogInfo
import dev.patrickgold.florisboard.ime.core.Preferences
import dev.patrickgold.florisboard.ime.core.SubtypeManager
import dev.patrickgold.florisboard.ime.dictionary.DictionaryManager
import dev.patrickgold.florisboard.ime.spelling.SpellingManager
import dev.patrickgold.florisboard.ime.theme.ThemeManager
import dev.patrickgold.florisboard.res.AssetManager
import dev.patrickgold.florisboard.res.FlorisRef
import timber.log.Timber
import java.io.File
import kotlin.Exception
@Suppress("unused")
class FlorisApplication : Application() {
companion object {
private const val ICU_DATA_ASSET_PATH = "icu/icudt69l.dat"
private external fun nativeInitICUData(path: NativeStr): Int
init {
try {
System.loadLibrary("florisboard-native")
} catch (_: Exception) {
}
}
}
override fun onCreate() {
super.onCreate()
try {
if (BuildConfig.DEBUG) {
Timber.plant(Timber.DebugTree())
}
Flog.install(
applicationContext = this,
isFloggingEnabled = BuildConfig.DEBUG,
flogTopics = LogTopic.ALL,
flogLevels = Flog.LEVEL_ALL,
flogOutputs = Flog.OUTPUT_CONSOLE
)
initICU()
CrashUtility.install(this)
val prefs = Preferences.initDefault(this)
val assetManager = AssetManager.init(this)
SpellingManager.init(this, FlorisRef.assets("ime/spelling/config.json"))
SubtypeManager.init(this)
DictionaryManager.init(this)
ThemeManager.init(this, assetManager)
prefs.initDefaultPreferences()
} catch (e: Exception) {
CrashUtility.stageException(e)
return
}
/*Register a receiver so user config can be applied once device protracted storage is available*/
if(!UserManagerCompat.isUserUnlocked(this) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
registerReceiver(BootComplete(), IntentFilter(Intent.ACTION_USER_UNLOCKED))
}
}
fun initICU(): Boolean {
try {
val context = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
createDeviceProtectedStorageContext()
} else {
this
}
val androidAssetManager = context.assets ?: return false
val dstDataFile = File(context.cacheDir, "icudt.dat")
dstDataFile.outputStream().use { os ->
androidAssetManager.open(ICU_DATA_ASSET_PATH).use { it.copyTo(os) }
}
val status = nativeInitICUData(dstDataFile.absolutePath.toNativeStr())
return if (status != 0) {
flogError { "Native ICU data initializing failed with error code $status!" }
false
} else {
flogInfo { "Successfully loaded ICU data!" }
true
}
} catch (e: Exception) {
flogError { e.toString() }
return false
}
}
fun init() {
CrashUtility.install(this)
val prefs = Preferences.initDefault(this)
val assetManager = AssetManager.init(this)
SubtypeManager.init(this)
DictionaryManager.init(this)
ThemeManager.init(this, assetManager)
prefs.initDefaultPreferences()
}
private class BootComplete : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if(Intent.ACTION_USER_UNLOCKED == intent?.action){
try {
(context as FlorisApplication).unregisterReceiver(this)
context.init()
} catch (e : Exception) {
e.fillInStackTrace()
}
}
}
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
package dev.patrickgold.florisboard
import dev.patrickgold.florisboard.ime.core.FlorisBoard
/**
* This class only exists to prevent accidental IME deactivation after an update
* of FlorisBoard to a new version when the location of the FlorisBoard class has
* changed. The Android Framework uses the service class path as the IME id,
* using this extension here makes sure it won't change ever again for the system.
*
* Important: DO NOT PUT ANY LOGIC INTO THIS CLASS. Make the necessary changes
* within the FlorisBoard class instead.
*/
class FlorisImeService : FlorisBoard()

View File

@@ -0,0 +1,143 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
package dev.patrickgold.florisboard
import android.service.textservice.SpellCheckerService
import android.view.textservice.SentenceSuggestionsInfo
import android.view.textservice.SuggestionsInfo
import android.view.textservice.TextInfo
import dev.patrickgold.florisboard.common.FlorisLocale
import dev.patrickgold.florisboard.debug.LogTopic
import dev.patrickgold.florisboard.debug.flogInfo
import dev.patrickgold.florisboard.ime.core.Subtype
import dev.patrickgold.florisboard.ime.core.SubtypeManager
import dev.patrickgold.florisboard.ime.dictionary.DictionaryManager
import dev.patrickgold.florisboard.ime.spelling.SpellingService
import kotlinx.coroutines.runBlocking
class FlorisSpellCheckerService : SpellCheckerService() {
companion object {
private const val USE_FLORIS_SUBTYPES_LOCALE: String = "zz"
}
private val dictionaryManager get() = DictionaryManager.default()
private val spellingService: SpellingService = SpellingService.globalInstance()
private val subtypeManager get() = SubtypeManager.default()
override fun onCreate() {
flogInfo(LogTopic.SPELL_EVENTS)
super.onCreate()
dictionaryManager.loadUserDictionariesIfNecessary()
}
override fun createSession(): Session {
flogInfo(LogTopic.SPELL_EVENTS)
return FlorisSpellCheckerSession()
}
override fun onDestroy() {
flogInfo(LogTopic.SPELL_EVENTS)
super.onDestroy()
}
private inner class FlorisSpellCheckerSession : Session() {
private var cachedSpellingLocale: FlorisLocale? = null
override fun onCreate() {
flogInfo(LogTopic.SPELL_EVENTS) { "Session locale: $locale" }
setupSpellingIfNecessary()
}
private fun setupSpellingIfNecessary() {
val evaluatedLocale = when (locale) {
null -> Subtype.DEFAULT.locale
USE_FLORIS_SUBTYPES_LOCALE -> (subtypeManager.getActiveSubtype() ?: Subtype.DEFAULT).locale
else -> FlorisLocale.from(locale)
}
if (evaluatedLocale != cachedSpellingLocale) {
cachedSpellingLocale = evaluatedLocale
}
}
private fun spellMultiple(
spellingLocale: FlorisLocale,
textInfos: Array<out TextInfo>,
suggestionsLimit: Int
): Array<SuggestionsInfo> = runBlocking {
val retInfos = Array(textInfos.size) { n ->
val word = textInfos[n].text ?: ""
spellingService.spellAsync(spellingLocale, word, suggestionsLimit)
}
Array(textInfos.size) { n ->
retInfos[n].await().apply {
setCookieAndSequence(textInfos[n].cookie, textInfos[n].sequence)
}
}
}
override fun onGetSuggestions(textInfo: TextInfo?, suggestionsLimit: Int): SuggestionsInfo {
flogInfo(LogTopic.SPELL_EVENTS) { "text=${textInfo?.text}, limit=$suggestionsLimit" }
textInfo?.text ?: return SpellingService.emptySuggestionsInfo()
setupSpellingIfNecessary()
val spellingLocale = cachedSpellingLocale ?: return SpellingService.emptySuggestionsInfo()
return spellingService.spell(spellingLocale, textInfo.text, suggestionsLimit)
}
override fun onGetSuggestionsMultiple(
textInfos: Array<out TextInfo>?,
suggestionsLimit: Int,
sequentialWords: Boolean
): Array<SuggestionsInfo> {
flogInfo(LogTopic.SPELL_EVENTS)
textInfos ?: return emptyArray()
setupSpellingIfNecessary()
val spellingLocale = cachedSpellingLocale ?: return emptyArray()
return spellMultiple(spellingLocale, textInfos, suggestionsLimit)
}
override fun onGetSentenceSuggestionsMultiple(
textInfos: Array<out TextInfo>?,
suggestionsLimit: Int
): Array<SentenceSuggestionsInfo> {
flogInfo(LogTopic.SPELL_EVENTS)
// TODO: implement custom solution here instead of calling the default implementation
return super.onGetSentenceSuggestionsMultiple(textInfos, suggestionsLimit)
}
override fun onCancel() {
flogInfo(LogTopic.SPELL_EVENTS)
super.onCancel()
}
override fun onClose() {
flogInfo(LogTopic.SPELL_EVENTS)
super.onClose()
}
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package dev.patrickgold.florisboard.ime.core
package dev.patrickgold.florisboard.common
import android.content.ClipData
import android.content.ClipboardManager
@@ -26,6 +26,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.viewbinding.ViewBinding
import com.google.android.material.snackbar.Snackbar
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.core.Preferences
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
@@ -64,12 +65,12 @@ abstract class FlorisActivity<V : ViewBinding> : AppCompatActivity(), CoroutineS
messageSnackbar = null
}
protected fun showMessage(@StringRes snackbarMessageResId: Int) {
fun showMessage(@StringRes snackbarMessageResId: Int) {
val snackbarMessage = resources.getString(snackbarMessageResId)
showMessage(snackbarMessage)
}
protected fun showMessage(snackbarMessage: String) {
fun showMessage(snackbarMessage: String) {
messageSnackbar?.dismiss()
messageSnackbar = Snackbar.make(binding.root, snackbarMessage, Snackbar.LENGTH_LONG).apply {
setAction(android.R.string.ok) {
@@ -78,39 +79,43 @@ abstract class FlorisActivity<V : ViewBinding> : AppCompatActivity(), CoroutineS
show() }
}
protected fun showError(throwable: Throwable) {
fun showError(throwable: Throwable) {
val snackbarMessage = resources.getString(R.string.assets__error__snackbar_message)
showError(snackbarMessage, throwable)
}
protected fun showError(@StringRes snackbarMessageResId: Int, throwable: Throwable) {
fun showError(@StringRes snackbarMessageResId: Int, throwable: Throwable) {
val snackbarMessage = resources.getString(snackbarMessageResId)
showError(snackbarMessage, throwable)
}
protected fun showError(snackbarMessage: String, throwable: Throwable) {
fun showError(snackbarMessage: String, throwable: Throwable) {
errorDialog?.dismiss()
errorDialog = null
errorSnackbar?.dismiss()
errorSnackbar = Snackbar.make(binding.root, snackbarMessage, Snackbar.LENGTH_LONG).apply {
setAction(R.string.assets__error__details) {
errorDialog?.dismiss()
errorDialog = AlertDialog.Builder(this@FlorisActivity).run {
setTitle(R.string.assets__error__details)
setMessage(errorThrowable?.stackTraceToString())
setPositiveButton(android.R.string.ok, null)
setNeutralButton(R.string.crash_dialog__copy_to_clipboard) { _, _ ->
val clipboardManager = getSystemService(Context.CLIPBOARD_SERVICE)
if (clipboardManager != null && clipboardManager is ClipboardManager) {
clipboardManager.setPrimaryClip(ClipData.newPlainText(errorThrowable.toString(), errorThrowable.toString()))
}
}
create()
show()
}
showErrorDialog()
}
show()
}
errorThrowable = throwable
}
fun showErrorDialog(throwable: Throwable? = errorThrowable) {
errorDialog?.dismiss()
errorDialog = AlertDialog.Builder(this@FlorisActivity).run {
setTitle(R.string.assets__error__details)
setMessage(throwable?.stackTraceToString())
setPositiveButton(android.R.string.ok, null)
setNeutralButton(R.string.crash_dialog__copy_to_clipboard) { _, _ ->
val clipboardManager = getSystemService(Context.CLIPBOARD_SERVICE)
if (clipboardManager != null && clipboardManager is ClipboardManager) {
clipboardManager.setPrimaryClip(ClipData.newPlainText(throwable.toString(), throwable.toString()))
}
}
create()
show()
}
}
}

View File

@@ -0,0 +1,306 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
package dev.patrickgold.florisboard.common
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.util.*
/**
* Project-specific locale class wrapping [java.util.Locale]. The wrapping is
* necessary to provide consistent language display names and tags across the
* whole code base.
*
* This class would be ideal for Kotlin's value classes, though AndroidX.Room
* does not like this at all, so this is a "normal" class.
*
* To construct a FlorisLocale, use one of the many from() methods provided.
*
* @see java.util.Locale
*/
@Serializable(with = FlorisLocale.Serializer::class)
class FlorisLocale private constructor(val base: Locale) {
companion object {
/** Delimiter for a language tag. */
private const val DELIMITER_LANGUAGE_TAG = '-'
/** Delimiter for a locale tag. */
private const val DELIMITER_LOCALE_TAG = '_'
/** Delimiter regex to split language/locale tags. */
private val DELIMITER_SPLITTER = """[${DELIMITER_LANGUAGE_TAG}${DELIMITER_LOCALE_TAG}]""".toRegex()
/** Constant locale for ROOT */
val ROOT = from("", "", "")
/** Constant locale for ENGLISH */
val ENGLISH = from("en", "", "")
/**
* Wraps a [java.util.Locale] and returns the [FlorisLocale].
*
* @return The wrapped locale.
*/
fun from(javaLocale: Locale) = FlorisLocale(javaLocale)
/**
* Constructs a new [FlorisLocale] with given [language].
*
* @param language A two-letter language code.
*
* @return A new [FlorisLocale].
*/
fun from(language: String) = from(Locale(language))
/**
* Constructs a new [FlorisLocale] with given [language] and [country].
*
* @param language A two-letter language code.
* @param country A two-letter country code.
*
* @return A new [FlorisLocale].
*/
fun from(language: String, country: String) = from(Locale(language, country))
/**
* Constructs a new [FlorisLocale] with given [language], [country] and [variant].
*
* @param language A two-letter language code.
* @param country A two-letter country code.
* @param variant A two-letter variant code.
*
* @return A new [FlorisLocale].
*/
fun from(language: String, country: String, variant: String) = from(Locale(language, country, variant))
/**
* Constructs a new [FlorisLocale] from given [str].
*
* @param str Either a language or locale tag in string form.
*
* @return A new [FlorisLocale].
*/
fun fromTag(str: String) = when {
str.contains(DELIMITER_SPLITTER) -> {
val lc = str.split(DELIMITER_SPLITTER)
if (lc.size >= 3) {
from(lc[0], lc[1], lc[2])
} else {
from(lc[0], lc[1])
}
}
else -> from(str)
}
/**
* Gets the current value of the default locale for this instance of
* the Java Virtual Machine.
*
* @see java.util.Locale.getDefault
*/
fun default() = FlorisLocale(Locale.getDefault())
}
/**
* Builds a locale or language tag for this locale by using [delimiter].
*
* @param delimiter The delimiter to use between the components.
*
* @return The generated tag for this locale. May be an empty string if
* [language], [country] and [variant] are not specified.
*/
private fun buildLocaleString(delimiter: Char) = stringBuilder {
val language = base.language
val country = base.country
val variant = base.variant
append(language)
if (language.isNotBlank() && country.isNotBlank()) {
append(delimiter)
}
append(country)
if (country.isNotBlank() && variant.isNotBlank()) {
append(delimiter)
}
append(variant)
}
/**
* Returns the language code of this locale.
*
* @see java.util.Locale.getLanguage
*/
val language: String get() = base.language
/**
* Returns the country/region code for this locale.
*
* @see java.util.Locale.getCountry
*/
val country: String get() = base.country
/**
* Returns the variant code for this locale.
*
* @see java.util.Locale.getVariant
*/
val variant: String get() = base.variant
/**
* Returns a three-letter abbreviation of this locale's language.
*
* @see java.util.Locale.getISO3Language
*/
val iso3Language: String get() = base.isO3Language
/**
* Returns a three-letter abbreviation of this locale's country.
*
* @see java.util.Locale.getISO3Country
*/
val iso3Country: String get() = base.isO3Country
/**
* Generates the language tag for this locale in the format `xx`,
* `xx-YY` or `xx-YY-zzz` and returns it as a string.
*
* xx: Two-letter language code
* YY: Two-letter country code
* zzz: Three letter variant
*
* @return The language tag for this locale. May be an empty string if
* [language], [country] and [variant] are not specified.
*/
fun languageTag(): String = buildLocaleString(DELIMITER_LANGUAGE_TAG)
/**
* Generates the locale tag for this locale in the format `xx`,
* `xx_YY` or `xx_YY_zzz` and returns it as a string.
*
* xx: Two-letter language code
* YY: Two-letter country code
* zzz: Three letter variant
*
* @return The locale tag for this locale. May be an empty string if
* [language], [country] and [variant] are not specified.
*/
fun localeTag(): String = buildLocaleString(DELIMITER_LOCALE_TAG)
/**
* Returns the name of this locale's language, localized to [locale].
*
* @see java.util.Locale.getDisplayLanguage
*/
fun displayLanguage(locale: FlorisLocale = default()): String = base.getDisplayLanguage(locale.base)
/**
* Returns the name of this locale's country, localized to [locale].
*
* @see java.util.Locale.getDisplayCountry
*/
fun displayCountry(locale: FlorisLocale = default()): String = base.getDisplayCountry(locale.base)
/**
* Returns a name for the locale's variant code that is appropriate for
* display to the user.
*
* @see java.util.Locale.getDisplayVariant
*/
fun displayVariant(locale: FlorisLocale = default()): String = base.getDisplayVariant(locale.base)
/**
* Returns the display name for this locale, localized to [locale] in
* the format `Language`, `Language (Country)` or `Language (Country) \[VARIANT]`.
*
* @param locale The locale to use for generating the display name for
* this locale, or [default] if otherwise.
*
* @return The display name for this locale. May be an empty string if
* [language], [country] and [variant] are not specified.
*/
fun displayName(locale: FlorisLocale = default()) = stringBuilder {
val languageName = displayLanguage(locale).ifBlank { base.language }
val countryName = displayCountry(locale).ifBlank { base.country }
val variantName = displayVariant(locale).ifBlank { base.variant }
append(languageName)
if (countryName.isNotBlank()) {
if (languageName.isNotBlank()) {
append(' ')
}
append('(')
append(countryName)
append(')')
}
if (variantName.isNotBlank()) {
if (languageName.isNotBlank() || countryName.isNotBlank()) {
append(' ')
}
append('[')
append(variantName.uppercase())
append(']')
}
}
/**
* Generate a debug string representing this locale. Not to be confused
* with [java.util.Locale.toString], which produces a locale tag. If such
* tag is needed, use [localeTag].
*
* @return The debug representation of this locale.
*/
override fun toString() = "FlorisLocale { l=${base.language} c=${base.country} v=${base.variant} }"
/**
* Equality check for this locale.
*/
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as FlorisLocale
if (base != other.base) return false
return true
}
/**
* Returns the hash code for this locale.
*/
override fun hashCode(): Int {
return base.hashCode()
}
/**
* The JSON (de)serializer for FlorisLocale.
*/
class Serializer : KSerializer<FlorisLocale> {
override val descriptor: SerialDescriptor =
PrimitiveSerialDescriptor("FlorisLocale", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: FlorisLocale) {
encoder.encodeString(value.languageTag())
}
override fun deserialize(decoder: Decoder): FlorisLocale {
return fromTag(decoder.decodeString())
}
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package dev.patrickgold.florisboard.ime.core
package dev.patrickgold.florisboard.common
import android.content.Context
import android.util.AttributeSet

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* 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
*
* http://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.
*/
package dev.patrickgold.florisboard.common
import java.nio.ByteBuffer
/**
* Type alias for a native pointer.
*/
typealias NativePtr = Long
/**
* Constant value for a native null pointer.
*/
const val NATIVE_NULLPTR: NativePtr = 0L
/**
* Type alias for a native string in standard UTF-8 encoding.
*/
typealias NativeStr = ByteBuffer
/**
* Converts a native string to a Java string.
*/
fun NativeStr.toJavaString(): String {
val bytes: ByteArray
if (this.hasArray()) {
bytes = this.array()
} else {
bytes = ByteArray(this.remaining())
this.get(bytes)
}
return String(bytes, Charsets.UTF_8)
}
/**
* Converts a Java string to a native string.
*/
fun String.toNativeStr(): NativeStr {
val bytes = this.toByteArray(Charsets.UTF_8)
val buffer = ByteBuffer.allocateDirect(bytes.size)
buffer.put(bytes)
buffer.rewind()
return buffer
}
/**
* Generic interface for a native instance object. Defines the basic
* methods which each native instance wrapper should define and be able
* to handle to.
*/
interface NativeInstanceWrapper {
/**
* Returns the native pointer of this instance. The returned pointer
* is only valid if [dispose] has not been previously called.
*
* @return The native null pointer for this instance.
*/
fun nativePtr(): NativePtr
/**
* Deletes the native object and frees allocated resources. After
* invoking this method one MUST NOT touch this instance ever again.
*/
fun dispose()
}

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