diff --git a/README.md b/README.md index eb8d421e8caddd9ca04404024c6521d25d6bf7d6..3f8cd7ab4d240150acff53e0900bbaaf08c94dd3 100644 --- a/README.md +++ b/README.md @@ -40,5 +40,6 @@ Each platform maintains multiple types of releases: Copyright (c) 2018 SIL International. All rights reserved. Licensed under the [MIT](./windows/src/LICENSE.md) License. -[KMFL](./linux) is licensed under GNU General Public License as published by the Free Software Foundation; either [version 2](./linux/libkmfl/COPYING) of the License, or (at your option) any later version. + +[Keyman for Linux](./linux) is licensed under the [MIT](./windows/src/LICENSE.md) License apart from [ibus-kmfl](./linux/ibus-kmfl) which is licensed under the GNU General Public License as published by the Free Software Foundation; either [version 2](./linux/ibus-kmfl/COPYING) of the License, or (at your option) any later version. diff --git a/android/KMAPro/build.gradle b/android/KMAPro/build.gradle index c8afa7e178ac50fd853f3d16b9984e12bc8db634..ed4c88d466f464c8770278a1130ccb1456b151c7 100644 --- a/android/KMAPro/build.gradle +++ b/android/KMAPro/build.gradle @@ -8,7 +8,7 @@ buildscript { } } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle:3.1.2' classpath 'com.github.triplet.gradle:play-publisher:1.2.0' classpath 'com.google.gms:google-services:3.1.2' classpath 'io.fabric.tools:gradle:1.25.1' diff --git a/android/KMAPro/gradle/wrapper/gradle-wrapper.properties b/android/KMAPro/gradle/wrapper/gradle-wrapper.properties index 7cff8b29df2e1729dc72260b5718c710517242e0..eefda80448ec0fc98388959b61ccb38e468f92f2 100644 --- a/android/KMAPro/gradle/wrapper/gradle-wrapper.properties +++ b/android/KMAPro/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Oct 30 09:32:59 ICT 2017 +#Sat Apr 14 11:26:38 ICT 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/android/KMAPro/kMAPro/build.gradle b/android/KMAPro/kMAPro/build.gradle index dbbd876b4506ce6c0a5c9ef4c9de49aab568e012..76dd2c55f0ec4ae3631d8dd931dead97371773a9 100644 --- a/android/KMAPro/kMAPro/build.gradle +++ b/android/KMAPro/kMAPro/build.gradle @@ -3,8 +3,8 @@ apply plugin: 'com.github.triplet.play' apply plugin: 'io.fabric' android { - compileSdkVersion 25 - buildToolsVersion "26.0.2" + compileSdkVersion 27 + buildToolsVersion "27.0.3" playAccountConfigs { defaultAccountConfig { if (project.hasProperty("keys_json_file")) { @@ -15,7 +15,7 @@ android { defaultConfig { applicationId "com.tavultesoft.kmapro" minSdkVersion 15 - targetSdkVersion 25 + targetSdkVersion 27 //dumpProperties(project.ext) // Use this to dump all external properties for debugging TeamCity integration @@ -100,14 +100,17 @@ repositories { } } -dependencies { - api(name: 'keyman-engine', ext: 'aar') +ext { + currentFirebaseVersion = "15.0.2" +} +dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.android.support:support-v4:25.4.0' - implementation 'com.google.firebase:firebase-core:11.8.0' - implementation 'com.google.firebase:firebase-crash:11.8.0' - implementation('com.crashlytics.sdk.android:crashlytics:2.9.0@aar') { + implementation 'com.android.support:support-v4:27.1.1' + api(name: 'keyman-engine', ext: 'aar') + implementation "com.google.firebase:firebase-core:$currentFirebaseVersion" + implementation "com.google.firebase:firebase-crash:$currentFirebaseVersion" + implementation('com.crashlytics.sdk.android:crashlytics:2.9.2@aar') { transitive = true } } diff --git a/android/KMAPro/kMAPro/src/main/AndroidManifest.xml b/android/KMAPro/kMAPro/src/main/AndroidManifest.xml index a2b3148af4d4c944db123285034a2547655f2788..3aebaadabfa8b0034c82f484f6b68566a7d6a99d 100644 --- a/android/KMAPro/kMAPro/src/main/AndroidManifest.xml +++ b/android/KMAPro/kMAPro/src/main/AndroidManifest.xml @@ -11,6 +11,7 @@ android:hardwareAccelerated="true" android:allowBackup="true" android:icon="@drawable/ic_launcher" + android:roundIcon="@drawable/ic_launcher_round" android:label="@string/app_name" android:theme="@style/AppTheme" > @@ -57,16 +58,99 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + - - + + + + + + + + diff --git a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-downloads-ap.png b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-downloads-ap.png index c17936dc7ec52acc0871a2c45fc3a82914174582..93a95bf426b8bd5624a849d87d35afd2bdef77d1 100644 Binary files a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-downloads-ap.png and b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-downloads-ap.png differ diff --git a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-downloads-at.png b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-downloads-at.png index fe464fd0fc3f19bb2879d83aa0a2a881ce6a7199..19da0c46ce1bd87da1e3008354a4721421263185 100644 Binary files a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-downloads-at.png and b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-downloads-at.png differ diff --git a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-file-browser-ap.png b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-file-browser-ap.png index a42d508f76ffdafdc8a18b263f2ce627554c499a..e0957ac4dfed929d470e992e1416502331b80d91 100644 Binary files a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-file-browser-ap.png and b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-file-browser-ap.png differ diff --git a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-file-browser-at.png b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-file-browser-at.png new file mode 100644 index 0000000000000000000000000000000000000000..4cd32d02c771a425171c02f9b2ede2e4ba7e2547 Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-file-browser-at.png differ diff --git a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-install1-ap.png b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-install1-ap.png index f090694618a63646e9e7feff4f88081245eaf5d2..1eca6c744baa43730599a9811c653dd3ed800d36 100644 Binary files a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-install1-ap.png and b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-install1-ap.png differ diff --git a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-install1-at.png b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-install1-at.png index 8a0e48301060f609a8c18602ee9ac2c1f6ba2c2a..9e9012a32670505d7f556da6a6e45664b009a639 100644 Binary files a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-install1-at.png and b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-install1-at.png differ diff --git a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-kmp-downloaded-ap.png b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-kmp-downloaded-ap.png deleted file mode 100644 index 126412ba21071944b6cd87632658c75d5d6ee5fb..0000000000000000000000000000000000000000 Binary files a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-kmp-downloaded-ap.png and /dev/null differ diff --git a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-welcome-ap.png b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-welcome-ap.png index 2952c447f1f695a6a4b204f06d1d864b485b6c91..46b783dcb18fcdc0eb618f3aada942427ea50950 100644 Binary files a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-welcome-ap.png and b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-welcome-ap.png differ diff --git a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-welcome-at.png b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-welcome-at.png index 6182a5afa7df1527ab0fe0bd49dfb0d228986e23..1876ff9bca3dcaa1d6259adc0f97f2152e696ce4 100644 Binary files a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-welcome-at.png and b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/dist-welcome-at.png differ diff --git a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/uninstall-delete-a.png b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/uninstall-delete-a.png new file mode 100644 index 0000000000000000000000000000000000000000..d08d7e4cd0b3680c302b599444b87090441efaa3 Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/uninstall-delete-a.png differ diff --git a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/uninstall-list-a.png b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/uninstall-list-a.png new file mode 100644 index 0000000000000000000000000000000000000000..fde4bf26328152ea1c8a4c8b2a17a5afed53f805 Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/uninstall-list-a.png differ diff --git a/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/uninstall-notification-a.png b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/uninstall-notification-a.png new file mode 100644 index 0000000000000000000000000000000000000000..ba61f308461bdf5e5d2c2ad40d358f65855a5bc9 Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/assets/info/img/app/10.0/uninstall-notification-a.png differ diff --git a/android/KMAPro/kMAPro/src/main/assets/info/info.html b/android/KMAPro/kMAPro/src/main/assets/info/info.html index 8c8135823da9158971f15d488b164bee64ac82dd..4fd12f18a57212ddaf1278863817c5eb99fa8697 100644 --- a/android/KMAPro/kMAPro/src/main/assets/info/info.html +++ b/android/KMAPro/kMAPro/src/main/assets/info/info.html @@ -58,503 +58,576 @@
-

- Getting Started -

- - -
-
-

Phone

-
-
-

Tablet

+

+ Getting Started +

+ +
+
+

Phone

+
+
+

Tablet

+
-
-
-

- Keyman for Android lets you type in over 600 languages on Android mobiles and tablets. - To get started, here are some helpful hints: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Keyboard Keys
(Keyboard Present)
Install or select another language/keyboard
Hide the keyboard
Backspace
Return
Shift key. Long press this key to access the CTRL, ALT and CTRL ALT keys - (which can access additional key layers) -
Keys with a small dot in the top right corner indicate a long press key. Access - further functionality by long pressing the key -
Toolbar Icons
Share your text via Mail, Text, Facebook or Twitter
Open the Keyman Browser to use the web in your language
Open the menu for additional options
Adjust the font size
Delete all current text
Load this help page
Open the initial setup screen
-

+
+

+ Keyman for Android lets you type in over 600 languages on Android mobiles and tablets. + To get started, here are some helpful hints: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Keyboard Keys
(Keyboard Present)
Install or select another language/keyboard
Hide the keyboard
Backspace
Return
Shift key. Long press this key to access the CTRL, ALT and CTRL ALT keys + (which can access additional key layers) +
Keys with a small dot in the top right corner indicate a long press key. Access + further functionality by long pressing the key +
Toolbar Icons
Share your text via Mail, Text, or Twitter
Open the Keyman Browser to use the web in your language
Open the menu for additional options
Adjust the font size
Delete all current text
Load this help page
Open the initial setup screen
+ +

Switching between Keyboards

+

+ To switch keyboards, follow these steps: +

+ Step 1) +
+ With the keyboard visible, touch the globe key: +
+ +
+ This will bring up a list of all currently installed languages (the default is English + EuroLatin2). If you have already downloaded additional languages, they will appear here. + Simply select them and the keyboard will re-appear with the new language. +

+ If you haven't installed any languages as yet, touch the + + button in the top right corner of your screen. +

+ Step 2) +
+ A list of all available languages will appear. Scroll through this list until you find + the language you want to install. Some languages may have multiple keyboards - for + example we have 10+ different Tamil keyboards. +
+ +

+ Select the language and keyboard you want to install - a popup will ask for confirmation, + hit the Download button. +
+ +

+ Step 3) +
+ Once the download is complete, the new keyboard will be selected. Touch the Return button on the top left corner of the popup and the new + keyboard will become active. +
+ +

-

Switching between Keyboards

-

- To switch keyboards, follow these steps: -

- Step 1) -
- With the keyboard visible, touch the globe key: -
- -
- This will bring up a list of all currently installed languages (the default is English - EuroLatin2). If you have already downloaded additional languages, they will appear here. - Simply select them and the keyboard will re-appear with the new language. -

- If you haven't installed any languages as yet, touch the + - button in the top right corner of your screen. -

- Step 2) -
- A list of all available languages will appear. Scroll through this list until you find - the language you want to install. Some languages may have multiple keyboards - for - example we have 10+ different Tamil keyboards. -
- -

- Select the language and keyboard you want to install - a popup will ask for confirmation, - hit the Download button. -
- -

- Step 3) -
- Once the download is complete, the new keyboard will be selected. Touch the Return button on the top left corner of the popup and the new - keyboard will become active. -
- -

-

+

Removing a Keyboard

+

+ To uninstall a keyboard, follow these steps: +

+ Step 1) +
+ With the keyboard visible, touch the globe key: +
+ +

+ Step 2) +
+ A list of all available languages will appear. Scroll through this list until you find + the keyboard you want to uninstall +
+ +

+ Step 3) +
+ Long press the keyboard and release to get a prompt to delete the keyboard. +
+ +

+ Step 4) + Press "Delete" to uninstall the keyboard. You'll see a notification when the keyboard is deleted. +
+ +

-

Hotkey

-

- To switch between languages while using an external keyboard (i.e. a bluetooth keyboard), a quick and easy way is to - use a hotkey combination. Press and hold 'Ctrl' and then press 'Tab'. - You should see a list of languages/keyboards. Tap on any available language of your choice. -

+

Hotkey

+

+ To switch between languages while using an external keyboard (i.e. a bluetooth keyboard), a quick and easy way is to + use a hotkey combination. Press and hold 'Ctrl' and then press 'Tab'. + You should see a list of languages/keyboards. Tap on any available language of your choice. +

-

Accessing Keyboard Help

-

- Step 1) Open the keyboard list by touching the globe key. -

-

-
-

- Step 2) Touch the info icon for your keyboard. -

-

-
+

Accessing Keyboard Help

+

+ Step 1) Open the keyboard list by touching the globe key. +

+

+
+

+ Step 2) Touch the info icon for your keyboard. +

+

+
-

Installing System Wide Keyboards

-

- Step 1) Open the Keyman app and select the menu for additional options. - The screenshots below are of a device running Android 7.1 Nougat. -

-

-
-

- Step 2) Select 'Get Started' and then select 'Enable Keyman as a system-wide keyboard'. -

-

-
-

- This will open an Android settings screen for 'Available virtual keyboard'. -

-

-
-

- Step 3) Enable 'Keyman' as an available virtual keyboard. - This will bring up two confirmation dialogs. -

-

-
-

-
-

- Select 'OK' on both. Now when the on-screen keyboard appears for apps other than Keyman, - you'll see a keyboard icon at the bottom right. -

-

-
-

- Click the keyboard icon whenever you want to change the current system keyboard. -

-

-

+

Installing System Wide Keyboards

+

+ Step 1) Open the Keyman app and select the menu for additional options. + The screenshots below are of a device running Android 7.1 Nougat. +

+

+
+

+ Step 2) Select 'Get Started' and then select 'Enable Keyman as a system-wide keyboard'. +

+

+
+

+ This will open an Android settings screen for 'Available virtual keyboard'. +

+

+
+

+ Step 3) Enable 'Keyman' as an available virtual keyboard. + This will bring up two confirmation dialogs. +

+

+
+

+
+

+ Select 'OK' on both. Now when the on-screen keyboard appears for apps other than Keyman, + you'll see a keyboard icon at the bottom right. +

+

+
+

+ Click the keyboard icon whenever you want to change the current system keyboard. +

+

+

-

Installing Custom Keyboards

-

- Step 1) From a Chrome browser, click the link to your keyboard package .kmp file. This example is for GFF Amharic 7. -

-

-

- Step 2) If the browser prompts to use "Keyman" to open the file, click on "Keyman" and proceed to Step 3. - Otherwise, wait for the browser to finish downloading the .kmp file. - When the browser has finished downloading the KMP file, you will need to browse to the KMP file and select it. - Select the Menu, then "Downloads", and select the downloaded KMP file. -

-

-

- Step 3) On Android 6.0 (Marshmallow) and higher, mobile apps need to request permissions to access storage. Keyman - for Android needs access to read storage for installing the KMP file. At the dialog, select "ALLOW". Once authorized, - Keyman for Android won't need to ask for storage permission again, unless the user revokes or uninstalls the app. -

-

-

- Step 4) Keyman for Android will parse the metadata in the package. If the keyboard package includes a "welcome.htm" - file, this will be displayed at the confirmation to install the keyboard package. -

-

-

- If "welcome.htm" is not included, a generic page with the package ID and package version will be shown. Click the - left "Install" button to install the entire keyboard package. -

-

- Step 5) All the keyboards in the package are installed as a group. In this example, the package only has the - "GFF Amharic 7" keyboard, so it becomes the active keyboard. -

-

-

- Once the keyboard has been downloaded, you should be able to use it as normal. -
- To learn how to create a custom installable keyboard, - click here. -

+

Installing Custom Keyboards

+

+ Step 1) Click the link to your custom keyboard package file. The link in this example is for Khmer Angkor keyboard. +

+

+

+ Step 2) Browse to the KMP file. Once the KMP file is on your device, you will need to browse to the KMP file and select it. + If using the Chrome browser, select the Menu, then "Downloads", and select the downloaded KMP file. +

+

+

+ Otherwise, use the "Downloads" or file browser app available on your Android device to select the downloaded KMP file. + If your default file browser doesn't prompt for Keyman to open the package file, you may need to use a different file + browser from the Google Play store. +

+

+

+ Selecting the KMP file should bring you to Step 3) +

+

+ Step 3) On Android 6.0 (Marshmallow) and higher, mobile apps need to request permissions to access storage. Keyman + for Android needs access to read storage for installing the KMP file. At the dialog, select "ALLOW". Once authorized, + Keyman for Android won't need to ask for storage permission again, unless the user revokes or uninstalls the app. +

+

+

+ Older versions of Android grant Storage permissions at app installation time, so those users can skip this step. +

+

+ Step 4) Keyman for Android will parse the metadata in the package. If the keyboard package includes a "welcome.htm" + file, this will be displayed at the confirmation to install the keyboard package. +

+

+

+ If "welcome.htm" is not included, a generic page with the package ID and package version will be shown. Click the + left "Install" button to install the entire keyboard package. +

+

+ Step 5) All the keyboards in the package are installed as a group. In this example, the package only has the + "Khmer Angkor" keyboard, so it becomes the active keyboard. +

+

+

+ Once the keyboard has been downloaded, you should be able to use it as normal. +
+ To learn how to create a custom installable keyboard, + click here. +

-

Granting storage permission

-

- If Keyman for Android is permanently denied storage access, attempts to install custom keyboards will fail with the - notification "Storage permission request was denied". Perform these steps to grant Keyman for Android access to storage -

-

- Step 1) Go to Android Settings. -
- Step 2) Depending on your device, click "Apps", "Apps & notifications", or "App permissions" and grant Keyman - storage permission. The screenshot below is from Android 7.1 Nougat. -

-

+

Granting storage permission

+

+ If Keyman for Android is permanently denied storage access, attempts to install custom keyboards will fail with the + notification "Storage permission request was denied". Perform these steps to grant Keyman for Android access to storage +

+

+ Step 1) Go to Android Settings. +
+ Step 2) Depending on your device, click "Apps", "Apps & notifications", or "App permissions" and grant Keyman + storage permission. The screenshot below is from Android 7.1 Nougat. +

+

-

Use the Keyman Browser

-

- Step 1) Click the Keyman Browser button in the Keyman app -
- Step 2) Enter the URL of a website to visit into the address bar, for example google.com. - Keyman Browser will load the page and detect your language if it is present, and reformat it to show your - language instead of square boxes. -
- Step 3) Use the bookmark button to save the current page for browsing later. -
- Step 4) Use the Globe icon to swap between languages. -

+

Use the Keyman Browser

+

+ Step 1) Click the Keyman Browser button in the Keyman app +
+ Step 2) Enter the URL of a website to visit into the address bar, for example google.com. + Keyman Browser will load the page and detect your language if it is present, and reformat it to show your + language instead of square boxes. +
+ Step 3) Use the bookmark button to save the current page for browsing later. +
+ Step 4) Use the Globe icon to swap between languages. +

-

Integrate Keyman with your App or Website

-

- If you are interested in learning how Keyman can be integrated into your own app or - website, visit keyman.com/engine -

+

Integrate Keyman with your App or Website

+

+ If you are interested in learning how Keyman can be integrated into your own app or + website, visit keyman.com/engine +

-

Further Help

-

- For more information on Keyman, visit keyman.com -

- For more information on Keyman for Android, visit keyman.com/android -

-
+

Further Help

+

+ For more information on Keyman, visit keyman.com +

+ For more information on Keyman for Android, visit keyman.com/android +

+
+ +
+

+ Keyman for Android lets you type in over 600 languages on Android mobiles and tablets. + To get started, here are some helpful hints: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Keyboard Keys
(Keyboard Present)
Install or select another language/keyboard
Hide the keyboard
Backspace
Return
Shift key. Long press this key to access the CTRL, ALT and CTRL ALT keys + (which can access additional key layers) +
Keys with a small dot in the top right corner indicate a long press key. Access + further functionality by long pressing the key +
Toolbar Icons
Share your text via Mail, Text, or Twitter
Open the Keyman Browser to use the web in your language
Adjust the font size
Delete all current text
Link to this info page
Open the initial setup screen
-
-

- Keyman for Android lets you type in over 600 languages on Android mobiles and tablets. - To get started, here are some helpful hints: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Keyboard Keys
(Keyboard Present)
Install or select another language/keyboard
Hide the keyboard
Backspace
Return
Shift key. Long press this key to access the CTRL, ALT and CTRL ALT keys - (which can access additional key layers) -
Keys with a small dot in the top right corner indicate a long press key. Access - further functionality by long pressing the key -
Toolbar Icons
Share your text via Mail, Text, Facebook or Twitter
Open the Keyman Browser to use the web in your language
Adjust the font size
Delete all current text
Link to this info page
Open the initial setup screen
-

+

Switching between Keyboards

+

+ To switch keyboards, follow these steps: +

+ Step 1) +
+ With the keyboard visible, touch the globe key: +
+ +
+ This will bring up a list of all currently installed languages (the default is English EuroLatin2). + If you have already downloaded additional languages, they will appear here. + Simply select them and the keyboard will re-appear with the new language. +

+ If you haven't installed any languages as yet, touch the + + button in the top right corner of your screen. +

+ Step 2) +
+ A list of all available languages will appear. + Scroll through this list until you find the language you want to install. + Some languages may have multiple keyboards - for example we have 10+ different Tamil keyboards. +
+ +

+ Select the language and keyboard you want to install - a popup will ask for confirmation, hit the Download button. +
+ +

+ Step 3) +
+ Once the download is complete, the new keyboard will be selected. Touch the Return button on the top left corner of the popup and the new + keyboard will become active. +
+ +

-

Switching between Keyboards

-

- To switch keyboards, follow these steps: -

- Step 1) -
- With the keyboard visible, touch the globe key: -
- -
- This will bring up a list of all currently installed languages (the default is English EuroLatin2). - If you have already downloaded additional languages, they will appear here. - Simply select them and the keyboard will re-appear with the new language. -

- If you haven't installed any languages as yet, touch the + - button in the top right corner of your screen. -

- Step 2) -
- A list of all available languages will appear. - Scroll through this list until you find the language you want to install. - Some languages may have multiple keyboards - for example we have 10+ different Tamil keyboards. -
- -

- Select the language and keyboard you want to install - a popup will ask for confirmation, hit the Download button. -
- -

- Step 3) -
- Once the download is complete, the new keyboard will be selected. Touch the Return button on the top left corner of the popup and the new - keyboard will become active. -
- -

-

+

Removing a Keyboard

+

+ To uninstall a keyboard, follow these steps: +

+ Step 1) +
+ With the keyboard visible, touch the globe key: +
+ +

+ Step 2) +
+ A list of all available languages will appear. Scroll through this list until you find + the keyboard you want to uninstall +
+ +

+ Step 3) +
+ Long press the keyboard and release to get a prompt to delete the keyboard. +
+ +

+ Step 4) + Press "Delete" to uninstall the keyboard. You'll see a notification when the keyboard is deleted. +
+ +

-

Hotkey

-

- To switch between languages while using an external keyboard (i.e. a bluetooth keyboard), a quick and easy way is to - use a hotkey combination. Press and hold 'Ctrl' and then press 'Tab'. - You should see a list of languages/keyboards. Tap on any available language of your choice. -

+

Hotkey

+

+ To switch between languages while using an external keyboard (i.e. a bluetooth keyboard), a quick and easy way is to + use a hotkey combination. Press and hold 'Ctrl' and then press 'Tab'. + You should see a list of languages/keyboards. Tap on any available language of your choice. +

-

Accessing Keyboard Help

-

- Step 1) Open the keyboard list by touching the globe key. -

-

-
-

- Step 2) Touch the info icon for your keyboard. -

-

-
+

Accessing Keyboard Help

+

+ Step 1) Open the keyboard list by touching the globe key. +

+

+
+

+ Step 2) Touch the info icon for your keyboard. +

+

+
-

Installing System Wide Keyboards

-

- Step 1) Open the Keyman app. The screenshots below are of a device running Android 7.1 Nougat. -

-

-
-

- Step 2) Select 'Get Started' and then select 'Enable Keyman as a system-wide keyboard'. -

-

-
-

- This will open an Android settings screen for 'Available virtual keyboard'. -

-

-
-

- Step 3) Enable 'Keyman' as an available virtual keyboard. This will bring up two confirmation dialogs. -

-

-
-

-
-

- Select 'OK' on both. Now when the on-screen keyboard appears for apps other than Keyman, you'll see a keyboard - icon at the bottom right. -

-

-
-

- Click the keyboard icon whenever you want to change the current system keyboard. -

-

+

Installing System Wide Keyboards

+

+ Step 1) Open the Keyman app. The screenshots below are of a device running Android 7.1 Nougat. +

+

+
+

+ Step 2) Select 'Get Started' and then select 'Enable Keyman as a system-wide keyboard'. +

+

+
+

+ This will open an Android settings screen for 'Available virtual keyboard'. +

+

+
+

+ Step 3) Enable 'Keyman' as an available virtual keyboard. This will bring up two confirmation dialogs. +

+

+
+

+
+

+ Select 'OK' on both. Now when the on-screen keyboard appears for apps other than Keyman, you'll see a keyboard + icon at the bottom right. +

+

+
+

+ Click the keyboard icon whenever you want to change the current system keyboard. +

+

-

Installing Custom Keyboards

-

- Step 1) From a Chrome browser, click the link to your keyboard package .kmp file. This example is for GFF Amharic 7. -

-

-

- Step 2) If the browser prompts to use "Keyman" to open the file, click on "Keyman" and proceed to Step 3. - Otherwise, wait for the browser to finish downloading the .kmp file. - When the browser has finished downloading the KMP file, you will need to browse to the KMP file and select it. - Select the Menu, then "Downloads", and select the downloaded KMP file. -

-

-

- Step 3) On Android 6.0 (Marshmallow) and higher, mobile apps need to request permissions to access storage. Keyman - for Android needs access to read storage for installing the KMP file. At the dialog, select "ALLOW". Once authorized, - Keyman for Android won't need to ask for storage permission again, unless the user revokes or uninstalls the app. -

-

-

- Step 4) Keyman for Android will parse the metadata in the package. If the keyboard package includes a "welcome.htm" - file, this will be displayed at the confirmation to install the keyboard package. -

-

-

- If "welcome.htm" is not included, a generic page with the package ID and package version will be shown. Click the - left "Install" button to install the entire keyboard package. -

-

- Step 5) All the keyboards in the package are installed as a group. In this example, the package only has the - "GFF Amharic 7" keyboard, so it becomes the active keyboard. -

-

-

- Once the keyboard has been downloaded, you should be able to use it as normal. -
- To learn how to create a custom installable keyboard, - click here. -

+

Installing Custom Keyboards

+

+ Step 1) Click the link to your custom keyboard package file. The link in this example is for Khmer Angkor keyboard. +

+

+

+ Step 2) Browse to the KMP file. Once the KMP file is on your device, you will need to browse to the KMP file and select it. + If using the Chrome browser, select the Menu, then "Downloads", and select the downloaded KMP file. +

+

+

+ Otherwise, use the "Downloads" or file browser app available on your Android device to select the downloaded KMP file. + If your default file browser doesn't prompt for Keyman to open the package file, you may need to use a different file + browser from the Google Play store. +

+

+

+ Selecting the KMP file should bring you to Step 3) +

+

+ Step 3) On Android 6.0 (Marshmallow) and higher, mobile apps need to request permissions to access storage. Keyman + for Android needs access to read storage for installing the KMP file. At the dialog, select "ALLOW". Once authorized, + Keyman for Android won't need to ask for storage permission again, unless the user revokes or uninstalls the app. +

+

+

+ Older versions of Android grant Storage permissions at app installation time, so those users can skip this step. +

+

+ Step 4) Keyman for Android will parse the metadata in the package. If the keyboard package includes a "welcome.htm" + file, this will be displayed at the confirmation to install the keyboard package. +

+

+

+ If "welcome.htm" is not included, a generic page with the package ID and package version will be shown. Click the + left "Install" button to install the entire keyboard package. +

+

+ Step 5) All the keyboards in the package are installed as a group. In this example, the package only has the + "Khmer Angkor" keyboard, so it becomes the active keyboard. +

+

+

+ Once the keyboard has been downloaded, you should be able to use it as normal. +
+ To learn how to create a custom installable keyboard, + click here. +

-

Granting storage permission

-

- If Keyman for Android is permanently denied storage access, attempts to install custom keyboards will fail with the - notification "Storage permission request was denied". Perform these steps to grant Keyman for Android access to storage -

-

- Step 1) Go to Android Settings. -
- Step 2) Depending on your device, click "Apps", "Apps & notifications", or "App permissions" and grant Keyman - storage permission. The screenshot below is from Android 7.1 Nougat. -

-

+

Granting storage permission

+

+ If Keyman for Android is permanently denied storage access, attempts to install custom keyboards will fail with the + notification "Storage permission request was denied". Perform these steps to grant Keyman for Android access to storage +

+

+ Step 1) Go to Android Settings. +
+ Step 2) Depending on your device, click "Apps", "Apps & notifications", or "App permissions" and grant Keyman + storage permission. The screenshot below is from Android 7.1 Nougat. +

+

-

Use the Keyman Browser

-

- Step 1) Click the Keyman Browser button in the Keyman app -
- Step 2) Enter the URL of a website to visit into the address bar, for example google.com. - Keyman Browser will load the page and detect your language if it is present, and reformat it to show your - language instead of square boxes. -
- Step 3) Use the bookmark button to save the current page for browsing later. -
- Step 4) Use the Globe icon to swap between languages. -

+

Use the Keyman Browser

+

+ Step 1) Click the Keyman Browser button in the Keyman app +
+ Step 2) Enter the URL of a website to visit into the address bar, for example google.com. + Keyman Browser will load the page and detect your language if it is present, and reformat it to show your + language instead of square boxes. +
+ Step 3) Use the bookmark button to save the current page for browsing later. +
+ Step 4) Use the Globe icon to swap between languages. +

-

Integrate Keyman with your App or Website

-

- If you are interested in learning how Keyman can be integrated into your own app or website, visit - keyman.com/engine -

+

Integrate Keyman with your App or Website

+

+ If you are interested in learning how Keyman can be integrated into your own app or website, visit + keyman.com/engine +

-

Further Help

-

- For more information on Keyman, visit keyman.com -

- For more information on Keyman for Android, visit keyman.com/android -

-
+

Further Help

+

+ For more information on Keyman, visit keyman.com +

+ For more information on Keyman for Android, visit keyman.com/android +

+
diff --git a/android/KMAPro/kMAPro/src/main/java/com/keyman/android/SystemKeyboard.java b/android/KMAPro/kMAPro/src/main/java/com/keyman/android/SystemKeyboard.java index eec7a8a53ac7ad32d757901e407668d6dfe2a07a..cdbab125a5b6a27a64bcaee5074d255ff81bfe67 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/keyman/android/SystemKeyboard.java +++ b/android/KMAPro/kMAPro/src/main/java/com/keyman/android/SystemKeyboard.java @@ -71,7 +71,6 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven */ @Override public View onCreateInputView() { - //Log.i("SystemKeyboard", "onCreateInputView"); if (inputView == null) { inputView = KMManager.createInputView(this); } @@ -105,7 +104,6 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven KMManager.onStartInput(attribute, restarting); KMManager.resetContext(KeyboardType.KEYBOARD_TYPE_SYSTEM); - //Log.i("SystemKeyboard", "onStartInput"); InputConnection ic = getCurrentInputConnection(); if (ic != null) { ExtractedText icText = ic.getExtractedText(new ExtractedTextRequest(), 0); @@ -123,13 +121,11 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven @Override public void onStartInputView(EditorInfo attribute, boolean restarting) { super.onStartInputView(attribute, restarting); - //Log.i("SystemKeyboard", "onStartInputView"); } @Override public void onUpdateExtractingVisibility(EditorInfo ei) { super.onUpdateExtractingVisibility(ei); - //Log.i("SystemKeyboard", "onUpdateExtractingVisibility"); } @Override diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/InfoActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/InfoActivity.java index 9945b8e4ee4384d8ae60f0f9d0f71948f8db44e0..877cd84ea7ee49e5adb4f10128d1137047ec8f1e 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/InfoActivity.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/InfoActivity.java @@ -9,24 +9,26 @@ import java.util.HashMap; import com.tavultesoft.kmea.KMManager; -import android.net.Uri; +import android.content.Context; +import android.graphics.Bitmap; import android.os.Bundle; import android.view.Gravity; import android.view.View; -import android.webkit.WebSettings.LayoutAlgorithm; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.TextView; import android.annotation.SuppressLint; import android.app.ActionBar; import android.app.Activity; -import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; public class InfoActivity extends Activity { - private final String kmBaseUrl = "http://keyman.com/android/app/"; + private WebView webView; + private final String kmBaseUrl = "https://keyman.com/android/app/"; private String kmUrl = ""; private final String htmlPath = "file:///android_asset/info/info.html"; @@ -34,7 +36,8 @@ public class InfoActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - //getWindow().requestFeature(Window.FEATURE_PROGRESS); + final Context context = this; + final ActionBar actionBar = getActionBar(); actionBar.setLogo(R.drawable.keyman_logo); @@ -54,7 +57,6 @@ public class InfoActivity extends Activity { } catch (NameNotFoundException e) { // Could not get version number } - version.setText(ver); actionBar.setCustomView(version); @@ -83,46 +85,44 @@ public class InfoActivity extends Activity { installedKbs = currentKbID; kmUrl = String.format("%s?active=%s&installed=%s", kmBaseUrl, currentKbID, installedKbs); - WebView webView = (WebView) findViewById(R.id.webView); - webView.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); + webView = (WebView) findViewById(R.id.infoWebView); + webView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN); webView.getSettings().setJavaScriptEnabled(true); webView.getSettings().setUseWideViewPort(true); webView.getSettings().setLoadWithOverviewMode(true); webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); - /* - final Activity activity = this; + webView.setWebChromeClient(new WebChromeClient() { - public void onProgressChanged(WebView view, int progress) { - activity.setProgress(progress * 1000); - } }); - */ - webView.setWebViewClient(new WebViewClient() { @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { - // Handle the error } @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { - if (url.equals(kmUrl) || url.equals(htmlPath)) { + if (url != null && !url.toLowerCase().equals("about:blank")) { view.loadUrl(url); - } else { - Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - startActivity(i); - } + } return true; } + + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + } + + @Override + public void onPageFinished(WebView view, String url) { + } }); - if (KMManager.hasConnection(this)) { + if (KMManager.hasConnection(context)) { // Load app info page from server webView.loadUrl(kmUrl); } else { - webView.loadUrl(htmlPath); // Load app info page from assets + webView.loadUrl(htmlPath); } } diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java index 92eb652fc14ef064f647f955c2edb948f9c6f633..de1a6ef384fb617c4ea5a3abecae9ed3e12cca41 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java @@ -152,6 +152,9 @@ public class MainActivity extends Activity implements OnKeyboardEventListener, O textView.setTextSize((float) textSize); textView.setSelection(textView.getText().length()); + + + boolean didCheckUserData = prefs.getBoolean(MainActivity.didCheckUserDataKey, false); if (!didCheckUserData && (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)) { try { @@ -227,6 +230,8 @@ public class MainActivity extends Activity implements OnKeyboardEventListener, O protected void onResume() { super.onResume(); KMManager.onResume(); + KMManager.hideSystemKeyboard(); + if (!KMManager.keyboardExists(this, KMManager.KMDefault_UndefinedPackageID, KMManager.KMDefault_KeyboardID, KMManager.KMDefault_LanguageID)) { HashMap kbInfo = new HashMap(); @@ -316,7 +321,7 @@ public class MainActivity extends Activity implements OnKeyboardEventListener, O } break; default : - Log.d(TAG, "Unrecognized protocol " + data.getScheme()); + Log.e(TAG, "Unrecognized protocol " + data.getScheme()); } } intent.setData(null); @@ -609,15 +614,12 @@ public class MainActivity extends Activity implements OnKeyboardEventListener, O public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == PERMISSION_REQUEST_STORAGE) { // Request for storage permission - Log.d(TAG, "Received response for Storage permission request"); if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Permission has been granted. Resume task needing this permission - Log.d(TAG, "Permission: " + permissions[0] + " was " + grantResults[0]); useLocalKMP(data); } else { // Permission request denied String message = "Storage permission request was denied. Unable to install keyboard package"; - Log.d(TAG, message); Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show(); } @@ -629,16 +631,13 @@ public class MainActivity extends Activity implements OnKeyboardEventListener, O if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { - Log.d(TAG, "Read external storage permission granted"); useLocalKMP(data); } else { - Log.d(TAG, "Read external storage permission denied"); // Permission is missing and must be requested requestStoragePermission(); } } else { // Permission automatically granted on older Android versions - Log.d(TAG, "Read external storage permission granted"); useLocalKMP(data); } } @@ -698,7 +697,6 @@ public class MainActivity extends Activity implements OnKeyboardEventListener, O cacheKMPFile.delete(); } - Log.d(TAG, "Copying " + filename + " to app cache"); FileUtils.copy(inputFile, new FileOutputStream(cacheKMPFile)); } else { String noKeyboardsInstalledMessage = " is not a valid keyboard package file.\nNo keyboards were installed."; diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/PackageActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/PackageActivity.java index dc35ae42eb45324f30bb32ddb4e6c24f5f3c5dfd..decb73ca97c69e519adec3463efdc99ef4454e25 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/PackageActivity.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/PackageActivity.java @@ -53,10 +53,6 @@ public class PackageActivity extends Activity { final String pkgId = PackageProcessor.getPackageID(kmpFile); String pkgVersion = PackageProcessor.getPackageVersion(kmpFile, false); - if (pkgVersion == null || pkgVersion.isEmpty()) { - String message = "Invalid package version in " + kmpFile.getName(); - showErrorDialog(context, pkgId, message); - } String pkgName = PackageProcessor.getPackageName(kmpFile, false); try { @@ -77,10 +73,7 @@ public class PackageActivity extends Activity { packageActivityTitle.setTextSize(getResources().getDimension(R.dimen.package_label_textsize)); packageActivityTitle.setGravity(Gravity.CENTER); - String titleStr = "Install Keyboard Package"; - if (pkgVersion != null) { - titleStr += " " + pkgVersion; - } + String titleStr = "Install Keyboard Package " + pkgVersion; packageActivityTitle.setText(titleStr); actionBar.setCustomView(packageActivityTitle); @@ -89,7 +82,7 @@ public class PackageActivity extends Activity { final Button installButton = (Button) findViewById(R.id.installButton); final Button cancelButton = (Button) findViewById(R.id.cancelButton); - webView = (WebView) findViewById(R.id.webView); + webView = (WebView) findViewById(R.id.packageWebView); webView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); webView.getSettings().setJavaScriptEnabled(true); webView.getSettings().setUseWideViewPort(true); @@ -110,7 +103,7 @@ public class PackageActivity extends Activity { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { - if (!url.toLowerCase().equals("about:blank")) + if (url != null && !url.toLowerCase().equals("about:blank")) view.loadUrl(url); return true; @@ -141,7 +134,7 @@ public class PackageActivity extends Activity { webView.loadUrl("file:///" + files[0].getAbsolutePath()); } else { // No welcome.htm so display minimal package information - String keyboardString = (pkgName.toLowerCase().endsWith("keyboard")) ? "" : " Keyboard "; + String keyboardString = (pkgName != null && pkgName.toLowerCase().endsWith("keyboard")) ? "" : " Keyboard "; String htmlString = String.format( "

The %s%s Package

", pkgName, keyboardString); diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/WebBrowserActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/WebBrowserActivity.java index 139806dced57cb2f5d158fae468ce7a864c54492..3d72f77bbaa5df75f75218ef94c4cfd1111e6f5f 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/WebBrowserActivity.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/WebBrowserActivity.java @@ -72,7 +72,7 @@ public class WebBrowserActivity extends Activity { actionBar.setCustomView(webBarLayout); setContentView(R.layout.activity_web_browser); - webView = (WebView) findViewById(R.id.webView); + webView = (WebView) findViewById(R.id.browserWebView); addressField = (EditText) findViewById(R.id.address_field); clearButton = (ImageButton) findViewById(R.id.clear_button); stopButton = (ImageButton) findViewById(R.id.stop_button); @@ -224,15 +224,11 @@ public class WebBrowserActivity extends Activity { closeButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - // Hide the current keyboard so when Keyman app returns, there aren't 2 keyboards visible #220 - InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(addressField.getWindowToken(), 0); finish(); overridePendingTransition(0, android.R.anim.fade_out); } }); - webView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); webView.getSettings().setJavaScriptEnabled(true); webView.getSettings().setUseWideViewPort(true); @@ -381,13 +377,8 @@ public class WebBrowserActivity extends Activity { if (webView != null && webView.canGoBack()) { webView.goBack(); } else { - // Hide the current keyboard so when Keyman app returns, there aren't 2 keyboards visible - InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(addressField.getWindowToken(), 0); - super.onBackPressed(); finish(); - //overridePendingTransition(0, android.R.anim.fade_out); } } diff --git a/android/KMAPro/kMAPro/src/main/res/drawable-hdpi/ic_launcher_round.png b/android/KMAPro/kMAPro/src/main/res/drawable-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..7dd8b598eae7b296a5c26813e5d227b0fe86cc98 Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/res/drawable-hdpi/ic_launcher_round.png differ diff --git a/android/KMAPro/kMAPro/src/main/res/drawable-mdpi/ic_launcher_round.png b/android/KMAPro/kMAPro/src/main/res/drawable-mdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..ab69e103370560ef297b5aed865b7b7970aba259 Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/res/drawable-mdpi/ic_launcher_round.png differ diff --git a/android/KMAPro/kMAPro/src/main/res/drawable-xhdpi/ic_launcher_round.png b/android/KMAPro/kMAPro/src/main/res/drawable-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..444310ccedebe14f64fdd0481b02f127728d7060 Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/res/drawable-xhdpi/ic_launcher_round.png differ diff --git a/android/KMAPro/kMAPro/src/main/res/drawable-xxhdpi/ic_launcher_round.png b/android/KMAPro/kMAPro/src/main/res/drawable-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..e3a2e6b8ad8dd42e123f56ee7270e07d6a38ff19 Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/res/drawable-xxhdpi/ic_launcher_round.png differ diff --git a/android/KMAPro/kMAPro/src/main/res/drawable-xxxhdpi/ic_launcher_round.png b/android/KMAPro/kMAPro/src/main/res/drawable-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..d7503dec54ffbdba442c2b6c8e75d6fcb603bd1f Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/res/drawable-xxxhdpi/ic_launcher_round.png differ diff --git a/android/KMAPro/kMAPro/src/main/res/layout/activity_info.xml b/android/KMAPro/kMAPro/src/main/res/layout/activity_info.xml index 8750492213412fa23d666b249d45cb5266034d3d..58fc10f5a2b59417e207eb122fae57178088329b 100644 --- a/android/KMAPro/kMAPro/src/main/res/layout/activity_info.xml +++ b/android/KMAPro/kMAPro/src/main/res/layout/activity_info.xml @@ -3,10 +3,10 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".WebBrowserActivity" > + tools:context=".InfoActivity" > + android:scrollbars="vertical"> diff --git a/android/KMAPro/kMAPro/src/main/res/layout/activity_package_installer.xml b/android/KMAPro/kMAPro/src/main/res/layout/activity_package_installer.xml index efeea07e0aa4757ba432e18bd3c66612210e1c46..9012906492de016f978040a6248795cd66f85273 100644 --- a/android/KMAPro/kMAPro/src/main/res/layout/activity_package_installer.xml +++ b/android/KMAPro/kMAPro/src/main/res/layout/activity_package_installer.xml @@ -7,7 +7,7 @@ tools:context=".PackageActivity" > diff --git a/android/KMAPro/kMAPro/src/main/res/layout/activity_web_browser.xml b/android/KMAPro/kMAPro/src/main/res/layout/activity_web_browser.xml index 61a4ef87a1b27d801cfae616df4130bb99e8ffe6..dbeb4ea88fe88dc79657c1817df733a10b87a1f5 100644 --- a/android/KMAPro/kMAPro/src/main/res/layout/activity_web_browser.xml +++ b/android/KMAPro/kMAPro/src/main/res/layout/activity_web_browser.xml @@ -6,7 +6,7 @@ tools:context=".WebBrowserActivity" >

More help

Letters
Symbols
Accent
Marks
Type`#\'"^%&*~-_:@.|,
Result `  ̏ ´ ˝ ˆ ˇ  ̑ ˘ ˜ ˉ  ̱ ¨ ˚ ˙ . ¸
Other
Letters
Type = thencegjnostyz\'
Result ɔ ə ɂ ɲ ŋ ɵ ß þ ȝ ʒ ꞌ
Ɔ Ə Ɂ Ɲ Ŋ Ɵ ẞ Þ Ȝ Ʒ Ꞌ

Type \\ thendegknos
Result ð ɛ ǥ ĸ ʼn ø ſ
Ð Ɛ Ǥ Ø
Digraphs Typea\\ed\\zf\\if\\li\\jl\\jn\\jo\\eo\\i
Result æ dž fi fl ij lj nj œ ƣ
Æ Dž DŽ IJ Lj LJ Nj NJ Œ Ƣ
Punctuation
and Symbols
Type\\?\\!<<>>\\f\\m\\P\\S\\T\\t\\|\\c\\p\\rt\\m
Result¿¡«»ªº§‡†¦©℗®™

Type\\:\\\'\\,\\_\\M\\N\\-\\~\\...\\.\\>
Result¨´¸¯—–­¬…·•
Numbers
and Fractions
Type\\+\\x\\/\\*\\%\\u
Result±×÷°‰µ

Typen\\o\\1\\2\\3\\4\\5\\6\\7\\8\\9\\0
Result№¹²³⁴⁵⁶⁷⁸⁹⁰

Type1//21//32//31//43//41//52//53//54//51//65//61//83//85//87//8
Result½⅓⅔¼¾⅕⅖⅗⅘⅙⅚⅛⅜⅝⅞
Currency
Symbols
Type $ thencefhlnNpPrRwy
Result¢€₱₴₤₪₦£₧₨₹₩¥

Type $ thenCdDFgGkKt
Result¤₫₯₣₰₲₡₭₮
';this.KM=0;this.KBVER="1.6";this.KVKL={"tablet":{"font":"Tahoma","layer":[{"id":"default","row":[{"id":1,"key":[{"id":"K_Q","text":"q","sk":[{"id":"U_A78C"}]},{"id":"K_W","text":"w","sk":[{"id":"U_1E81"},{"id":"U_1E83"},{"id":"U_0175"},{"id":"U_1E85"},{"id":"U_1E98"},{"id":"U_1E87"},{"id":"U_1E89"}]},{"id":"K_E","text":"e","sk":[{"text":"\u00E8","id":"U_00E8"},{"text":"\u0205","id":"U_0205"},{"text":"\u00E9","id":"U_00E9"},{"text":"\u00EA","id":"U_00EA"},{"text":"\u011B","id":"U_011B"},{"text":"\u0207","id":"U_0207"},{"text":"\u0115","id":"U_0115"},{"text":"\u1EBD","id":"U_1EBD"},{"text":"\u0113","id":"U_0113"},{"text":"\u00EB","id":"U_00EB"},{"text":"\u0117","id":"U_0117"},{"text":"\u1EB9","id":"U_1EB9"},{"text":"\u0119","id":"U_0119"},{"text":"\u0259","id":"U_0259"},{"text":"\u025B","id":"U_025B"}]},{"id":"K_R","text":"r","sk":[{"id":"U_0211"},{"id":"U_0155"},{"id":"U_0159"},{"id":"U_0213"},{"id":"U_024D"},{"id":"U_1E5F"},{"id":"U_1E59"},{"id":"U_1E5B"},{"id":"U_0157"}]},{"id":"K_T","text":"t","sk":[{"text":"\u0165","id":"U_0165"},{"text":"\u0167","id":"U_0167"},{"text":"\u1E6F","id":"U_1E6F"},{"text":"\u1E97","id":"U_1E97"},{"text":"\u1E6B","id":"U_1E6B"},{"text":"\u1E6D","id":"U_1E6D"},{"text":"\u0163","id":"U_0163"},{"text":"\u021B","id":"U_021B"},{"text":"\u00FE","id":"U_00FE"}]},{"id":"K_Y","text":"y","sk":[{"id":"U_1EF3"},{"id":"U_00FD"},{"id":"U_0177"},{"id":"U_1EF9"},{"id":"U_0233"},{"id":"U_00FF"},{"id":"U_1E99"},{"id":"U_1E8F"},{"id":"U_1EF5"}]},{"id":"K_U","text":"u","sk":[{"id":"U_00F9"},{"id":"U_0215"},{"id":"U_00FA"},{"id":"U_0171"},{"id":"U_00FB"},{"id":"U_01D4"},{"id":"U_0217"},{"id":"U_016D"},{"id":"U_0169"},{"id":"U_016B"},{"id":"U_00FC"},{"id":"U_016F"},{"id":"U_1EE5"},{"id":"U_0173"}]},{"id":"K_I","text":"i","sk":[{"id":"U_00EC"},{"id":"U_0209"},{"id":"U_00ED"},{"id":"U_00EE"},{"id":"U_01D0"},{"id":"U_020B"},{"id":"U_012D"},{"id":"U_0129"},{"id":"U_012B"},{"id":"U_00EF"},{"id":"U_0131"},{"id":"U_1ECB"},{"id":"U_012F"},{"id":"U_0272"},{"id":"U_0133"}]},{"id":"K_O","text":"o","sk":[{"id":"U_00F2"},{"id":"U_020D"},{"id":"U_00F3"},{"id":"U_0151"},{"id":"U_00F4"},{"id":"U_01D2"},{"id":"U_020F"},{"id":"U_014F"},{"id":"U_00F5"},{"id":"U_014D"},{"id":"U_00F6"},{"id":"U_022F"},{"id":"U_1ECD"},{"id":"U_01EB"},{"id":"U_0275"},{"id":"U_00F8"},{"id":"U_0254"},{"id":"U_0153"},{"id":"U_01A3"}]},{"id":"K_P","text":"p","sk":[{"id":"U_1E55"},{"id":"U_0070"},{"id":"U_1E57"}]}]},{"id":2,"key":[{"id":"K_A","text":"a","pad":"40","sk":[{"id":"U_00E0"},{"id":"U_0201"},{"id":"U_00E1"},{"id":"U_00E2"},{"id":"U_01CE"},{"id":"U_0203"},{"id":"U_0103"},{"id":"U_00E3"},{"id":"U_0101"},{"id":"U_00E4"},{"id":"U_00E5"},{"id":"U_0227"},{"id":"U_1EA1"},{"id":"U_0105"},{"id":"U_00E6"}]},{"id":"K_S","text":"s","sk":[{"text":"\u015B","id":"U_015B"},{"text":"\u015D","id":"U_015D"},{"text":"\u0161","id":"U_0161"},{"text":"\u1E61","id":"U_1E61"},{"text":"\u1E63","id":"U_1E63"},{"text":"\u015F","id":"U_015F"},{"text":"\u0219","id":"U_0219"},{"text":"\u00DF","id":"U_00DF"},{"text":"\u017F","id":"U_017F"}]},{"id":"K_D","text":"d","sk":[{"id":"U_010F"},{"id":"U_0111"},{"id":"U_1E0F"},{"id":"U_1E0B"},{"id":"U_1E0D"},{"id":"U_1E11"},{"id":"U_00F0"},{"id":"U_01C6"}]},{"id":"K_F","text":"f","sk":[{"id":"U_1E1F"},{"id":"U_FB01"},{"id":"U_FB02"}]},{"id":"K_G","text":"g","sk":[{"id":"U_01F5"},{"id":"U_011D"},{"id":"U_01E7"},{"id":"U_011F"},{"id":"U_0067"},{"id":"U_1E21"},{"id":"U_0121"},{"id":"U_0123"},{"id":"U_0242"},{"id":"U_01E5"}]},{"id":"K_H","text":"h","sk":[{"id":"U_0125"},{"id":"U_021F"},{"id":"U_1E2B"},{"id":"U_0127"},{"id":"U_1E96"},{"id":"U_1E27"},{"id":"U_1E23"},{"id":"U_1E25"},{"id":"U_1E29"}]},{"id":"K_J","text":"j","sk":[{"id":"U_0135"},{"id":"U_01F0"},{"id":"U_0249"},{"id":"U_0237"}]},{"id":"K_K","text":"k","sk":[{"id":"U_1E31"},{"id":"U_01E9"},{"id":"U_1E35"},{"id":"U_1E33"},{"id":"U_0137"},{"id":"U_0138"}]},{"id":"K_L","text":"l","sk":[{"id":"U_013A"},{"id":"U_013E"},{"id":"U_026B"},{"id":"U_0142"},{"id":"U_1E3B"},{"id":"U_0140"},{"id":"U_1E37"},{"id":"U_013C"},{"id":"U_01C9"}]},{"id":"T_new_20","text":"","width":"10","sp":"10"}]},{"id":3,"key":[{"id":"K_SHIFT","text":"*Shift*","width":"100","sp":"1","nextlayer":"shift"},{"id":"K_Z","text":"z","sk":[{"id":"U_017A"},{"id":"U_1E91"},{"id":"U_017E"},{"id":"U_01B6"},{"id":"U_1E95"},{"id":"U_017C"},{"id":"U_1E93"},{"id":"U_2C6C"},{"id":"U_0292"},{"id":"U_01EF"}]},{"id":"K_X","text":"x","sk":[{"id":"U_1E8D"},{"id":"U_1E8B"}]},{"id":"K_C","text":"c","sk":[{"id":"U_0107"},{"id":"U_0109"},{"id":"U_010D"},{"id":"U_010B"},{"id":"U_00E7"}]},{"id":"K_V","text":"v","sk":[{"id":"U_1E7D"},{"id":"U_1E7F"}]},{"id":"K_B","text":"b","sk":[{"id":"U_0180"},{"id":"U_1E07"},{"id":"U_1E03"},{"id":"U_1E05"}]},{"id":"K_N","text":"n","sk":[{"id":"U_014B"},{"id":"U_01F9"},{"id":"U_0144"},{"id":"U_0148"},{"id":"U_00F1"},{"id":"U_1E49"},{"id":"U_1E45"},{"id":"U_1E47"},{"id":"U_0146"},{"id":"U_0149"},{"id":"U_01CC"}]},{"id":"K_M","text":"m","sk":[{"id":"U_1E3F"},{"id":"U_1E41"},{"id":"U_1E43"}]},{"id":"K_PERIOD","text":".","sk":[{"id":"K_COMMA","text":","},{"id":"U_0021"},{"id":"U_003F"},{"id":"U_0027"},{"id":"U_0022"},{"id":"U_005C"},{"id":"U_003A"},{"id":"U_003B"}]},{"id":"K_BKSP","text":"*BkSp*","width":"100","sp":"1"}]},{"id":4,"key":[{"id":"K_NUMERALS","text":"*123*","width":"150","sp":"1","nextlayer":"numeric"},{"id":"K_LOPT","text":"*Menu*","width":"100","sp":"1"},{"id":"T_new_34","text":"","width":"10","sp":"10"},{"id":"K_SPACE","text":"","width":"610","sp":"0"},{"id":"T_new_36","text":"","width":"10","sp":"10"},{"id":"K_ENTER","text":"*Enter*","width":"140","sp":"1"}]}]},{"id":"shift","row":[{"id":1,"key":[{"id":"K_Q","text":"Q","sk":[{"id":"U_A78B"}]},{"id":"K_W","text":"W","sk":[{"id":"U_1E80"},{"id":"U_1E82"},{"id":"U_0174"},{"id":"U_1E84"},{"id":"U_1E86"},{"id":"U_1E88"}]},{"id":"K_E","text":"E","sk":[{"id":"U_00C8"},{"id":"U_0204"},{"id":"U_00C9"},{"id":"U_00CA"},{"id":"U_011A"},{"id":"U_0206"},{"id":"U_0114"},{"id":"U_1EBC"},{"id":"U_0112"},{"id":"U_00CB"},{"id":"U_0116"},{"id":"U_1EB8"},{"id":"U_0118"},{"id":"U_018F"},{"id":"U_0190"}]},{"id":"K_R","text":"R","sk":[{"id":"U_0210"},{"id":"U_0154"},{"id":"U_0158"},{"id":"U_0212"},{"id":"U_024C"},{"id":"U_1E5E"},{"id":"U_1E58"},{"id":"U_1E5A"},{"id":"U_0156"}]},{"id":"K_T","text":"T","sk":[{"text":"\u0164","id":"U_0164"},{"text":"\u0166","id":"U_0166"},{"text":"\u1E6E","id":"U_1E6E"},{"text":"\u1E6A","id":"U_1E6A"},{"text":"\u1E6C","id":"U_1E6C"},{"text":"\u0162","id":"U_0162"},{"text":"\u021A","id":"U_021A"},{"text":"\u00DE","id":"U_00DE"}]},{"id":"K_Y","text":"Y","sk":[{"id":"U_1EF2"},{"id":"U_00DD"},{"id":"U_0176"},{"id":"U_1EF8"},{"id":"U_0232"},{"id":"U_0178"},{"id":"U_1E8E"},{"id":"U_1EF4"}]},{"id":"K_U","text":"U","sk":[{"id":"U_00D9"},{"id":"U_0214"},{"id":"U_00DA"},{"id":"U_0170"},{"id":"U_00DB"},{"id":"U_01D3"},{"id":"U_0216"},{"id":"U_016C"},{"id":"U_0168"},{"id":"U_016A"},{"id":"U_00DC"},{"id":"U_016E"},{"id":"U_1EE4"},{"id":"U_0172"}]},{"id":"K_I","text":"I","sk":[{"id":"U_00CC"},{"id":"U_0208"},{"id":"U_00CD"},{"id":"U_00CE"},{"id":"U_01CF"},{"id":"U_020A"},{"id":"U_012C"},{"id":"U_0128"},{"id":"U_012A"},{"id":"U_00CF"},{"id":"U_0130"},{"id":"U_1ECA"},{"id":"U_012E"},{"id":"U_019D"}]},{"id":"K_O","text":"O","sk":[{"id":"U_00D2"},{"id":"U_020C"},{"id":"U_00D3"},{"id":"U_0150"},{"id":"U_00D4"},{"id":"U_01D1"},{"id":"U_020E"},{"id":"U_014E"},{"id":"U_00D5"},{"id":"U_014C"},{"id":"U_00D6"},{"id":"U_022E"},{"id":"U_1ECC"},{"id":"U_01EA"},{"id":"U_019F"},{"id":"U_00D8"},{"id":"U_0186"},{"id":"U_0152"},{"id":"U_01A2"}]},{"id":"K_P","text":"P","sk":[{"id":"U_1E54"},{"id":"U_0050"},{"id":"U_1E56"}]}]},{"id":2,"key":[{"id":"K_A","text":"A","pad":"40","sk":[{"id":"U_00C0"},{"id":"U_0200"},{"id":"U_00C1"},{"id":"U_00C2"},{"id":"U_01CD"},{"id":"U_0202"},{"id":"U_0102"},{"id":"U_00C3"},{"id":"U_0100"},{"id":"U_00C4"},{"id":"U_00C5"},{"id":"U_0226"},{"id":"U_1EA0"},{"id":"U_0104"},{"id":"U_00C6"}]},{"id":"K_S","text":"S","sk":[{"text":"\u015A","id":"U_015A"},{"text":"\u015C","id":"U_015C"},{"text":"\u0160","id":"U_0160"},{"text":"\u1E60","id":"U_1E60"},{"text":"\u1E62","id":"U_1E62"},{"text":"\u015E","id":"U_015E"},{"text":"\u0218","id":"U_0218"},{"text":"\u1E9E","id":"U_1E9E"}]},{"id":"K_D","text":"D","sk":[{"id":"U_010E"},{"id":"U_0110"},{"id":"U_1E0E"},{"id":"U_1E0A"},{"id":"U_1E0C"},{"id":"U_1E10"},{"id":"U_00D0"},{"id":"U_01C5"},{"id":"U_01C4"}]},{"id":"K_F","text":"F","sk":[{"id":"U_1E1E"}]},{"id":"K_G","text":"G","sk":[{"id":"U_01F4"},{"id":"U_011C"},{"id":"U_01E6"},{"id":"U_011E"},{"id":"U_0047"},{"id":"U_1E20"},{"id":"U_0120"},{"id":"U_0122"},{"id":"U_0241"},{"id":"U_01E4"}]},{"id":"K_H","text":"H","sk":[{"id":"U_0124"},{"id":"U_021E"},{"id":"U_1E2A"},{"id":"U_0126"},{"id":"U_1E26"},{"id":"U_1E22"},{"id":"U_1E24"},{"id":"U_1E28"}]},{"id":"K_J","text":"J","sk":[{"id":"U_0134"},{"id":"U_0248"}]},{"id":"K_K","text":"K","sk":[{"id":"U_1E30"},{"id":"U_01E8"},{"id":"U_1E34"},{"id":"U_1E32"},{"id":"U_0136"}]},{"id":"K_L","text":"L","sk":[{"id":"U_0139"},{"id":"U_013D"},{"id":"U_2C62"},{"id":"U_0141"},{"id":"U_1E3A"},{"id":"U_013F"},{"id":"U_1E36"},{"id":"U_013B"},{"id":"U_01C8"},{"id":"U_01C7"}]},{"id":"T_new_60","text":"","width":"10","sp":"10"}]},{"id":3,"key":[{"id":"K_SHIFT","text":"*Shift*","width":"100","sp":"2","nextlayer":"default"},{"id":"K_Z","text":"Z","sk":[{"id":"U_021C"},{"id":"U_0179"},{"id":"U_1E90"},{"id":"U_017D"},{"id":"U_01B5"},{"id":"U_1E94"},{"id":"U_017B"},{"id":"U_1E92"},{"id":"U_2C6B"},{"id":"U_01B7"},{"id":"U_01EE"}]},{"id":"K_X","text":"X","sk":[{"id":"U_1E8C"},{"id":"U_1E8A"}]},{"id":"K_C","text":"C","sk":[{"id":"U_0106"},{"id":"U_0108"},{"id":"U_010C"},{"id":"U_010A"},{"id":"U_00C7"}]},{"id":"K_V","text":"V","sk":[{"id":"U_1E7C"},{"id":"U_1E7E"}]},{"id":"K_B","text":"B","sk":[{"id":"U_0243"},{"id":"U_1E06"},{"id":"U_1E02"},{"id":"U_1E04"}]},{"id":"K_N","text":"N","sk":[{"id":"U_014A"},{"id":"U_01F8"},{"id":"U_0143"},{"id":"U_0147"},{"id":"U_00D1"},{"id":"U_1E48"},{"id":"U_1E44"},{"id":"U_1E46"},{"id":"U_0145"},{"id":"U_01CB"},{"id":"U_01CA"}]},{"id":"K_M","text":"M","sk":[{"id":"U_1E3E"},{"id":"U_1E40"},{"id":"U_1E42"}]},{"id":"K_PERIOD","text":".","layer":"default","sk":[{"text":",","id":"K_COMMA"},{"text":"!","id":"U_0021","layer":"default"},{"text":"?","id":"U_003F","layer":"default"},{"text":"'","id":"U_0027","layer":"default"},{"text":"\"","id":"U_0022","layer":"default"},{"text":"\\","id":"U_005C","layer":"default"},{"text":":","id":"U_003A","layer":"default"},{"text":";","id":"U_003B","layer":"default"}]},{"id":"K_BKSP","text":"*BkSp*","width":"100","sp":"1"}]},{"id":4,"key":[{"id":"K_NUMERALS","text":"*123*","width":"150","sp":"1","nextlayer":"numeric"},{"id":"K_LOPT","text":"*Menu*","width":"100","sp":"1"},{"id":"T_new_74","text":"","width":"10","sp":"10"},{"id":"K_SPACE","text":"","width":"610","sp":"0"},{"id":"T_new_76","text":"","width":"10","sp":"10"},{"id":"K_ENTER","text":"*Enter*","width":"140","sp":"1"}]}]},{"id":"numeric","row":[{"id":1,"key":[{"id":"K_1","text":"1","sp":"0","sk":[{"id":"U_00B9"},{"id":"U_00BD"},{"id":"U_2153"},{"id":"U_00BC"},{"id":"U_2155"},{"id":"U_2159"},{"id":"U_215B"}]},{"id":"K_2","text":"2","sp":"0","sk":[{"id":"U_00B2"},{"id":"U_2154"},{"id":"U_2156"}]},{"id":"K_3","text":"3","sp":"0","sk":[{"id":"U_00B3"},{"id":"U_00BE"},{"id":"U_2157"},{"id":"U_215C"}]},{"id":"K_4","text":"4","sp":"0","sk":[{"id":"U_2074"},{"id":"U_2158"}]},{"id":"K_5","text":"5","sp":"0","sk":[{"id":"U_2075"},{"id":"U_215A"},{"id":"U_215D"}]},{"id":"K_6","text":"6","sp":"0","sk":[{"id":"U_2076"}]},{"id":"K_7","text":"7","sp":"0","sk":[{"id":"U_2077"},{"id":"U_215E"}]},{"id":"K_8","text":"8","sp":"0","sk":[{"id":"U_2078"}]},{"id":"K_9","text":"9","sp":"0","sk":[{"id":"U_2079"}]},{"id":"K_0","text":"0","sp":"0","sk":[{"id":"U_2070"}]}]},{"id":2,"key":[{"id":"U_0024","text":"$","pad":"40"},{"id":"U_0040","text":"@"},{"id":"U_0023","text":"#"},{"id":"U_0025","text":"%","sk":[{"id":"U_2030"},{"id":"U_2031"}]},{"id":"U_0026","text":"&"},{"id":"U_005F","text":"_"},{"id":"U_003D","text":"="},{"id":"U_007C","text":"|"},{"id":"U_002F","text":"\/","sk":[{"text":"\\","id":"U_005C"}]},{"id":"T_new_164","text":"","width":"10","sp":"10"}]},{"id":3,"key":[{"id":"K_LOWER","text":"*abc*","width":"100","sp":"1","nextlayer":"default"},{"id":"U_005B","text":"[","sk":[{"id":"U_007B"},{"id":"U_00AB"},{"id":"U_003C"}]},{"id":"U_0028","text":"("},{"id":"U_0029","text":")"},{"id":"U_005D","text":"]","sk":[{"id":"U_007D"},{"id":"U_00BB"},{"id":"U_003E"}]},{"id":"U_002B","text":"+"},{"id":"U_002D","text":"-"},{"id":"U_002A","text":"*"},{"id":"K_PERIOD","text":".","sk":[{"id":"K_COMMA","text":","},{"id":"U_0021"},{"id":"U_003F"},{"id":"U_0027"},{"id":"U_0022"},{"id":"U_005C"},{"id":"U_003A"},{"id":"U_003B"}]},{"id":"K_BKSP","text":"*BkSp*","width":"100","sp":"1"}]},{"id":4,"key":[{"id":"K_CURRENCIES","text":"*Currency*","width":"150","sp":"1","nextlayer":"currency"},{"id":"K_LOPT","text":"*Menu*","width":"100","sp":"1"},{"id":"T_new_178","text":"","width":"10","sp":"10"},{"id":"K_SPACE","text":"","width":"610","sp":"0"},{"id":"T_new_180","text":"","width":"10","sp":"10"},{"id":"K_ENTER","text":"*Enter*","width":"140","sp":"1"}]}]},{"id":"symbol","row":[{"id":1,"key":[{"id":"U_0060","text":"`"},{"id":"U_007E","text":"~"},{"id":"U_005E","text":"^"},{"id":"U_00A8","text":"\u00A8"},{"id":"U_00B4","text":"\u00B4"},{"id":"U_00B8","text":"\u00B8"},{"id":"U_00AF","text":"\u00AF"},{"id":"U_00BF","text":"\u00BF"},{"id":"U_00A1","text":"\u00A1"},{"id":"U_00AC","text":"\u00AC"}]},{"id":2,"key":[{"id":"U_00AA","text":"\u00AA","pad":"40"},{"id":"U_00BA","text":"\u00BA"},{"id":"U_00B6","text":"\u00B6"},{"id":"U_00A7","text":"\u00A7"},{"id":"U_2021","text":"\u2021"},{"id":"U_2020","text":"\u2020"},{"id":"U_00A6","text":"\u00A6"},{"id":"U_2122","text":"\u2122"},{"id":"U_2116","text":"\u2116"},{"id":"T_new_336","text":"","width":"10","sp":"10"}]},{"id":3,"key":[{"id":"K_LOWER","text":"*abc*","width":"100","sp":"1","nextlayer":"default"},{"id":"U_00A9","text":"\u00A9"},{"id":"U_2117","text":"\u2117"},{"id":"U_00AE","text":"\u00AE"},{"id":"U_2014","text":"\u2014"},{"id":"U_2013","text":"\u2013"},{"id":"U_2022","text":"\u2022"},{"id":"U_00B7","text":"\u00B7"},{"id":"U_2026","text":"\u2026","sk":[{"id":"U_00B1"},{"id":"U_00D7"},{"id":"U_00F7"},{"id":"U_00B5"},{"id":"U_00B0"},{"id":"U_2031"}]},{"id":"K_BKSP","text":"*BkSp*","width":"100","sp":"1"}]},{"id":4,"key":[{"id":"K_CURRENCIES","text":"*Currency*","width":"150","sp":"1","nextlayer":"numeric"},{"id":"K_LOPT","text":"*Menu*","width":"100","sp":"1"},{"id":"T_new_350","text":"","width":"10","sp":"10"},{"id":"K_SPACE","text":"","width":"610","sp":"0"},{"id":"T_new_352","text":"","width":"10","sp":"10"},{"id":"K_ENTER","text":"*Enter*","width":"140","sp":"1"}]}]},{"id":"currency","row":[{"id":1,"key":[{"id":"U_00A2","text":"\u00A2","nextlayer":"numeric"},{"id":"U_20AC","text":"\u20AC","nextlayer":"numeric"},{"id":"U_20A4","text":"\u20A4","nextlayer":"numeric"},{"id":"U_00A3","text":"\u00A3","nextlayer":"numeric"},{"id":"U_20AA","text":"\u20AA","nextlayer":"numeric"},{"id":"U_20A8","text":"\u20A8","nextlayer":"numeric"},{"id":"U_20B9","text":"\u20B9","nextlayer":"numeric"},{"id":"U_20A9","text":"\u20A9","nextlayer":"numeric"},{"id":"U_00A5","text":"\u00A5","nextlayer":"numeric"},{"id":"U_00A4","text":"\u00A4","nextlayer":"numeric"}]},{"id":2,"key":[{"id":"U_20AB","text":"\u20AB","pad":"40"},{"id":"U_20AF","text":"\u20AF"},{"id":"U_20B1","text":"\u20B1"},{"id":"U_20A3","text":"\u20A3"},{"id":"U_20B0","text":"\u20B0"},{"id":"U_20B2","text":"\u20B2"},{"id":"U_20B4","text":"\u20B4"},{"id":"U_20A1","text":"\u20A1"},{"id":"U_20AD","text":"\u20AD"},{"id":"T_new_2717","text":"","width":"10","sp":"10"}]},{"id":3,"key":[{"id":"K_LOWER","text":"*abc*","width":"100","sp":"1","nextlayer":"default"},{"id":"U_20A6","text":"\u20A6"},{"id":"U_20A7","text":"\u20A7"},{"id":"U_20AE","text":"\u20AE"},{"id":"U_0BF9","text":"\u0BF9"},{"id":"U_09F3","text":"\u09F3"},{"id":"U_0E3F","text":"\u0E3F"},{"id":"T_new_2725","text":"","sp":"9"},{"id":"T_new_2726","text":"","sp":"9"},{"id":"K_BKSP","text":"*BkSp*","width":"100","sp":"1"}]},{"id":4,"key":[{"id":"K_SYMBOLS","text":"*Symbol*","width":"150","sp":"1","nextlayer":"symbol"},{"id":"K_LOPT","text":"*Menu*","width":"100","sp":"1"},{"id":"T_new_2731","text":"","width":"10","sp":"10"},{"id":"K_SPACE","text":"","width":"610","sp":"0"},{"id":"T_new_2733","text":"","width":"10","sp":"10"},{"id":"K_ENTER","text":"*Enter*","width":"140","sp":"1"}]}]}]}};this.s15="`#'\"^%&*~-_:@.|,=\\$";this.s16="àèìǹòùẁỳÀÈÌǸÒÙẀỲ";this.s17="aeinouwyAEINOUWY";this.s18="ȁȅȉȍȑȕȀȄȈȌȐȔ";this.s19="aeioruAEIORU";this.s20="áćéǵíḱĺḿńóṕŕśúẃýźÁĆÉǴÍḰĹḾŃÓṔŔŚÚẂÝŹ";this.s21="acegiklmnoprsuwyzACEGIKLMNOPRSUWYZ";this.s22="őűŐŰ";this.s23="ouOU";this.s24="âĉêĝĥîĵôŝûŵŷẑÂĈÊĜĤÎĴÔŜÛŴŶẐ";this.s25="aceghijosuwyzACEGHIJOSUWYZ";this.s26="ǎǍčČďĎěĚǧǦȟȞǐǏǰǩǨľĽňŇǒǑřŘšŠťŤǔǓǯǮžŽ";this.s27="aAcCdDeEgGhHiIjkKlLnNoOrRsStTuUxXzZ";this.s28="ȂȃȆȇȊȋȎȏȒȓȖȗ";this.s29="AaEeIiOoRrUu";this.s30="ăĂĕĔğĞḫḪĭĬŏŎŭŬ";this.s31="aAeEgGhHiIoOuU";this.s32="ãÃẽẼĩĨɫⱢñÑõÕũŨṽṼỹỸ";this.s33="aAeEiIlLnNoOuUvVyY";this.s34="ĀāɃƀĐđĒēḠḡĦħĪīɈɉŁłŌōɌɍŦŧŪūȲȳƵƶ";this.s35="AaBbDdEeGgHhIiJjLlOoRrTtUuYyZz";this.s36="ḆḇḎḏẖḴḵḺḻṈṉṞṟṮṯẔẕ";this.s37="BbDdhKkLlNnRrTtZz";this.s38="äëḧïöẗüẅẍÿÄËḦÏÖÜẄẌŸ";this.s39="aehiotuwxyAEHIOUWXY";this.s40="åÅůŮẘẙșȘțȚ";this.s41="aAuUwysStT";this.s42="ȧȦḃḂċĊḋḊėĖḟḞġĠḣḢıİȷŀĿṁṀṅṄȯȮṗṖṙṘṡṠṫṪẇẆẋẊẏẎżŻ";this.s43="aAbBcCdDeEfFgGhHiIjlLmMnNoOpPrRsStTwWxXyYzZ";this.s44="ẠạḄḅḌḍẸẹḤḥỊịḲḳḶḷṂṃṆṇỌọṚṛṢṣṬṭỤụṾṿẈẉỴỵẒẓ";this.s45="AaBbDdEeHhIiKkLlMmNnOoRrSsTtUuVvWwYyZz";this.s46="ąĄçÇḑḐęĘģĢḩḨįĮķĶļĻņŅǫǪŗŖşŞţŢųŲⱬⱫ";this.s47="aAcCdDeEgGhHiIkKlLnNoOrRsStTuUzZ";this.s48="ƆɔƏəɁɂƝɲŊŋƟɵẞßÞþȜȝƷʒ";this.s49="CcEeGgJjNnOoSsTtYyZz";this.s50="©ÐðƐɛªǤǥĸ—º–ʼnØø¶℗®§ſ‡†µ×¡¦¨¬­¯°±´·¸¿÷‰•¹²³⁴⁵⁶⁷⁸⁹⁰";this.s51="cDdEefGgkMmNnOoPprSsTtux!|:~-_*+'.,?/%>1234567890";this.s52="¤¢₯₫€€₱₣₲₰₴₡₭₤₦₪₧£₹₨₮₩¥";this.s53="CcDdEefFGghkKlNnPpRrtwy";this.s56="tablet";this.s57="phone";this.KVER="9.0.487.0";this.gs=function(t,e) {return this.g0(t,e);};this.g0=function(t,e) {var k=KeymanWeb,r=0,m=0;if(k.KKM(e,16400,49)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"¡");}else if(k.KKM(e,16400,222)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ꞌ");}else if(k.KKM(e,16400,222)&&k.KCM(1,t,"\"",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"\"");}else if(k.KKM(e,16400,222)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,222)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,222)) {r=m=1;k.KO(0,t,"\"");k.KDO(-1,t,0);}else if(k.KKM(e,16400,51)&&k.KCM(1,t,"#",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"#");}else if(k.KKM(e,16400,51)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,51)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,51)) {r=m=1;k.KO(0,t,"#");k.KDO(-1,t,0);}else if(k.KKM(e,16400,52)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"$");}else if(k.KKM(e,16400,52)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,52)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,52)) {r=m=1;k.KO(0,t,"$");k.KDO(-1,t,0);}else if(k.KKM(e,16400,53)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"‰");}else if(k.KKM(e,16400,53)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"%");}else if(k.KKM(e,16400,53)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,53)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,53)) {r=m=1;k.KO(0,t,"%");k.KDO(-1,t,0);}else if(k.KKM(e,16400,55)&&k.KCM(1,t,"&",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"&");}else if(k.KKM(e,16400,55)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,55)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,55)) {r=m=1;k.KO(0,t,"&");k.KDO(-1,t,0);}else if(k.KKM(e,16384,222)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ꞌ");}else if(k.KKM(e,16384,222)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"´");}else if(k.KKM(e,16384,222)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"'");}else if(k.KKM(e,16384,222)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16384,222)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16384,222)) {r=m=1;k.KO(0,t,"'");k.KDO(-1,t,0);}else if(k.KKM(e,16400,56)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"°");}else if(k.KKM(e,16400,56)&&k.KCM(1,t,"*",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"*");}else if(k.KKM(e,16400,56)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,56)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,56)) {r=m=1;k.KO(0,t,"*");k.KDO(-1,t,0);}else if(k.KKM(e,16400,187)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"±");}else if(k.KKM(e,16384,188)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"¸");}else if(k.KKM(e,16384,188)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,",");}else if(k.KKM(e,16384,188)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16384,188)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16384,188)) {r=m=1;k.KO(0,t,",");k.KDO(-1,t,0);}else if(k.KKM(e,16384,189)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"­");}else if(k.KKM(e,16384,189)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"-");}else if(k.KKM(e,16384,189)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16384,189)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16384,189)) {r=m=1;k.KO(0,t,"-");k.KDO(-1,t,0);}else if(k.KKM(e,16384,190)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"·");}else if(k.KKM(e,16384,190)&&k.KCM(2,t,"·.",2)) {r=m=1;k.KO(2,t,"…");}else if(k.KKM(e,16384,190)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,".");}else if(k.KKM(e,16384,190)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16384,190)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16384,190)) {r=m=1;k.KO(0,t,".");k.KDO(-1,t,0);}else if(k.KKM(e,16384,191)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"÷");}else if(k.KKM(e,16384,48)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"⁰");}else if(k.KKM(e,16384,49)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"¹");}else if(k.KKM(e,16384,50)&&k.KCM(3,t,"1//",3)) {r=m=1;k.KO(3,t,"½");}else if(k.KKM(e,16384,50)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"²");}else if(k.KKM(e,16384,50)&&k.KCM(2,t,"¹/",2)) {r=m=1;k.KO(2,t,"½");}else if(k.KKM(e,16384,51)&&k.KCM(3,t,"1//",3)) {r=m=1;k.KO(3,t,"⅓");}else if(k.KKM(e,16384,51)&&k.KCM(3,t,"2//",3)) {r=m=1;k.KO(3,t,"⅔");}else if(k.KKM(e,16384,51)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"³");}else if(k.KKM(e,16384,51)&&k.KCM(2,t,"¹/",2)) {r=m=1;k.KO(2,t,"⅓");}else if(k.KKM(e,16384,51)&&k.KCM(2,t,"²/",2)) {r=m=1;k.KO(2,t,"⅔");}else if(k.KKM(e,16384,52)&&k.KCM(3,t,"1//",3)) {r=m=1;k.KO(3,t,"¼");}else if(k.KKM(e,16384,52)&&k.KCM(3,t,"3//",3)) {r=m=1;k.KO(3,t,"¾");}else if(k.KKM(e,16384,52)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"⁴");}else if(k.KKM(e,16384,52)&&k.KCM(2,t,"¹/",2)) {r=m=1;k.KO(2,t,"¼");}else if(k.KKM(e,16384,52)&&k.KCM(2,t,"³/",2)) {r=m=1;k.KO(2,t,"¾");}else if(k.KKM(e,16384,53)&&k.KCM(3,t,"1//",3)) {r=m=1;k.KO(3,t,"⅕");}else if(k.KKM(e,16384,53)&&k.KCM(3,t,"2//",3)) {r=m=1;k.KO(3,t,"⅖");}else if(k.KKM(e,16384,53)&&k.KCM(3,t,"3//",3)) {r=m=1;k.KO(3,t,"⅗");}else if(k.KKM(e,16384,53)&&k.KCM(3,t,"4//",3)) {r=m=1;k.KO(3,t,"⅘");}else if(k.KKM(e,16384,53)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"⁵");}else if(k.KKM(e,16384,54)&&k.KCM(3,t,"1//",3)) {r=m=1;k.KO(3,t,"⅙");}else if(k.KKM(e,16384,54)&&k.KCM(3,t,"5//",3)) {r=m=1;k.KO(3,t,"⅚");}else if(k.KKM(e,16384,54)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"⁶");}else if(k.KKM(e,16384,55)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"⁷");}else if(k.KKM(e,16384,56)&&k.KCM(3,t,"1//",3)) {r=m=1;k.KO(3,t,"⅛");}else if(k.KKM(e,16384,56)&&k.KCM(3,t,"3//",3)) {r=m=1;k.KO(3,t,"⅜");}else if(k.KKM(e,16384,56)&&k.KCM(3,t,"5//",3)) {r=m=1;k.KO(3,t,"⅝");}else if(k.KKM(e,16384,56)&&k.KCM(3,t,"7//",3)) {r=m=1;k.KO(3,t,"⅞");}else if(k.KKM(e,16384,56)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"⁸");}else if(k.KKM(e,16384,56)&&k.KCM(2,t,"¹/",2)) {r=m=1;k.KO(2,t,"⅛");}else if(k.KKM(e,16384,56)&&k.KCM(2,t,"³/",2)) {r=m=1;k.KO(2,t,"⅜");}else if(k.KKM(e,16384,56)&&k.KCM(2,t,"⁵/",2)) {r=m=1;k.KO(2,t,"⅝");}else if(k.KKM(e,16384,56)&&k.KCM(2,t,"⁷/",2)) {r=m=1;k.KO(2,t,"⅞");}else if(k.KKM(e,16384,57)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"⁹");}else if(k.KKM(e,16400,186)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"¨");}else if(k.KKM(e,16400,186)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,":");}else if(k.KKM(e,16400,186)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,186)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,186)) {r=m=1;k.KO(0,t,":");k.KDO(-1,t,0);}else if(k.KKM(e,16400,188)&&k.KCM(1,t,"<",1)&&k.KDM(0,t,1)) {r=m=1;k.KO(1,t,"<<");k.KDO(-1,t,1);}else if(k.KKM(e,16400,188)&&k.KCM(1,t,"<",1)) {r=m=1;k.KO(1,t,"«");}else if(k.KKM(e,16400,188)&&k.KCM(1,t,"«",1)) {r=m=1;k.KO(1,t,"<<");k.KDO(-1,t,1);}else if(k.KKM(e,16384,187)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"=");}else if(k.KKM(e,16384,187)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16384,187)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16384,187)) {r=m=1;k.KO(0,t,"=");k.KDO(-1,t,0);}else if(k.KKM(e,16400,190)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"•");}else if(k.KKM(e,16400,190)&&k.KCM(1,t,">",1)&&k.KDM(0,t,1)) {r=m=1;k.KO(1,t,">>");k.KDO(-1,t,1);}else if(k.KKM(e,16400,190)&&k.KCM(1,t,">",1)) {r=m=1;k.KO(1,t,"»");}else if(k.KKM(e,16400,190)&&k.KCM(1,t,"»",1)) {r=m=1;k.KO(1,t,">>");k.KDO(-1,t,1);}else if(k.KKM(e,16400,191)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"¿");}else if(k.KKM(e,16400,50)&&k.KCM(1,t,"@",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"@");}else if(k.KKM(e,16400,50)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,50)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,50)) {r=m=1;k.KO(0,t,"@");k.KDO(-1,t,0);}else if(k.KKM(e,16400,65)&&k.KCM(1,t,"`",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"À");}else if(k.KKM(e,16400,65)&&k.KCM(1,t,"#",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ȁ");}else if(k.KKM(e,16400,65)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Á");}else if(k.KKM(e,16400,65)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Â");}else if(k.KKM(e,16400,65)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ǎ");}else if(k.KKM(e,16400,65)&&k.KCM(1,t,"&",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ȃ");}else if(k.KKM(e,16400,65)&&k.KCM(1,t,"*",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ă");}else if(k.KKM(e,16400,65)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ã");}else if(k.KKM(e,16400,65)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ā");}else if(k.KKM(e,16400,65)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ä");}else if(k.KKM(e,16400,65)&&k.KCM(1,t,"@",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Å");}else if(k.KKM(e,16400,65)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ȧ");}else if(k.KKM(e,16400,65)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ạ");}else if(k.KKM(e,16400,65)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ą");}else if(k.KKM(e,16400,66)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ƀ");}else if(k.KKM(e,16400,66)&&k.KCM(1,t,"_",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḇ");}else if(k.KKM(e,16400,66)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḃ");}else if(k.KKM(e,16400,66)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḅ");}else if(k.KKM(e,16400,67)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ć");}else if(k.KKM(e,16400,67)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ĉ");}else if(k.KKM(e,16400,67)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Č");}else if(k.KKM(e,16400,67)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ċ");}else if(k.KKM(e,16400,67)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ç");}else if(k.KKM(e,16400,67)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ɔ");}else if(k.KKM(e,16400,67)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"¤");}else if(k.KKM(e,16400,68)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ď");}else if(k.KKM(e,16400,68)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Đ");}else if(k.KKM(e,16400,68)&&k.KCM(1,t,"_",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḏ");}else if(k.KKM(e,16400,68)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḋ");}else if(k.KKM(e,16400,68)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḍ");}else if(k.KKM(e,16400,68)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḑ");}else if(k.KKM(e,16400,68)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ð");}else if(k.KKM(e,16400,68)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"₯");}else if(k.KKM(e,16400,69)&&k.KCM(2,t,"A\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"Æ");}else if(k.KKM(e,16400,69)&&k.KCM(2,t,"O\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"Œ");}else if(k.KKM(e,16400,69)&&k.KCM(1,t,"`",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"È");}else if(k.KKM(e,16400,69)&&k.KCM(1,t,"#",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ȅ");}else if(k.KKM(e,16400,69)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"É");}else if(k.KKM(e,16400,69)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ê");}else if(k.KKM(e,16400,69)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ě");}else if(k.KKM(e,16400,69)&&k.KCM(1,t,"&",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ȇ");}else if(k.KKM(e,16400,69)&&k.KCM(1,t,"*",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ĕ");}else if(k.KKM(e,16400,69)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ẽ");}else if(k.KKM(e,16400,69)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ē");}else if(k.KKM(e,16400,69)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ë");}else if(k.KKM(e,16400,69)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ė");}else if(k.KKM(e,16400,69)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ẹ");}else if(k.KKM(e,16400,69)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ę");}else if(k.KKM(e,16400,69)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ə");}else if(k.KKM(e,16400,69)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ɛ");}else if(k.KKM(e,16400,69)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"€");}else if(k.KKM(e,16400,70)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḟ");}else if(k.KKM(e,16400,70)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"₣");}else if(k.KKM(e,16400,71)&&k.KCM(2,t,"N\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"Ŋ");}else if(k.KKM(e,16400,71)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"G̃");}else if(k.KKM(e,16400,71)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ǵ");}else if(k.KKM(e,16400,71)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ĝ");}else if(k.KKM(e,16400,71)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ǧ");}else if(k.KKM(e,16400,71)&&k.KCM(1,t,"*",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ğ");}else if(k.KKM(e,16400,71)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḡ");}else if(k.KKM(e,16400,71)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ġ");}else if(k.KKM(e,16400,71)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ģ");}else if(k.KKM(e,16400,71)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ɂ");}else if(k.KKM(e,16400,71)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ǥ");}else if(k.KKM(e,16400,71)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"₲");}else if(k.KKM(e,16400,72)&&k.KCM(2,t,"T\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"Þ");}else if(k.KKM(e,16400,72)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ĥ");}else if(k.KKM(e,16400,72)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ȟ");}else if(k.KKM(e,16400,72)&&k.KCM(1,t,"*",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḫ");}else if(k.KKM(e,16400,72)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ħ");}else if(k.KKM(e,16400,72)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḧ");}else if(k.KKM(e,16400,72)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḣ");}else if(k.KKM(e,16400,72)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḥ");}else if(k.KKM(e,16400,72)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḩ");}else if(k.KKM(e,16400,73)&&k.KCM(2,t,"O\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"Ƣ");}else if(k.KKM(e,16400,73)&&k.KCM(1,t,"`",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ì");}else if(k.KKM(e,16400,73)&&k.KCM(1,t,"#",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ȉ");}else if(k.KKM(e,16400,73)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Í");}else if(k.KKM(e,16400,73)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Î");}else if(k.KKM(e,16400,73)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ǐ");}else if(k.KKM(e,16400,73)&&k.KCM(1,t,"&",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ȋ");}else if(k.KKM(e,16400,73)&&k.KCM(1,t,"*",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ĭ");}else if(k.KKM(e,16400,73)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ĩ");}else if(k.KKM(e,16400,73)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ī");}else if(k.KKM(e,16400,73)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ï");}else if(k.KKM(e,16400,73)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"İ");}else if(k.KKM(e,16400,73)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ị");}else if(k.KKM(e,16400,73)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Į");}else if(k.KKM(e,16400,74)&&k.KCM(2,t,"I\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"IJ");}else if(k.KKM(e,16400,74)&&k.KCM(2,t,"L\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"LJ");}else if(k.KKM(e,16400,74)&&k.KCM(2,t,"N\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"NJ");}else if(k.KKM(e,16400,74)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ĵ");}else if(k.KKM(e,16400,74)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ɉ");}else if(k.KKM(e,16400,74)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ɲ");}else if(k.KKM(e,16400,75)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḱ");}else if(k.KKM(e,16400,75)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ǩ");}else if(k.KKM(e,16400,75)&&k.KCM(1,t,"_",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḵ");}else if(k.KKM(e,16400,75)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḳ");}else if(k.KKM(e,16400,75)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ķ");}else if(k.KKM(e,16400,75)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"₭");}else if(k.KKM(e,16400,76)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ĺ");}else if(k.KKM(e,16400,76)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ľ");}else if(k.KKM(e,16400,76)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ɫ");}else if(k.KKM(e,16400,76)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ł");}else if(k.KKM(e,16400,76)&&k.KCM(1,t,"_",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḻ");}else if(k.KKM(e,16400,76)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ŀ");}else if(k.KKM(e,16400,76)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḷ");}else if(k.KKM(e,16400,76)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ļ");}else if(k.KKM(e,16400,77)&&k.KCM(2,t,"T\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"™");}else if(k.KKM(e,16400,77)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ḿ");}else if(k.KKM(e,16400,77)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ṁ");}else if(k.KKM(e,16400,77)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ṃ");}else if(k.KKM(e,16400,77)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"—");}else if(k.KKM(e,16400,78)&&k.KCM(1,t,"`",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ǹ");}else if(k.KKM(e,16400,78)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ń");}else if(k.KKM(e,16400,78)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ň");}else if(k.KKM(e,16400,78)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ñ");}else if(k.KKM(e,16400,78)&&k.KCM(1,t,"_",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ṉ");}else if(k.KKM(e,16400,78)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ṅ");}else if(k.KKM(e,16400,78)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ṇ");}else if(k.KKM(e,16400,78)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ņ");}else if(k.KKM(e,16400,78)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ŋ");}else if(k.KKM(e,16400,78)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"–");}else if(k.KKM(e,16400,78)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"₦");}else if(k.KKM(e,16400,79)&&k.KCM(2,t,"N\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"№");}else if(k.KKM(e,16400,79)&&k.KCM(1,t,"`",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ò");}else if(k.KKM(e,16400,79)&&k.KCM(1,t,"#",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ȍ");}else if(k.KKM(e,16400,79)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ó");}else if(k.KKM(e,16400,79)&&k.KCM(1,t,"\"",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ő");}else if(k.KKM(e,16400,79)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ô");}else if(k.KKM(e,16400,79)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ǒ");}else if(k.KKM(e,16400,79)&&k.KCM(1,t,"&",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ȏ");}else if(k.KKM(e,16400,79)&&k.KCM(1,t,"*",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ŏ");}else if(k.KKM(e,16400,79)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Õ");}else if(k.KKM(e,16400,79)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ō");}else if(k.KKM(e,16400,79)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ö");}else if(k.KKM(e,16400,79)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ȯ");}else if(k.KKM(e,16400,79)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ọ");}else if(k.KKM(e,16400,79)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ǫ");}else if(k.KKM(e,16400,79)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ɵ");}else if(k.KKM(e,16400,79)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ø");}else if(k.KKM(e,16400,80)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"P̈");}else if(k.KKM(e,16400,80)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ṕ");}else if(k.KKM(e,16400,80)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ṗ");}else if(k.KKM(e,16400,80)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"¶");}else if(k.KKM(e,16400,80)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"₧");}else if(k.KKM(e,16400,82)&&k.KCM(1,t,"#",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ȑ");}else if(k.KKM(e,16400,82)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ŕ");}else if(k.KKM(e,16400,82)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ř");}else if(k.KKM(e,16400,82)&&k.KCM(1,t,"&",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ȓ");}else if(k.KKM(e,16400,82)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ɍ");}else if(k.KKM(e,16400,82)&&k.KCM(1,t,"_",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ṟ");}else if(k.KKM(e,16400,82)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ṙ");}else if(k.KKM(e,16400,82)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ṛ");}else if(k.KKM(e,16400,82)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ŗ");}else if(k.KKM(e,16400,82)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"₹");}else if(k.KKM(e,16400,83)&&k.KCM(2,t,"S\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"ẞ");}else if(k.KKM(e,16400,83)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ś");}else if(k.KKM(e,16400,83)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ŝ");}else if(k.KKM(e,16400,83)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Š");}else if(k.KKM(e,16400,83)&&k.KCM(1,t,"@",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ș");}else if(k.KKM(e,16400,83)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ṡ");}else if(k.KKM(e,16400,83)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ṣ");}else if(k.KKM(e,16400,83)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ş");}else if(k.KKM(e,16400,83)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ẞ");}else if(k.KKM(e,16400,83)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"§");}else if(k.KKM(e,16400,84)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ť");}else if(k.KKM(e,16400,84)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ŧ");}else if(k.KKM(e,16400,84)&&k.KCM(1,t,"_",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ṯ");}else if(k.KKM(e,16400,84)&&k.KCM(1,t,"@",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ț");}else if(k.KKM(e,16400,84)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ṫ");}else if(k.KKM(e,16400,84)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ṭ");}else if(k.KKM(e,16400,84)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ţ");}else if(k.KKM(e,16400,84)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Þ");}else if(k.KKM(e,16400,84)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"‡");}else if(k.KKM(e,16400,85)&&k.KCM(1,t,"`",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ù");}else if(k.KKM(e,16400,85)&&k.KCM(1,t,"#",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ȕ");}else if(k.KKM(e,16400,85)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ú");}else if(k.KKM(e,16400,85)&&k.KCM(1,t,"\"",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ű");}else if(k.KKM(e,16400,85)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Û");}else if(k.KKM(e,16400,85)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ǔ");}else if(k.KKM(e,16400,85)&&k.KCM(1,t,"&",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ȗ");}else if(k.KKM(e,16400,85)&&k.KCM(1,t,"*",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ŭ");}else if(k.KKM(e,16400,85)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ũ");}else if(k.KKM(e,16400,85)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ū");}else if(k.KKM(e,16400,85)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ü");}else if(k.KKM(e,16400,85)&&k.KCM(1,t,"@",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ů");}else if(k.KKM(e,16400,85)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ụ");}else if(k.KKM(e,16400,85)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ų");}else if(k.KKM(e,16400,86)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ṽ");}else if(k.KKM(e,16400,86)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ṿ");}else if(k.KKM(e,16400,87)&&k.KCM(1,t,"`",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ẁ");}else if(k.KKM(e,16400,87)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ẃ");}else if(k.KKM(e,16400,87)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ŵ");}else if(k.KKM(e,16400,87)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ẅ");}else if(k.KKM(e,16400,87)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ẇ");}else if(k.KKM(e,16400,87)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ẉ");}else if(k.KKM(e,16400,88)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ǯ");}else if(k.KKM(e,16400,88)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ẍ");}else if(k.KKM(e,16400,88)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ẋ");}else if(k.KKM(e,16400,89)&&k.KCM(1,t,"`",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ỳ");}else if(k.KKM(e,16400,89)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ý");}else if(k.KKM(e,16400,89)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ŷ");}else if(k.KKM(e,16400,89)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ỹ");}else if(k.KKM(e,16400,89)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ȳ");}else if(k.KKM(e,16400,89)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ÿ");}else if(k.KKM(e,16400,89)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ẏ");}else if(k.KKM(e,16400,89)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ỵ");}else if(k.KKM(e,16400,89)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ȝ");}else if(k.KKM(e,16400,90)&&k.KCM(2,t,"D\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"DŽ");}else if(k.KKM(e,16400,90)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ź");}else if(k.KKM(e,16400,90)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ẑ");}else if(k.KKM(e,16400,90)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ž");}else if(k.KKM(e,16400,90)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ƶ");}else if(k.KKM(e,16400,90)&&k.KCM(1,t,"_",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ẕ");}else if(k.KKM(e,16400,90)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ż");}else if(k.KKM(e,16400,90)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ẓ");}else if(k.KKM(e,16400,90)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ⱬ");}else if(k.KKM(e,16400,90)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"Ʒ");}else if(k.KKM(e,16384,220)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"\\");}else if(k.KKM(e,16384,220)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16384,220)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16384,220)) {r=m=1;k.KO(0,t,"\\");k.KDO(-1,t,0);}else if(k.KKM(e,16400,54)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"^");}else if(k.KKM(e,16400,54)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,54)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,54)) {r=m=1;k.KO(0,t,"^");k.KDO(-1,t,0);}else if(k.KKM(e,16400,189)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"¯");}else if(k.KKM(e,16400,189)&&k.KCM(1,t,"_",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"_");}else if(k.KKM(e,16400,189)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,189)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,189)) {r=m=1;k.KO(0,t,"_");k.KDO(-1,t,0);}else if(k.KKM(e,16384,192)&&k.KCM(1,t,"`",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"`");}else if(k.KKM(e,16384,192)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16384,192)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16384,192)) {r=m=1;k.KO(0,t,"`");k.KDO(-1,t,0);}else if(k.KKM(e,16384,65)&&k.KCM(1,t,"`",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"à");}else if(k.KKM(e,16384,65)&&k.KCM(1,t,"#",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ȁ");}else if(k.KKM(e,16384,65)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"á");}else if(k.KKM(e,16384,65)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"â");}else if(k.KKM(e,16384,65)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ǎ");}else if(k.KKM(e,16384,65)&&k.KCM(1,t,"&",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ȃ");}else if(k.KKM(e,16384,65)&&k.KCM(1,t,"*",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ă");}else if(k.KKM(e,16384,65)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ã");}else if(k.KKM(e,16384,65)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ā");}else if(k.KKM(e,16384,65)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ä");}else if(k.KKM(e,16384,65)&&k.KCM(1,t,"@",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"å");}else if(k.KKM(e,16384,65)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ȧ");}else if(k.KKM(e,16384,65)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ạ");}else if(k.KKM(e,16384,65)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ą");}else if(k.KKM(e,16384,66)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ƀ");}else if(k.KKM(e,16384,66)&&k.KCM(1,t,"_",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḇ");}else if(k.KKM(e,16384,66)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḃ");}else if(k.KKM(e,16384,66)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḅ");}else if(k.KKM(e,16384,67)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ć");}else if(k.KKM(e,16384,67)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ĉ");}else if(k.KKM(e,16384,67)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"č");}else if(k.KKM(e,16384,67)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ċ");}else if(k.KKM(e,16384,67)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ç");}else if(k.KKM(e,16384,67)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ɔ");}else if(k.KKM(e,16384,67)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"©");}else if(k.KKM(e,16384,67)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"¢");}else if(k.KKM(e,16384,68)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ď");}else if(k.KKM(e,16384,68)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"đ");}else if(k.KKM(e,16384,68)&&k.KCM(1,t,"_",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḏ");}else if(k.KKM(e,16384,68)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḋ");}else if(k.KKM(e,16384,68)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḍ");}else if(k.KKM(e,16384,68)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḑ");}else if(k.KKM(e,16384,68)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ð");}else if(k.KKM(e,16384,68)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"₫");}else if(k.KKM(e,16384,69)&&k.KCM(2,t,"a\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"æ");}else if(k.KKM(e,16384,69)&&k.KCM(2,t,"o\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"œ");}else if(k.KKM(e,16384,69)&&k.KCM(1,t,"`",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"è");}else if(k.KKM(e,16384,69)&&k.KCM(1,t,"#",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ȅ");}else if(k.KKM(e,16384,69)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"é");}else if(k.KKM(e,16384,69)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ê");}else if(k.KKM(e,16384,69)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ě");}else if(k.KKM(e,16384,69)&&k.KCM(1,t,"&",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ȇ");}else if(k.KKM(e,16384,69)&&k.KCM(1,t,"*",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ĕ");}else if(k.KKM(e,16384,69)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ẽ");}else if(k.KKM(e,16384,69)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ē");}else if(k.KKM(e,16384,69)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ë");}else if(k.KKM(e,16384,69)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ė");}else if(k.KKM(e,16384,69)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ẹ");}else if(k.KKM(e,16384,69)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ę");}else if(k.KKM(e,16384,69)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ə");}else if(k.KKM(e,16384,69)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ɛ");}else if(k.KKM(e,16384,69)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"€");}else if(k.KKM(e,16384,70)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḟ");}else if(k.KKM(e,16384,70)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ª");}else if(k.KKM(e,16384,70)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"₱");}else if(k.KKM(e,16384,71)&&k.KCM(2,t,"n\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"ŋ");}else if(k.KKM(e,16384,71)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"g̃");}else if(k.KKM(e,16384,71)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ǵ");}else if(k.KKM(e,16384,71)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ĝ");}else if(k.KKM(e,16384,71)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ǧ");}else if(k.KKM(e,16384,71)&&k.KCM(1,t,"*",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ğ");}else if(k.KKM(e,16384,71)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḡ");}else if(k.KKM(e,16384,71)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ġ");}else if(k.KKM(e,16384,71)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ģ");}else if(k.KKM(e,16384,71)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ɂ");}else if(k.KKM(e,16384,71)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ǥ");}else if(k.KKM(e,16384,71)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"₰");}else if(k.KKM(e,16384,72)&&k.KCM(2,t,"t\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"þ");}else if(k.KKM(e,16384,72)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ĥ");}else if(k.KKM(e,16384,72)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ȟ");}else if(k.KKM(e,16384,72)&&k.KCM(1,t,"*",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḫ");}else if(k.KKM(e,16384,72)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ħ");}else if(k.KKM(e,16384,72)&&k.KCM(1,t,"_",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ẖ");}else if(k.KKM(e,16384,72)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḧ");}else if(k.KKM(e,16384,72)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḣ");}else if(k.KKM(e,16384,72)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḥ");}else if(k.KKM(e,16384,72)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḩ");}else if(k.KKM(e,16384,72)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"₴");}else if(k.KKM(e,16384,73)&&k.KCM(2,t,"f\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"fi");}else if(k.KKM(e,16384,73)&&k.KCM(2,t,"o\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"ƣ");}else if(k.KKM(e,16384,73)&&k.KCM(1,t,"`",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ì");}else if(k.KKM(e,16384,73)&&k.KCM(1,t,"#",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ȉ");}else if(k.KKM(e,16384,73)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"í");}else if(k.KKM(e,16384,73)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"î");}else if(k.KKM(e,16384,73)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ǐ");}else if(k.KKM(e,16384,73)&&k.KCM(1,t,"&",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ȋ");}else if(k.KKM(e,16384,73)&&k.KCM(1,t,"*",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ĭ");}else if(k.KKM(e,16384,73)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ĩ");}else if(k.KKM(e,16384,73)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ī");}else if(k.KKM(e,16384,73)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ï");}else if(k.KKM(e,16384,73)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ı");}else if(k.KKM(e,16384,73)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ị");}else if(k.KKM(e,16384,73)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"į");}else if(k.KKM(e,16384,74)&&k.KCM(2,t,"i\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"ij");}else if(k.KKM(e,16384,74)&&k.KCM(2,t,"L\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"Lj");}else if(k.KKM(e,16384,74)&&k.KCM(2,t,"l\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"lj");}else if(k.KKM(e,16384,74)&&k.KCM(2,t,"N\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"Nj");}else if(k.KKM(e,16384,74)&&k.KCM(2,t,"n\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"nj");}else if(k.KKM(e,16384,74)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ĵ");}else if(k.KKM(e,16384,74)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ǰ");}else if(k.KKM(e,16384,74)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ɉ");}else if(k.KKM(e,16384,74)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ȷ");}else if(k.KKM(e,16384,74)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ɲ");}else if(k.KKM(e,16384,75)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḱ");}else if(k.KKM(e,16384,75)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ǩ");}else if(k.KKM(e,16384,75)&&k.KCM(1,t,"_",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḵ");}else if(k.KKM(e,16384,75)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḳ");}else if(k.KKM(e,16384,75)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ķ");}else if(k.KKM(e,16384,75)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ĸ");}else if(k.KKM(e,16384,75)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"₡");}else if(k.KKM(e,16384,76)&&k.KCM(2,t,"f\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"fl");}else if(k.KKM(e,16384,76)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ĺ");}else if(k.KKM(e,16384,76)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ľ");}else if(k.KKM(e,16384,76)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ɫ");}else if(k.KKM(e,16384,76)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ł");}else if(k.KKM(e,16384,76)&&k.KCM(1,t,"_",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḻ");}else if(k.KKM(e,16384,76)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ŀ");}else if(k.KKM(e,16384,76)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḷ");}else if(k.KKM(e,16384,76)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ļ");}else if(k.KKM(e,16384,76)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"₤");}else if(k.KKM(e,16384,77)&&k.KCM(2,t,"t\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"™");}else if(k.KKM(e,16384,77)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ḿ");}else if(k.KKM(e,16384,77)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ṁ");}else if(k.KKM(e,16384,77)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ṃ");}else if(k.KKM(e,16384,77)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"º");}else if(k.KKM(e,16384,78)&&k.KCM(1,t,"`",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ǹ");}else if(k.KKM(e,16384,78)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ń");}else if(k.KKM(e,16384,78)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ň");}else if(k.KKM(e,16384,78)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ñ");}else if(k.KKM(e,16384,78)&&k.KCM(1,t,"_",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ṉ");}else if(k.KKM(e,16384,78)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ṅ");}else if(k.KKM(e,16384,78)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ṇ");}else if(k.KKM(e,16384,78)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ņ");}else if(k.KKM(e,16384,78)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ŋ");}else if(k.KKM(e,16384,78)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ʼn");}else if(k.KKM(e,16384,78)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"₪");}else if(k.KKM(e,16384,79)&&k.KCM(2,t,"n\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"№");}else if(k.KKM(e,16384,79)&&k.KCM(1,t,"`",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ò");}else if(k.KKM(e,16384,79)&&k.KCM(1,t,"#",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ȍ");}else if(k.KKM(e,16384,79)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ó");}else if(k.KKM(e,16384,79)&&k.KCM(1,t,"\"",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ő");}else if(k.KKM(e,16384,79)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ô");}else if(k.KKM(e,16384,79)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ǒ");}else if(k.KKM(e,16384,79)&&k.KCM(1,t,"&",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ȏ");}else if(k.KKM(e,16384,79)&&k.KCM(1,t,"*",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ŏ");}else if(k.KKM(e,16384,79)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"õ");}else if(k.KKM(e,16384,79)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ō");}else if(k.KKM(e,16384,79)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ö");}else if(k.KKM(e,16384,79)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ȯ");}else if(k.KKM(e,16384,79)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ọ");}else if(k.KKM(e,16384,79)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ǫ");}else if(k.KKM(e,16384,79)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ɵ");}else if(k.KKM(e,16384,79)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ø");}else if(k.KKM(e,16384,80)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"p̈");}else if(k.KKM(e,16384,80)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ṕ");}else if(k.KKM(e,16384,80)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ṗ");}else if(k.KKM(e,16384,80)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"℗");}else if(k.KKM(e,16384,80)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"£");}else if(k.KKM(e,16384,82)&&k.KCM(1,t,"#",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ȑ");}else if(k.KKM(e,16384,82)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ŕ");}else if(k.KKM(e,16384,82)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ř");}else if(k.KKM(e,16384,82)&&k.KCM(1,t,"&",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ȓ");}else if(k.KKM(e,16384,82)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ɍ");}else if(k.KKM(e,16384,82)&&k.KCM(1,t,"_",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ṟ");}else if(k.KKM(e,16384,82)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ṙ");}else if(k.KKM(e,16384,82)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ṛ");}else if(k.KKM(e,16384,82)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ŗ");}else if(k.KKM(e,16384,82)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"®");}else if(k.KKM(e,16384,82)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"₨");}else if(k.KKM(e,16384,83)&&k.KCM(2,t,"s\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"ß");}else if(k.KKM(e,16384,83)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ś");}else if(k.KKM(e,16384,83)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ŝ");}else if(k.KKM(e,16384,83)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"š");}else if(k.KKM(e,16384,83)&&k.KCM(1,t,"@",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ș");}else if(k.KKM(e,16384,83)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ṡ");}else if(k.KKM(e,16384,83)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ṣ");}else if(k.KKM(e,16384,83)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ş");}else if(k.KKM(e,16384,83)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ß");}else if(k.KKM(e,16384,83)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ſ");}else if(k.KKM(e,16384,84)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ť");}else if(k.KKM(e,16384,84)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ŧ");}else if(k.KKM(e,16384,84)&&k.KCM(1,t,"_",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ṯ");}else if(k.KKM(e,16384,84)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ẗ");}else if(k.KKM(e,16384,84)&&k.KCM(1,t,"@",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ț");}else if(k.KKM(e,16384,84)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ṫ");}else if(k.KKM(e,16384,84)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ṭ");}else if(k.KKM(e,16384,84)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ţ");}else if(k.KKM(e,16384,84)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"þ");}else if(k.KKM(e,16384,84)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"†");}else if(k.KKM(e,16384,84)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"₮");}else if(k.KKM(e,16384,85)&&k.KCM(1,t,"`",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ù");}else if(k.KKM(e,16384,85)&&k.KCM(1,t,"#",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ȕ");}else if(k.KKM(e,16384,85)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ú");}else if(k.KKM(e,16384,85)&&k.KCM(1,t,"\"",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ű");}else if(k.KKM(e,16384,85)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"û");}else if(k.KKM(e,16384,85)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ǔ");}else if(k.KKM(e,16384,85)&&k.KCM(1,t,"&",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ȗ");}else if(k.KKM(e,16384,85)&&k.KCM(1,t,"*",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ŭ");}else if(k.KKM(e,16384,85)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ũ");}else if(k.KKM(e,16384,85)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ū");}else if(k.KKM(e,16384,85)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ü");}else if(k.KKM(e,16384,85)&&k.KCM(1,t,"@",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ů");}else if(k.KKM(e,16384,85)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ụ");}else if(k.KKM(e,16384,85)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ų");}else if(k.KKM(e,16384,85)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"µ");}else if(k.KKM(e,16384,86)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ṽ");}else if(k.KKM(e,16384,86)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ṿ");}else if(k.KKM(e,16384,87)&&k.KCM(1,t,"`",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ẁ");}else if(k.KKM(e,16384,87)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ẃ");}else if(k.KKM(e,16384,87)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ŵ");}else if(k.KKM(e,16384,87)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ẅ");}else if(k.KKM(e,16384,87)&&k.KCM(1,t,"@",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ẘ");}else if(k.KKM(e,16384,87)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ẇ");}else if(k.KKM(e,16384,87)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ẉ");}else if(k.KKM(e,16384,87)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"₩");}else if(k.KKM(e,16384,88)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ǯ");}else if(k.KKM(e,16384,88)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ẍ");}else if(k.KKM(e,16384,88)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ẋ");}else if(k.KKM(e,16384,88)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"×");}else if(k.KKM(e,16384,89)&&k.KCM(1,t,"`",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ỳ");}else if(k.KKM(e,16384,89)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ý");}else if(k.KKM(e,16384,89)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ŷ");}else if(k.KKM(e,16384,89)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ỹ");}else if(k.KKM(e,16384,89)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ȳ");}else if(k.KKM(e,16384,89)&&k.KCM(1,t,":",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ÿ");}else if(k.KKM(e,16384,89)&&k.KCM(1,t,"@",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ẙ");}else if(k.KKM(e,16384,89)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ẏ");}else if(k.KKM(e,16384,89)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ỵ");}else if(k.KKM(e,16384,89)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ȝ");}else if(k.KKM(e,16384,89)&&k.KCM(1,t,"$",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"¥");}else if(k.KKM(e,16384,90)&&k.KCM(2,t,"D\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"Dž");}else if(k.KKM(e,16384,90)&&k.KCM(2,t,"d\\",2)&&k.KDM(0,t,0)) {r=m=1;k.KO(2,t,"dž");}else if(k.KKM(e,16384,90)&&k.KCM(1,t,"'",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ź");}else if(k.KKM(e,16384,90)&&k.KCM(1,t,"^",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ẑ");}else if(k.KKM(e,16384,90)&&k.KCM(1,t,"%",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ž");}else if(k.KKM(e,16384,90)&&k.KCM(1,t,"-",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ƶ");}else if(k.KKM(e,16384,90)&&k.KCM(1,t,"_",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ẕ");}else if(k.KKM(e,16384,90)&&k.KCM(1,t,".",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ż");}else if(k.KKM(e,16384,90)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ẓ");}else if(k.KKM(e,16384,90)&&k.KCM(1,t,",",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ⱬ");}else if(k.KKM(e,16384,90)&&k.KCM(1,t,"=",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"ʒ");}else if(k.KKM(e,16400,220)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"¦");}else if(k.KKM(e,16400,220)&&k.KCM(1,t,"|",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"|");}else if(k.KKM(e,16400,220)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,220)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,220)) {r=m=1;k.KO(0,t,"|");k.KDO(-1,t,0);}else if(k.KKM(e,16400,192)&&k.KCM(1,t,"\\",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"¬");}else if(k.KKM(e,16400,192)&&k.KCM(1,t,"~",1)&&k.KDM(0,t,0)) {r=m=1;k.KO(1,t,"~");}else if(k.KKM(e,16400,192)&&k.KIFS(31,this.s56,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,192)&&k.KIFS(31,this.s57,t)) {r=m=1;r=this.g1(t,e);}else if(k.KKM(e,16400,192)) {r=m=1;k.KO(0,t,"~");k.KDO(-1,t,0);}return r;};this.g1=function(t,e) {var k=KeymanWeb,r=0,m=0;return r;};this.KHF=function(e) { - var h = document.getElementsByTagName('head'); - var stext = - "#keyboard_europeanlatin_help { text-align: left; padding: 0; background: #f5e3de; font-size: 8pt; font-family: Tahoma; cursor: default; padding: 4px; }"+ - "#keyboard_europeanlatin_help table { margin-top: 0; }"+ - "#keyboard_europeanlatin_help tr.out td { padding: 4px; border: solid 1px #ad4a28; font-size: 10pt; font-family: Cambria, Tahoma; font-weight: bold; text-align: center; background: white; }"+ - "#keyboard_europeanlatin_help th { padding: 2px 2px; font-size: 8pt; font-family: Tahoma; }"+ - "#keyboard_europeanlatin_help span.elkey { font-weight: normal; background: #e0e0e0; border: outset 1px; padding: 2px 6px; }"+ - "#keyboard_europeanlatin_help th.prompt { text-align: left; white-space: nowrap; }"+ - "#keyboard_europeanlatin_help tr.key th.prompt { background: white; border: none; font-weight: normal; text-align: right; }"+ - "#keyboard_europeanlatin_help tr.key th.title { background: white; border: none; font-weight: bold; vertical-align: middle; text-align: left; padding: 1px; }"+ - "#keyboard_europeanlatin_help tr.key th { min-width: 14px; margin: 2px; font-weight: normal; text-align: center; background: #e0e0e0; border: outset 1px; padding: 2px 2px; }"+ - "#keyboard_europeanlatin_help tr.out th.prompt { background: white; border: none; font-weight: normal; text-align: right; }"+ - "#keyboard_europeanlatin_help tr.gap th { background: white; border: none; height: 7px; }"+ - "#keyboard_europeanlatin_help p { font-weight: bold; }"+ - "#keyboard_eurolatin_tabsheets { color: black; border: solid 1px #ad4a28; margin: 0 4px 4px 4px; background: white; z-index: 101; }"+ - ".keyboard_eurolatin_tabsheet_selected { display: block; padding: 6px 6px 0 6px; }"+ - ".keyboard_eurolatin_tabsheet { display: none; }"+ - "#keyboard_eurolatin_tabs { margin: 4px 4px 0 4px; z-index: 100; }"+ - ".keyboard_eurolatin_tab { background: white; color: #ad4a28; border: solid 1px #ad4a28; display: inline; padding: 1px 4px 0px 4px; height: 16px; }"+ - ".keyboard_eurolatin_tab_selected { background: white; color: #ad4a28; border: solid 1px #ad4a28; display: inline; padding: 1px 4px; border-bottom: none; margin-top: -1px; height: 18px;}"; - - var style = document.createElement("style"); - style.setAttribute("type", "text/css"); - if(style.styleSheet){// IE - style.styleSheet.cssText = stext; - } else {// w3c - var cssText = document.createTextNode(stext); - style.appendChild(cssText); - } - if(h && h.length > 0) - h[0].appendChild(style); - - e=document.getElementById('keyboard_europeanlatin_help'); - if (typeof e.onselectstart!="undefined") //IE route - e.onselectstart=function(){return false;}; - else - { - e.style.MozUserSelect="none"; - e.style.KhtmlUserSelect="none"; - e.style.UserSelect="none"; - } - var ch = e.getElementsByTagName('td'); - - for(var i = 0; i < ch.length; i++) - { - if(ch[i].attributes['o']) - { - var sxv = ch[i].attributes['x'].value, so = ch[i].attributes['o'].value, sc = ch[i].attributes['c'].value; - if(ch[i].attributes['p']) var sp = ch[i].attributes['p'].value; else var sp = ''; - // ch[i].title = 'The following combinations are available: '+so; - var ce = function(tag){return document.createElement(tag);} - var sx = '', sy = '', sz = (sp == '' ? '' : sy); - var e2 = ce('div'); - for(var j = 0; j < sc.length; j++) - { - var chvo = so.charAt(j), chvc = sc.charAt(j), chvp = sp.charAt(j); - /* Special case for characters p umlaut, g tilde because they aren't precomposed */ - if(sxv == ':' && chvo == 'p') { chvo = 'p̈'; chvp = 'P̈'; } - if(sxv == '~' && chvo == 'g') { chvo = 'g̃'; chvp = 'G̃'; } - sx += ''; - sy += ''; - if(sp != '') sz += ''; - } - e2.innerHTML = sx+''+sy+''+sz+(sz == '' ? '' : '')+'
'+sxv+chvc+''+chvo+''+chvp+'
'; - - var es = e2.style; - es.background = '#f3ffdf'; - es.border = 'solid 1px #ad4a28'; - es.padding = '2px'; - es.display = 'none'; - es.position = 'absolute'; - es.left = (ch[i].offsetLeft+4)+'px'; - es.top = '24px'; - e2.onclick = function() { KeymanWeb.KT(); window.event.cancelBubble=true; return false; } - - ch[i].kmw_subitems = e2; - ch[i].appendChild(e2); - ch[i].onmouseover = function() { this.style.background = KeymanWeb_KeyHoverColor; this.kmw_subitems.style.left=this.offsetLeft+4+'px'; this.kmw_subitems.style.top=(this.offsetParent.offsetTop+this.offsetTop+this.offsetHeight-2)+'px'; this.kmw_subitems.style.display = 'block'; return false; } - ch[i].onmouseout = function() { this.style.background = ''; this.kmw_subitems.style.display = 'none'; return false; } - } - else - { - ch[i].onmouseover = function() { this.style.background = KeymanWeb_KeyHoverColor; return false; } - ch[i].onmouseout = function() { this.style.background = ''; return false; } - } - - ch[i].onclick = function(e) { with(this) { if(attributes['x']) KeymanWeb.KT(attributes['x'].value,0); else if(innerHTML != ' ') KeymanWeb.KT(innerHTML); else KeymanWeb.KT(''); } if(!e)e=window.event;if(e) e.cancelBubble=true;} - ch[i].onmousedown = function(e) { KeymanWeb.KSF(); if(!e)e=window.event;if(e) e.cancelBubble=true; } - } - - e.onclick=function() { KeymanWeb.KT(''); return false; } - e.onmousedown=function() { KeymanWeb.KSF(); return false; } - - e = document.getElementById('keyboard_eurolatin_tabs'); - e2 = document.getElementById('keyboard_eurolatin_tabsheets'); - var ch = [document.getElementById('keyboard_eurolatin_letters_tab'), document.getElementById('keyboard_eurolatin_symbols_tab')]; - var ch2 = [document.getElementById('keyboard_eurolatin_letters_tabsheet'), document.getElementById('keyboard_eurolatin_symbols_tabsheet')]; - for(var i = 0; i < ch.length; i++) - ch[i].onclick = (function(i) { return function(e) - { - for(var j = 0; j < ch.length; j++) - { - ch[j].className = "keyboard_eurolatin_tab" + (i == j ? "_selected" : ""); - ch2[j].className = "keyboard_eurolatin_tabsheet" + (i == j ? "_selected" : ""); - } - } - })(i); -} -} \ No newline at end of file diff --git a/android/KMEA/app/src/main/assets/cloud/sil_euro_latin-1.8.js b/android/KMEA/app/src/main/assets/cloud/sil_euro_latin-1.8.js new file mode 100644 index 0000000000000000000000000000000000000000..ea29ce348cfbb8407afeb8e62ede5b5166ec8a24 --- /dev/null +++ b/android/KMEA/app/src/main/assets/cloud/sil_euro_latin-1.8.js @@ -0,0 +1,110 @@ +if(typeof keyman === 'undefined') {console.log('Keyboard requires KeymanWeb 10.0 or later');if(typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later");} else {KeymanWeb.KR(new Keyboard_sil_euro_latin());}function Keyboard_sil_euro_latin(){this.KI="Keyboard_sil_euro_latin";this.KN="EuroLatin (SIL)";this.KMINVER="10.0";this.KV=null;this.KH='

More help

Letters
Symbols
Accent
Marks
Type`#\'"^%&*~-_:@.|,
Result `  ̏ ´ ˝ ˆ ˇ  ̑ ˘ ˜ ˉ  ̱ ¨ ˚ ˙ . ¸
Other
Letters
Type = thencegjnostyz\'
Result ɔ ə ɂ ɲ ŋ ɵ ß þ ȝ ʒ ꞌ
Ɔ Ə Ɂ Ɲ Ŋ Ɵ ẞ Þ Ȝ Ʒ Ꞌ

Type \\ thendegknos
Result ð ɛ ǥ ĸ ʼn ø ſ
Ð Ɛ Ǥ Ø
Digraphs Typea\\ed\\zf\\if\\li\\jl\\jn\\jo\\eo\\i
Result æ dž fi fl ij lj nj œ ƣ
Æ Dž DŽ IJ Lj LJ Nj NJ Œ Ƣ
Punctuation
and Symbols
Type\\?\\!<<>>\\f\\m\\P\\S\\T\\t\\|\\c\\p\\rt\\m
Result¿¡«»ªº§‡†¦©℗®™

Type\\:\\\'\\,\\_\\M\\N\\-\\~\\...\\.\\>
Result¨´¸¯—–­¬…·•
Numbers
and Fractions
Type\\+\\x\\/\\*\\%\\u
Result±×÷°‰µ

Typen\\o\\1\\2\\3\\4\\5\\6\\7\\8\\9\\0
Result№¹²³⁴⁵⁶⁷⁸⁹⁰

Type1//21//32//31//43//41//52//53//54//51//65//61//83//85//87//8
Result½⅓⅔¼¾⅕⅖⅗⅘⅙⅚⅛⅜⅝⅞
Currency
Symbols
Type $ thencefhlnNpPrRwy
Result¢€₱₴₤₪₦£₧₨₹₩¥

Type $ thenCdDFgGkKt
Result¤₫₯₣₰₲₡₭₮
';this.KM=0;this.KBVER="1.8";this.KMBM=0x0010;this.KVKD="T_G_Tilde T_P_Dieresis";this.KVKL={"tablet":{"font":"Tahoma","layer":[{"id":"default","row":[{"id":1,"key":[{"id":"K_Q","text":"q","sk":[{"id":"U_A78C"}]},{"id":"K_W","text":"w","sk":[{"id":"U_1E81"},{"id":"U_1E83"},{"id":"U_0175"},{"id":"U_1E85"},{"id":"U_1E98"},{"id":"U_1E87"},{"id":"U_1E89"}]},{"id":"K_E","text":"e","sk":[{"text":"\u00E8","id":"U_00E8"},{"text":"\u0205","id":"U_0205"},{"text":"\u00E9","id":"U_00E9"},{"text":"\u00EA","id":"U_00EA"},{"text":"\u011B","id":"U_011B"},{"text":"\u0207","id":"U_0207"},{"text":"\u0115","id":"U_0115"},{"text":"\u1EBD","id":"U_1EBD"},{"text":"\u0113","id":"U_0113"},{"text":"\u00EB","id":"U_00EB"},{"text":"\u0117","id":"U_0117"},{"text":"\u1EB9","id":"U_1EB9"},{"text":"\u0119","id":"U_0119"},{"text":"\u0259","id":"U_0259"},{"text":"\u025B","id":"U_025B"}]},{"id":"K_R","text":"r","sk":[{"id":"U_0211"},{"id":"U_0155"},{"id":"U_0159"},{"id":"U_0213"},{"id":"U_024D"},{"id":"U_1E5F"},{"id":"U_1E59"},{"id":"U_1E5B"},{"id":"U_0157"}]},{"id":"K_T","text":"t","sk":[{"text":"\u0165","id":"U_0165"},{"text":"\u0167","id":"U_0167"},{"text":"\u1E6F","id":"U_1E6F"},{"text":"\u1E97","id":"U_1E97"},{"text":"\u1E6B","id":"U_1E6B"},{"text":"\u1E6D","id":"U_1E6D"},{"text":"\u0163","id":"U_0163"},{"text":"\u021B","id":"U_021B"},{"text":"\u00FE","id":"U_00FE"}]},{"id":"K_Y","text":"y","sk":[{"id":"U_1EF3"},{"id":"U_00FD"},{"id":"U_0177"},{"id":"U_1EF9"},{"id":"U_0233"},{"id":"U_00FF"},{"id":"U_1E99"},{"id":"U_1E8F"},{"id":"U_1EF5"}]},{"id":"K_U","text":"u","sk":[{"id":"U_00F9"},{"id":"U_0215"},{"id":"U_00FA"},{"id":"U_0171"},{"id":"U_00FB"},{"id":"U_01D4"},{"id":"U_0217"},{"id":"U_016D"},{"id":"U_0169"},{"id":"U_016B"},{"id":"U_00FC"},{"id":"U_016F"},{"id":"U_1EE5"},{"id":"U_0173"}]},{"id":"K_I","text":"i","sk":[{"id":"U_00EC"},{"id":"U_0209"},{"id":"U_00ED"},{"id":"U_00EE"},{"id":"U_01D0"},{"id":"U_020B"},{"id":"U_012D"},{"id":"U_0129"},{"id":"U_012B"},{"id":"U_00EF"},{"id":"U_0131"},{"id":"U_1ECB"},{"id":"U_012F"},{"id":"U_0272"},{"id":"U_0133"}]},{"id":"K_O","text":"o","sk":[{"id":"U_00F2"},{"id":"U_020D"},{"id":"U_00F3"},{"id":"U_0151"},{"id":"U_00F4"},{"id":"U_01D2"},{"id":"U_020F"},{"id":"U_014F"},{"id":"U_00F5"},{"id":"U_014D"},{"id":"U_00F6"},{"id":"U_022F"},{"id":"U_1ECD"},{"id":"U_01EB"},{"id":"U_0275"},{"id":"U_00F8"},{"id":"U_0254"},{"id":"U_0153"},{"id":"U_01A3"}]},{"id":"K_P","text":"p","sk":[{"text":"\u1E55","id":"U_1E55"},{"text":"p\u0308","id":"T_P_Dieresis"},{"text":"\u1E57","id":"U_1E57"}]}]},{"id":2,"key":[{"id":"K_A","text":"a","pad":"40","sk":[{"id":"U_00E0"},{"id":"U_0201"},{"id":"U_00E1"},{"id":"U_00E2"},{"id":"U_01CE"},{"id":"U_0203"},{"id":"U_0103"},{"id":"U_00E3"},{"id":"U_0101"},{"id":"U_00E4"},{"id":"U_00E5"},{"id":"U_0227"},{"id":"U_1EA1"},{"id":"U_0105"},{"id":"U_00E6"}]},{"id":"K_S","text":"s","sk":[{"text":"\u015B","id":"U_015B"},{"text":"\u015D","id":"U_015D"},{"text":"\u0161","id":"U_0161"},{"text":"\u1E61","id":"U_1E61"},{"text":"\u1E63","id":"U_1E63"},{"text":"\u015F","id":"U_015F"},{"text":"\u0219","id":"U_0219"},{"text":"\u00DF","id":"U_00DF"},{"text":"\u017F","id":"U_017F"}]},{"id":"K_D","text":"d","sk":[{"id":"U_010F"},{"id":"U_0111"},{"id":"U_1E0F"},{"id":"U_1E0B"},{"id":"U_1E0D"},{"id":"U_1E11"},{"id":"U_00F0"},{"id":"U_01C6"}]},{"id":"K_F","text":"f","sk":[{"id":"U_1E1F"},{"id":"U_FB01"},{"id":"U_FB02"}]},{"id":"K_G","text":"g","sk":[{"text":"\u01F5","id":"U_01F5"},{"text":"\u011D","id":"U_011D"},{"text":"\u01E7","id":"U_01E7"},{"text":"\u011F","id":"U_011F"},{"text":"g\u0303","id":"T_G_Tilde"},{"text":"\u1E21","id":"U_1E21"},{"text":"\u0121","id":"U_0121"},{"text":"\u0123","id":"U_0123"},{"text":"\u0242","id":"U_0242"},{"text":"\u01E5","id":"U_01E5"}]},{"id":"K_H","text":"h","sk":[{"id":"U_0125"},{"id":"U_021F"},{"id":"U_1E2B"},{"id":"U_0127"},{"id":"U_1E96"},{"id":"U_1E27"},{"id":"U_1E23"},{"id":"U_1E25"},{"id":"U_1E29"}]},{"id":"K_J","text":"j","sk":[{"id":"U_0135"},{"id":"U_01F0"},{"id":"U_0249"},{"id":"U_0237"}]},{"id":"K_K","text":"k","sk":[{"id":"U_1E31"},{"id":"U_01E9"},{"id":"U_1E35"},{"id":"U_1E33"},{"id":"U_0137"},{"id":"U_0138"}]},{"id":"K_L","text":"l","sk":[{"id":"U_013A"},{"id":"U_013E"},{"id":"U_026B"},{"id":"U_0142"},{"id":"U_1E3B"},{"id":"U_0140"},{"id":"U_1E37"},{"id":"U_013C"},{"id":"U_01C9"}]},{"id":"T_new_20","text":"","width":"10","sp":"10"}]},{"id":3,"key":[{"id":"K_SHIFT","text":"*Shift*","width":"100","sp":"1","nextlayer":"shift"},{"id":"K_Z","text":"z","sk":[{"id":"U_017A"},{"id":"U_1E91"},{"id":"U_017E"},{"id":"U_01B6"},{"id":"U_1E95"},{"id":"U_017C"},{"id":"U_1E93"},{"id":"U_2C6C"},{"id":"U_0292"},{"id":"U_01EF"}]},{"id":"K_X","text":"x","sk":[{"id":"U_1E8D"},{"id":"U_1E8B"}]},{"id":"K_C","text":"c","sk":[{"id":"U_0107"},{"id":"U_0109"},{"id":"U_010D"},{"id":"U_010B"},{"id":"U_00E7"}]},{"id":"K_V","text":"v","sk":[{"id":"U_1E7D"},{"id":"U_1E7F"}]},{"id":"K_B","text":"b","sk":[{"id":"U_0180"},{"id":"U_1E07"},{"id":"U_1E03"},{"id":"U_1E05"}]},{"id":"K_N","text":"n","sk":[{"id":"U_014B"},{"id":"U_01F9"},{"id":"U_0144"},{"id":"U_0148"},{"id":"U_00F1"},{"id":"U_1E49"},{"id":"U_1E45"},{"id":"U_1E47"},{"id":"U_0146"},{"id":"U_0149"},{"id":"U_01CC"}]},{"id":"K_M","text":"m","sk":[{"id":"U_1E3F"},{"id":"U_1E41"},{"id":"U_1E43"}]},{"id":"K_PERIOD","text":".","sk":[{"id":"K_COMMA","text":","},{"id":"U_0021"},{"id":"U_003F"},{"id":"U_0027"},{"id":"U_0022"},{"id":"U_005C"},{"id":"U_003A"},{"id":"U_003B"}]},{"id":"K_BKSP","text":"*BkSp*","width":"100","sp":"1"}]},{"id":4,"key":[{"id":"K_NUMERALS","text":"*123*","width":"150","sp":"1","nextlayer":"numeric"},{"id":"K_LOPT","text":"*Menu*","width":"100","sp":"1"},{"id":"T_new_34","text":"","width":"10","sp":"10"},{"id":"K_SPACE","text":"","width":"610","sp":"0"},{"id":"T_new_36","text":"","width":"10","sp":"10"},{"id":"K_ENTER","text":"*Enter*","width":"140","sp":"1"}]}]},{"id":"shift","row":[{"id":1,"key":[{"id":"K_Q","text":"Q","sk":[{"id":"U_A78B"}]},{"id":"K_W","text":"W","sk":[{"id":"U_1E80"},{"id":"U_1E82"},{"id":"U_0174"},{"id":"U_1E84"},{"id":"U_1E86"},{"id":"U_1E88"}]},{"id":"K_E","text":"E","sk":[{"id":"U_00C8"},{"id":"U_0204"},{"id":"U_00C9"},{"id":"U_00CA"},{"id":"U_011A"},{"id":"U_0206"},{"id":"U_0114"},{"id":"U_1EBC"},{"id":"U_0112"},{"id":"U_00CB"},{"id":"U_0116"},{"id":"U_1EB8"},{"id":"U_0118"},{"id":"U_018F"},{"id":"U_0190"}]},{"id":"K_R","text":"R","sk":[{"id":"U_0210"},{"id":"U_0154"},{"id":"U_0158"},{"id":"U_0212"},{"id":"U_024C"},{"id":"U_1E5E"},{"id":"U_1E58"},{"id":"U_1E5A"},{"id":"U_0156"}]},{"id":"K_T","text":"T","sk":[{"text":"\u0164","id":"U_0164"},{"text":"\u0166","id":"U_0166"},{"text":"\u1E6E","id":"U_1E6E"},{"text":"\u1E6A","id":"U_1E6A"},{"text":"\u1E6C","id":"U_1E6C"},{"text":"\u0162","id":"U_0162"},{"text":"\u021A","id":"U_021A"},{"text":"\u00DE","id":"U_00DE"}]},{"id":"K_Y","text":"Y","sk":[{"id":"U_1EF2"},{"id":"U_00DD"},{"id":"U_0176"},{"id":"U_1EF8"},{"id":"U_0232"},{"id":"U_0178"},{"id":"U_1E8E"},{"id":"U_1EF4"}]},{"id":"K_U","text":"U","sk":[{"id":"U_00D9"},{"id":"U_0214"},{"id":"U_00DA"},{"id":"U_0170"},{"id":"U_00DB"},{"id":"U_01D3"},{"id":"U_0216"},{"id":"U_016C"},{"id":"U_0168"},{"id":"U_016A"},{"id":"U_00DC"},{"id":"U_016E"},{"id":"U_1EE4"},{"id":"U_0172"}]},{"id":"K_I","text":"I","sk":[{"id":"U_00CC"},{"id":"U_0208"},{"id":"U_00CD"},{"id":"U_00CE"},{"id":"U_01CF"},{"id":"U_020A"},{"id":"U_012C"},{"id":"U_0128"},{"id":"U_012A"},{"id":"U_00CF"},{"id":"U_0130"},{"id":"U_1ECA"},{"id":"U_012E"},{"id":"U_019D"}]},{"id":"K_O","text":"O","sk":[{"id":"U_00D2"},{"id":"U_020C"},{"id":"U_00D3"},{"id":"U_0150"},{"id":"U_00D4"},{"id":"U_01D1"},{"id":"U_020E"},{"id":"U_014E"},{"id":"U_00D5"},{"id":"U_014C"},{"id":"U_00D6"},{"id":"U_022E"},{"id":"U_1ECC"},{"id":"U_01EA"},{"id":"U_019F"},{"id":"U_00D8"},{"id":"U_0186"},{"id":"U_0152"},{"id":"U_01A2"}]},{"id":"K_P","text":"P","sk":[{"text":"\u1E54","id":"U_1E54"},{"text":"P\u0308","id":"T_P_Dieresis"},{"text":"\u1E56","id":"U_1E56"}]}]},{"id":2,"key":[{"id":"K_A","text":"A","pad":"40","sk":[{"id":"U_00C0"},{"id":"U_0200"},{"id":"U_00C1"},{"id":"U_00C2"},{"id":"U_01CD"},{"id":"U_0202"},{"id":"U_0102"},{"id":"U_00C3"},{"id":"U_0100"},{"id":"U_00C4"},{"id":"U_00C5"},{"id":"U_0226"},{"id":"U_1EA0"},{"id":"U_0104"},{"id":"U_00C6"}]},{"id":"K_S","text":"S","sk":[{"text":"\u015A","id":"U_015A"},{"text":"\u015C","id":"U_015C"},{"text":"\u0160","id":"U_0160"},{"text":"\u1E60","id":"U_1E60"},{"text":"\u1E62","id":"U_1E62"},{"text":"\u015E","id":"U_015E"},{"text":"\u0218","id":"U_0218"},{"text":"\u1E9E","id":"U_1E9E"}]},{"id":"K_D","text":"D","sk":[{"id":"U_010E"},{"id":"U_0110"},{"id":"U_1E0E"},{"id":"U_1E0A"},{"id":"U_1E0C"},{"id":"U_1E10"},{"id":"U_00D0"},{"id":"U_01C5"},{"id":"U_01C4"}]},{"id":"K_F","text":"F","sk":[{"id":"U_1E1E"}]},{"id":"K_G","text":"G","sk":[{"text":"\u01F4","id":"U_01F4"},{"text":"\u011C","id":"U_011C"},{"text":"\u01E6","id":"U_01E6"},{"text":"\u011E","id":"U_011E"},{"text":"G\u0303","id":"T_G_Tilde"},{"text":"\u1E20","id":"U_1E20"},{"text":"\u0120","id":"U_0120"},{"text":"\u0122","id":"U_0122"},{"text":"\u0241","id":"U_0241"},{"text":"\u01E4","id":"U_01E4"}]},{"id":"K_H","text":"H","sk":[{"id":"U_0124"},{"id":"U_021E"},{"id":"U_1E2A"},{"id":"U_0126"},{"id":"U_1E26"},{"id":"U_1E22"},{"id":"U_1E24"},{"id":"U_1E28"}]},{"id":"K_J","text":"J","sk":[{"id":"U_0134"},{"id":"U_0248"}]},{"id":"K_K","text":"K","sk":[{"id":"U_1E30"},{"id":"U_01E8"},{"id":"U_1E34"},{"id":"U_1E32"},{"id":"U_0136"}]},{"id":"K_L","text":"L","sk":[{"id":"U_0139"},{"id":"U_013D"},{"id":"U_2C62"},{"id":"U_0141"},{"id":"U_1E3A"},{"id":"U_013F"},{"id":"U_1E36"},{"id":"U_013B"},{"id":"U_01C8"},{"id":"U_01C7"}]},{"id":"T_new_60","text":"","width":"10","sp":"10"}]},{"id":3,"key":[{"id":"K_SHIFT","text":"*Shift*","width":"100","sp":"2","nextlayer":"default"},{"id":"K_Z","text":"Z","sk":[{"id":"U_021C"},{"id":"U_0179"},{"id":"U_1E90"},{"id":"U_017D"},{"id":"U_01B5"},{"id":"U_1E94"},{"id":"U_017B"},{"id":"U_1E92"},{"id":"U_2C6B"},{"id":"U_01B7"},{"id":"U_01EE"}]},{"id":"K_X","text":"X","sk":[{"id":"U_1E8C"},{"id":"U_1E8A"}]},{"id":"K_C","text":"C","sk":[{"id":"U_0106"},{"id":"U_0108"},{"id":"U_010C"},{"id":"U_010A"},{"id":"U_00C7"}]},{"id":"K_V","text":"V","sk":[{"id":"U_1E7C"},{"id":"U_1E7E"}]},{"id":"K_B","text":"B","sk":[{"id":"U_0243"},{"id":"U_1E06"},{"id":"U_1E02"},{"id":"U_1E04"}]},{"id":"K_N","text":"N","sk":[{"id":"U_014A"},{"id":"U_01F8"},{"id":"U_0143"},{"id":"U_0147"},{"id":"U_00D1"},{"id":"U_1E48"},{"id":"U_1E44"},{"id":"U_1E46"},{"id":"U_0145"},{"id":"U_01CB"},{"id":"U_01CA"}]},{"id":"K_M","text":"M","sk":[{"id":"U_1E3E"},{"id":"U_1E40"},{"id":"U_1E42"}]},{"id":"K_PERIOD","text":".","layer":"default","sk":[{"text":",","id":"K_COMMA"},{"text":"!","id":"U_0021","layer":"default"},{"text":"?","id":"U_003F","layer":"default"},{"text":"'","id":"U_0027","layer":"default"},{"text":"\"","id":"U_0022","layer":"default"},{"text":"\\","id":"U_005C","layer":"default"},{"text":":","id":"U_003A","layer":"default"},{"text":";","id":"U_003B","layer":"default"}]},{"id":"K_BKSP","text":"*BkSp*","width":"100","sp":"1"}]},{"id":4,"key":[{"id":"K_NUMERALS","text":"*123*","width":"150","sp":"1","nextlayer":"numeric"},{"id":"K_LOPT","text":"*Menu*","width":"100","sp":"1"},{"id":"T_new_74","text":"","width":"10","sp":"10"},{"id":"K_SPACE","text":"","width":"610","sp":"0"},{"id":"T_new_76","text":"","width":"10","sp":"10"},{"id":"K_ENTER","text":"*Enter*","width":"140","sp":"1"}]}]},{"id":"numeric","row":[{"id":1,"key":[{"id":"K_1","text":"1","sp":"0","sk":[{"id":"U_00B9"},{"id":"U_00BD"},{"id":"U_2153"},{"id":"U_00BC"},{"id":"U_2155"},{"id":"U_2159"},{"id":"U_215B"}]},{"id":"K_2","text":"2","sp":"0","sk":[{"id":"U_00B2"},{"id":"U_2154"},{"id":"U_2156"}]},{"id":"K_3","text":"3","sp":"0","sk":[{"id":"U_00B3"},{"id":"U_00BE"},{"id":"U_2157"},{"id":"U_215C"}]},{"id":"K_4","text":"4","sp":"0","sk":[{"id":"U_2074"},{"id":"U_2158"}]},{"id":"K_5","text":"5","sp":"0","sk":[{"id":"U_2075"},{"id":"U_215A"},{"id":"U_215D"}]},{"id":"K_6","text":"6","sp":"0","sk":[{"id":"U_2076"}]},{"id":"K_7","text":"7","sp":"0","sk":[{"id":"U_2077"},{"id":"U_215E"}]},{"id":"K_8","text":"8","sp":"0","sk":[{"id":"U_2078"}]},{"id":"K_9","text":"9","sp":"0","sk":[{"id":"U_2079"}]},{"id":"K_0","text":"0","sp":"0","sk":[{"id":"U_2070"}]}]},{"id":2,"key":[{"id":"U_0024","text":"$","pad":"40"},{"id":"U_0040","text":"@"},{"id":"U_0023","text":"#"},{"id":"U_0025","text":"%","sk":[{"id":"U_2030"},{"id":"U_2031"}]},{"id":"U_0026","text":"&"},{"id":"U_005F","text":"_"},{"id":"U_003D","text":"="},{"id":"U_007C","text":"|"},{"id":"U_002F","text":"\/","sk":[{"text":"\\","id":"U_005C"}]},{"id":"T_new_164","text":"","width":"10","sp":"10"}]},{"id":3,"key":[{"id":"K_LOWER","text":"*abc*","width":"100","sp":"1","nextlayer":"default"},{"id":"U_005B","text":"[","sk":[{"id":"U_007B"},{"id":"U_00AB"},{"id":"U_003C"}]},{"id":"U_0028","text":"("},{"id":"U_0029","text":")"},{"id":"U_005D","text":"]","sk":[{"id":"U_007D"},{"id":"U_00BB"},{"id":"U_003E"}]},{"id":"U_002B","text":"+"},{"id":"U_002D","text":"-"},{"id":"U_002A","text":"*"},{"id":"K_PERIOD","text":".","sk":[{"id":"K_COMMA","text":","},{"id":"U_0021"},{"id":"U_003F"},{"id":"U_0027"},{"id":"U_0022"},{"id":"U_005C"},{"id":"U_003A"},{"id":"U_003B"}]},{"id":"K_BKSP","text":"*BkSp*","width":"100","sp":"1"}]},{"id":4,"key":[{"id":"K_CURRENCIES","text":"*Currency*","width":"150","sp":"1","nextlayer":"currency"},{"id":"K_LOPT","text":"*Menu*","width":"100","sp":"1"},{"id":"T_new_178","text":"","width":"10","sp":"10"},{"id":"K_SPACE","text":"","width":"610","sp":"0"},{"id":"T_new_180","text":"","width":"10","sp":"10"},{"id":"K_ENTER","text":"*Enter*","width":"140","sp":"1"}]}]},{"id":"symbol","row":[{"id":1,"key":[{"id":"U_0060","text":"`"},{"id":"U_007E","text":"~"},{"id":"U_005E","text":"^"},{"id":"U_00A8","text":"\u00A8"},{"id":"U_00B4","text":"\u00B4"},{"id":"U_00B8","text":"\u00B8"},{"id":"U_00AF","text":"\u00AF"},{"id":"U_00BF","text":"\u00BF"},{"id":"U_00A1","text":"\u00A1"},{"id":"U_00AC","text":"\u00AC"}]},{"id":2,"key":[{"id":"U_00AA","text":"\u00AA","pad":"40"},{"id":"U_00BA","text":"\u00BA"},{"id":"U_00B6","text":"\u00B6"},{"id":"U_00A7","text":"\u00A7"},{"id":"U_2021","text":"\u2021"},{"id":"U_2020","text":"\u2020"},{"id":"U_00A6","text":"\u00A6"},{"id":"U_2122","text":"\u2122"},{"id":"U_2116","text":"\u2116"},{"id":"T_new_336","text":"","width":"10","sp":"10"}]},{"id":3,"key":[{"id":"K_LOWER","text":"*abc*","width":"100","sp":"1","nextlayer":"default"},{"id":"U_00A9","text":"\u00A9"},{"id":"U_2117","text":"\u2117"},{"id":"U_00AE","text":"\u00AE"},{"id":"U_2014","text":"\u2014"},{"id":"U_2013","text":"\u2013"},{"id":"U_2022","text":"\u2022"},{"id":"U_00B7","text":"\u00B7"},{"id":"U_2026","text":"\u2026","sk":[{"id":"U_00B1"},{"id":"U_00D7"},{"id":"U_00F7"},{"id":"U_00B5"},{"id":"U_00B0"},{"id":"U_2031"}]},{"id":"K_BKSP","text":"*BkSp*","width":"100","sp":"1"}]},{"id":4,"key":[{"id":"K_CURRENCIES","text":"*Currency*","width":"150","sp":"1","nextlayer":"numeric"},{"id":"K_LOPT","text":"*Menu*","width":"100","sp":"1"},{"id":"T_new_350","text":"","width":"10","sp":"10"},{"id":"K_SPACE","text":"","width":"610","sp":"0"},{"id":"T_new_352","text":"","width":"10","sp":"10"},{"id":"K_ENTER","text":"*Enter*","width":"140","sp":"1"}]}]},{"id":"currency","row":[{"id":1,"key":[{"id":"U_00A2","text":"\u00A2","nextlayer":"numeric"},{"id":"U_20AC","text":"\u20AC","nextlayer":"numeric"},{"id":"U_20A4","text":"\u20A4","nextlayer":"numeric"},{"id":"U_00A3","text":"\u00A3","nextlayer":"numeric"},{"id":"U_20AA","text":"\u20AA","nextlayer":"numeric"},{"id":"U_20A8","text":"\u20A8","nextlayer":"numeric"},{"id":"U_20B9","text":"\u20B9","nextlayer":"numeric"},{"id":"U_20A9","text":"\u20A9","nextlayer":"numeric"},{"id":"U_00A5","text":"\u00A5","nextlayer":"numeric"},{"id":"U_00A4","text":"\u00A4","nextlayer":"numeric"}]},{"id":2,"key":[{"id":"U_20AB","text":"\u20AB","pad":"40"},{"id":"U_20AF","text":"\u20AF"},{"id":"U_20B1","text":"\u20B1"},{"id":"U_20A3","text":"\u20A3"},{"id":"U_20B0","text":"\u20B0"},{"id":"U_20B2","text":"\u20B2"},{"id":"U_20B4","text":"\u20B4"},{"id":"U_20A1","text":"\u20A1"},{"id":"U_20AD","text":"\u20AD"},{"id":"T_new_2717","text":"","width":"10","sp":"10"}]},{"id":3,"key":[{"id":"K_LOWER","text":"*abc*","width":"100","sp":"1","nextlayer":"default"},{"id":"U_20A6","text":"\u20A6"},{"id":"U_20A7","text":"\u20A7"},{"id":"U_20AE","text":"\u20AE"},{"id":"U_0BF9","text":"\u0BF9"},{"id":"U_09F3","text":"\u09F3"},{"id":"U_0E3F","text":"\u0E3F"},{"id":"T_new_2725","text":"","sp":"9"},{"id":"T_new_2726","text":"","sp":"9"},{"id":"K_BKSP","text":"*BkSp*","width":"100","sp":"1"}]},{"id":4,"key":[{"id":"K_SYMBOLS","text":"*Symbol*","width":"150","sp":"1","nextlayer":"symbol"},{"id":"K_LOPT","text":"*Menu*","width":"100","sp":"1"},{"id":"T_new_2731","text":"","width":"10","sp":"10"},{"id":"K_SPACE","text":"","width":"610","sp":"0"},{"id":"T_new_2733","text":"","width":"10","sp":"10"},{"id":"K_ENTER","text":"*Enter*","width":"140","sp":"1"}]}]}]}};this.s13=KeymanWeb.KLOAD(this.KI,"option_key","");this.s14="`#'\"^%&*~-_:@.|,=\\$";this.s15="àèìǹòùẁỳÀÈÌǸÒÙẀỲ";this.s16="aeinouwyAEINOUWY";this.s17="ȁȅȉȍȑȕȀȄȈȌȐȔ";this.s18="aeioruAEIORU";this.s19="áćéǵíḱĺḿńóṕŕśúẃýźÁĆÉǴÍḰĹḾŃÓṔŔŚÚẂÝŹ";this.s20="acegiklmnoprsuwyzACEGIKLMNOPRSUWYZ";this.s21="őűŐŰ";this.s22="ouOU";this.s23="âĉêĝĥîĵôŝûŵŷẑÂĈÊĜĤÎĴÔŜÛŴŶẐ";this.s24="aceghijosuwyzACEGHIJOSUWYZ";this.s25="ǎǍčČďĎěĚǧǦȟȞǐǏǰǩǨľĽňŇǒǑřŘšŠťŤǔǓǯǮžŽ";this.s26="aAcCdDeEgGhHiIjkKlLnNoOrRsStTuUxXzZ";this.s27="ȂȃȆȇȊȋȎȏȒȓȖȗ";this.s28="AaEeIiOoRrUu";this.s29="ăĂĕĔğĞḫḪĭĬŏŎŭŬ";this.s30="aAeEgGhHiIoOuU";this.s31="ãÃẽẼĩĨɫⱢñÑõÕũŨṽṼỹỸ";this.s32="aAeEiIlLnNoOuUvVyY";this.s33="ĀāɃƀĐđĒēḠḡĦħĪīɈɉŁłŌōɌɍŦŧŪūȲȳƵƶ";this.s34="AaBbDdEeGgHhIiJjLlOoRrTtUuYyZz";this.s35="ḆḇḎḏẖḴḵḺḻṈṉṞṟṮṯẔẕ";this.s36="BbDdhKkLlNnRrTtZz";this.s37="äëḧïöẗüẅẍÿÄËḦÏÖÜẄẌŸ";this.s38="aehiotuwxyAEHIOUWXY";this.s39="åÅůŮẘẙșȘțȚ";this.s40="aAuUwysStT";this.s41="ȧȦḃḂċĊḋḊėĖḟḞġĠḣḢıİȷŀĿṁṀṅṄȯȮṗṖṙṘṡṠṫṪẇẆẋẊẏẎżŻ";this.s42="aAbBcCdDeEfFgGhHiIjlLmMnNoOpPrRsStTwWxXyYzZ";this.s43="ẠạḄḅḌḍẸẹḤḥỊịḲḳḶḷṂṃṆṇỌọṚṛṢṣṬṭỤụṾṿẈẉỴỵẒẓ";this.s44="AaBbDdEeHhIiKkLlMmNnOoRrSsTtUuVvWwYyZz";this.s45="ąĄçÇḑḐęĘģĢḩḨįĮķĶļĻņŅǫǪŗŖşŞţŢųŲⱬⱫ";this.s46="aAcCdDeEgGhHiIkKlLnNoOrRsStTuUzZ";this.s47="ƆɔƏəɁɂƝɲŊŋƟɵẞßÞþȜȝƷʒ";this.s48="CcEeGgJjNnOoSsTtYyZz";this.s49="©ÐðƐɛªǤǥĸ—º–ʼnØø¶℗®§ſ‡†µ×¡¦¨¬­¯°±´·¸¿÷‰•¹²³⁴⁵⁶⁷⁸⁹⁰";this.s50="cDdEefGgkMmNnOoPprSsTtux!|:~-_*+'.,?/%>1234567890";this.s51="¤¢₯₫€€₱₣₲₰₴₡₭₤₦₪₧£₹₨₮₩¥";this.s52="CcDdEefFGghkKlNnPpRrtwy";this.s55="touch";this.s56="touch";this.s57="touch";this.s58="touch";this.s59="touch";this.s60="";this.s61="";this.s62="";this.KVER="10.0.1099.0";this.gs=function(t,e) {return this.g0(t,e);};this.g0=function(t,e) {var k=KeymanWeb,r=0,m=0;if(k.KKM(e,16384,256)&&k.KIFS(31,this.s56,t)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"g̃");}else if(k.KKM(e,16400,256)&&k.KIFS(31,this.s57,t)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"G̃");}else if(k.KKM(e,16384,257)&&k.KIFS(31,this.s58,t)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"p̈");}else if(k.KKM(e,16400,257)&&k.KIFS(31,this.s59,t)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"P̈");}else if(k.KKM(e,16400,49)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"¡");}else if(k.KKM(e,16400,222)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ꞌ");}else if(k.KKM(e,16400,222)&&k.KFCM(2,t,['\"',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"\"");}else if(k.KKM(e,16400,222)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16400,222)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,"\"");k.KDO(-1,t,0);}else if(k.KKM(e,16400,51)&&k.KFCM(2,t,['#',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"#");}else if(k.KKM(e,16400,51)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16400,51)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,"#");k.KDO(-1,t,0);}else if(k.KKM(e,16400,52)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"$");}else if(k.KKM(e,16400,52)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16400,52)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,"$");k.KDO(-1,t,0);}else if(k.KKM(e,16400,53)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"‰");}else if(k.KKM(e,16400,53)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"%");}else if(k.KKM(e,16400,53)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16400,53)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,"%");k.KDO(-1,t,0);}else if(k.KKM(e,16400,55)&&k.KFCM(2,t,['&',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"&");}else if(k.KKM(e,16400,55)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16400,55)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,"&");k.KDO(-1,t,0);}else if(k.KKM(e,16384,222)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ꞌ");}else if(k.KKM(e,16384,222)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"´");}else if(k.KKM(e,16384,222)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"'");}else if(k.KKM(e,16384,222)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16384,222)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,"'");k.KDO(-1,t,0);}else if(k.KKM(e,16400,56)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"°");}else if(k.KKM(e,16400,56)&&k.KFCM(2,t,['*',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"*");}else if(k.KKM(e,16400,56)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16400,56)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,"*");k.KDO(-1,t,0);}else if(k.KKM(e,16400,187)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"±");}else if(k.KKM(e,16384,188)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"¸");}else if(k.KKM(e,16384,188)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,",");}else if(k.KKM(e,16384,188)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16384,188)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,",");k.KDO(-1,t,0);}else if(k.KKM(e,16384,189)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"­");}else if(k.KKM(e,16384,189)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"-");}else if(k.KKM(e,16384,189)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16384,189)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,"-");k.KDO(-1,t,0);}else if(k.KKM(e,16384,190)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"·");}else if(k.KKM(e,16384,190)&&k.KFCM(2,t,['·','.'])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"…");}else if(k.KKM(e,16384,190)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,".");}else if(k.KKM(e,16384,190)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16384,190)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,".");k.KDO(-1,t,0);}else if(k.KKM(e,16384,191)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"÷");}else if(k.KKM(e,16384,48)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"⁰");}else if(k.KKM(e,16384,49)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"¹");}else if(k.KKM(e,16384,50)&&k.KFCM(3,t,['1','/','/'])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"½");}else if(k.KKM(e,16384,50)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"²");}else if(k.KKM(e,16384,50)&&k.KFCM(2,t,['¹','/'])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"½");}else if(k.KKM(e,16384,51)&&k.KFCM(3,t,['1','/','/'])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"⅓");}else if(k.KKM(e,16384,51)&&k.KFCM(3,t,['2','/','/'])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"⅔");}else if(k.KKM(e,16384,51)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"³");}else if(k.KKM(e,16384,51)&&k.KFCM(2,t,['¹','/'])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"⅓");}else if(k.KKM(e,16384,51)&&k.KFCM(2,t,['²','/'])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"⅔");}else if(k.KKM(e,16384,52)&&k.KFCM(3,t,['1','/','/'])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"¼");}else if(k.KKM(e,16384,52)&&k.KFCM(3,t,['3','/','/'])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"¾");}else if(k.KKM(e,16384,52)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"⁴");}else if(k.KKM(e,16384,52)&&k.KFCM(2,t,['¹','/'])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"¼");}else if(k.KKM(e,16384,52)&&k.KFCM(2,t,['³','/'])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"¾");}else if(k.KKM(e,16384,53)&&k.KFCM(3,t,['1','/','/'])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"⅕");}else if(k.KKM(e,16384,53)&&k.KFCM(3,t,['2','/','/'])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"⅖");}else if(k.KKM(e,16384,53)&&k.KFCM(3,t,['3','/','/'])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"⅗");}else if(k.KKM(e,16384,53)&&k.KFCM(3,t,['4','/','/'])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"⅘");}else if(k.KKM(e,16384,53)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"⁵");}else if(k.KKM(e,16384,54)&&k.KFCM(3,t,['1','/','/'])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"⅙");}else if(k.KKM(e,16384,54)&&k.KFCM(3,t,['5','/','/'])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"⅚");}else if(k.KKM(e,16384,54)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"⁶");}else if(k.KKM(e,16384,55)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"⁷");}else if(k.KKM(e,16384,56)&&k.KFCM(3,t,['1','/','/'])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"⅛");}else if(k.KKM(e,16384,56)&&k.KFCM(3,t,['3','/','/'])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"⅜");}else if(k.KKM(e,16384,56)&&k.KFCM(3,t,['5','/','/'])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"⅝");}else if(k.KKM(e,16384,56)&&k.KFCM(3,t,['7','/','/'])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"⅞");}else if(k.KKM(e,16384,56)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"⁸");}else if(k.KKM(e,16384,56)&&k.KFCM(2,t,['¹','/'])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"⅛");}else if(k.KKM(e,16384,56)&&k.KFCM(2,t,['³','/'])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"⅜");}else if(k.KKM(e,16384,56)&&k.KFCM(2,t,['⁵','/'])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"⅝");}else if(k.KKM(e,16384,56)&&k.KFCM(2,t,['⁷','/'])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"⅞");}else if(k.KKM(e,16384,57)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"⁹");}else if(k.KKM(e,16400,186)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"¨");}else if(k.KKM(e,16400,186)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,":");}else if(k.KKM(e,16400,186)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16400,186)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,":");k.KDO(-1,t,0);}else if(k.KKM(e,16400,188)&&k.KFCM(1,t,['<'])&&this.s13===this.s60) {r=m=1;k.KDC(1,t);k.KO(-1,t,"«");}else if(k.KKM(e,16400,188)&&k.KFCM(2,t,['<',{t:'d',d:1}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"<<");k.KDO(-1,t,1);}else if(k.KKM(e,16400,188)&&k.KFCM(1,t,['«'])) {r=m=1;k.KDC(1,t);k.KO(-1,t,"<<");k.KDO(-1,t,1);}else if(k.KKM(e,16384,187)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"=");}else if(k.KKM(e,16384,187)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16384,187)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,"=");k.KDO(-1,t,0);}else if(k.KKM(e,16400,190)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"•");}else if(k.KKM(e,16400,190)&&k.KFCM(1,t,['>'])&&this.s13===this.s61) {r=m=1;k.KDC(1,t);k.KO(-1,t,"»");}else if(k.KKM(e,16400,190)&&k.KFCM(2,t,['>',{t:'d',d:1}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,">>");k.KDO(-1,t,1);}else if(k.KKM(e,16400,190)&&k.KFCM(1,t,['»'])) {r=m=1;k.KDC(1,t);k.KO(-1,t,">>");k.KDO(-1,t,1);}else if(k.KKM(e,16400,191)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"¿");}else if(k.KKM(e,16400,50)&&k.KFCM(2,t,['@',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"@");}else if(k.KKM(e,16400,50)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16400,50)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,"@");k.KDO(-1,t,0);}else if(k.KKM(e,16400,65)&&k.KFCM(2,t,['`',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"À");}else if(k.KKM(e,16400,65)&&k.KFCM(2,t,['#',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ȁ");}else if(k.KKM(e,16400,65)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Á");}else if(k.KKM(e,16400,65)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Â");}else if(k.KKM(e,16400,65)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ǎ");}else if(k.KKM(e,16400,65)&&k.KFCM(2,t,['&',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ȃ");}else if(k.KKM(e,16400,65)&&k.KFCM(2,t,['*',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ă");}else if(k.KKM(e,16400,65)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ã");}else if(k.KKM(e,16400,65)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ā");}else if(k.KKM(e,16400,65)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ä");}else if(k.KKM(e,16400,65)&&k.KFCM(2,t,['@',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Å");}else if(k.KKM(e,16400,65)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ȧ");}else if(k.KKM(e,16400,65)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ạ");}else if(k.KKM(e,16400,65)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ą");}else if(k.KKM(e,16400,66)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ƀ");}else if(k.KKM(e,16400,66)&&k.KFCM(2,t,['_',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḇ");}else if(k.KKM(e,16400,66)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḃ");}else if(k.KKM(e,16400,66)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḅ");}else if(k.KKM(e,16400,67)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ć");}else if(k.KKM(e,16400,67)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ĉ");}else if(k.KKM(e,16400,67)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Č");}else if(k.KKM(e,16400,67)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ċ");}else if(k.KKM(e,16400,67)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ç");}else if(k.KKM(e,16400,67)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ɔ");}else if(k.KKM(e,16400,67)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"¤");}else if(k.KKM(e,16400,68)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ď");}else if(k.KKM(e,16400,68)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Đ");}else if(k.KKM(e,16400,68)&&k.KFCM(2,t,['_',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḏ");}else if(k.KKM(e,16400,68)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḋ");}else if(k.KKM(e,16400,68)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḍ");}else if(k.KKM(e,16400,68)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḑ");}else if(k.KKM(e,16400,68)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ð");}else if(k.KKM(e,16400,68)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"₯");}else if(k.KKM(e,16400,69)&&k.KFCM(3,t,['A','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"Æ");}else if(k.KKM(e,16400,69)&&k.KFCM(3,t,['O','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"Œ");}else if(k.KKM(e,16400,69)&&k.KFCM(2,t,['`',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"È");}else if(k.KKM(e,16400,69)&&k.KFCM(2,t,['#',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ȅ");}else if(k.KKM(e,16400,69)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"É");}else if(k.KKM(e,16400,69)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ê");}else if(k.KKM(e,16400,69)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ě");}else if(k.KKM(e,16400,69)&&k.KFCM(2,t,['&',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ȇ");}else if(k.KKM(e,16400,69)&&k.KFCM(2,t,['*',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ĕ");}else if(k.KKM(e,16400,69)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ẽ");}else if(k.KKM(e,16400,69)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ē");}else if(k.KKM(e,16400,69)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ë");}else if(k.KKM(e,16400,69)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ė");}else if(k.KKM(e,16400,69)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ẹ");}else if(k.KKM(e,16400,69)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ę");}else if(k.KKM(e,16400,69)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ə");}else if(k.KKM(e,16400,69)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ɛ");}else if(k.KKM(e,16400,69)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"€");}else if(k.KKM(e,16400,70)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḟ");}else if(k.KKM(e,16400,70)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"₣");}else if(k.KKM(e,16400,71)&&k.KFCM(3,t,['N','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"Ŋ");}else if(k.KKM(e,16400,71)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"G̃");}else if(k.KKM(e,16400,71)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ǵ");}else if(k.KKM(e,16400,71)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ĝ");}else if(k.KKM(e,16400,71)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ǧ");}else if(k.KKM(e,16400,71)&&k.KFCM(2,t,['*',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ğ");}else if(k.KKM(e,16400,71)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḡ");}else if(k.KKM(e,16400,71)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ġ");}else if(k.KKM(e,16400,71)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ģ");}else if(k.KKM(e,16400,71)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ɂ");}else if(k.KKM(e,16400,71)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ǥ");}else if(k.KKM(e,16400,71)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"₲");}else if(k.KKM(e,16400,72)&&k.KFCM(3,t,['T','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"Þ");}else if(k.KKM(e,16400,72)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ĥ");}else if(k.KKM(e,16400,72)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ȟ");}else if(k.KKM(e,16400,72)&&k.KFCM(2,t,['*',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḫ");}else if(k.KKM(e,16400,72)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ħ");}else if(k.KKM(e,16400,72)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḧ");}else if(k.KKM(e,16400,72)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḣ");}else if(k.KKM(e,16400,72)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḥ");}else if(k.KKM(e,16400,72)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḩ");}else if(k.KKM(e,16400,73)&&k.KFCM(3,t,['O','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"Ƣ");}else if(k.KKM(e,16400,73)&&k.KFCM(2,t,['`',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ì");}else if(k.KKM(e,16400,73)&&k.KFCM(2,t,['#',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ȉ");}else if(k.KKM(e,16400,73)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Í");}else if(k.KKM(e,16400,73)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Î");}else if(k.KKM(e,16400,73)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ǐ");}else if(k.KKM(e,16400,73)&&k.KFCM(2,t,['&',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ȋ");}else if(k.KKM(e,16400,73)&&k.KFCM(2,t,['*',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ĭ");}else if(k.KKM(e,16400,73)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ĩ");}else if(k.KKM(e,16400,73)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ī");}else if(k.KKM(e,16400,73)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ï");}else if(k.KKM(e,16400,73)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"İ");}else if(k.KKM(e,16400,73)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ị");}else if(k.KKM(e,16400,73)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Į");}else if(k.KKM(e,16400,74)&&k.KFCM(3,t,['I','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"IJ");}else if(k.KKM(e,16400,74)&&k.KFCM(3,t,['L','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"LJ");}else if(k.KKM(e,16400,74)&&k.KFCM(3,t,['N','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"NJ");}else if(k.KKM(e,16400,74)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ĵ");}else if(k.KKM(e,16400,74)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ɉ");}else if(k.KKM(e,16400,74)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ɲ");}else if(k.KKM(e,16400,75)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḱ");}else if(k.KKM(e,16400,75)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ǩ");}else if(k.KKM(e,16400,75)&&k.KFCM(2,t,['_',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḵ");}else if(k.KKM(e,16400,75)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḳ");}else if(k.KKM(e,16400,75)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ķ");}else if(k.KKM(e,16400,75)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"₭");}else if(k.KKM(e,16400,76)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ĺ");}else if(k.KKM(e,16400,76)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ľ");}else if(k.KKM(e,16400,76)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ɫ");}else if(k.KKM(e,16400,76)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ł");}else if(k.KKM(e,16400,76)&&k.KFCM(2,t,['_',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḻ");}else if(k.KKM(e,16400,76)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ŀ");}else if(k.KKM(e,16400,76)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḷ");}else if(k.KKM(e,16400,76)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ļ");}else if(k.KKM(e,16400,77)&&k.KFCM(3,t,['T','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"™");}else if(k.KKM(e,16400,77)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ḿ");}else if(k.KKM(e,16400,77)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ṁ");}else if(k.KKM(e,16400,77)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ṃ");}else if(k.KKM(e,16400,77)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"—");}else if(k.KKM(e,16400,78)&&k.KFCM(2,t,['`',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ǹ");}else if(k.KKM(e,16400,78)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ń");}else if(k.KKM(e,16400,78)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ň");}else if(k.KKM(e,16400,78)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ñ");}else if(k.KKM(e,16400,78)&&k.KFCM(2,t,['_',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ṉ");}else if(k.KKM(e,16400,78)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ṅ");}else if(k.KKM(e,16400,78)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ṇ");}else if(k.KKM(e,16400,78)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ņ");}else if(k.KKM(e,16400,78)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ŋ");}else if(k.KKM(e,16400,78)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"–");}else if(k.KKM(e,16400,78)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"₦");}else if(k.KKM(e,16400,79)&&k.KFCM(3,t,['N','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"№");}else if(k.KKM(e,16400,79)&&k.KFCM(2,t,['`',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ò");}else if(k.KKM(e,16400,79)&&k.KFCM(2,t,['#',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ȍ");}else if(k.KKM(e,16400,79)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ó");}else if(k.KKM(e,16400,79)&&k.KFCM(2,t,['\"',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ő");}else if(k.KKM(e,16400,79)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ô");}else if(k.KKM(e,16400,79)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ǒ");}else if(k.KKM(e,16400,79)&&k.KFCM(2,t,['&',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ȏ");}else if(k.KKM(e,16400,79)&&k.KFCM(2,t,['*',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ŏ");}else if(k.KKM(e,16400,79)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Õ");}else if(k.KKM(e,16400,79)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ō");}else if(k.KKM(e,16400,79)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ö");}else if(k.KKM(e,16400,79)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ȯ");}else if(k.KKM(e,16400,79)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ọ");}else if(k.KKM(e,16400,79)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ǫ");}else if(k.KKM(e,16400,79)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ɵ");}else if(k.KKM(e,16400,79)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ø");}else if(k.KKM(e,16400,80)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"P̈");}else if(k.KKM(e,16400,80)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ṕ");}else if(k.KKM(e,16400,80)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ṗ");}else if(k.KKM(e,16400,80)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"¶");}else if(k.KKM(e,16400,80)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"₧");}else if(k.KKM(e,16400,82)&&k.KFCM(2,t,['#',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ȑ");}else if(k.KKM(e,16400,82)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ŕ");}else if(k.KKM(e,16400,82)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ř");}else if(k.KKM(e,16400,82)&&k.KFCM(2,t,['&',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ȓ");}else if(k.KKM(e,16400,82)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ɍ");}else if(k.KKM(e,16400,82)&&k.KFCM(2,t,['_',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ṟ");}else if(k.KKM(e,16400,82)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ṙ");}else if(k.KKM(e,16400,82)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ṛ");}else if(k.KKM(e,16400,82)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ŗ");}else if(k.KKM(e,16400,82)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"₹");}else if(k.KKM(e,16400,83)&&k.KFCM(3,t,['S','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"ẞ");}else if(k.KKM(e,16400,83)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ś");}else if(k.KKM(e,16400,83)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ŝ");}else if(k.KKM(e,16400,83)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Š");}else if(k.KKM(e,16400,83)&&k.KFCM(2,t,['@',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ș");}else if(k.KKM(e,16400,83)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ṡ");}else if(k.KKM(e,16400,83)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ṣ");}else if(k.KKM(e,16400,83)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ş");}else if(k.KKM(e,16400,83)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ẞ");}else if(k.KKM(e,16400,83)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"§");}else if(k.KKM(e,16400,84)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ť");}else if(k.KKM(e,16400,84)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ŧ");}else if(k.KKM(e,16400,84)&&k.KFCM(2,t,['_',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ṯ");}else if(k.KKM(e,16400,84)&&k.KFCM(2,t,['@',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ț");}else if(k.KKM(e,16400,84)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ṫ");}else if(k.KKM(e,16400,84)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ṭ");}else if(k.KKM(e,16400,84)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ţ");}else if(k.KKM(e,16400,84)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Þ");}else if(k.KKM(e,16400,84)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"‡");}else if(k.KKM(e,16400,85)&&k.KFCM(2,t,['`',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ù");}else if(k.KKM(e,16400,85)&&k.KFCM(2,t,['#',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ȕ");}else if(k.KKM(e,16400,85)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ú");}else if(k.KKM(e,16400,85)&&k.KFCM(2,t,['\"',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ű");}else if(k.KKM(e,16400,85)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Û");}else if(k.KKM(e,16400,85)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ǔ");}else if(k.KKM(e,16400,85)&&k.KFCM(2,t,['&',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ȗ");}else if(k.KKM(e,16400,85)&&k.KFCM(2,t,['*',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ŭ");}else if(k.KKM(e,16400,85)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ũ");}else if(k.KKM(e,16400,85)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ū");}else if(k.KKM(e,16400,85)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ü");}else if(k.KKM(e,16400,85)&&k.KFCM(2,t,['@',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ů");}else if(k.KKM(e,16400,85)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ụ");}else if(k.KKM(e,16400,85)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ų");}else if(k.KKM(e,16400,86)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ṽ");}else if(k.KKM(e,16400,86)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ṿ");}else if(k.KKM(e,16400,87)&&k.KFCM(2,t,['`',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ẁ");}else if(k.KKM(e,16400,87)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ẃ");}else if(k.KKM(e,16400,87)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ŵ");}else if(k.KKM(e,16400,87)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ẅ");}else if(k.KKM(e,16400,87)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ẇ");}else if(k.KKM(e,16400,87)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ẉ");}else if(k.KKM(e,16400,88)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ǯ");}else if(k.KKM(e,16400,88)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ẍ");}else if(k.KKM(e,16400,88)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ẋ");}else if(k.KKM(e,16400,89)&&k.KFCM(2,t,['`',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ỳ");}else if(k.KKM(e,16400,89)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ý");}else if(k.KKM(e,16400,89)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ŷ");}else if(k.KKM(e,16400,89)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ỹ");}else if(k.KKM(e,16400,89)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ȳ");}else if(k.KKM(e,16400,89)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ÿ");}else if(k.KKM(e,16400,89)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ẏ");}else if(k.KKM(e,16400,89)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ỵ");}else if(k.KKM(e,16400,89)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ȝ");}else if(k.KKM(e,16400,90)&&k.KFCM(3,t,['D','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"DŽ");}else if(k.KKM(e,16400,90)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ź");}else if(k.KKM(e,16400,90)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ẑ");}else if(k.KKM(e,16400,90)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ž");}else if(k.KKM(e,16400,90)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ƶ");}else if(k.KKM(e,16400,90)&&k.KFCM(2,t,['_',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ẕ");}else if(k.KKM(e,16400,90)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ż");}else if(k.KKM(e,16400,90)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ẓ");}else if(k.KKM(e,16400,90)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ⱬ");}else if(k.KKM(e,16400,90)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"Ʒ");}else if(k.KKM(e,16384,220)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"\\");}else if(k.KKM(e,16384,220)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16384,220)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,"\\");k.KDO(-1,t,0);}else if(k.KKM(e,16400,54)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"^");}else if(k.KKM(e,16400,54)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16400,54)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,"^");k.KDO(-1,t,0);}else if(k.KKM(e,16400,189)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"¯");}else if(k.KKM(e,16400,189)&&k.KFCM(2,t,['_',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"_");}else if(k.KKM(e,16400,189)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16400,189)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,"_");k.KDO(-1,t,0);}else if(k.KKM(e,16384,192)&&k.KFCM(2,t,['`',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"`");}else if(k.KKM(e,16384,192)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16384,192)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,"`");k.KDO(-1,t,0);}else if(k.KKM(e,16384,65)&&k.KFCM(2,t,['`',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"à");}else if(k.KKM(e,16384,65)&&k.KFCM(2,t,['#',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ȁ");}else if(k.KKM(e,16384,65)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"á");}else if(k.KKM(e,16384,65)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"â");}else if(k.KKM(e,16384,65)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ǎ");}else if(k.KKM(e,16384,65)&&k.KFCM(2,t,['&',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ȃ");}else if(k.KKM(e,16384,65)&&k.KFCM(2,t,['*',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ă");}else if(k.KKM(e,16384,65)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ã");}else if(k.KKM(e,16384,65)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ā");}else if(k.KKM(e,16384,65)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ä");}else if(k.KKM(e,16384,65)&&k.KFCM(2,t,['@',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"å");}else if(k.KKM(e,16384,65)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ȧ");}else if(k.KKM(e,16384,65)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ạ");}else if(k.KKM(e,16384,65)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ą");}else if(k.KKM(e,16384,66)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ƀ");}else if(k.KKM(e,16384,66)&&k.KFCM(2,t,['_',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḇ");}else if(k.KKM(e,16384,66)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḃ");}else if(k.KKM(e,16384,66)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḅ");}else if(k.KKM(e,16384,67)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ć");}else if(k.KKM(e,16384,67)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ĉ");}else if(k.KKM(e,16384,67)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"č");}else if(k.KKM(e,16384,67)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ċ");}else if(k.KKM(e,16384,67)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ç");}else if(k.KKM(e,16384,67)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ɔ");}else if(k.KKM(e,16384,67)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"©");}else if(k.KKM(e,16384,67)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"¢");}else if(k.KKM(e,16384,68)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ď");}else if(k.KKM(e,16384,68)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"đ");}else if(k.KKM(e,16384,68)&&k.KFCM(2,t,['_',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḏ");}else if(k.KKM(e,16384,68)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḋ");}else if(k.KKM(e,16384,68)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḍ");}else if(k.KKM(e,16384,68)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḑ");}else if(k.KKM(e,16384,68)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ð");}else if(k.KKM(e,16384,68)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"₫");}else if(k.KKM(e,16384,69)&&k.KFCM(3,t,['a','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"æ");}else if(k.KKM(e,16384,69)&&k.KFCM(3,t,['o','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"œ");}else if(k.KKM(e,16384,69)&&k.KFCM(2,t,['`',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"è");}else if(k.KKM(e,16384,69)&&k.KFCM(2,t,['#',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ȅ");}else if(k.KKM(e,16384,69)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"é");}else if(k.KKM(e,16384,69)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ê");}else if(k.KKM(e,16384,69)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ě");}else if(k.KKM(e,16384,69)&&k.KFCM(2,t,['&',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ȇ");}else if(k.KKM(e,16384,69)&&k.KFCM(2,t,['*',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ĕ");}else if(k.KKM(e,16384,69)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ẽ");}else if(k.KKM(e,16384,69)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ē");}else if(k.KKM(e,16384,69)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ë");}else if(k.KKM(e,16384,69)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ė");}else if(k.KKM(e,16384,69)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ẹ");}else if(k.KKM(e,16384,69)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ę");}else if(k.KKM(e,16384,69)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ə");}else if(k.KKM(e,16384,69)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ɛ");}else if(k.KKM(e,16384,69)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"€");}else if(k.KKM(e,16384,70)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḟ");}else if(k.KKM(e,16384,70)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ª");}else if(k.KKM(e,16384,70)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"₱");}else if(k.KKM(e,16384,71)&&k.KFCM(3,t,['n','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"ŋ");}else if(k.KKM(e,16384,71)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"g̃");}else if(k.KKM(e,16384,71)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ǵ");}else if(k.KKM(e,16384,71)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ĝ");}else if(k.KKM(e,16384,71)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ǧ");}else if(k.KKM(e,16384,71)&&k.KFCM(2,t,['*',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ğ");}else if(k.KKM(e,16384,71)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḡ");}else if(k.KKM(e,16384,71)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ġ");}else if(k.KKM(e,16384,71)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ģ");}else if(k.KKM(e,16384,71)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ɂ");}else if(k.KKM(e,16384,71)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ǥ");}else if(k.KKM(e,16384,71)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"₰");}else if(k.KKM(e,16384,72)&&k.KFCM(3,t,['t','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"þ");}else if(k.KKM(e,16384,72)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ĥ");}else if(k.KKM(e,16384,72)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ȟ");}else if(k.KKM(e,16384,72)&&k.KFCM(2,t,['*',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḫ");}else if(k.KKM(e,16384,72)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ħ");}else if(k.KKM(e,16384,72)&&k.KFCM(2,t,['_',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ẖ");}else if(k.KKM(e,16384,72)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḧ");}else if(k.KKM(e,16384,72)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḣ");}else if(k.KKM(e,16384,72)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḥ");}else if(k.KKM(e,16384,72)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḩ");}else if(k.KKM(e,16384,72)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"₴");}else if(k.KKM(e,16384,73)&&k.KFCM(3,t,['f','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"fi");}else if(k.KKM(e,16384,73)&&k.KFCM(3,t,['o','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"ƣ");}else if(k.KKM(e,16384,73)&&k.KFCM(2,t,['`',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ì");}else if(k.KKM(e,16384,73)&&k.KFCM(2,t,['#',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ȉ");}else if(k.KKM(e,16384,73)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"í");}else if(k.KKM(e,16384,73)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"î");}else if(k.KKM(e,16384,73)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ǐ");}else if(k.KKM(e,16384,73)&&k.KFCM(2,t,['&',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ȋ");}else if(k.KKM(e,16384,73)&&k.KFCM(2,t,['*',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ĭ");}else if(k.KKM(e,16384,73)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ĩ");}else if(k.KKM(e,16384,73)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ī");}else if(k.KKM(e,16384,73)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ï");}else if(k.KKM(e,16384,73)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ı");}else if(k.KKM(e,16384,73)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ị");}else if(k.KKM(e,16384,73)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"į");}else if(k.KKM(e,16384,74)&&k.KFCM(3,t,['i','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"ij");}else if(k.KKM(e,16384,74)&&k.KFCM(3,t,['L','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"Lj");}else if(k.KKM(e,16384,74)&&k.KFCM(3,t,['l','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"lj");}else if(k.KKM(e,16384,74)&&k.KFCM(3,t,['N','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"Nj");}else if(k.KKM(e,16384,74)&&k.KFCM(3,t,['n','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"nj");}else if(k.KKM(e,16384,74)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ĵ");}else if(k.KKM(e,16384,74)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ǰ");}else if(k.KKM(e,16384,74)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ɉ");}else if(k.KKM(e,16384,74)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ȷ");}else if(k.KKM(e,16384,74)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ɲ");}else if(k.KKM(e,16384,75)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḱ");}else if(k.KKM(e,16384,75)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ǩ");}else if(k.KKM(e,16384,75)&&k.KFCM(2,t,['_',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḵ");}else if(k.KKM(e,16384,75)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḳ");}else if(k.KKM(e,16384,75)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ķ");}else if(k.KKM(e,16384,75)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ĸ");}else if(k.KKM(e,16384,75)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"₡");}else if(k.KKM(e,16384,76)&&k.KFCM(3,t,['f','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"fl");}else if(k.KKM(e,16384,76)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ĺ");}else if(k.KKM(e,16384,76)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ľ");}else if(k.KKM(e,16384,76)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ɫ");}else if(k.KKM(e,16384,76)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ł");}else if(k.KKM(e,16384,76)&&k.KFCM(2,t,['_',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḻ");}else if(k.KKM(e,16384,76)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ŀ");}else if(k.KKM(e,16384,76)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḷ");}else if(k.KKM(e,16384,76)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ļ");}else if(k.KKM(e,16384,76)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"₤");}else if(k.KKM(e,16384,77)&&k.KFCM(3,t,['t','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"™");}else if(k.KKM(e,16384,77)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ḿ");}else if(k.KKM(e,16384,77)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ṁ");}else if(k.KKM(e,16384,77)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ṃ");}else if(k.KKM(e,16384,77)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"º");}else if(k.KKM(e,16384,78)&&k.KFCM(2,t,['`',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ǹ");}else if(k.KKM(e,16384,78)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ń");}else if(k.KKM(e,16384,78)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ň");}else if(k.KKM(e,16384,78)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ñ");}else if(k.KKM(e,16384,78)&&k.KFCM(2,t,['_',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ṉ");}else if(k.KKM(e,16384,78)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ṅ");}else if(k.KKM(e,16384,78)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ṇ");}else if(k.KKM(e,16384,78)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ņ");}else if(k.KKM(e,16384,78)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ŋ");}else if(k.KKM(e,16384,78)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ʼn");}else if(k.KKM(e,16384,78)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"₪");}else if(k.KKM(e,16384,79)&&k.KFCM(3,t,['n','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"№");}else if(k.KKM(e,16384,79)&&k.KFCM(2,t,['`',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ò");}else if(k.KKM(e,16384,79)&&k.KFCM(2,t,['#',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ȍ");}else if(k.KKM(e,16384,79)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ó");}else if(k.KKM(e,16384,79)&&k.KFCM(2,t,['\"',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ő");}else if(k.KKM(e,16384,79)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ô");}else if(k.KKM(e,16384,79)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ǒ");}else if(k.KKM(e,16384,79)&&k.KFCM(2,t,['&',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ȏ");}else if(k.KKM(e,16384,79)&&k.KFCM(2,t,['*',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ŏ");}else if(k.KKM(e,16384,79)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"õ");}else if(k.KKM(e,16384,79)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ō");}else if(k.KKM(e,16384,79)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ö");}else if(k.KKM(e,16384,79)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ȯ");}else if(k.KKM(e,16384,79)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ọ");}else if(k.KKM(e,16384,79)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ǫ");}else if(k.KKM(e,16384,79)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ɵ");}else if(k.KKM(e,16384,79)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ø");}else if(k.KKM(e,16384,80)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"p̈");}else if(k.KKM(e,16384,80)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ṕ");}else if(k.KKM(e,16384,80)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ṗ");}else if(k.KKM(e,16384,80)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"℗");}else if(k.KKM(e,16384,80)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"£");}else if(k.KKM(e,16384,82)&&k.KFCM(2,t,['#',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ȑ");}else if(k.KKM(e,16384,82)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ŕ");}else if(k.KKM(e,16384,82)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ř");}else if(k.KKM(e,16384,82)&&k.KFCM(2,t,['&',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ȓ");}else if(k.KKM(e,16384,82)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ɍ");}else if(k.KKM(e,16384,82)&&k.KFCM(2,t,['_',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ṟ");}else if(k.KKM(e,16384,82)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ṙ");}else if(k.KKM(e,16384,82)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ṛ");}else if(k.KKM(e,16384,82)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ŗ");}else if(k.KKM(e,16384,82)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"®");}else if(k.KKM(e,16384,82)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"₨");}else if(k.KKM(e,16384,83)&&k.KFCM(3,t,['s','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"ß");}else if(k.KKM(e,16384,83)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ś");}else if(k.KKM(e,16384,83)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ŝ");}else if(k.KKM(e,16384,83)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"š");}else if(k.KKM(e,16384,83)&&k.KFCM(2,t,['@',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ș");}else if(k.KKM(e,16384,83)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ṡ");}else if(k.KKM(e,16384,83)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ṣ");}else if(k.KKM(e,16384,83)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ş");}else if(k.KKM(e,16384,83)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ß");}else if(k.KKM(e,16384,83)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ſ");}else if(k.KKM(e,16384,84)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ť");}else if(k.KKM(e,16384,84)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ŧ");}else if(k.KKM(e,16384,84)&&k.KFCM(2,t,['_',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ṯ");}else if(k.KKM(e,16384,84)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ẗ");}else if(k.KKM(e,16384,84)&&k.KFCM(2,t,['@',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ț");}else if(k.KKM(e,16384,84)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ṫ");}else if(k.KKM(e,16384,84)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ṭ");}else if(k.KKM(e,16384,84)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ţ");}else if(k.KKM(e,16384,84)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"þ");}else if(k.KKM(e,16384,84)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"†");}else if(k.KKM(e,16384,84)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"₮");}else if(k.KKM(e,16384,85)&&k.KFCM(2,t,['`',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ù");}else if(k.KKM(e,16384,85)&&k.KFCM(2,t,['#',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ȕ");}else if(k.KKM(e,16384,85)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ú");}else if(k.KKM(e,16384,85)&&k.KFCM(2,t,['\"',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ű");}else if(k.KKM(e,16384,85)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"û");}else if(k.KKM(e,16384,85)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ǔ");}else if(k.KKM(e,16384,85)&&k.KFCM(2,t,['&',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ȗ");}else if(k.KKM(e,16384,85)&&k.KFCM(2,t,['*',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ŭ");}else if(k.KKM(e,16384,85)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ũ");}else if(k.KKM(e,16384,85)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ū");}else if(k.KKM(e,16384,85)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ü");}else if(k.KKM(e,16384,85)&&k.KFCM(2,t,['@',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ů");}else if(k.KKM(e,16384,85)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ụ");}else if(k.KKM(e,16384,85)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ų");}else if(k.KKM(e,16384,85)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"µ");}else if(k.KKM(e,16384,86)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ṽ");}else if(k.KKM(e,16384,86)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ṿ");}else if(k.KKM(e,16384,87)&&k.KFCM(2,t,['`',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ẁ");}else if(k.KKM(e,16384,87)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ẃ");}else if(k.KKM(e,16384,87)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ŵ");}else if(k.KKM(e,16384,87)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ẅ");}else if(k.KKM(e,16384,87)&&k.KFCM(2,t,['@',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ẘ");}else if(k.KKM(e,16384,87)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ẇ");}else if(k.KKM(e,16384,87)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ẉ");}else if(k.KKM(e,16384,87)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"₩");}else if(k.KKM(e,16384,88)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ǯ");}else if(k.KKM(e,16384,88)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ẍ");}else if(k.KKM(e,16384,88)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ẋ");}else if(k.KKM(e,16384,88)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"×");}else if(k.KKM(e,16384,89)&&k.KFCM(2,t,['`',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ỳ");}else if(k.KKM(e,16384,89)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ý");}else if(k.KKM(e,16384,89)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ŷ");}else if(k.KKM(e,16384,89)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ỹ");}else if(k.KKM(e,16384,89)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ȳ");}else if(k.KKM(e,16384,89)&&k.KFCM(2,t,[':',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ÿ");}else if(k.KKM(e,16384,89)&&k.KFCM(2,t,['@',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ẙ");}else if(k.KKM(e,16384,89)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ẏ");}else if(k.KKM(e,16384,89)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ỵ");}else if(k.KKM(e,16384,89)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ȝ");}else if(k.KKM(e,16384,89)&&k.KFCM(2,t,['$',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"¥");}else if(k.KKM(e,16384,90)&&k.KFCM(3,t,['D','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"Dž");}else if(k.KKM(e,16384,90)&&k.KFCM(3,t,['d','\\',{t:'d',d:0}])) {r=m=1;k.KDC(3,t);k.KO(-1,t,"dž");}else if(k.KKM(e,16384,90)&&k.KFCM(2,t,['\'',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ź");}else if(k.KKM(e,16384,90)&&k.KFCM(2,t,['^',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ẑ");}else if(k.KKM(e,16384,90)&&k.KFCM(2,t,['%',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ž");}else if(k.KKM(e,16384,90)&&k.KFCM(2,t,['-',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ƶ");}else if(k.KKM(e,16384,90)&&k.KFCM(2,t,['_',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ẕ");}else if(k.KKM(e,16384,90)&&k.KFCM(2,t,['.',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ż");}else if(k.KKM(e,16384,90)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ẓ");}else if(k.KKM(e,16384,90)&&k.KFCM(2,t,[',',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ⱬ");}else if(k.KKM(e,16384,90)&&k.KFCM(2,t,['=',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"ʒ");}else if(k.KKM(e,16400,220)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"¦");}else if(k.KKM(e,16400,220)&&k.KFCM(2,t,['|',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"|");}else if(k.KKM(e,16400,220)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16400,220)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,"|");k.KDO(-1,t,0);}else if(k.KKM(e,16400,192)&&k.KFCM(2,t,['\\',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"¬");}else if(k.KKM(e,16400,192)&&k.KFCM(2,t,['~',{t:'d',d:0}])) {r=m=1;k.KDC(2,t);k.KO(-1,t,"~");}else if(k.KKM(e,16400,192)&&k.KIFS(31,this.s55,t)) {r=m=1;k.KDC(0,t);r=this.g1(t,e);}else if(k.KKM(e,16400,192)&&this.s13===this.s62) {r=m=1;k.KDC(0,t);k.KO(-1,t,"~");k.KDO(-1,t,0);}return r;};this.g1=function(t,e) {var k=KeymanWeb,r=0,m=0;return r;};this.KHF=function(e) { + var h = document.getElementsByTagName('head'); + var stext = + "#keyboard_europeanlatin_help { text-align: left; padding: 0; background: #f5e3de; font-size: 8pt; font-family: Tahoma; cursor: default; padding: 4px; }"+ + "#keyboard_europeanlatin_help table { margin-top: 0; }"+ + "#keyboard_europeanlatin_help tr.out td { padding: 4px; border: solid 1px #ad4a28; font-size: 10pt; font-family: Cambria, Tahoma; font-weight: bold; text-align: center; background: white; }"+ + "#keyboard_europeanlatin_help th { padding: 2px 2px; font-size: 8pt; font-family: Tahoma; }"+ + "#keyboard_europeanlatin_help span.elkey { font-weight: normal; background: #e0e0e0; border: outset 1px; padding: 2px 6px; }"+ + "#keyboard_europeanlatin_help th.prompt { text-align: left; white-space: nowrap; }"+ + "#keyboard_europeanlatin_help tr.key th.prompt { background: white; border: none; font-weight: normal; text-align: right; }"+ + "#keyboard_europeanlatin_help tr.key th.title { background: white; border: none; font-weight: bold; vertical-align: middle; text-align: left; padding: 1px; }"+ + "#keyboard_europeanlatin_help tr.key th { min-width: 14px; margin: 2px; font-weight: normal; text-align: center; background: #e0e0e0; border: outset 1px; padding: 2px 2px; }"+ + "#keyboard_europeanlatin_help tr.out th.prompt { background: white; border: none; font-weight: normal; text-align: right; }"+ + "#keyboard_europeanlatin_help tr.gap th { background: white; border: none; height: 7px; }"+ + "#keyboard_europeanlatin_help p { font-weight: bold; }"+ + "#keyboard_eurolatin_tabsheets { color: black; border: solid 1px #ad4a28; margin: 0 4px 4px 4px; background: white; z-index: 101; }"+ + ".keyboard_eurolatin_tabsheet_selected { display: block; padding: 6px 6px 0 6px; }"+ + ".keyboard_eurolatin_tabsheet { display: none; }"+ + "#keyboard_eurolatin_tabs { margin: 4px 4px 0 4px; z-index: 100; }"+ + ".keyboard_eurolatin_tab { background: white; color: #ad4a28; border: solid 1px #ad4a28; display: inline; padding: 1px 4px 0px 4px; height: 16px; }"+ + ".keyboard_eurolatin_tab_selected { background: white; color: #ad4a28; border: solid 1px #ad4a28; display: inline; padding: 1px 4px; border-bottom: none; margin-top: -1px; height: 18px;}"; + + var style = document.createElement("style"); + style.setAttribute("type", "text/css"); + if(style.styleSheet){// IE + style.styleSheet.cssText = stext; + } else {// w3c + var cssText = document.createTextNode(stext); + style.appendChild(cssText); + } + if(h && h.length > 0) + h[0].appendChild(style); + + e=document.getElementById('keyboard_europeanlatin_help'); + if (typeof e.onselectstart!="undefined") //IE route + e.onselectstart=function(){return false;}; + else + { + e.style.MozUserSelect="none"; + e.style.KhtmlUserSelect="none"; + e.style.UserSelect="none"; + } + var ch = e.getElementsByTagName('td'); + + for(var i = 0; i < ch.length; i++) + { + if(ch[i].attributes['o']) + { + var sxv = ch[i].attributes['x'].value, so = ch[i].attributes['o'].value, sc = ch[i].attributes['c'].value; + if(ch[i].attributes['p']) var sp = ch[i].attributes['p'].value; else var sp = ''; + // ch[i].title = 'The following combinations are available: '+so; + var ce = function(tag){return document.createElement(tag);} + var sx = '', sy = '', sz = (sp == '' ? '' : sy); + var e2 = ce('div'); + for(var j = 0; j < sc.length; j++) + { + var chvo = so.charAt(j), chvc = sc.charAt(j), chvp = sp.charAt(j); + /* Special case for characters p umlaut, g tilde because they aren't precomposed */ + if(sxv == ':' && chvo == 'p') { chvo = 'p̈'; chvp = 'P̈'; } + if(sxv == '~' && chvo == 'g') { chvo = 'g̃'; chvp = 'G̃'; } + sx += ''; + sy += ''; + if(sp != '') sz += ''; + } + e2.innerHTML = sx+''+sy+''+sz+(sz == '' ? '' : '')+'
'+sxv+chvc+''+chvo+''+chvp+'
'; + + var es = e2.style; + es.background = '#f3ffdf'; + es.border = 'solid 1px #ad4a28'; + es.padding = '2px'; + es.display = 'none'; + es.position = 'absolute'; + es.left = (ch[i].offsetLeft+4)+'px'; + es.top = '24px'; + e2.onclick = function() { KeymanWeb.KT(); window.event.cancelBubble=true; return false; } + + ch[i].kmw_subitems = e2; + ch[i].appendChild(e2); + ch[i].onmouseover = function() { this.style.background = KeymanWeb_KeyHoverColor; this.kmw_subitems.style.left=this.offsetLeft+4+'px'; this.kmw_subitems.style.top=(this.offsetParent.offsetTop+this.offsetTop+this.offsetHeight-2)+'px'; this.kmw_subitems.style.display = 'block'; return false; } + ch[i].onmouseout = function() { this.style.background = ''; this.kmw_subitems.style.display = 'none'; return false; } + } + else + { + ch[i].onmouseover = function() { this.style.background = KeymanWeb_KeyHoverColor; return false; } + ch[i].onmouseout = function() { this.style.background = ''; return false; } + } + + ch[i].onclick = function(e) { with(this) { if(attributes['x']) KeymanWeb.KT(attributes['x'].value,0); else if(innerHTML != ' ') KeymanWeb.KT(innerHTML); else KeymanWeb.KT(''); } if(!e)e=window.event;if(e) e.cancelBubble=true;} + ch[i].onmousedown = function(e) { KeymanWeb.KSF(); if(!e)e=window.event;if(e) e.cancelBubble=true; } + } + + e.onclick=function() { KeymanWeb.KT(''); return false; } + e.onmousedown=function() { KeymanWeb.KSF(); return false; } + + e = document.getElementById('keyboard_eurolatin_tabs'); + e2 = document.getElementById('keyboard_eurolatin_tabsheets'); + var ch = [document.getElementById('keyboard_eurolatin_letters_tab'), document.getElementById('keyboard_eurolatin_symbols_tab')]; + var ch2 = [document.getElementById('keyboard_eurolatin_letters_tabsheet'), document.getElementById('keyboard_eurolatin_symbols_tabsheet')]; + for(var i = 0; i < ch.length; i++) + ch[i].onclick = (function(i) { return function(e) + { + for(var j = 0; j < ch.length; j++) + { + ch[j].className = "keyboard_eurolatin_tab" + (i == j ? "_selected" : ""); + ch2[j].className = "keyboard_eurolatin_tabsheet" + (i == j ? "_selected" : ""); + } + } + })(i); +} +} \ No newline at end of file diff --git a/android/KMEA/app/src/main/assets/keyboard.html b/android/KMEA/app/src/main/assets/keyboard.html index 3896f8030e1e0069f1a5c6e469d4661faaa62470..4fc56b405332ce584e3798db117edac8a93c600d 100644 --- a/android/KMEA/app/src/main/assets/keyboard.html +++ b/android/KMEA/app/src/main/assets/keyboard.html @@ -1,6 +1,6 @@ @@ -16,8 +16,8 @@ function init() { //document.body.style.backgroundColor="transparent"; - window.console.log('Device type = '+device); - window.console.log('Keyboard height = '+oskHeight); + //window.console.log('Device type = '+device); + //window.console.log('Keyboard height = '+oskHeight); var kmw=window['keyman']; kmw.init({'app':device,'fonts':'packages/'}); kmw['util']['setOption']('attachType','manual'); @@ -57,7 +57,7 @@ if(oskWidth <= 0) { oskWidth = window.jsInterface.getKeyboardWidth(); } - window.console.log('Keyboard width = '+oskWidth); + //window.console.log('Keyboard width = '+oskWidth); return oskWidth; } @@ -66,16 +66,12 @@ var name = typeof(keyboardProperties.internalName) == 'undefined' ? keyboardProperties.keyboardName : keyboardProperties.internalName; var kmw=window['keyman']; var isChiral = kmw.isChiral(name); - window.console.log('For keyboard "' + name + '"'); - window.console.log('setIsChiral = ' + isChiral); window.jsInterface.setIsChiral(isChiral); return true; } function setKeymanLanguage(keyboardName, internalName, languageName, langId, kbdFile, font, oskFont, package) { - //oskFont.files = ['NotoSansSyriacWestern-Regular.svg#NotoSansSyriacWesternRegular']; - //window.console.log('oskFonts = '+JSON.stringify(oskFont)); var kmw=window['keyman']; var kbdInterface=kmw['interface']; @@ -108,11 +104,11 @@ }; if (font) { k.KFont = font; - window.console.log('keyboard.html assigning k.KFont = ' + font); + //window.console.log('keyboard.html assigning k.KFont = ' + font); } if (oskFont) { k.KOskFont = oskFont; - window.console.log('keyboard.html assigning k.KOskFont = ' + oskFont); + //window.console.log('keyboard.html assigning k.KOskFont = ' + oskFont); } kbdInterface.registerStub(k); @@ -121,7 +117,7 @@ } function insertText(dn, s) { - window.console.log('insertText('+ dn +', ' + s +');'); + //window.console.log('insertText('+ dn +', ' + s +');'); window.jsInterface.insertText(dn, s); } @@ -198,7 +194,6 @@ fragmentToggle = (fragmentToggle + 1) % 100; var kmw = window['keyman']; var pos = kmw['touchMenuPos'](); - window.console.log('showHelpBubble ' + pos); window.location.hash = 'showHelpBubble-' + fragmentToggle + '+keyPos=' + pos; } @@ -206,18 +201,18 @@ var kmw=window['keyman']; // KMW only needs keyID to process the popup key. keyText merely logged to console - window.console.log('executePopupKey('+keyID+'); keyText: ' + keyText); + //window.console.log('executePopupKey('+keyID+'); keyText: ' + keyText); kmw['executePopupKey'](keyID); } function executeHardwareKeystroke(code, shift, lstates) { var kmw=window['keyman']; - window.console.log('executeHardwareKeystroke:('+code+', ' + shift + ', ' + lstates + ');'); + //window.console.log('executeHardwareKeystroke:('+code+', ' + shift + ', ' + lstates + ');'); try { var r = kmw['executeHardwareKeystroke'](code, shift, lstates); - window.console.log('executeHardwareKeystroke completed with '+r); + //window.console.log('executeHardwareKeystroke completed with '+r); } catch(e) { - window.console.log('oops: '+e); + window.console.log('executeHardwareKeystroke exception: '+e); } } @@ -241,8 +236,7 @@ diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ConfirmDialogFragment.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ConfirmDialogFragment.java index 68f41ca769d0882832df080419e4f83a7e150765..adcb739be131cafb66bef3ab419a1038434426ad 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ConfirmDialogFragment.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ConfirmDialogFragment.java @@ -37,7 +37,7 @@ public class ConfirmDialogFragment extends DialogFragment { public void onClick(DialogInterface dialog, int which) { // Cancel dialog.dismiss(); - ((Activity)getContext()).finish(); + getActivity().finish(); } }) .create(); diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java index a65235f92a3185ab10442f29e179294f0335959d..5a6a5c5ae7c59db500365c3a2a18db88eba8ee63 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java @@ -130,6 +130,7 @@ final class KMKeyboard extends WebView { // Send console errors to Firebase Analytics. // (Ignoring spurious message "No keyboard stubs exist = ...") // TODO: Analyze if this error warrants reverting to default keyboard + // TODO: Fix base error rather than trying to ignore it "No keyboard stubs exist" if ((cm.messageLevel() == ConsoleMessage.MessageLevel.ERROR) && (!cm.message().startsWith("No keyboard stubs exist"))) { sendKMWError(cm.lineNumber(), cm.sourceId(), cm.message()); Toast.makeText(context, "Fatal Error with " + currentKeyboard + @@ -168,6 +169,11 @@ final class KMKeyboard extends WebView { setBackgroundColor(0); } + public void hideKeyboard() { + String jsString = "javascript:hideKeyboard()"; + loadUrl(jsString); + } + public void executeHardwareKeystroke(int code, int shift, int lstates) { String jsFormat = "javascript:executeHardwareKeystroke(%d,%d, %d)"; String jsString = String.format(jsFormat, code, shift, lstates); @@ -255,7 +261,7 @@ final class KMKeyboard extends WebView { * @return String */ public static String textFontFilename() { - return keyboardRoot + txtFont; + return txtFont.isEmpty() ? "" : keyboardRoot + txtFont; } /** @@ -346,9 +352,6 @@ final class KMKeyboard extends WebView { String jsFormat = "javascript:setKeymanLanguage('%s','%s','%s','%s','%s', %s, %s, '%s')"; String jsString = String.format(jsFormat, keyboardName, keyboardID, languageName, languageID, keyboardPath, tFont, oFont, packageID); loadUrl(jsString); - if (KMManager.isDebugMode()) { - Log.d("KMKeyboard", jsString); - } this.packageID = packageID; this.keyboardID = keyboardID; @@ -450,9 +453,6 @@ final class KMKeyboard extends WebView { String jsFormat = "javascript:setKeymanLanguage('%s','%s','%s','%s','%s', %s, %s, '%s')"; String jsString = String.format(jsFormat, keyboardName, keyboardID, languageName, languageID, keyboardPath, tFont, oFont, packageID); loadUrl(jsString); - if (KMManager.isDebugMode()) { - Log.d("KMKeyboard", jsString); - } this.packageID = packageID; this.keyboardID = keyboardID; diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardDownloaderActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardDownloaderActivity.java index e8eb0ded850eeacbe22466d2b1fae05f5436a105..52943fe9ba44c620381a7825111222e18a397026 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardDownloaderActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardDownloaderActivity.java @@ -44,7 +44,7 @@ public class KMKeyboardDownloaderActivity extends Activity { public static final String ARG_URL = "KMKeyboardActivity.url"; public static final String ARG_FILENAME = "KMKeyboardActivity.filename"; - public static final String kKeymanApiBaseURL = "https://api.keyman.com/cloud/3.0/"; + public static final String kKeymanApiBaseURL = "https://api.keyman.com/cloud/3.0/languages"; public static final String kKeymanApiRemoteURL = "https://r.keymanweb.com/api/2.0/remote?url="; // Keyman public keys @@ -191,7 +191,7 @@ public class KMKeyboardDownloaderActivity extends Activity { remoteUrl = url; } else { // Keyman cloud - remoteUrl = String.format("%slanguages/%s/%s?version=%s&device=%s", kKeymanApiBaseURL, langID, kbID, BuildConfig.VERSION_NAME, deviceType); + remoteUrl = String.format("%s/%s/%s?version=%s&device=%s&languageidtype=bcp47", kKeymanApiBaseURL, langID, kbID, BuildConfig.VERSION_NAME, deviceType); } ret = downloadNonKMPKeyboard(remoteUrl); @@ -252,7 +252,7 @@ public class KMKeyboardDownloaderActivity extends Activity { } String fontBaseUri = options.optString(KMKey_FontBaseURI, ""); - JSONObject language, keyboard; + JSONObject language, keyboard = null; if (!isCustom) { // Keyman cloud keyboard distribution via JSON language = kbData.optJSONObject(KMKey_Language); @@ -267,7 +267,13 @@ public class KMKeyboardDownloaderActivity extends Activity { throw new Exception(exceptionStr); } - keyboard = keyboards.getJSONObject(0); + // In case keyboards array contains multiple keyboards, get the one with matching keyboard ID + for (int index = 0; index < keyboards.length(); index++) { + keyboard = keyboards.getJSONObject(index); + if (keyboard != null && (kbID.equals(keyboard.getString(KMManager.KMKey_ID)))) { + break; + } + } if (keyboard == null) { throw new Exception(exceptionStr); } diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java index 2721865b910f4ca3439834db68cfee60cf9decf0..b459163271a92099a51c4886b45b091fbe4480e8 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java @@ -130,9 +130,9 @@ public final class KMManager { public static final String KMDefault_AssetPackages = "packages"; // Default Keyboard Info - public static final String KMDefault_KeyboardID = "european2"; + public static final String KMDefault_KeyboardID = "sil_euro_latin"; public static final String KMDefault_LanguageID = "en"; - public static final String KMDefault_KeyboardName = "EuroLatin2 Keyboard"; + public static final String KMDefault_KeyboardName = "EuroLatin (SIL) Keyboard"; public static final String KMDefault_LanguageName = "English"; public static final String KMDefault_KeyboardFont = "{\"family\":\"LatinWeb\",\"source\":[\"DejaVuSans.ttf\"]}"; @@ -183,7 +183,7 @@ public final class KMManager { } else if (keyboardType == KeyboardType.KEYBOARD_TYPE_SYSTEM) { initSystemKeyboard(appContext); } else { - Log.w(TAG, "Cannot initialize: Invalid keyboard type"); + Log.e(TAG, "Cannot initialize: Invalid keyboard type"); } // Initializes the PackageProcessor with the base resource directory, which is the parent directory @@ -220,8 +220,6 @@ public final class KMManager { private static void initInAppKeyboard(Context appContext) { if (InAppKeyboard == null) { - if (isDebugMode()) - Log.d(TAG, "Initializing In-App Keyboard..."); int kbHeight = appContext.getResources().getDimensionPixelSize(R.dimen.keyboard_height); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, kbHeight); params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE); @@ -237,8 +235,6 @@ public final class KMManager { private static void initSystemKeyboard(Context appContext) { if (SystemKeyboard == null) { - if (isDebugMode()) - Log.d(TAG, "Initializing System Keyboard..."); int kbHeight = appContext.getResources().getDimensionPixelSize(R.dimen.keyboard_height); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, kbHeight); params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE); @@ -252,6 +248,12 @@ public final class KMManager { } } + public static void hideSystemKeyboard() { + if (SystemKeyboard != null) { + SystemKeyboard.hideKeyboard(); + } + } + @SuppressLint("InflateParams") public static View createInputView(InputMethodService inputMethodService) { //final Context context = appContext; @@ -305,9 +307,11 @@ public final class KMManager { public static void onResume() { if (InAppKeyboard != null) { + InAppKeyboard.resumeTimers(); InAppKeyboard.onResume(); } if (SystemKeyboard != null) { + SystemKeyboard.resumeTimers(); SystemKeyboard.onResume(); } } @@ -520,7 +524,7 @@ public final class KMManager { boolean shouldClearCache = false; HashMap kbInfo = kbList.get(0); String kbID = kbInfo.get(KMKey_KeyboardID); - if (kbID.equals("us")) { + if (kbID.equals("us") || (kbID.equals("european2"))) { HashMap newKbInfo = new HashMap(); newKbInfo.put(KMManager.KMKey_PackageID, KMManager.KMDefault_UndefinedPackageID); newKbInfo.put(KMManager.KMKey_KeyboardID, KMManager.KMDefault_KeyboardID); @@ -732,7 +736,7 @@ public final class KMManager { return SystemKeyboard; } else { // What should we do if KeyboardType.KEYBOARD_TYPE_UNDEFINED? - Log.w("KMManager", "Invalid keyboard"); + Log.e("KMManager", "Invalid keyboard"); return null; } } @@ -1062,12 +1066,13 @@ public final class KMManager { public static boolean updateText(KeyboardType kbType, String text) { boolean result = false; + String kmText = ""; + if (text != null) { + kmText = text.toString().replace("\\", "\\u005C").replace("'", "\\u0027").replace("\n", "\\n"); + } + if (kbType == KeyboardType.KEYBOARD_TYPE_INAPP) { if (InAppKeyboard != null && InAppKeyboardLoaded && !InAppKeyboardShouldIgnoreTextChange) { - String kmText = ""; - if (text != null) { - kmText = text.toString().replace("\\", "\\u005C").replace("'", "\\u0027").replace("\n", "\\n"); - } InAppKeyboard.loadUrl(String.format("javascript:updateKMText('%s')", kmText)); result = true; } @@ -1075,10 +1080,6 @@ public final class KMManager { InAppKeyboardShouldIgnoreTextChange = false; } else if (kbType == KeyboardType.KEYBOARD_TYPE_SYSTEM) { if (SystemKeyboard != null && SystemKeyboardLoaded && !SystemKeyboardShouldIgnoreTextChange) { - String kmText = ""; - if (text != null) { - kmText = text.toString().replace("\\", "\\u005C").replace("'", "\\u0027").replace("\n", "\\n"); - } SystemKeyboard.loadUrl(String.format("javascript:updateKMText('%s')", kmText)); result = true; } @@ -1246,9 +1247,6 @@ public final class KMManager { public void onPageFinished(WebView view, String url) { if (url.endsWith(KMFilename_KeyboardHtml)) { InAppKeyboardLoaded = true; - if (isDebugMode()) { - Log.d("KMManager", "In-App Keyboard loaded."); - } if (!InAppKeyboard.keyboardSet) { SharedPreferences prefs = context.getSharedPreferences(context.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); @@ -1424,10 +1422,6 @@ public final class KMManager { public void onPageFinished(WebView view, String url) { if (url.endsWith(KMFilename_KeyboardHtml)) { SystemKeyboardLoaded = true; - if (isDebugMode()) { - Log.d("KMManager", "System Keyboard loaded."); - } - if (!SystemKeyboard.keyboardSet) { SharedPreferences prefs = context.getSharedPreferences(context.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); int index = prefs.getInt(KMManager.KMKey_UserKeyboardIndex, 0); @@ -1613,9 +1607,6 @@ public final class KMManager { // Store the current keyboard chirality status from KMW in InAppKeyboard @JavascriptInterface public void setIsChiral(boolean isChiral) { - if (isDebugMode()) { - Log.d("KMManager", "InAppKeyboard chirality: " + String.valueOf(isChiral)); - } InAppKeyboard.setChirality(isChiral); } @@ -1626,8 +1617,9 @@ public final class KMManager { mainLoop.post(new Runnable() { public void run() { if (InAppKeyboard.subKeysWindow != null || KMTextView.activeView == null || KMTextView.activeView.getClass() != KMTextView.class) { - if (KMTextView.activeView == null) + if ((KMTextView.activeView == null) && isDebugMode()) { Log.w("IAK: JS Handler", "insertText failed: activeView is null"); + } return; } @@ -1727,9 +1719,6 @@ public final class KMManager { // Store the current keyboard chirality status from KMW in SystemKeyboard @JavascriptInterface public void setIsChiral(boolean isChiral) { - if (isDebugMode()) { - Log.d("KMManager", "SystemKeyboard chirality: " + String.valueOf(isChiral)); - } SystemKeyboard.setChirality(isChiral); } @@ -1745,7 +1734,9 @@ public final class KMManager { InputConnection ic = IMService.getCurrentInputConnection(); if (ic == null) { - Log.w("SWK: JS Handler", "insertText failed: InputConnection is null"); + if (isDebugMode()) { + Log.w("SWK: JS Handler", "insertText failed: InputConnection is null"); + } return; } diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMTextView.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMTextView.java index e4ab1c5149b4c42a340d8392faef547c4c75fb85..525ce1d96496cd32265adf792259806754cd37ac 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMTextView.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMTextView.java @@ -102,21 +102,17 @@ public final class KMTextView extends EditText { @Override public void onFocusChange(View v, boolean hasFocus) { if (hasFocus) { - if (KMManager.isDebugMode()) - Log.d("OnFocusChange", "gotFocus: " + v.toString()); activeView = v; if (KMManager.InAppKeyboardLoaded) { KMTextView textView = (KMTextView) activeView; int selStart = textView.getSelectionStart(); int selEnd = textView.getSelectionEnd(); - KMManager.InAppKeyboard.loadUrl(String.format("javascript:updateKMText('%s')", textView.getText().toString())); - KMManager.InAppKeyboard.loadUrl(String.format("javascript:updateKMSelectionRange(%d,%d)", selStart, selEnd)); + KMManager.updateText(KeyboardType.KEYBOARD_TYPE_INAPP, textView.getText().toString()); + KMManager.updateSelectionRange(KeyboardType.KEYBOARD_TYPE_INAPP, selStart, selEnd); KMManager.resetContext(KeyboardType.KEYBOARD_TYPE_INAPP); } showKeyboard(); } else { - if (KMManager.isDebugMode()) - Log.d("OnFocusChange", "lostFocus: " + v.toString()); activeView = null; dismissKeyboard(); } @@ -166,8 +162,6 @@ public final class KMTextView extends EditText { Activity activity = (Activity) context; Window mainWindow = activity.getWindow(); if (hasWindowFocus) { - if (KMManager.isDebugMode()) - Log.d("onWindowFocusChanged", "gotFocus:" + mainWindow.toString()); KMManager.KMInAppKeyboardWebViewClient.context = context; activeView = mainWindow.getCurrentFocus(); @@ -179,25 +173,18 @@ public final class KMTextView extends EditText { } if (activeView != null && activeView.equals(this)) { - if (KMManager.isDebugMode()) { - Log.d("onWindowFocusChanged", "activeView = " + activeView.toString()); - } if (KMManager.InAppKeyboardLoaded) { KMTextView textView = (KMTextView) activeView; int selStart = textView.getSelectionStart(); int selEnd = textView.getSelectionEnd(); - KMManager.InAppKeyboard.loadUrl(String.format("javascript:updateKMText('%s')", textView.getText().toString())); - KMManager.InAppKeyboard.loadUrl(String.format("javascript:updateKMSelectionRange(%d,%d)", selStart, selEnd)); + KMManager.updateText(KeyboardType.KEYBOARD_TYPE_INAPP, textView.getText().toString()); + KMManager.updateSelectionRange(KeyboardType.KEYBOARD_TYPE_INAPP, selStart, selEnd); } if (keyboardVisible) { showKeyboard(); } } - } else { - if (KMManager.isDebugMode()) { - Log.d("onWindowFocusChanged", "lostFocus:" + mainWindow.toString()); - } } } @@ -291,8 +278,6 @@ public final class KMTextView extends EditText { mainLayout.requestLayout(); mainLayout.invalidate(); - if (KMManager.isDebugMode()) - Log.d("showKeyboard()", "Keyboard shown"); KeyboardEventHandler.notifyListeners(kbEventListeners, KeyboardType.KEYBOARD_TYPE_INAPP, EventType.KEYBOARD_SHOWN, null); } @@ -308,8 +293,6 @@ public final class KMTextView extends EditText { keyboardLayout.setEnabled(false); keyboardVisible = false; - if (KMManager.isDebugMode()) - Log.d("dismissKeyboard()", "Keyboard dismissed"); KeyboardEventHandler.notifyListeners(kbEventListeners, KeyboardType.KEYBOARD_TYPE_INAPP, EventType.KEYBOARD_DISMISSED, null); } diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardPickerActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardPickerActivity.java index c5c46d926e84279a3fd2fc54d5c5a5d8bf486c72..95a0a5549cf38c6cd74aac5c0a03789d053fad29 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardPickerActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardPickerActivity.java @@ -91,10 +91,8 @@ public final class KeyboardPickerActivity extends Activity implements OnKeyboard setContentView(R.layout.list_layout); listView = (ListView) findViewById(R.id.listView); - File file = new File(context.getDir("userdata", Context.MODE_PRIVATE), KMManager.KMFilename_KeyboardsList); - if (file.exists()) { - keyboardsList = getKeyboardsList(context); - } else { + keyboardsList = getKeyboardsList(context); + if (keyboardsList == null) { keyboardsList = new ArrayList>(); HashMap kbInfo = new HashMap(); kbInfo.put(KMManager.KMKey_PackageID, KMManager.KMDefault_UndefinedPackageID); @@ -107,7 +105,12 @@ public final class KeyboardPickerActivity extends Activity implements OnKeyboard kbInfo.put(KMManager.KMKey_CustomKeyboard, "N"); kbInfo.put(KMManager.KMKey_Font, KMManager.KMDefault_KeyboardFont); keyboardsList.add(kbInfo); - saveKeyboardsList(context); + + // We'd prefer not to overwrite a file if it exists + File file = new File(context.getDir("userdata", Context.MODE_PRIVATE), KMManager.KMFilename_KeyboardsList); + if (!file.exists()) { + saveKeyboardsList(context); + } } String[] from = new String[]{KMManager.KMKey_LanguageName, KMManager.KMKey_KeyboardName}; @@ -567,7 +570,8 @@ public final class KeyboardPickerActivity extends Activity implements OnKeyboard String languageID = keyboardsList.get(i).get(KMManager.KMKey_LanguageID); String keyboardID = keyboardsList.get(i).get(KMManager.KMKey_KeyboardID); String kbVersion = keyboardsList.get(i).get(KMManager.KMKey_KeyboardVersion); - String url = String.format("%slanguages/%s/%s?version=%s&device=%s", KMKeyboardDownloaderActivity.kKeymanApiBaseURL, languageID, keyboardID, BuildConfig.VERSION_NAME, deviceType); + String url = String.format("%s/%s/%s?version=%s&device=%s&languageidtype=bcp47", + KMKeyboardDownloaderActivity.kKeymanApiBaseURL, languageID, keyboardID, BuildConfig.VERSION_NAME, deviceType); JSONObject kbData = jsonParser.getJSONObjectFromUrl(url); JSONObject language = kbData.optJSONObject(KMKeyboardDownloaderActivity.KMKey_Language); JSONArray keyboards = language.getJSONArray(KMKeyboardDownloaderActivity.KMKey_LanguageKeyboards); diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java index 4a41972839cd44ab418a7bf3c13e17484338a8aa..8a37501b94946e255559a2672e78d9f91757e5a2 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java @@ -363,8 +363,9 @@ public final class LanguageListActivity extends Activity implements OnKeyboardDo } else { deviceType = "androidphone"; } - - jsonObj = jsonParser.getJSONObjectFromUrl(KMKeyboardDownloaderActivity.kKeymanApiBaseURL + "languages?version=" + BuildConfig.VERSION_NAME + "&device=" + deviceType); + String remoteUrl = String.format("%s?version=%s&device=%s&languageidtype=bcp47", + KMKeyboardDownloaderActivity.kKeymanApiBaseURL, BuildConfig.VERSION_NAME, deviceType); + jsonObj = jsonParser.getJSONObjectFromUrl(remoteUrl); } catch (Exception e) { jsonObj = null; } diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/packages/PackageProcessor.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/packages/PackageProcessor.java index 040d355786b214bf74f6e04c502e76eb54a02439..8d0c506a10a7bfce19757919985a48b5499993bd 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/packages/PackageProcessor.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/packages/PackageProcessor.java @@ -33,6 +33,7 @@ import org.json.JSONObject; */ public class PackageProcessor { private static File resourceRoot = null; + public static final String PPDefault_Version = "1.0"; public static void initialize(File resourceRoot) { PackageProcessor.resourceRoot = resourceRoot; @@ -100,7 +101,7 @@ public class PackageProcessor { JSONParser parser = new JSONParser(); return parser.getJSONObjectFromFile(infoFile); } else { - Log.d("PackageProcessor", infoFile.toString() + " does not exist."); + Log.e("PackageProcessor", infoFile.toString() + " does not exist."); return null; } } @@ -192,21 +193,22 @@ public class PackageProcessor { return name; } } catch (Exception e) { - return null; + // Developer will never allow package name to be undefined, but just in case, reuse package ID + return getPackageID(kmpPath); } } /** * Simply extracts the package's version number. + * If undefined, return default version "1.0" * @param json The metadata JSONObject for the package. * @return The version number (via String) - * @throws JSONException */ - public static String getPackageVersion(JSONObject json) throws JSONException { - if(json == null) { - return null; - } else { + public static String getPackageVersion(JSONObject json) { + try { return json.getJSONObject("info").getJSONObject("version").getString("description"); + } catch (JSONException e) { + return PPDefault_Version; } } @@ -221,7 +223,7 @@ public class PackageProcessor { return version; } } catch (Exception e) { - return null; + return PPDefault_Version; } } diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/Connection.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/Connection.java index 6d6a8ef9da571a377f66f63917d0ae2120519c41..645633121653a747fe456ccac2a6d64423f0e18a 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/Connection.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/Connection.java @@ -88,14 +88,11 @@ public final class Connection { urlValid = true; ret = true; } else { - Log.d("util.Connection", "HttpURLConnection response code: " + status); - // Handle HTTP Status Codes 3xx if (HttpURLConnection.HTTP_MULT_CHOICE <= status && status <= HttpURLConnection.HTTP_USE_PROXY && status != HttpURLConnection.HTTP_NOT_MODIFIED) { urlStr = urlConnection.getHeaderField("Location"); - Log.d("util.Connection", "Redirecting from " + url + " to " + urlStr); } else { // Abort for all other Status Codes break; diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/FileUtils.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/FileUtils.java index 9cd855ec38aa834c4937a8fcc117aabae7090df3..c8626a14e49025b9f84976d2cc639d791bde3e8f 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/FileUtils.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/FileUtils.java @@ -96,8 +96,6 @@ public final class FileUtils { } if (!tmpFile.renameTo(file)) { ret = DOWNLOAD_ERROR; - } else if (KMManager.isDebugMode()) { - Log.d("FileUtils", "Download finished for filename " + file.toString()); } } else { ret = DOWNLOAD_ERROR; @@ -109,9 +107,7 @@ public final class FileUtils { if (tmpFile.exists()) { tmpFile.delete(); } - if (KMManager.isDebugMode()) { - Log.d("FileUtils", "Could not download filename " + file.toString()); - } + Log.e("FileUtils", "Could not download filename " + file.toString()); } Connection.disconnect(); diff --git a/android/KMEA/app/src/test/java/com/tavultesoft/kmea/packages/PackageProcessorTest.java b/android/KMEA/app/src/test/java/com/tavultesoft/kmea/packages/PackageProcessorTest.java index d82409d276733a16b60ac646f3429cff02f2c0dc..4ddadc43f636210880f3413a3a15a389b438d051 100644 --- a/android/KMEA/app/src/test/java/com/tavultesoft/kmea/packages/PackageProcessorTest.java +++ b/android/KMEA/app/src/test/java/com/tavultesoft/kmea/packages/PackageProcessorTest.java @@ -35,12 +35,18 @@ public class PackageProcessorTest { private static final File TEST_GFF_KMP_TARGET_ALT = new File(TEST_EXTRACTION_ROOT, "packages" + File.separator + TEST_GFF_KMP_NAME_ALT); + private static final String TEST_GFF_KMP_NAME_UNDEFINED_VER = TEST_GFF_KMP_NAME; + private static final File TEST_GFF_KMP_FILE_UNDEFINED_VER = new File(TEST_RESOURCE_ROOT, "v" + File.separator + TEST_GFF_KMP_NAME_UNDEFINED_VER + ".kmp"); + private static final File TEST_GFF_KMP_TARGET_UNDEFINED_VER = new File(TEST_EXTRACTION_ROOT, "packages" + + File.separator + TEST_GFF_KMP_NAME_UNDEFINED_VER); + private static final int TEST_GFF_KBD_COUNT = 2; private static final String TEST_GFF_PACKAGE_NAME = "GFF Amharic Keyboard"; private static final String TEST_GFF_KBD_ID = "gff_amh_7"; private static File tempPkg; private static File tempPkgAlt; + private static File tempPkgUndefinedVer; // Each test gets a fresh version of the extracted package. @Before @@ -63,6 +69,15 @@ public class PackageProcessorTest { } } + // Some tests wish to utilize package with undefined version... + public void extractUndefinedVerTestPackage() { + PackageProcessor.initialize(TEST_EXTRACTION_ROOT); + try { + tempPkgUndefinedVer = PackageProcessor.unzipKMP(TEST_GFF_KMP_FILE_UNDEFINED_VER); + } catch (IOException e) { + System.err.println(e); + } + } /** * Post-test cleanup. While the temp/ directory is .gitignore'd, this provides an extra layer @@ -73,6 +88,7 @@ public class PackageProcessorTest { public void eraseTestPackages() throws IOException { FileUtils.deleteDirectory(tempPkg); FileUtils.deleteQuietly(tempPkgAlt); + FileUtils.deleteQuietly(tempPkgUndefinedVer); FileUtils.deleteDirectory(TEST_GFF_KMP_TARGET); } @@ -218,6 +234,14 @@ public class PackageProcessorTest { Assert.assertNotEquals(TEST_GFF_KMP_NAME, PackageProcessor.getPackageName(json)); } + @Test + public void test_getPackageVersion() throws Exception { + extractUndefinedVerTestPackage(); + JSONObject json = PackageProcessor.loadPackageInfo(tempPkgUndefinedVer); + + Assert.assertEquals(PackageProcessor.PPDefault_Version, PackageProcessor.getPackageVersion(json)); + } + @Test public void test_versionChecks() throws Exception { Assert.assertFalse(PackageProcessor.isDowngrade(TEST_GFF_KMP_FILE)); diff --git a/android/KMEA/build.gradle b/android/KMEA/build.gradle index 97d43c4dd2ac50be18aa3cb52beb04836e908c32..b6cb00b4fccf9911941bd7337adb2f4b7c83ee96 100644 --- a/android/KMEA/build.gradle +++ b/android/KMEA/build.gradle @@ -1,17 +1,17 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { - jcenter() google() + jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle:3.1.2' } } allprojects { repositories { - jcenter() google() + jcenter() } } diff --git a/android/KMEA/gradle/wrapper/gradle-wrapper.properties b/android/KMEA/gradle/wrapper/gradle-wrapper.properties index a56ec474c2a365e7443f7d234027f4917c768109..41c09b90bc80b4ac360c8a9acc89542eea0d95d0 100644 --- a/android/KMEA/gradle/wrapper/gradle-wrapper.properties +++ b/android/KMEA/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/android/KMEA/test_resources/v/gff_amh_7_test_json.kmp b/android/KMEA/test_resources/v/gff_amh_7_test_json.kmp new file mode 100644 index 0000000000000000000000000000000000000000..5d6d76388c2d74a18ccf9d1217c2f5896e84f6ca Binary files /dev/null and b/android/KMEA/test_resources/v/gff_amh_7_test_json.kmp differ diff --git a/android/Samples/KMSample1/app/build.gradle b/android/Samples/KMSample1/app/build.gradle index 90fe1da883f20e4a5295691058cf13d845d794fa..a2a5e2cbec93034c12d3ac7c1675897864841f88 100644 --- a/android/Samples/KMSample1/app/build.gradle +++ b/android/Samples/KMSample1/app/build.gradle @@ -1,13 +1,13 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion "26.0.2" + compileSdkVersion 27 + buildToolsVersion "27.0.3" defaultConfig { applicationId "com.keyman.kmsample1" minSdkVersion 15 - targetSdkVersion 25 + targetSdkVersion 27 versionCode 1 versionName "1.0" } @@ -20,18 +20,23 @@ android { } repositories { + google() flatDir { dirs 'libs' } - google() +} + +ext { + currentFirebaseVersion = "15.0.2" } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.android.support:appcompat-v7:25.2.0' - implementation 'com.google.firebase:firebase-core:11.8.0' - implementation 'com.google.firebase:firebase-crash:11.8.0' - implementation('com.crashlytics.sdk.android:crashlytics:2.9.0@aar') { + implementation 'com.android.support:appcompat-v7:27.1.1' + implementation 'com.android.support:support-v4:27.1.1' + implementation "com.google.firebase:firebase-core:$currentFirebaseVersion" + implementation "com.google.firebase:firebase-crash:$currentFirebaseVersion" + implementation('com.crashlytics.sdk.android:crashlytics:2.9.2@aar') { transitive = true } api (name:'keyman-engine', ext:'aar') diff --git a/android/Samples/KMSample1/build.gradle b/android/Samples/KMSample1/build.gradle index 22690c837d056871fb70de7fb4e5cdcac9832823..c6db9aa806c657ed364e2a254e6d0eaa3acf1342 100644 --- a/android/Samples/KMSample1/build.gradle +++ b/android/Samples/KMSample1/build.gradle @@ -6,7 +6,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle:3.1.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -15,6 +15,7 @@ buildscript { allprojects { repositories { + google() jcenter() } } diff --git a/android/Samples/KMSample1/gradle/wrapper/gradle-wrapper.properties b/android/Samples/KMSample1/gradle/wrapper/gradle-wrapper.properties index dade367f1042da843437a3220e6d9f359873cbb5..330e907be4e2b7e7de339f6e250f5d58ddef8974 100644 --- a/android/Samples/KMSample1/gradle/wrapper/gradle-wrapper.properties +++ b/android/Samples/KMSample1/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/android/Samples/KMSample2/app/build.gradle b/android/Samples/KMSample2/app/build.gradle index 725b8346c38917010fc134bb85a7aefabcb4f115..181c6d4f130f1fea264777fa1b3b36870aa474c1 100644 --- a/android/Samples/KMSample2/app/build.gradle +++ b/android/Samples/KMSample2/app/build.gradle @@ -1,13 +1,13 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion "26.0.2" + compileSdkVersion 27 + buildToolsVersion "27.0.3" defaultConfig { applicationId "com.keyman.kmsample2" minSdkVersion 15 - targetSdkVersion 25 + targetSdkVersion 27 versionCode 1 versionName "1.0" } @@ -20,18 +20,23 @@ android { } repositories { + google() flatDir { dirs 'libs' } - google() +} + +ext { + currentFirebaseVersion = "15.0.2" } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.android.support:appcompat-v7:25.2.0' - implementation 'com.google.firebase:firebase-core:11.8.0' - implementation 'com.google.firebase:firebase-crash:11.8.0' - implementation('com.crashlytics.sdk.android:crashlytics:2.9.0@aar') { + implementation 'com.android.support:appcompat-v7:27.1.1' + implementation 'com.android.support:support-v4:27.1.1' + implementation "com.google.firebase:firebase-core:$currentFirebaseVersion" + implementation "com.google.firebase:firebase-crash:$currentFirebaseVersion" + implementation('com.crashlytics.sdk.android:crashlytics:2.9.2@aar') { transitive = true } api (name:'keyman-engine', ext:'aar') diff --git a/android/Samples/KMSample2/build.gradle b/android/Samples/KMSample2/build.gradle index 6b9a6dc60daf610356654ae393192730567810da..c6db9aa806c657ed364e2a254e6d0eaa3acf1342 100644 --- a/android/Samples/KMSample2/build.gradle +++ b/android/Samples/KMSample2/build.gradle @@ -2,11 +2,11 @@ buildscript { repositories { - jcenter() google() + jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle:3.1.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -15,6 +15,7 @@ buildscript { allprojects { repositories { + google() jcenter() } } diff --git a/android/Samples/KMSample2/gradle/wrapper/gradle-wrapper.properties b/android/Samples/KMSample2/gradle/wrapper/gradle-wrapper.properties index 6730497cf8606279e53fad964429cba250db8576..478707bafe9ea88634f5524f00dc8607b45dfc00 100644 --- a/android/Samples/KMSample2/gradle/wrapper/gradle-wrapper.properties +++ b/android/Samples/KMSample2/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/android/Tests/KeyboardHarness/app/build.gradle b/android/Tests/KeyboardHarness/app/build.gradle index b031c663fc367c5788441df711721a8ce0f1abee..630a0584d7a4c925b50777b562d45e53a9c58bc9 100644 --- a/android/Tests/KeyboardHarness/app/build.gradle +++ b/android/Tests/KeyboardHarness/app/build.gradle @@ -1,13 +1,13 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion "26.0.2" + compileSdkVersion 27 + buildToolsVersion "27.0.3" defaultConfig { applicationId "com.keyman.android.tests.keyboardHarness" minSdkVersion 15 - targetSdkVersion 25 + targetSdkVersion 27 versionCode 1 versionName "1.0" } @@ -20,18 +20,23 @@ android { } repositories { + google() flatDir { dirs 'libs' } - google() +} + +ext { + currentFirebaseVersion = "15.0.2" } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.android.support:appcompat-v7:25.2.0' - implementation 'com.google.firebase:firebase-core:11.8.0' - implementation 'com.google.firebase:firebase-crash:11.8.0' - implementation('com.crashlytics.sdk.android:crashlytics:2.9.0@aar') { + implementation 'com.android.support:appcompat-v7:27.1.1' + implementation 'com.android.support:support-v4:27.1.1' + implementation "com.google.firebase:firebase-core:$currentFirebaseVersion" + implementation "com.google.firebase:firebase-crash:$currentFirebaseVersion" + implementation('com.crashlytics.sdk.android:crashlytics:2.9.2@aar') { transitive = true } api (name:'keyman-engine', ext:'aar') diff --git a/android/Tests/KeyboardHarness/app/src/main/assets/cloud/platformtest-1.0.js b/android/Tests/KeyboardHarness/app/src/main/assets/cloud/platformtest-1.0.js new file mode 100644 index 0000000000000000000000000000000000000000..e62165ce22391c721d1fb06c119e0d9faace698f --- /dev/null +++ b/android/Tests/KeyboardHarness/app/src/main/assets/cloud/platformtest-1.0.js @@ -0,0 +1,380 @@ + +KeymanWeb.KR(new Keyboard_platformtest()); + +function Keyboard_platformtest() +{ + + this.KI = "Keyboard_platformtest"; + this.KN = "PlatformTest"; + this.KMINVER = "9.0"; + this.KV = null; + this.KH = ''; + this.KM = 0; + this.KBVER = "1.0"; + this.KMBM = 0x0000; + this.s17 = "touch"; + this.s18 = "hardware"; + this.s21 = "windows"; + this.s22 = "android"; + this.s23 = "ios"; + this.s24 = "macosx"; + this.s25 = "linux"; + this.s28 = "desktop"; + this.s29 = "tablet"; + this.s30 = "phone"; + this.s33 = "native"; + this.s34 = "web"; + this.s37 = "ie"; + this.s38 = "chrome"; + this.s39 = "edge"; + this.s40 = "firefox"; + this.s41 = "safari"; + this.s42 = "opera"; + this.s45 = "touch"; + this.s46 = "hardware"; + this.s49 = "platform-x"; + this.s52 = "WinDOWS"; + this.s53 = "ANDroid"; + this.s54 = "iOS"; + this.s55 = "macOSX"; + this.s56 = "LINUX"; + this.s58 = "touch"; + this.s59 = "hardware"; + this.s60 = "windows"; + this.s61 = "android"; + this.s62 = "ios"; + this.s63 = "macosx"; + this.s64 = "linux"; + this.s65 = "desktop"; + this.s66 = "tablet"; + this.s67 = "phone"; + this.s68 = "native"; + this.s69 = "web"; + this.s70 = "ie"; + this.s71 = "chrome"; + this.s72 = "edge"; + this.s73 = "firefox"; + this.s74 = "safari"; + this.s75 = "opera"; + this.s76 = "touch"; + this.s77 = "hardware"; + this.s78 = "platform-x"; + this.s79 = "WinDOWS"; + this.s80 = "ANDroid"; + this.s81 = "iOS"; + this.s82 = "macOSX"; + this.s83 = "LINUX"; + this.KVER = "10.0.1109.0"; + this.gs = function(t, e) { + return this.g0(t, e); + }; + this.g0 = function(t, e) { + var k = KeymanWeb, + r = 0, + m = 0; + if (k.KKM(e, 16384, 65)) { + r = m = 1; + r = this.g1(t, e); + } + if (!m && k.KIK(e)) { + r = 1; + r = this.g9(t, e); + } + return r; + }; + this.g1 = function(t, e) { + var k = KeymanWeb, + r = 1, + m = 0; + if (k.KIFS(31, this.s17, t)) { + m = 1; + k.KO(0, t, "touch"); + } else if (k.KIFS(31, this.s18, t)) { + m = 1; + k.KO(0, t, "hardware"); + } + if (m) { + r = this.g2(t, e); + } + if (!m) { + k.KO(-1, t, "undefined"); + r = this.g2(t, e); + } + return r; + }; + this.g2 = function(t, e) { + var k = KeymanWeb, + r = 1, + m = 0; + if (k.KIFS(31, this.s21, t)) { + m = 1; + k.KO(0, t, " windows"); + } else if (k.KIFS(31, this.s22, t)) { + m = 1; + k.KO(0, t, " android"); + } else if (k.KIFS(31, this.s23, t)) { + m = 1; + k.KO(0, t, " ios"); + } else if (k.KIFS(31, this.s24, t)) { + m = 1; + k.KO(0, t, " macosx"); + } else if (k.KIFS(31, this.s25, t)) { + m = 1; + k.KO(0, t, " linux"); + } + if (m) { + r = this.g3(t, e); + } + if (!m) { + k.KO(-1, t, " undefined"); + r = this.g3(t, e); + } + return r; + }; + this.g3 = function(t, e) { + var k = KeymanWeb, + r = 1, + m = 0; + if (k.KIFS(31, this.s28, t)) { + m = 1; + k.KO(0, t, " desktop"); + } else if (k.KIFS(31, this.s29, t)) { + m = 1; + k.KO(0, t, " tablet"); + } else if (k.KIFS(31, this.s30, t)) { + m = 1; + k.KO(0, t, " phone"); + } + if (m) { + r = this.g4(t, e); + } + if (!m) { + k.KO(-1, t, " undefined"); + r = this.g4(t, e); + } + return r; + }; + this.g4 = function(t, e) { + var k = KeymanWeb, + r = 1, + m = 0; + if (k.KIFS(31, this.s33, t)) { + m = 1; + k.KO(0, t, " native"); + } else if (k.KIFS(31, this.s34, t)) { + m = 1; + k.KO(0, t, " web"); + } + if (m) { + r = this.g5(t, e); + } + if (!m) { + k.KO(-1, t, " undefined"); + r = this.g5(t, e); + } + return r; + }; + this.g5 = function(t, e) { + var k = KeymanWeb, + r = 1, + m = 0; + if (k.KIFS(31, this.s37, t)) { + m = 1; + k.KO(0, t, " ie"); + } else if (k.KIFS(31, this.s38, t)) { + m = 1; + k.KO(0, t, " chrome"); + } else if (k.KIFS(31, this.s39, t)) { + m = 1; + k.KO(0, t, " edge"); + } else if (k.KIFS(31, this.s40, t)) { + m = 1; + k.KO(0, t, " firefox"); + } else if (k.KIFS(31, this.s41, t)) { + m = 1; + k.KO(0, t, " safari"); + } else if (k.KIFS(31, this.s42, t)) { + m = 1; + k.KO(0, t, " opera"); + } + if (m) { + r = this.g6(t, e); + } + if (!m) { + k.KO(-1, t, " undefined"); + r = this.g6(t, e); + } + return r; + }; + this.g6 = function(t, e) { + var k = KeymanWeb, + r = 1, + m = 0; + if (!k.KIFS(31, this.s45, t)) { + m = 1; + k.KO(0, t, " !touch"); + } else if (!k.KIFS(31, this.s46, t)) { + m = 1; + k.KO(0, t, " !hardware"); + } + if (m) { + r = this.g7(t, e); + } + if (!m) { + k.KO(-1, t, " undefined"); + r = this.g7(t, e); + } + return r; + }; + this.g7 = function(t, e) { + var k = KeymanWeb, + r = 1, + m = 0; + if (k.KIFS(31, this.s49, t)) { + m = 1; + k.KO(0, t, " platform-x"); + } + if (m) { + r = this.g8(t, e); + } + if (!m) { + k.KO(-1, t, " undefined"); + r = this.g8(t, e); + } + return r; + }; + this.g8 = function(t, e) { + var k = KeymanWeb, + r = 1, + m = 0; + if (k.KIFS(31, this.s52, t)) { + m = 1; + k.KO(0, t, " windows"); + } else if (k.KIFS(31, this.s53, t)) { + m = 1; + k.KO(0, t, " android"); + } else if (k.KIFS(31, this.s54, t)) { + m = 1; + k.KO(0, t, " ios"); + } else if (k.KIFS(31, this.s55, t)) { + m = 1; + k.KO(0, t, " macosx"); + } else if (k.KIFS(31, this.s56, t)) { + m = 1; + k.KO(0, t, " linux"); + } + if (!m) { + k.KO(-1, t, " undefined"); + } + return r; + }; + this.g9 = function(t, e) { + var k = KeymanWeb, + r = 0, + m = 0; + if (k.KKM(e, 16384, 69) && k.KIFS(31, this.s79, t)) { + r = m = 1; + k.KO(0, t, " Windows"); + } else if (k.KKM(e, 16384, 69) && k.KIFS(31, this.s80, t)) { + r = m = 1; + k.KO(0, t, " Android"); + } else if (k.KKM(e, 16384, 69) && k.KIFS(31, this.s81, t)) { + r = m = 1; + k.KO(0, t, " iOS"); + } else if (k.KKM(e, 16384, 69) && k.KIFS(31, this.s82, t)) { + r = m = 1; + k.KO(0, t, " macOS"); + } else if (k.KKM(e, 16384, 69) && k.KIFS(31, this.s83, t)) { + r = m = 1; + k.KO(0, t, " Linux"); + } else if (k.KKM(e, 16384, 69)) { + r = m = 1; + k.KO(0, t, " [OS Undefined (case insensitive test)]"); + } else if (k.KKM(e, 16384, 73) && k.KIFS(31, this.s65, t)) { + r = m = 1; + k.KO(0, t, " Desktop"); + } else if (k.KKM(e, 16384, 73) && k.KIFS(31, this.s66, t)) { + r = m = 1; + k.KO(0, t, " Tablet"); + } else if (k.KKM(e, 16384, 73) && k.KIFS(31, this.s67, t)) { + r = m = 1; + k.KO(0, t, " Phone"); + } else if (k.KKM(e, 16384, 73)) { + r = m = 1; + k.KO(0, t, " [FF Undefined]"); + } else if (k.KKM(e, 16384, 79) && k.KIFS(31, this.s60, t)) { + r = m = 1; + k.KO(0, t, " Windows"); + } else if (k.KKM(e, 16384, 79) && k.KIFS(31, this.s61, t)) { + r = m = 1; + k.KO(0, t, " Android"); + } else if (k.KKM(e, 16384, 79) && k.KIFS(31, this.s62, t)) { + r = m = 1; + k.KO(0, t, " iOS"); + } else if (k.KKM(e, 16384, 79) && k.KIFS(31, this.s63, t)) { + r = m = 1; + k.KO(0, t, " OSX"); + } else if (k.KKM(e, 16384, 79) && k.KIFS(31, this.s64, t)) { + r = m = 1; + k.KO(0, t, " Linux"); + } else if (k.KKM(e, 16384, 79)) { + r = m = 1; + k.KO(0, t, " [OS Undefined]"); + } else if (k.KKM(e, 16384, 80) && k.KIFS(31, this.s58, t)) { + r = m = 1; + k.KO(0, t, "Touch"); + } else if (k.KKM(e, 16384, 80) && k.KIFS(31, this.s59, t)) { + r = m = 1; + k.KO(0, t, "Hardware"); + } else if (k.KKM(e, 16384, 80)) { + r = m = 1; + k.KO(0, t, "[UI Undefined]"); + } else if (k.KKM(e, 16384, 82) && k.KIFS(31, this.s78, t)) { + r = m = 1; + k.KO(0, t, " Platform-X"); + } else if (k.KKM(e, 16384, 82)) { + r = m = 1; + k.KO(0, t, " [Platform-X Undefined]"); + } else if (k.KKM(e, 16384, 84) && !k.KIFS(31, this.s76, t)) { + r = m = 1; + k.KO(0, t, " !Touch"); + } else if (k.KKM(e, 16384, 84) && !k.KIFS(31, this.s77, t)) { + r = m = 1; + k.KO(0, t, " !Hardware"); + } else if (k.KKM(e, 16384, 84)) { + r = m = 1; + k.KO(0, t, " [Inverted OS Undefined]"); + } else if (k.KKM(e, 16384, 85) && k.KIFS(31, this.s68, t)) { + r = m = 1; + k.KO(0, t, " Native"); + } else if (k.KKM(e, 16384, 85) && k.KIFS(31, this.s69, t)) { + r = m = 1; + k.KO(0, t, " Web"); + } else if (k.KKM(e, 16384, 85)) { + r = m = 1; + k.KO(0, t, " [Nativeness Undefined]"); + } else if (k.KKM(e, 16384, 89) && k.KIFS(31, this.s70, t)) { + r = m = 1; + k.KO(0, t, " IE"); + } else if (k.KKM(e, 16384, 89) && k.KIFS(31, this.s71, t)) { + r = m = 1; + k.KO(0, t, " Chrome"); + } else if (k.KKM(e, 16384, 89) && k.KIFS(31, this.s72, t)) { + r = m = 1; + k.KO(0, t, " Edge"); + } else if (k.KKM(e, 16384, 89) && k.KIFS(31, this.s73, t)) { + r = m = 1; + k.KO(0, t, " Firefox"); + } else if (k.KKM(e, 16384, 89) && k.KIFS(31, this.s74, t)) { + r = m = 1; + k.KO(0, t, " Safari"); + } else if (k.KKM(e, 16384, 89) && k.KIFS(31, this.s75, t)) { + r = m = 1; + k.KO(0, t, " Opera"); + } else if (k.KKM(e, 16384, 89)) { + r = m = 1; + k.KO(0, t, " [Browser Undefined]"); + } + return r; + }; +} diff --git a/android/Tests/KeyboardHarness/app/src/main/java/com/keyman/android/tests/keyboardHarness/MainActivity.java b/android/Tests/KeyboardHarness/app/src/main/java/com/keyman/android/tests/keyboardHarness/MainActivity.java index 37f438a1f837838914ba9bccfc4be9d6ba423500..95bc28e72f60a96919c55d429e8f24b2bbceb23f 100644 --- a/android/Tests/KeyboardHarness/app/src/main/java/com/keyman/android/tests/keyboardHarness/MainActivity.java +++ b/android/Tests/KeyboardHarness/app/src/main/java/com/keyman/android/tests/keyboardHarness/MainActivity.java @@ -56,6 +56,17 @@ public class MainActivity extends Activity implements OnKeyboardEventListener, O longpressKBbInfo.put(KMManager.KMKey_KeyboardVersion, "1.0"); longpressKBbInfo.put(KMManager.KMKey_Font, "code2001.ttf"); KMManager.addKeyboard(this, longpressKBbInfo); + + // Platform test keyboard + HashMap platformtestKBbInfo = new HashMap(); + platformtestKBbInfo.put(KMManager.KMKey_PackageID, "cloud"); + platformtestKBbInfo.put(KMManager.KMKey_KeyboardID, "platformtest"); + platformtestKBbInfo.put(KMManager.KMKey_LanguageID, "en"); + platformtestKBbInfo.put(KMManager.KMKey_KeyboardName, "platformtest Keyboard"); + platformtestKBbInfo.put(KMManager.KMKey_LanguageName, "English"); + platformtestKBbInfo.put(KMManager.KMKey_KeyboardVersion, "1.0"); + platformtestKBbInfo.put(KMManager.KMKey_Font, KeyboardFont); + KMManager.addKeyboard(this, platformtestKBbInfo); } @Override diff --git a/android/Tests/KeyboardHarness/build.gradle b/android/Tests/KeyboardHarness/build.gradle index 6b9a6dc60daf610356654ae393192730567810da..c6db9aa806c657ed364e2a254e6d0eaa3acf1342 100644 --- a/android/Tests/KeyboardHarness/build.gradle +++ b/android/Tests/KeyboardHarness/build.gradle @@ -2,11 +2,11 @@ buildscript { repositories { - jcenter() google() + jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle:3.1.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -15,6 +15,7 @@ buildscript { allprojects { repositories { + google() jcenter() } } diff --git a/android/Tests/KeyboardHarness/gradle/wrapper/gradle-wrapper.properties b/android/Tests/KeyboardHarness/gradle/wrapper/gradle-wrapper.properties index bb759f148c833c252a79202bfbac2356ae711cec..89bf9a1635ff0aa6747db4978b38a3f7f0f59527 100644 --- a/android/Tests/KeyboardHarness/gradle/wrapper/gradle-wrapper.properties +++ b/android/Tests/KeyboardHarness/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/android/history.md b/android/history.md index 019cee50d6791b708d828dbec9b3633d41bc20d3..2b0f261db8d184fc13be562f2b9c449598868b0c 100644 --- a/android/history.md +++ b/android/history.md @@ -1,7 +1,112 @@ # Keyman for Android + ## 11.0 alpha * Move to 11.0 +* Add round launcher icons +* Change default keyboard from `european` to `sil_euro_latin` (#1112) + +## 2018-08-23 10.0.505 stable +* Validate keyboard ID when downloading keyboard from keman cloud (#1121) + +## 2018-08-22 10.0.504 stable +* Fixes crash when installed keyboards list is invalid (#1119) + +## 2018-08-16 10.0.503 stable +* Fixes crashes for release configurations when InputConfiguration or package name is null (#1103) + +## 2018-07-06 10.0.502 stable +* Fixes issue for embedded Android, iOS apps where a keyboard with varying row counts in different layers could crash (#1055) + +## 2018-06-28 10.0.500 stable +* 10.0 stable release + +## 2018-06-27 10.0.405 beta +* Fixes issue where next layer was not correctly selected when the first longpress key pressed (#1027) +* Fixes issue where a quote character in some contexts could cause the keyboard to fail (#1028) + +## 2018-06-26 10.0.404 beta +* Add documentation for version 10.0 (#1023) + +## 2018-06-21 10.0.403 beta +* Fixes an issue where opening a menu could cause the keyboard to unload (#1014) + +## 2018-06-20 10.0.402 beta +* Support script subtags for keyboard languages supplied from cloud (#1012) + +## 2018-06-15 10.0.401 beta +* No changes to Keyman for Android + +## 2018-06-13 10.0.400 beta +* No changes to Keyman for Android + +## 2018-06-11 10.0.399 beta +* Consolidate Info view (#972) +* Platform tests (in keyboards) are now consistent across all platforms (#969) + +## 2018-06-05 10.0.398 beta +* Fix globe button for system keyboard (#942) + +## 2018-05-27 10.0.397 beta +* Improve intent-filter for *.kmp extensions (#902) + +## 2018-05-22 10.0.396 beta +* No changes to Keyman for Android. + +## 2018-05-22 10.0.395 beta +* No changes to Keyman for Android. + +## 2018-05-18 10.0.394 beta +* No changes to Keyman for Android. + +## 2018-05-17 10.0.393 beta +* No changes to Keyman for Android. + +## 2018-05-11 10.0.392 beta +* Fix globe button when exiting in-app browser (#848) + +## 2018-05-11 10.0.391 beta +* Update compile and target Android SDK version to 27 (#750) + +## 2018-05-08 10.0.386 beta +* Fix crashes from invalid package name/version (#819) +* Clean up console log (#748) + +## 2018-04-30 10.0.385 beta +* No changes to Keyman for Android (updated Keyman Web Engine, #834) + +## 2018-04-30 10.0.384 beta +* No changes to Keyman for Android. + +## 2018-05-03 10.0.383 beta +* No changes to Keyman for Android. + +## 2018-04-30 10.0.382 beta +* No changes to Keyman for Android (updated Keyman Web Engine, #797) + +## 2018-04-30 10.0.381 beta +* Fix OSK missing some keys on older Android configurations (#781) + +## 2018-04-30 10.0.380 beta +* No changes to Keyman for Android. + +## 2018-04-27 10.0.379 beta +* Fixed app crash when cancelling Keyboard download dialog (#786) + +## 2018-04-25 10.0.378 beta +* No changes to Keyman for Android (updated Keyman Web Engine, #772). + +## 2018-04-25 10.0.377 beta +* No changes to Keyman for Android (updated Keyman Web Engine, #773). + +## 2018-04-24 10.0.376 beta +* Hide system OSK when resuming Keyman app. Disable text suggestions (#711) + +## 2018-04-12 10.0.375 beta +* No changes to Keyman for Android. + +## 2018-04-12 10.0.374 beta +* Fixes for back button in web browser (#737) ## 2018-03-22 10.0.373 beta * Initial beta release of Keyman for Android 10.0 diff --git a/ios/build.sh b/ios/build.sh index 3a9ab7da3d776b3cf35b18c4560b8885c80c477a..05f14a10b7171f5651549783549c0bbd38ce34ee 100755 --- a/ios/build.sh +++ b/ios/build.sh @@ -12,6 +12,7 @@ display_usage ( ) { echo " -clean Removes all previously-existing build products for KMEI and the Keyman app before building." echo " -no-kmw Uses existing keyman.js, doesn't try to build" echo " -only-framework Builds only the KeymanEngine framework; does not attempt to build the app." + echo " -no-carthage Disables downloading and building for dependencies." echo " -no-codesign Disables code-signing for the Keyman application, allowing it to be performed separately later." echo " Will not construct the archive and .ipa. (includes -no-archive)" echo " -no-archive Bypasses the archive and .ipa preparation stage." diff --git a/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj b/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj index 26138a7d5b18bbb21a6f690d49f81405a542dfa8..82b72fd0d5cdd6510b7912d704830bdb8a322f32 100644 --- a/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj +++ b/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj @@ -25,6 +25,7 @@ 1645D5952036C6FF0076C51B /* KeymanPackage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1645D5942036C6FF0076C51B /* KeymanPackage.swift */; }; 1645D5972036C9F80076C51B /* KMPKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1645D5962036C9F80076C51B /* KMPKeyboard.swift */; }; 165C8B8D1FD8220600D4A78D /* Zip.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 165C8B8B1FD8220600D4A78D /* Zip.framework */; }; + 165EB3A12098993900040A69 /* KeyboardError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 165EB3A02098993900040A69 /* KeyboardError.swift */; }; 1687ACCE1FD8DE5300926D69 /* XCGLogger.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1687ACCC1FD8DE5300926D69 /* XCGLogger.framework */; }; 1687ACCF1FD8DE5300926D69 /* ObjcExceptionBridging.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1687ACCD1FD8DE5300926D69 /* ObjcExceptionBridging.framework */; }; 6CD5DFAA150F6DC8007A5DDE /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 6CD5DFA8150F6DC8007A5DDE /* icon.png */; }; @@ -174,6 +175,7 @@ 1645D5942036C6FF0076C51B /* KeymanPackage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeymanPackage.swift; sourceTree = ""; }; 1645D5962036C9F80076C51B /* KMPKeyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMPKeyboard.swift; sourceTree = ""; }; 165C8B8B1FD8220600D4A78D /* Zip.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Zip.framework; path = ../../Carthage/Build/iOS/Zip.framework; sourceTree = ""; }; + 165EB3A02098993900040A69 /* KeyboardError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardError.swift; sourceTree = ""; }; 1687ACCC1FD8DE5300926D69 /* XCGLogger.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCGLogger.framework; path = ../../Carthage/Build/iOS/XCGLogger.framework; sourceTree = ""; }; 1687ACCD1FD8DE5300926D69 /* ObjcExceptionBridging.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjcExceptionBridging.framework; path = ../../Carthage/Build/iOS/ObjcExceptionBridging.framework; sourceTree = ""; }; 6C0A140E151EA930007FA4AD /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; @@ -293,6 +295,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 165EB39F2098992D00040A69 /* Errors */ = { + isa = PBXGroup; + children = ( + 165EB3A02098993900040A69 /* KeyboardError.swift */, + ); + path = Errors; + sourceTree = ""; + }; 6C0A13F9151EA151007FA4AD /* Resources */ = { isa = PBXGroup; children = ( @@ -581,6 +591,7 @@ F273AB9615641D9300A47CEE /* Classes */ = { isa = PBXGroup; children = ( + 165EB39F2098992D00040A69 /* Errors */, C055E6E81F99EA320035C2DD /* Extension */, C0452BA91F9F1CAF0064431A /* Model */, C024C9921FA6EB340060583B /* Notification */, @@ -870,6 +881,7 @@ C0EF3E7B1F95B65300CE9BD4 /* KeymanWebDelegate.swift in Sources */, C06D37411F81F5C400F61AE0 /* LanguageViewController.swift in Sources */, C06D37421F81F5C400F61AE0 /* KeyboardPickerButton.swift in Sources */, + 165EB3A12098993900040A69 /* KeyboardError.swift in Sources */, C05F432D1FBD5A4C0058CBD4 /* KeyboardAPICall.swift in Sources */, C055E6EB1F99ED090035C2DD /* RegisteredFont.swift in Sources */, 1645D5972036C9F80076C51B /* KMPKeyboard.swift in Sources */, diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Constants.swift b/ios/engine/KMEI/KeymanEngine/Classes/Constants.swift index 161e3bbf7ec95f6ec6e27513ca900f4a6a6a628f..f590810d18aae882fd5efb67f08684191ae47e4d 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Constants.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Constants.swift @@ -58,7 +58,12 @@ public enum Resources { } public enum Util { - /// Is the process of a custom keyboard extension. + /// Is the process of a custom keyboard extension. Avoid using this + /// in most situations as Manager.shared.isSystemKeyboard is more + /// reliable in situations where in-app and system keyboard can + /// be used in the same app, for example using the Web Browser in + /// the Keyman app. However, in initialization scenarios this test + /// makes sense. public static let isSystemKeyboard: Bool = { let infoDict = Bundle.main.infoDictionary let extensionInfo = infoDict?["NSExtension"] as? [AnyHashable: Any] diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Errors/KeyboardError.swift b/ios/engine/KMEI/KeymanEngine/Classes/Errors/KeyboardError.swift new file mode 100644 index 0000000000000000000000000000000000000000..bf705e360c756b0b0e6707baf26e174436974b39 --- /dev/null +++ b/ios/engine/KMEI/KeymanEngine/Classes/Errors/KeyboardError.swift @@ -0,0 +1,13 @@ +// +// KeyboardError.swift +// KeymanEngine +// +// Created by Jacob Bullock on 5/1/18. +// Copyright © 2018 SIL International. All rights reserved. +// + +import Foundation + +enum KeyboardError: Error { + case unchanged +} diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Extension/JSONDecoder.DateDecodingStrategy+ISO8601Fallback.swift b/ios/engine/KMEI/KeymanEngine/Classes/Extension/JSONDecoder.DateDecodingStrategy+ISO8601Fallback.swift index 961b2a5305573aab6216489afcf65bff915b19b3..ed187adfbb16cf09a9a9f5e15ae6bfe3d271afdc 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Extension/JSONDecoder.DateDecodingStrategy+ISO8601Fallback.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Extension/JSONDecoder.DateDecodingStrategy+ISO8601Fallback.swift @@ -9,6 +9,12 @@ import Foundation extension JSONDecoder.DateDecodingStrategy { + static var iso8601WithoutTimezone: JSONDecoder.DateDecodingStrategy { + let formatter = DateFormatter() + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" + return .formatted(formatter) + } static var ios8601WithFallback: JSONDecoder.DateDecodingStrategy { if #available(iOS 10.0, *) { return .iso8601 @@ -18,4 +24,13 @@ extension JSONDecoder.DateDecodingStrategy { formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ" return .formatted(formatter) } + + static var ios8601WithMilliseconds: JSONDecoder.DateDecodingStrategy { + let formatter = DateFormatter() + formatter.calendar = Calendar(identifier: .iso8601) + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.timeZone = TimeZone(secondsFromGMT: 0) + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX" + return .formatted( formatter ) + } } diff --git a/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift index 33f186166510c979a4da501e971436e17c7df47a..e4346ab29cdf53b67723ac7e00861de75831d7dc 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift @@ -33,9 +33,10 @@ open class InputViewController: UIInputViewController, KeymanWebDelegate { open var topBarImageView: UIImageView? var barHeightConstraints: [NSLayoutConstraint] = [] - + var barWidthConstraints: [NSLayoutConstraint] = [] var containerView: UIView? var containerHeightConstraints: [NSLayoutConstraint] = [] + var containerWidthConstraints: [NSLayoutConstraint] = [] var heightConstraint: NSLayoutConstraint! var isTopBarEnabled: Bool @@ -59,7 +60,7 @@ open class InputViewController: UIInputViewController, KeymanWebDelegate { } private var expandedHeight: CGFloat { - return CGFloat(Int(kmInputView.frame.height) % 1000) + + return Manager.shared.keyboardHeight + (isTopBarEnabled ? CGFloat(InputViewController.topBarHeight) : 0) } @@ -73,35 +74,39 @@ open class InputViewController: UIInputViewController, KeymanWebDelegate { } open override func updateViewConstraints() { - if view.frame.width == 0 || view.frame.height == 0 { - super.updateViewConstraints() - return + func addConstraints(_ constraints: [NSLayoutConstraint]) { + for constraint in constraints { + if !view.constraints.contains(constraint) { + view.addConstraint(constraint) + } + } } Manager.shared.updateViewConstraints() let topBarHeight = isTopBarEnabled ? CGFloat(InputViewController.topBarHeight) : 0 barHeightConstraints[0].constant = topBarHeight + addConstraints(barHeightConstraints) - for constraint in barHeightConstraints { - if !view.constraints.contains(constraint) { - view.addConstraint(constraint) - } - } + barWidthConstraints[0].constant = Manager.shared.keyboardWidth + addConstraints(barWidthConstraints) - containerHeightConstraints[0].constant = CGFloat(Int(kmInputView.frame.height) % 1000) - for constraint in containerHeightConstraints { - if !view.constraints.contains(constraint) { - view.addConstraint(constraint) - } - } + containerHeightConstraints[0].constant = Manager.shared.keyboardHeight + addConstraints(containerHeightConstraints) + containerWidthConstraints[0].constant = Manager.shared.keyboardWidth + addConstraints(containerWidthConstraints) + + heightConstraint.constant = expandedHeight if !view.constraints.contains(heightConstraint) { - heightConstraint.constant = expandedHeight view.addConstraint(heightConstraint) - } else if heightConstraint.constant != expandedHeight { - heightConstraint.constant = expandedHeight } + + // After superview is resized, tell the + // manager to resize the keyboard view again + // because it loses its size? + Manager.shared.updateViewConstraints() + super.updateViewConstraints() } @@ -111,6 +116,10 @@ open class InputViewController: UIInputViewController, KeymanWebDelegate { let bgColor = UIColor(red: 210.0 / 255.0, green: 214.0 / 255.0, blue: 220.0 / 255.0, alpha: 1.0) view.backgroundColor = bgColor + // TODO: If the following line is enabled, the WKWebView does not respond to touch events + // Can figure out why one day maybe + //view.translatesAutoresizingMaskIntoConstraints = false + Manager.shared.inputViewDidLoad() Manager.shared.keymanWebDelegate = self @@ -130,6 +139,7 @@ open class InputViewController: UIInputViewController, KeymanWebDelegate { } open override func viewDidAppear(_ animated: Bool) { + Manager.shared.isSystemKeyboard = true super.viewDidAppear(animated) setConstraints() inputView?.setNeedsUpdateConstraints() @@ -143,8 +153,22 @@ open class InputViewController: UIInputViewController, KeymanWebDelegate { } } + open override func viewWillDisappear(_ animated: Bool) { + Manager.shared.isSystemKeyboard = false + super.viewWillDisappear(animated) + } + open override func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) { Manager.shared.inputViewWillRotate(to: toInterfaceOrientation, duration: duration) + super.willRotate(to: toInterfaceOrientation, duration: duration) + } + + open override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + coordinator.animateAlongsideTransition(in: nil, animation: nil, completion: { + _ in + self.updateViewConstraints() + }) } open override func textDidChange(_ textInput: UITextInput?) { @@ -236,12 +260,13 @@ open class InputViewController: UIInputViewController, KeymanWebDelegate { private func setConstraints() { let topBarHeight = isTopBarEnabled ? InputViewController.topBarHeight : 0 let viewsDict = ["bar": topBarImageView!, "container": containerView!] + let screenWidth = UIScreen.main.bounds.width + barHeightConstraints = NSLayoutConstraint.constraints( withVisualFormat: "V:[bar(\(topBarHeight))]", metrics: nil, views: viewsDict) + barWidthConstraints = NSLayoutConstraint.constraints( + withVisualFormat: "H:[bar(\(Int(screenWidth)))]", metrics: nil, views: viewsDict) - let screenWidth = UIScreen.main.bounds.width - let barWidthConstraints = NSLayoutConstraint.constraints( - withVisualFormat: "H:[bar(>=\(Int(screenWidth)))]", metrics: nil, views: viewsDict) let barVerticalPositionConstraints = NSLayoutConstraint.constraints( withVisualFormat: "V:|-0-[bar]", metrics: nil, views: viewsDict) let barHorizontalPositionConstraints = NSLayoutConstraint.constraints( @@ -252,13 +277,12 @@ open class InputViewController: UIInputViewController, KeymanWebDelegate { view.addConstraints(barVerticalPositionConstraints) view.addConstraints(barHorizontalPositionConstraints) - // note this appears to relate to the rotation fix bug; may not work on iPads as 1000 is not enough containerHeightConstraints = NSLayoutConstraint.constraints( - withVisualFormat: "V:[container(\(Int(kmInputView.frame.height) % 1000))]", + withVisualFormat: "V:[container(\(Manager.shared.keyboardHeight))]", metrics: nil, views: viewsDict) - let containerWidthConstraints = NSLayoutConstraint.constraints( - withVisualFormat: "H:[container(>=\(UInt(screenWidth)))]", metrics: nil, views: viewsDict) + containerWidthConstraints = NSLayoutConstraint.constraints( + withVisualFormat: "H:[container(\(UInt(screenWidth)))]", metrics: nil, views: viewsDict) let containerVericalPositionConstraints = NSLayoutConstraint.constraints( withVisualFormat: "V:[container]-0-|", metrics: nil, views: viewsDict) let containerHorizontalPositionConstraints = NSLayoutConstraint.constraints( diff --git a/ios/engine/KMEI/KeymanEngine/Classes/KeyPreviewView.swift b/ios/engine/KMEI/KeymanEngine/Classes/KeyPreviewView.swift index c2090a7082aea6497c9a4b751d55022bc6d55bec..8dcfb73047d4e3980a47234d2552d9b6f5e3b282 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/KeyPreviewView.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/KeyPreviewView.swift @@ -22,7 +22,7 @@ class KeyPreviewView: UIView { override init(frame: CGRect) { let isPortrait: Bool - if Util.isSystemKeyboard { + if Manager.shared.isSystemKeyboard { isPortrait = InputViewController.isPortrait } else { isPortrait = UIDevice.current.orientation.isPortrait @@ -37,7 +37,7 @@ class KeyPreviewView: UIView { let tbHeight = Manager.shared.isSystemKeyboardTopBarEnabled ? CGFloat(InputViewController.topBarHeight) : 0 - if Util.isSystemKeyboard && (viewPosY < -tbHeight) { + if Manager.shared.isSystemKeyboard && (viewPosY < -tbHeight) { adjY = viewPosY + tbHeight viewPosY = CGFloat(-tbHeight) viewHeight += adjY diff --git a/ios/engine/KMEI/KeymanEngine/Classes/KeyboardMenuView.swift b/ios/engine/KMEI/KeymanEngine/Classes/KeyboardMenuView.swift index 8e51c0f74aadab270704232c0defd1714f21dec3..01f98979a6be0bf4382191106f581dd826a19386 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/KeyboardMenuView.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/KeyboardMenuView.swift @@ -57,7 +57,7 @@ class KeyboardMenuView: UIView, UITableViewDelegate, UITableViewDataSource, UIGe init(keyFrame frame: CGRect, inputViewController: InputViewController, closeButtonTitle: String?) { let isPortrait: Bool - if Util.isSystemKeyboard { + if Manager.shared.isSystemKeyboard { isPortrait = InputViewController.isPortrait } else { isPortrait = UIDevice.current.orientation.isPortrait diff --git a/ios/engine/KMEI/KeymanEngine/Classes/KeyboardRepository/APIKeyboardRepository.swift b/ios/engine/KMEI/KeymanEngine/Classes/KeyboardRepository/APIKeyboardRepository.swift index f733365a0774cd35fe2f58147e7e6778117250da..f543484d7cc9cb4713cebe5ddb4e219eb9eef365 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/KeyboardRepository/APIKeyboardRepository.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/KeyboardRepository/APIKeyboardRepository.swift @@ -29,7 +29,8 @@ public class APIKeyboardRepository: KeyboardRepository { urlComponents.queryItems = [ URLQueryItem(name: "dateformat", value: "seconds"), URLQueryItem(name: "device", value: deviceType), - URLQueryItem(name: "version", value: keymanVersion) + URLQueryItem(name: "version", value: keymanVersion), + URLQueryItem(name: "languageidtype", value: "bcp47") ] log.info("Connecting to Keyman cloud: \(urlComponents.url!).") let task = URLSession.shared.dataTask(with: urlComponents.url!) { (data, response, error) in diff --git a/ios/engine/KMEI/KeymanEngine/Classes/KeyboardRepository/KeyboardRepository.swift b/ios/engine/KMEI/KeymanEngine/Classes/KeyboardRepository/KeyboardRepository.swift index 13e24a210160cefb164963ff62a6677513671987..97c90c80736abbdb56e2db83bced79bf48ac51dd 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/KeyboardRepository/KeyboardRepository.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/KeyboardRepository/KeyboardRepository.swift @@ -11,8 +11,9 @@ import Foundation public protocol KeyboardRepository: class { typealias CompletionHandler = (Error?) -> Void - weak var delegate: KeyboardRepositoryDelegate? { get set } + var delegate: KeyboardRepositoryDelegate? { get set } var languages: [String: Language]? { get } + var keyboards: [String: Keyboard]? { get } func installableKeyboard(withID keyboardID: String, languageID: String) -> InstallableKeyboard? func fetch(completionHandler: CompletionHandler?) @@ -20,12 +21,20 @@ public protocol KeyboardRepository: class { public extension KeyboardRepository { public func installableKeyboard(withID keyboardID: String, languageID: String) -> InstallableKeyboard? { - guard let language = languages?[languageID] else { + guard let keyboard = keyboards?.first(where: { $0.key == keyboardID })?.value else { return nil } - guard let keyboard = language.keyboards?.first(where: { $0.id == keyboardID }) else { - return nil + + // If the Keyboard (still) supports the requested language, use that one. + guard let language = keyboard.languages?.first(where: {$0.id == languageID}) ?? + // Otherwise, just use the first language listed for the keyboard. + keyboard.languages?.first ?? + // In cases where the keyboard fails to specify any language, use the requested one if it's in the collection. + languages?[languageID] + else { + return nil } + return InstallableKeyboard(keyboard: keyboard, language: language, isCustom: false) } diff --git a/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift index 5ebf8d786ce42465f411b117940ab8e80883307f..1dee45104d6ff111aa37a8a61b4fa3e7a0fd14cd 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift @@ -45,6 +45,7 @@ class KeymanWebViewController: UIViewController { webView = WKWebView(frame: frame ?? .zero, configuration: config) webView.isOpaque = false + webView.translatesAutoresizingMaskIntoConstraints = false webView.backgroundColor = UIColor.clear webView.navigationDelegate = self webView.scrollView.isScrollEnabled = false @@ -78,7 +79,20 @@ extension KeymanWebViewController { // FIXME: text is unused in the JS func executePopupKey(id: String, text: String) { - webView.evaluateJavaScript("executePopupKey('\(id)','\(text)');", completionHandler: nil) + // Text must be checked for ', ", and \ characters; they must be escaped properly! + do { + let encodingArray = [ text ]; + let jsonString = try String(data: JSONSerialization.data(withJSONObject: encodingArray), encoding: .utf8)! + let start = jsonString.index(jsonString.startIndex, offsetBy: 2) + let end = jsonString.index(jsonString.endIndex, offsetBy: -2) + let escapedText = jsonString[start.. Bool { if let keyboard = Storage.active.userDefaults.userKeyboard(withFullID: fullID) { - return setKeyboard(keyboard) + return setKeyboard(keyboard) } return false } + /// Set the current keyboard. /// - /// - Returns: Whether the keyboard was set successfully + /// - Throws: error if the keyboard was unchanged public func setKeyboard(_ kb: InstallableKeyboard) -> Bool { if kb.fullID == currentKeyboardID { log.info("Keyboard unchanged: \(kb.fullID)") return false + // throw KeyboardError.unchanged } log.info("Setting language: \(kb.fullID)") @@ -234,6 +247,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat NotificationCenter.default.post(name: Notifications.keyboardChanged, object: self, value: kb) + return true } @@ -297,7 +311,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat // Set a new keyboard if deleting the current one if kb.fullID == currentKeyboardID { - setKeyboard(userKeyboards[0]) + _ = setKeyboard(userKeyboards[0]) } if !userKeyboards.contains(where: { $0.id == kb.id }) { @@ -332,7 +346,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat return nil } let newIndex = (index + 1) % userKeyboards.count - setKeyboard(userKeyboards[newIndex]) + _ = setKeyboard(userKeyboards[newIndex]) return newIndex } @@ -395,7 +409,16 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat languageName = l["name"]! languageId = l["id"]! - installableKeyboards.append( InstallableKeyboard(id: keyboardID, name: name, languageID: languageId, languageName: languageName, version: version, isRTL: false, font: displayFont, oskFont: oskFont, isCustom: false)) + installableKeyboards.append( InstallableKeyboard( + id: keyboardID, + name: name, + languageID: languageId, + languageName: languageName, + version: version, + isRTL: false, + font: displayFont, + oskFont: oskFont, + isCustom: false)) } } @@ -410,16 +433,14 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat for keyboard in installableKeyboards { let storedPath = Storage.active.keyboardURL(for: keyboard) - - var installableFiles: [[Any]] = [["\(keyboardID).js", storedPath]] - if let _ = osk { - let oskPath = Storage.active.fontURL(forKeyboardID: keyboardID, filename: osk!) + if let osk = osk { + let oskPath = Storage.active.fontURL(forKeyboardID: keyboardID, filename: osk) installableFiles.append([osk, oskPath]) } - if let _ = font { - let displayPath = Storage.active.fontURL(forKeyboardID: keyboardID, filename: font!) + if let font = font { + let displayPath = Storage.active.fontURL(forKeyboardID: keyboardID, filename: font) installableFiles.append([font, displayPath]) } do { @@ -582,15 +603,29 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat downloadFailed(forKeyboards: [], error: error) return } + + decodeKeyboardData(data, decodingStrategy: .ios8601WithFallback) + } + private func decodeKeyboardData(_ data: Data, decodingStrategy : JSONDecoder.DateDecodingStrategy) { let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .ios8601WithFallback - do { - let keyboard = try decoder.decode(KeyboardAPICall.self, from: data) - return downloadKeyboard(keyboard) - } catch { - downloadFailed(forKeyboards: [], error: error) - return + decoder.dateDecodingStrategy = decodingStrategy + + if let keyboard = try? decoder.decode(KeyboardAPICall.self, from: data) { + downloadKeyboard(keyboard) + } else { + decoder.dateDecodingStrategy = .iso8601WithoutTimezone + if let keyboard = try? decoder.decode(KeyboardAPICall.self, from: data) { + downloadKeyboard(keyboard) + } else { + decoder.dateDecodingStrategy = .ios8601WithMilliseconds + do { + let keyboard = try decoder.decode(KeyboardAPICall.self, from: data) + downloadKeyboard(keyboard) + } catch { + downloadFailed(forKeyboards: [], error: error) + } + } } } @@ -844,7 +879,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat // MARK: - View management public var keyboardHeight: CGFloat { - if Util.isSystemKeyboard { + if isSystemKeyboard { return keyboardHeight(isPortrait: InputViewController.isPortrait) } else { return keyboardHeight(isPortrait: UIDevice.current.orientation.isPortrait) @@ -856,17 +891,18 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat } func keyboardHeight(isPortrait: Bool) -> CGFloat { + let parentHeight: CGFloat = keymanWeb.parent != nil ? keymanWeb.parent!.view.frame.height : CGFloat(100.0) if UIDevice.current.userInterfaceIdiom == .pad { if isPortrait { - return Util.isSystemKeyboard ? padPortraitSystemKeyboardHeight : padPortraitInAppKeyboardHeight + return isSystemKeyboard ? padPortraitSystemKeyboardHeight : parentHeight } else { - return Util.isSystemKeyboard ? padLandscapeSystemKeyboardHeight : padLandscapeInAppKeyboardHeight + return isSystemKeyboard ? padLandscapeSystemKeyboardHeight : parentHeight } } else { if isPortrait { - return Util.isSystemKeyboard ? phonePortraitSystemKeyboardHeight : phonePortraitInAppKeyboardHeight + return isSystemKeyboard ? phonePortraitSystemKeyboardHeight : parentHeight } else { - return Util.isSystemKeyboard ? phoneLandscapeSystemKeyboardHeight : phoneLandscapeInAppKeyboardHeight + return isSystemKeyboard ? phoneLandscapeSystemKeyboardHeight : parentHeight } } } @@ -879,30 +915,6 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat return CGSize(width: keyboardWidth, height: keyboardHeight) } - // Keyman interaction - private func resizeKeyboard() { - let newSize = keyboardSize - if didResizeToOrientation && Util.isSystemKeyboard && lastKeyboardSize == newSize { - didResizeToOrientation = false - return - } - lastKeyboardSize = newSize - - keymanWeb.frame = CGRect(origin: .zero, size: newSize) - - // Workaround for WKWebView bug with landscape orientation - // TODO: Check if still necessary and if there's a better solution - if Util.isSystemKeyboard { - perform(#selector(self.resizeDelay), with: self, afterDelay: 1.0) - } - - var oskHeight = Int(newSize.height) - oskHeight -= oskHeight % (Util.isSystemKeyboard ? 10 : 20) - - keymanWeb.setOskWidth(Int(newSize.width)) - keymanWeb.setOskHeight(oskHeight) - } - private var keymanScrollView: UIScrollView { return keymanWeb.webView.scrollView } @@ -995,17 +1007,17 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat currentKeyboardID = nil if let keyboard = keyboard { - setKeyboard(keyboard) + _ = setKeyboard(keyboard) } else if let keyboard = Storage.active.userDefaults.userKeyboards?[safe: 0] { - setKeyboard(keyboard) + _ = setKeyboard(keyboard) } else { - setKeyboard(Defaults.keyboard) + _ = setKeyboard(Defaults.keyboard) } } @objc func showHelpBubble() { // Help bubble is always disabled for system-wide keyboard - if Util.isSystemKeyboard || keyboardMenuView != nil { + if Manager.shared.isSystemKeyboard || keyboardMenuView != nil { return } @@ -1066,12 +1078,18 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat } func resizeKeyboardIfNeeded() { - // TODO: Check if necessary since resizeKeyboard() checks old size + // TODO: Eliminate this function; performance cost of resizing is + // probably minimal if no resizing actually happens + resizeKeyboard() + } + + // Keyman interaction + private func resizeKeyboard() { let newSize = keyboardSize - if newSize != lastKeyboardSize { - resizeKeyboard() - lastKeyboardSize = newSize - } + + keymanWeb.frame = CGRect(origin: .zero, size: newSize) + keymanWeb.setOskWidth(Int(newSize.width)) + keymanWeb.setOskHeight(Int(newSize.height)) } func resizeKeyboard(with orientation: UIInterfaceOrientation) { @@ -1081,11 +1099,8 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat let kbHeight = keyboardHeight(with: orientation) keymanWeb.frame = CGRect(x: 0.0, y: 0.0, width: kbWidth, height: kbHeight) - var oskHeight = Int(kbHeight) - oskHeight -= oskHeight % (Util.isSystemKeyboard ? 10 : 20) - keymanWeb.setOskWidth(Int(kbWidth)) - keymanWeb.setOskHeight(oskHeight) + keymanWeb.setOskHeight(Int(kbHeight)) } // MARK: - Text @@ -1137,7 +1152,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat var newKb = Defaults.keyboard if currentKeyboardID == nil && !shouldReloadKeyboard { - let userData = Util.isSystemKeyboard ? UserDefaults.standard : Storage.active.userDefaults + let userData = Manager.shared.isSystemKeyboard ? UserDefaults.standard : Storage.active.userDefaults if let id = userData.currentKeyboardID { if let kb = Storage.active.userDefaults.userKeyboard(withFullID: id) { newKb = kb @@ -1145,7 +1160,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat } else if let userKbs = Storage.active.userDefaults.userKeyboards, !userKbs.isEmpty { newKb = userKbs[0] } - setKeyboard(newKb) + _ = setKeyboard(newKb) } NotificationCenter.default.post(name: Notifications.keyboardLoaded, object: self, value: newKb) @@ -1167,7 +1182,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat keymanWebDelegate?.showKeyPreview(keymanWeb, keyFrame: keyFrame, preview: preview) if UIDevice.current.userInterfaceIdiom == .pad - || (Util.isSystemKeyboard && !isSystemKeyboardTopBarEnabled) + || (Manager.shared.isSystemKeyboard && !isSystemKeyboardTopBarEnabled) || subKeysView != nil { return } @@ -1228,7 +1243,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat dismissHelpBubble() isKeymanHelpOn = false - if Util.isSystemKeyboard { + if Manager.shared.isSystemKeyboard { let userData = UserDefaults.standard userData.set(true, forKey: Key.keyboardPickerDisplayed) userData.synchronize() diff --git a/ios/engine/KMEI/KeymanEngine/Classes/SubKeysView.swift b/ios/engine/KMEI/KeymanEngine/Classes/SubKeysView.swift index b4dc96bc5b87418e9edca388247dc4620b33d2cf..02d541a1887610264628e36951fc94c69b2b284f 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/SubKeysView.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/SubKeysView.swift @@ -23,7 +23,7 @@ class SubKeysView: UIView { let containerView: UIView init(keyFrame frame: CGRect, subKeys: [UIButton]) { - let isSystemKeyboard = Util.isSystemKeyboard + let isSystemKeyboard = Manager.shared.isSystemKeyboard var isPortrait = true if isSystemKeyboard { isPortrait = InputViewController.isPortrait diff --git a/ios/engine/KMEI/KeymanEngine/Classes/TextField.swift b/ios/engine/KMEI/KeymanEngine/Classes/TextField.swift index 0e656d55f4d49989339d2a63fae524bb68511375..80e44f4f255630f69ee180c4e9a15d5c90a43a6f 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/TextField.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/TextField.swift @@ -213,7 +213,7 @@ extension TextField: KeymanWebDelegate { if let viewController = viewController { Manager.shared.showKeyboardPicker(in: viewController, shouldAddKeyboard: false) } else { - Manager.shared.switchToNextKeyboard() + _ = Manager.shared.switchToNextKeyboard() } } } diff --git a/ios/engine/KMEI/KeymanEngine/Classes/TextView.swift b/ios/engine/KMEI/KeymanEngine/Classes/TextView.swift index df52e8a896131c84c62a8286f21ab2253cb1f311..ba2133a3f997799f9c7923fc31741f52a55d1fdc 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/TextView.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/TextView.swift @@ -219,7 +219,7 @@ extension TextView: KeymanWebDelegate { if let viewController = viewController { Manager.shared.showKeyboardPicker(in: viewController, shouldAddKeyboard: false) } else { - Manager.shared.switchToNextKeyboard() + _ = Manager.shared.switchToNextKeyboard() } } } diff --git a/ios/engine/KMEI/KeymanEngine/resources/Keyman.bundle/Contents/Resources/keyboard.html b/ios/engine/KMEI/KeymanEngine/resources/Keyman.bundle/Contents/Resources/keyboard.html index b4c12d1b96b61d101e500571dc1cd3e4357a65ad..a1129401c6f1509a13218e343070ce6a2faa9c76 100644 --- a/ios/engine/KMEI/KeymanEngine/resources/Keyman.bundle/Contents/Resources/keyboard.html +++ b/ios/engine/KMEI/KeymanEngine/resources/Keyman.bundle/Contents/Resources/keyboard.html @@ -83,9 +83,10 @@ var fragmentToggle = 0; function insertText(dn, s) { fragmentToggle = (fragmentToggle + 1) % 100; - window.location.hash = 'insertText-'+ fragmentToggle + '+dn=' + dn + '+s=' + toHex(s); + var insertHash = 'insertText-'+ fragmentToggle + '+dn=' + dn + '+s=' + toHex(s); + //window.location.hash = 'insertText-'+ fragmentToggle + '+dn=' + dn + '+s=' + toHex(s); if (typeof(window.webkit) != 'undefined') - window.webkit.messageHandlers.keyman.postMessage(window.location.hash); + window.webkit.messageHandlers.keyman.postMessage('#' + insertHash); } function oskCreateKeyPreview(x,y,w,h,t) @@ -94,17 +95,19 @@ var div = document.createElement('div'); div.innerHTML = t; var dt = div.firstChild.nodeValue; - window.location.hash = 'showKeyPreview-'+fragmentToggle+'+x='+x+'+y='+y+'+w='+w+'+h='+h+'+t='+toHex(dt); + var previewHash = 'showKeyPreview-'+fragmentToggle+'+x='+x+'+y='+y+'+w='+w+'+h='+h+'+t='+toHex(dt); + //window.location.hash = 'showKeyPreview-'+fragmentToggle+'+x='+x+'+y='+y+'+w='+w+'+h='+h+'+t='+toHex(dt); if (typeof(window.webkit) != 'undefined') - window.webkit.messageHandlers.keyman.postMessage(window.location.hash); + window.webkit.messageHandlers.keyman.postMessage('#' + previewHash); } function oskClearKeyPreview() { fragmentToggle = (fragmentToggle + 1) % 100; - window.location.hash = 'dismissKeyPreview-'+fragmentToggle; + var dismissHash = 'dismissKeyPreview-'+fragmentToggle; + //window.location.hash = 'dismissKeyPreview-'+fragmentToggle; if (typeof(window.webkit) != 'undefined') - window.webkit.messageHandlers.keyman.postMessage(window.location.hash); + window.webkit.messageHandlers.keyman.postMessage('#' + dismissHash); } oskCreatePopup = function(obj,x,y,w,h) @@ -126,32 +129,35 @@ if(shift) { hash = hash + '+font=' + 'SpecialOSK'; } - window.location.hash = hash; + //window.location.hash = hash; if (typeof(window.webkit) != 'undefined') - window.webkit.messageHandlers.keyman.postMessage(window.location.hash); + window.webkit.messageHandlers.keyman.postMessage('#' + hash); } } function menuKeyDown() { fragmentToggle = (fragmentToggle + 1) % 100; - window.location.hash = 'menuKeyDown-' + fragmentToggle; + var keyDownHash = 'menuKeyDown-' + fragmentToggle; + //window.location.hash = 'menuKeyDown-' + fragmentToggle; if (typeof(window.webkit) != 'undefined') - window.webkit.messageHandlers.keyman.postMessage(window.location.hash); + window.webkit.messageHandlers.keyman.postMessage('#' + keyDownHash); } function menuKeyUp() { fragmentToggle = (fragmentToggle + 1) % 100; - window.location.hash = 'menuKeyUp-'+fragmentToggle; + var keyUpHash = 'menuKeyUp-'+fragmentToggle; + //window.location.hash = 'menuKeyUp-'+fragmentToggle; if (typeof(window.webkit) != 'undefined') - window.webkit.messageHandlers.keyman.postMessage(window.location.hash); + window.webkit.messageHandlers.keyman.postMessage('#' + keyUpHash); } function hideKeyboard() { fragmentToggle = (fragmentToggle + 1) % 100; - window.location.hash = 'hideKeyboard-' + fragmentToggle; + var hideHash = 'hideKeyboard-' + fragmentToggle; + //window.location.hash = 'hideKeyboard-' + fragmentToggle; if (typeof(window.webkit) != 'undefined') - window.webkit.messageHandlers.keyman.postMessage(window.location.hash); + window.webkit.messageHandlers.keyman.postMessage('#' + hideHash); } function langMenuPos() { diff --git a/ios/engine/KMEI/KeymanEngineDemo/MainViewController.swift b/ios/engine/KMEI/KeymanEngineDemo/MainViewController.swift index 3493f15fff8c4fe356f269dbcf1e9b69e531c19c..f58bf15f95353ed18c0b2fde5ac18bf5a71332b4 100644 --- a/ios/engine/KMEI/KeymanEngineDemo/MainViewController.swift +++ b/ios/engine/KMEI/KeymanEngineDemo/MainViewController.swift @@ -276,8 +276,12 @@ class MainViewController: UIViewController, UIAlertViewDelegate, TextViewDelegat } @objc func showAlert(_ message: String) { - let alert = UIAlertView(title: "Keyboard Download Error", message: message, delegate: self, - cancelButtonTitle: "OK", otherButtonTitles: "") - alert.show() + let alertController = UIAlertController(title: "Keyboard Download Error", + message: message, + preferredStyle: UIAlertControllerStyle.alert) + alertController.addAction(UIAlertAction(title: "OK", + style: UIAlertActionStyle.default, + handler: nil)) + self.present(alertController, animated: true, completion: nil) } } diff --git a/ios/history.md b/ios/history.md index 4d4c33b167bb58010ad9ca388ea154a1e32765dc..4f307d82e3411f1b09c315b30c81d0c6d35729ec 100644 --- a/ios/history.md +++ b/ios/history.md @@ -1,7 +1,68 @@ # Keyman for iPhone and iPad Version History ## 11.0 alpha -* Move to 11.0 +* Replaced deprecated calls to UIAlertView and cleaned up extraneous blank buttons (#1002) +* Bookmark add button is enabled only when title/url fields have text (#1073) + +## 2018-07-06 10.0.203 stable +* Fixes an issue where a keyboard with varying row counts in different layers could crash (#1055) + +## 2018-06-28 10.0.200 stable +* 10.0 stable release + +## 2018-06-27 10.0.163 beta +* Fixes issue where next layer was not correctly selected when the first longpress key pressed (#1027) + +## 2018-06-26 10.0.162 beta +* Fixes miskey when pressing between two keys (#1020) + +## 2018-06-14 10.0.161 beta +* Fixes keyboard not responding to touch from #981 (#988) + +## 2018-06-13 10.0.160 beta +* No changes affecting iOS + +## 2018-06-13 10.0.159 beta +* No changes affecting iOS + +## 2018-06-13 10.0.158 beta +* Bug fix installing a keyboard with missing metadata (#982) + +## 2018-06-13 10.0.157 beta +* Improvements to device rotation (#981) + +## 2018-06-12 10.0.156 beta +* No changes affecting iOS + +## 2018-06-11 10.0.155 beta +* Platform tests (in keyboards) are now consistent across all platforms (#969) + +## 2018-06-07 10.0.154 beta +* Fixed API call to fetch BCP-47 language ids and make keyboard updates more robust (#961) + +## 2018-06-06 10.0.147-10.0.153 beta +* No actual code changes affecting iOS (#873) + +## 2018-05-18 10.0.146 beta +* Code cleanup to remove warnings, etc. (#805) + +## 2018-05-17 10.0.145 beta +* Fixes occasional repeated characters when typing rapidly (#865) + +## 2018-05-04 10.0.144 beta +* Refactor navigation bar branding. (#802) + +## 2018-05-04 10.0.143 beta +* Search google when an invalid URL is entered in the address bar. (#801) + +## 2018-05-03 10.0.142 beta +* Supports loading of keyboard .json files which include milliseconds in date formats (#804) + +## 2018-05-02 10.0.141 beta +* Fix alphabetical list to be case insensitive on new keyboard list. (#803) + +## 2018-04-25 10.0.140 beta +* Fixed lack of output for certain punctuation longpress keys. (#702) ## 2018-03-22 10.0.139 beta * Initial beta release of Keyman for iPhone and iPad 10 diff --git a/ios/keyman/Keyman/Keyman-Info.plist b/ios/keyman/Keyman/Keyman-Info.plist index 5b2a0711918c430953434a1fafd3df745922aa32..487d06ecf2d08bd946cc53f660a23de085c789d4 100644 --- a/ios/keyman/Keyman/Keyman-Info.plist +++ b/ios/keyman/Keyman/Keyman-Info.plist @@ -38,7 +38,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2.5.2 + 10.0.0 CFBundleSignature ???? CFBundleURLTypes @@ -53,7 +53,7 @@ CFBundleVersion - 2.5.120 + 10.0.0 ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS diff --git a/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj b/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj index 38d6352cd7092d4b686b07dcd97232e3b08889dd..79ef96593b589209683e7d6d7d1ae7237a581d95 100644 --- a/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj +++ b/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj @@ -7,6 +7,13 @@ objects = { /* Begin PBXBuildFile section */ + 162E2C9020924EEE00F40769 /* keyman_logo@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 162E2C8F20924EEE00F40769 /* keyman_logo@3x.png */; }; + 162E2C9920926C8600F40769 /* UIView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 162E2C9720926C8600F40769 /* UIView+Extensions.swift */; }; + 162E2C9B20926C9B00F40769 /* KMNavigationBarBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 162E2C9A20926C9B00F40769 /* KMNavigationBarBackgroundView.swift */; }; + 162E2C9D2092BFE400F40769 /* KMUnderscoreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 162E2C9C2092BFE400F40769 /* KMUnderscoreView.swift */; }; + 162E2C9F2092D36800F40769 /* UIDevice+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 162E2C9E2092D36800F40769 /* UIDevice+Extensions.swift */; }; + 165EB39A2097165B00040A69 /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 165EB3992097165B00040A69 /* UIColor+Extensions.swift */; }; + 165EB39C2097181D00040A69 /* KMView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 165EB39B2097181D00040A69 /* KMView.swift */; }; 1687ACCA1FD8269C00926D69 /* Zip.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 165C8B8F1FD8221800D4A78D /* Zip.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 1687ACD41FD8DE8000926D69 /* ObjcExceptionBridging.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1687ACD11FD8DE7600926D69 /* ObjcExceptionBridging.framework */; }; 1687ACD51FD8DE8000926D69 /* ObjcExceptionBridging.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 1687ACD11FD8DE7600926D69 /* ObjcExceptionBridging.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -199,7 +206,14 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 162E2C8F20924EEE00F40769 /* keyman_logo@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "keyman_logo@3x.png"; path = "Keyman Navbar/keyman_logo@3x.png"; sourceTree = ""; }; + 162E2C9720926C8600F40769 /* UIView+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Extensions.swift"; sourceTree = ""; }; + 162E2C9A20926C9B00F40769 /* KMNavigationBarBackgroundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMNavigationBarBackgroundView.swift; sourceTree = ""; }; + 162E2C9C2092BFE400F40769 /* KMUnderscoreView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMUnderscoreView.swift; sourceTree = ""; }; + 162E2C9E2092D36800F40769 /* UIDevice+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+Extensions.swift"; sourceTree = ""; }; 165C8B8F1FD8221800D4A78D /* Zip.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Zip.framework; path = ../../Carthage/Build/iOS/Zip.framework; sourceTree = ""; }; + 165EB3992097165B00040A69 /* UIColor+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extensions.swift"; sourceTree = ""; }; + 165EB39B2097181D00040A69 /* KMView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMView.swift; sourceTree = ""; }; 1687ACD01FD8DE7600926D69 /* XCGLogger.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCGLogger.framework; path = ../../Carthage/Build/iOS/XCGLogger.framework; sourceTree = ""; }; 1687ACD11FD8DE7600926D69 /* ObjcExceptionBridging.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjcExceptionBridging.framework; path = ../../Carthage/Build/iOS/ObjcExceptionBridging.framework; sourceTree = ""; }; 16A9229D20325253003CC98E /* Keyman-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Keyman-Info.plist"; sourceTree = SOURCE_ROOT; }; @@ -389,6 +403,43 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 162E2C9420926C8600F40769 /* Classes */ = { + isa = PBXGroup; + children = ( + 162E2C9520926C8600F40769 /* Controller */, + 162E2C9620926C8600F40769 /* Extensions */, + 162E2C9820926C8600F40769 /* View */, + ); + path = Classes; + sourceTree = ""; + }; + 162E2C9520926C8600F40769 /* Controller */ = { + isa = PBXGroup; + children = ( + ); + path = Controller; + sourceTree = ""; + }; + 162E2C9620926C8600F40769 /* Extensions */ = { + isa = PBXGroup; + children = ( + 162E2C9720926C8600F40769 /* UIView+Extensions.swift */, + 162E2C9E2092D36800F40769 /* UIDevice+Extensions.swift */, + 165EB3992097165B00040A69 /* UIColor+Extensions.swift */, + ); + path = Extensions; + sourceTree = ""; + }; + 162E2C9820926C8600F40769 /* View */ = { + isa = PBXGroup; + children = ( + 162E2C9A20926C9B00F40769 /* KMNavigationBarBackgroundView.swift */, + 162E2C9C2092BFE400F40769 /* KMUnderscoreView.swift */, + 165EB39B2097181D00040A69 /* KMView.swift */, + ); + path = View; + sourceTree = ""; + }; 9845A79A1A43983300544E2E /* KMWebBrowser */ = { isa = PBXGroup; children = ( @@ -594,6 +645,7 @@ 98ABADB9176935E400B62590 /* Keyman */ = { isa = PBXGroup; children = ( + 162E2C9420926C8600F40769 /* Classes */, 9845A7BE1A439A9200544E2E /* GetStartedViewController */, 98C893F119F0811A000B9AC8 /* Images.xcassets */, 9845A7C21A439A9200544E2E /* InfoViewController */, @@ -677,6 +729,7 @@ 98AFAEDC17FE2B6A00178C0A /* Keyman Navbar */ = { isa = PBXGroup; children = ( + 162E2C8F20924EEE00F40769 /* keyman_logo@3x.png */, 9820CE501A144F0400EA909A /* navbar-Landscape-568h@3x.png */, 9820CE511A144F0400EA909A /* navbar-Portrait@3x.png */, 9825527719CBEC10009CDD83 /* navbar-Landscape-568h@2x.png */, @@ -889,6 +942,7 @@ 981AFAB619EF44DE006706BF /* navbar-Landscape@2x.png in Resources */, 9845A8641A439B8F00544E2E /* delete.png in Resources */, 9820CE521A144F0400EA909A /* navbar-Landscape-568h@3x.png in Resources */, + 162E2C9020924EEE00F40769 /* keyman_logo@3x.png in Resources */, 9845A87E1A439B8F00544E2E /* info.html in Resources */, 981AFAB719EF44DE006706BF /* navbar-Portrait@2x~ipad.png in Resources */, 981AFAB819EF44DE006706BF /* textsize_down.png in Resources */, @@ -1024,17 +1078,23 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 165EB39C2097181D00040A69 /* KMView.swift in Sources */, C055F0B11F60E8D400140735 /* GetStartedViewController.swift in Sources */, C055F0B51F610FB200140735 /* DropDownListView.swift in Sources */, C059FCC01FD927EF00BD1A64 /* Log.swift in Sources */, C0E943F81F61234C00E7D98C /* UIImage+Helpers.swift in Sources */, C0E943FE1F61377900E7D98C /* MainViewController.swift in Sources */, + 162E2C9920926C8600F40769 /* UIView+Extensions.swift in Sources */, + 162E2C9B20926C9B00F40769 /* KMNavigationBarBackgroundView.swift in Sources */, C055F0B31F60F7A400140735 /* DropDownView.swift in Sources */, C0A1A6371F5E8C9100EAF822 /* WebBrowserViewController.swift in Sources */, C0E943FA1F6124E100E7D98C /* AppDelegate.swift in Sources */, C0A1A6351F5E786A00EAF822 /* BookmarksViewController.swift in Sources */, + 162E2C9D2092BFE400F40769 /* KMUnderscoreView.swift in Sources */, C0A1A6331F5E749000EAF822 /* SetUpViewController.swift in Sources */, + 162E2C9F2092D36800F40769 /* UIDevice+Extensions.swift in Sources */, C0A1A6311F5E4F4300EAF822 /* InfoViewController.swift in Sources */, + 165EB39A2097165B00040A69 /* UIColor+Extensions.swift in Sources */, C0FF769E1F5D4ECB00BD23C3 /* ActivityItemProvider.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/ios/keyman/Keyman/Keyman/AppDelegate.swift b/ios/keyman/Keyman/Keyman/AppDelegate.swift index dd330bf0e219c521bf174baddc3ef627f57da52a..0889392b390929e4fa9f28a4c066dbf498b9c1af 100644 --- a/ios/keyman/Keyman/Keyman/AppDelegate.swift +++ b/ios/keyman/Keyman/Keyman/AppDelegate.swift @@ -180,7 +180,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } catch { self.showKMPError(error as! KMPError) } - + //this can fail gracefully and not show errors to users do { try FileManager.default.removeItem(at: adhocDir) diff --git a/ios/keyman/Keyman/Keyman/Classes/Extensions/UIColor+Extensions.swift b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIColor+Extensions.swift new file mode 100644 index 0000000000000000000000000000000000000000..8664f3be77b352fa1b67a04d6d4e63aa51330714 --- /dev/null +++ b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIColor+Extensions.swift @@ -0,0 +1,24 @@ +// +// UIColor+Extensions.swift +// Keyman +// +// Created by Jacob Bullock on 4/29/18. +// Copyright © 2018 SIL International. All rights reserved. +// + +import Foundation +import UIKit + +extension UIColor { + static var keymanOrange: UIColor { + return UIColor(red: 244/255, green: 113/255, blue: 32/255, alpha: 1.0) + } + + static var keymanRed: UIColor { + return UIColor(red: 186/255, green: 32/255, blue: 52/255, alpha: 1.0) + } + + static var keymanBlue: UIColor { + return UIColor(red: 105/255, green: 183/255, blue: 211/255, alpha: 1.0) + } +} diff --git a/ios/keyman/Keyman/Keyman/Classes/Extensions/UIDevice+Extensions.swift b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIDevice+Extensions.swift new file mode 100644 index 0000000000000000000000000000000000000000..c7f6c850e59893bf4b5c6682167104f4d404355b --- /dev/null +++ b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIDevice+Extensions.swift @@ -0,0 +1,19 @@ +// +// UIDevice+Extensions.swift +// Keyman +// +// Created by Jacob Bullock on 4/26/18. +// Copyright © 2018 SIL International. All rights reserved. +// + +import Foundation +import UIKit + +extension UIDevice { + static var isIphoneX: Bool { + let iphonexScreenHeight: Int = 812 + let screenRect = UIScreen.main.bounds + let size = CGFloat.maximum(screenRect.width, screenRect.height) + return UIDevice.current.userInterfaceIdiom == .phone && size == CGFloat(iphonexScreenHeight) + } +} diff --git a/ios/keyman/Keyman/Keyman/Classes/Extensions/UIView+Extensions.swift b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIView+Extensions.swift new file mode 100644 index 0000000000000000000000000000000000000000..697acb77dc1454b564ddeceb26a6db5098c62b8a --- /dev/null +++ b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIView+Extensions.swift @@ -0,0 +1,74 @@ +// +// UIView+Extensions.swfit +// Keyman +// +// Created by Jacob Bullock on 4/26/18. +// Copyright © 2018 SIL International. All rights reserved. +// + +import Foundation +import UIKit + +extension UIView { + + func constrainEqually(to parent: UIView, + attribute: NSLayoutAttribute, + constant: CGFloat = 0) -> NSLayoutConstraint { + + let constraint = NSLayoutConstraint(item: self, + attribute: attribute, + relatedBy: .equal, + toItem: parent, + attribute: attribute, + multiplier: 1, + constant: constant) + return constraint + } + + func constrainEqually(to constant: CGFloat, attribute: NSLayoutAttribute) -> NSLayoutConstraint { + let constraint = NSLayoutConstraint( + item: self, + attribute: attribute, + relatedBy: .equal, + toItem: nil, + attribute: .notAnAttribute, + multiplier: 1.0, + constant: constant) + return constraint + } + + func constrainCorners(to parent: UIView, options: [String:CGFloat]) { + self.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint(item: self, + attribute: .top, + relatedBy: .equal, + toItem: parent, + attribute: .top, + multiplier: 1, + constant: (options["top.constant"] ?? 0)).isActive = true + + NSLayoutConstraint(item: self, + attribute: .bottom, + relatedBy: .equal, + toItem: parent, + attribute: .bottom, + multiplier: 1, + constant: (options["bottom.constant"] ?? 0)).isActive = true + + NSLayoutConstraint(item: self, + attribute: .leading, + relatedBy: .equal, + toItem: parent, + attribute: .leading, + multiplier: 1, + constant: (options["leading.constant"] ?? 0)).isActive = true + + NSLayoutConstraint(item: self, + attribute: .trailing, + relatedBy: .equal, + toItem: parent, + attribute: .trailing, + multiplier: 1, + constant: (options["trailing.constant"] ?? 0)).isActive = true + } +} diff --git a/ios/keyman/Keyman/Keyman/Classes/View/KMNavigationBarBackgroundView.swift b/ios/keyman/Keyman/Keyman/Classes/View/KMNavigationBarBackgroundView.swift new file mode 100644 index 0000000000000000000000000000000000000000..09eb4aeb6b8d65130aa2a0f03a9e20003a17961a --- /dev/null +++ b/ios/keyman/Keyman/Keyman/Classes/View/KMNavigationBarBackgroundView.swift @@ -0,0 +1,94 @@ +// +// KMNavigationBarBackgroundView.swift +// Keyman +// +// Created by Jacob Bullock on 4/26/18. +// Copyright © 2018 SIL International. All rights reserved. +// + +import Foundation +import UIKit + +class KMNavigationBarBackgroundView: UIView { + + let defaultImageLeading: Int = 10 + let iphonexImageLeading: Int = 25 + let underscoreHeight: Int = 3 + let logoImageWidth: Int = 100 + let logoImageHeightDiff: Int = -8 + + var imageLeadingConstraint: NSLayoutConstraint? + var logoImageView: UIImageView? + + required public init?(coder: NSCoder) { + super.init(coder: coder) + self.commonInit() + } + + public override init(frame: CGRect) { + super.init(frame: frame) + self.commonInit() + } + + func commonInit() { + self.backgroundColor = .clear + self.isUserInteractionEnabled = false + setupLogo() + setupUnderscore() + } + + func hideLogo() { + if let logoImageView = logoImageView { + logoImageView.alpha = 0 + } + } + + func setupUnderscore() { + let v = KMUnderscoreView(frame: CGRect()) + self.addSubview(v) + v.translatesAutoresizingMaskIntoConstraints = false + + v.constrainEqually(to: self, attribute: .bottom).isActive = true + v.constrainEqually(to: self, attribute: .leading).isActive = true + v.constrainEqually(to: self, attribute: .trailing).isActive = true + v.constrainEqually(to: CGFloat(underscoreHeight), attribute: .height).isActive = true + } + + func setupLogo() { + let image = UIImage(named: "keyman_logo") + let imageView = UIImageView(image: image) + imageView.contentMode = .scaleAspectFit + imageView.translatesAutoresizingMaskIntoConstraints = false + self.addSubview(imageView) + + imageView.constrainEqually(to: self, attribute: .centerY).isActive = true + imageView.constrainEqually(to: self, attribute: .centerY).isActive = true + imageView.constrainEqually(to: self, + attribute: .height, + constant: CGFloat(logoImageHeightDiff)).isActive = true + imageView.constrainEqually(to: CGFloat(logoImageWidth), attribute: .width).isActive = true + + imageLeadingConstraint = imageView.constrainEqually(to: self, + attribute: .leading, + constant: CGFloat(defaultImageLeading)) + imageLeadingConstraint?.isActive = true + + logoImageView = imageView + } + + func addToNavbar(_ navbar: UINavigationBar!) { + navbar.addSubview(self) + self.constrainCorners(to: navbar, options: ["top.constant": 0]) + } + + func setOrientation(_ orientation: UIInterfaceOrientation) { + var constant: CGFloat = CGFloat(defaultImageLeading) + if let constraint = imageLeadingConstraint { + if orientation.isLandscape && UIDevice.isIphoneX { + constant = CGFloat(iphonexImageLeading) + } + constraint.constant = constant + self.setNeedsLayout() + } + } +} diff --git a/ios/keyman/Keyman/Keyman/Classes/View/KMUnderscoreView.swift b/ios/keyman/Keyman/Keyman/Classes/View/KMUnderscoreView.swift new file mode 100644 index 0000000000000000000000000000000000000000..96e6a2f1ab6cfe0b8d821a84de310fca297168f8 --- /dev/null +++ b/ios/keyman/Keyman/Keyman/Classes/View/KMUnderscoreView.swift @@ -0,0 +1,34 @@ +// +// KMUnderscoreView.swift +// Keyman +// +// Created by Jacob Bullock on 4/26/18. +// Copyright © 2018 SIL International. All rights reserved. +// + +import Foundation +import UIKit + +class KMUnderscoreView: KMView { + override func draw(_ rect: CGRect) { + //percentage based widths for the color bar portion of the logo + let widths: [CGFloat] = [0.6, 0.25, 0.15] + let colors: [UIColor] = [ UIColor.keymanOrange, + UIColor.keymanRed, + UIColor.keymanBlue] + + var x: CGFloat = 0 + for i in 0..<(widths.count) { + let w: CGFloat = rect.width * widths[i] + let drect = CGRect(x: x, y: 0, width: w, height: rect.height) + let bpath: UIBezierPath = UIBezierPath(rect: drect) + + let color = colors[i] + color.set() + bpath.fill() + + x += w + } + + } +} diff --git a/ios/keyman/Keyman/Keyman/Classes/View/KMView.swift b/ios/keyman/Keyman/Keyman/Classes/View/KMView.swift new file mode 100644 index 0000000000000000000000000000000000000000..3f8a1efb1e1c855a1719ffde4e9c86ad332cd8ce --- /dev/null +++ b/ios/keyman/Keyman/Keyman/Classes/View/KMView.swift @@ -0,0 +1,25 @@ +// +// KMView.swift +// Keyman +// +// Created by Jacob Bullock on 4/29/18. +// Copyright © 2018 SIL International. All rights reserved. +// + +import Foundation +import UIKit + +class KMView: UIView { + required public init?(coder: NSCoder) { + super.init(coder: coder) + self.commonInit() + } + + public override init(frame: CGRect) { + super.init(frame: frame) + self.commonInit() + } + + func commonInit() { + } +} diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Contents.json b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Contents.json index 7b9945524dcdcfd4aa53f52cddfa5ca0df871e3b..8d740e45e348ed71900fc4cc1daf2e50a4356c95 100644 --- a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Contents.json +++ b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -1,5 +1,23 @@ { "images" : [ + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "2436h", + "filename" : "launch_iphonex_portrait@3x.png", + "minimum-system-version" : "11.0", + "orientation" : "portrait", + "scale" : "3x" + }, + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "2436h", + "filename" : "launch_iphoneX_landscape@3x.png", + "minimum-system-version" : "11.0", + "orientation" : "landscape", + "scale" : "3x" + }, { "extent" : "full-screen", "idiom" : "iphone", @@ -30,9 +48,9 @@ { "orientation" : "portrait", "idiom" : "iphone", + "filename" : "Default@2x.png", "extent" : "full-screen", "minimum-system-version" : "7.0", - "filename" : "Default@2x.png", "scale" : "2x" }, { @@ -47,83 +65,83 @@ { "orientation" : "portrait", "idiom" : "ipad", + "filename" : "Default-Portrait~ipad7.png", "extent" : "full-screen", "minimum-system-version" : "7.0", - "filename" : "Default-Portrait~ipad7.png", "scale" : "1x" }, { "orientation" : "landscape", "idiom" : "ipad", + "filename" : "Default-Landscape~ipad7.png", "extent" : "full-screen", "minimum-system-version" : "7.0", - "filename" : "Default-Landscape~ipad7.png", "scale" : "1x" }, { "orientation" : "portrait", "idiom" : "ipad", + "filename" : "Default-Portrait@2x~ipad7.png", "extent" : "full-screen", "minimum-system-version" : "7.0", - "filename" : "Default-Portrait@2x~ipad7.png", "scale" : "2x" }, { "orientation" : "landscape", "idiom" : "ipad", + "filename" : "Default-Landscape@2x~ipad7.png", "extent" : "full-screen", "minimum-system-version" : "7.0", - "filename" : "Default-Landscape@2x~ipad7.png", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "iphone", - "extent" : "full-screen", "filename" : "Default.png", + "extent" : "full-screen", "scale" : "1x" }, { "orientation" : "portrait", "idiom" : "iphone", - "extent" : "full-screen", "filename" : "Default@2x.png", + "extent" : "full-screen", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "iphone", - "extent" : "full-screen", "filename" : "Default-568h@2x.png", + "extent" : "full-screen", "subtype" : "retina4", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "ipad", - "extent" : "to-status-bar", "filename" : "Default-Portrait~ipad.png", + "extent" : "to-status-bar", "scale" : "1x" }, { "orientation" : "landscape", "idiom" : "ipad", - "extent" : "to-status-bar", "filename" : "Default-Landscape~ipad.png", + "extent" : "to-status-bar", "scale" : "1x" }, { "orientation" : "portrait", "idiom" : "ipad", - "extent" : "to-status-bar", "filename" : "Default-Portrait@2x~ipad.png", + "extent" : "to-status-bar", "scale" : "2x" }, { "orientation" : "landscape", "idiom" : "ipad", - "extent" : "to-status-bar", "filename" : "Default-Landscape@2x~ipad.png", + "extent" : "to-status-bar", "scale" : "2x" } ], diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/launch_iphoneX_landscape@3x.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/launch_iphoneX_landscape@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..adb9dfe6c1a9dfcf896cf4bd1af4b5f1ef0d8e97 Binary files /dev/null and b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/launch_iphoneX_landscape@3x.png differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/launch_iphonex_portrait@3x.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/launch_iphonex_portrait@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..22a3ab1f624086c3b95ee51f00d8452f6a40a63d Binary files /dev/null and b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/launch_iphonex_portrait@3x.png differ diff --git a/ios/keyman/Keyman/Keyman/KMWebBrowser/BookmarksViewController.swift b/ios/keyman/Keyman/Keyman/KMWebBrowser/BookmarksViewController.swift index d9e74ec564f220b18737a4018d0840167aef13b1..8d930f753ae8e2b0dd35a8a4a1a641d62ac0c21a 100644 --- a/ios/keyman/Keyman/Keyman/KMWebBrowser/BookmarksViewController.swift +++ b/ios/keyman/Keyman/Keyman/KMWebBrowser/BookmarksViewController.swift @@ -21,6 +21,10 @@ class BookmarksViewController: UIViewController, UITableViewDelegate, UITableVie // TODO: Create struct for bookmarks private var bookmarks = [[String: String]]() + weak var inputTitleField: UITextField? + weak var inputUrlField: UITextField? + weak var addAction: UIAlertAction? + convenience init() { self.init(nibName: "BookmarksViewController", bundle: nil) } @@ -46,27 +50,48 @@ class BookmarksViewController: UIViewController, UITableViewDelegate, UITableVie } @IBAction func addBookmark(_ sender: Any) { - let alert = UIAlertView(title: "Add Bookmark", message: "", delegate: self, - cancelButtonTitle: "Cancel", otherButtonTitles: "Add") - alert.alertViewStyle = .loginAndPasswordInput - if let textField = alert.textField(at: 0) { + let alertController = UIAlertController(title: "Add Bookmark", message: "", + preferredStyle: UIAlertControllerStyle.alert) + alertController.addTextField(configurationHandler: { (textField) in + //listen for changes + NotificationCenter.default.addObserver(self, + selector: #selector(BookmarksViewController.handleTextFieldTextChangedNotification(notification:)), + name: NSNotification.Name.UITextFieldTextDidChange, object: textField) textField.placeholder = "Title" - textField.text = webBrowser?.webView?.stringByEvaluatingJavaScript(from: "document.title") + textField.text = self.webBrowser?.webView?.stringByEvaluatingJavaScript(from: "document.title") textField.autocapitalizationType = .sentences textField.font = UIFont.systemFont(ofSize: 17) textField.keyboardType = .default textField.clearButtonMode = .whileEditing - } - if let textField = alert.textField(at: 1) { - textField.placeholder = "Url" - textField.text = webBrowser?.webView?.request?.mainDocumentURL?.absoluteString + self.inputTitleField = textField + }) + alertController.addTextField(configurationHandler: { (textField) in + //listen for changes + NotificationCenter.default.addObserver(self, + selector: #selector(BookmarksViewController.handleTextFieldTextChangedNotification(notification:)), + name: NSNotification.Name.UITextFieldTextDidChange, object: textField) + textField.placeholder = "URL" + textField.text = self.webBrowser?.webView?.request?.mainDocumentURL?.absoluteString textField.autocapitalizationType = .none textField.font = UIFont.systemFont(ofSize: 17) textField.keyboardType = UIKeyboardType.URL textField.clearButtonMode = .whileEditing - textField.isSecureTextEntry = false - } - alert.show() + self.inputUrlField = textField + }) + alertController.addAction(UIAlertAction(title: "Cancel", + style: UIAlertActionStyle.cancel, + handler: nil)) + + let addAlertAction = UIAlertAction(title: "Add", + style: UIAlertActionStyle.default, + handler: {_ in self.addBookmarkHandler() + }) + alertController.addAction(addAlertAction) + // save add action to toggle the enabled/disabled state when the text changes. + addAction = addAlertAction + updateAddButtonEnableState() + + self.present(alertController, animated: true, completion: nil) } private func checkIfEmpty() { @@ -162,23 +187,13 @@ class BookmarksViewController: UIViewController, UITableViewDelegate, UITableVie dismiss(animated: true, completion: nil) } - func alertView(_ alertView: UIAlertView, clickedButtonAt buttonIndex: Int) { - if buttonIndex == alertView.cancelButtonIndex { - return - } - guard let title = alertView.textField(at: 0)?.text, !title.isEmpty else { - let alert = UIAlertView(title: "Invalid Bookmark Title", message: "Please enter a valid title", - delegate: self, cancelButtonTitle: "OK", otherButtonTitles: "") - alert.show() - return - } - guard var urlString = alertView.textField(at: 1)?.text, let url = URL(string: urlString) else { - let alert = UIAlertView(title: "Invalid Bookmark Url", message: "Please enter a valid Url", - delegate: self, cancelButtonTitle: "OK", otherButtonTitles: "") - alert.show() + func addBookmarkHandler() { + guard let title = inputTitleField?.text, var urlString = inputUrlField?.text else { + // This should be impossible. return } - if url.scheme == nil { + let url = URL(string: urlString) + if url?.scheme == nil { let url = URL(string: "http://\(urlString)") urlString = url?.absoluteString ?? urlString } @@ -187,4 +202,19 @@ class BookmarksViewController: UIViewController, UITableViewDelegate, UITableVie saveBookmarks() tableView.reloadData() } + + //handler + @objc func handleTextFieldTextChangedNotification(notification: NSNotification) { + updateAddButtonEnableState() + } + + func updateAddButtonEnableState() { + guard let title = inputTitleField?.text, let url = inputUrlField?.text else { + addAction!.isEnabled = false + return + } + + // Enforce a minimum length of >= 1 for both the title and url text fields. + addAction!.isEnabled = title.count > 0 && url.count > 0 + } } diff --git a/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift b/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift index 2e14f2799e71227310c8e866454559cd22f0a6f5..8d031f7e8e297aef2242ed5ff3919331f3420641 100644 --- a/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift +++ b/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift @@ -26,6 +26,7 @@ class WebBrowserViewController: UIViewController, UIWebViewDelegate, UIAlertView @IBOutlet var globeButton: UIBarButtonItem! @IBOutlet var closeButton: UIBarButtonItem! + var navbarBackground: KMNavigationBarBackgroundView! var fontFamily = UIFont.systemFont(ofSize: UIFont.systemFontSize).fontName private var newFontFamily = "" @@ -54,42 +55,10 @@ class WebBrowserViewController: UIViewController, UIWebViewDelegate, UIAlertView webView.scalesPageToFit = true // Setup NavigationBar - let screenRect = UIScreen.main.bounds - let orientation = UIApplication.shared.statusBarOrientation - if UIDevice.current.userInterfaceIdiom == .phone { - let size = CGFloat.maximum(screenRect.size.height, screenRect.size.width) - if size > 568.0 { - // Navbar for iPhone 6 & 6 Plus - let image: UIImage - if UIInterfaceOrientationIsPortrait(orientation) { - image = #imageLiteral(resourceName: "kmwb-navbar-Portrait.png") - } else { - image = #imageLiteral(resourceName: "kmwb-navbar-Landscape-568h.png") - } - let bgImg = image.resizableImage( - withCapInsets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0), resizingMode: .stretch) - navBar.setBackgroundImage(bgImg, for: UIBarMetrics.default) - } else if size == 568 { - // Navbar for iPhone and iPod Touch with 4" Display - navBar.setBackgroundImage(#imageLiteral(resourceName: "kmwb-navbar-Portrait.png"), - for: UIBarMetrics.default) - navBar.setBackgroundImage(#imageLiteral(resourceName: "kmwb-navbar-Landscape-568h.png"), - for: UIBarMetrics.compact) - } else if size < 568.0 { - // Navbar for iPhone and iPod Touch with 3.5" Display - navBar.setBackgroundImage(#imageLiteral(resourceName: "kmwb-navbar-Portrait.png"), - for: UIBarMetrics.default) - navBar.setBackgroundImage(#imageLiteral(resourceName: "kmwb-navbar-Landscape.png"), - for: UIBarMetrics.compact) - } - } else { - // Navbar for iPad - if UIInterfaceOrientationIsPortrait(orientation) { - navBar.setBackgroundImage(#imageLiteral(resourceName: "kmwb-navbar-Portrait.png"), for: UIBarMetrics.default) - } else { - navBar.setBackgroundImage(#imageLiteral(resourceName: "kmwb-navbar-Landscape.png"), for: UIBarMetrics.default) - } - } + navbarBackground = KMNavigationBarBackgroundView() + navbarBackground.hideLogo() + navbarBackground.addToNavbar(navBar) + navbarBackground.setOrientation(UIApplication.shared.statusBarOrientation) // Setup address field let addressFrame = CGRect(x: 10, y: 4.0, width: navBar.frame.size.width - 20, height: 28) @@ -146,31 +115,8 @@ class WebBrowserViewController: UIViewController, UIWebViewDelegate, UIAlertView } override func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) { - let orientation: UIInterfaceOrientation = toInterfaceOrientation - if UIDevice.current.userInterfaceIdiom == .phone { - let screenRect = UIScreen.main.bounds - let size = CGFloat.maximum(screenRect.size.width, screenRect.size.height) - if size > 568.0 { - // TODO: Refactor since duplicated in viewDidLoad() - // Navbar for iPhone 6 & 6 Plus - let image: UIImage - if UIInterfaceOrientationIsPortrait(orientation) { - image = #imageLiteral(resourceName: "kmwb-navbar-Portrait.png") - } else { - image = #imageLiteral(resourceName: "kmwb-navbar-Landscape-568h.png") - } - let bgImg = image.resizableImage( - withCapInsets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0), resizingMode: .stretch) - navigationController?.navigationBar.setBackgroundImage(bgImg, for: UIBarMetrics.default) - } - } else { - let image: UIImage - if UIInterfaceOrientationIsPortrait(orientation) { - image = #imageLiteral(resourceName: "kmwb-navbar-Portrait.png") - } else { - image = #imageLiteral(resourceName: "kmwb-navbar-Landscape.png") - } - navigationController?.navigationBar.setBackgroundImage(image, for: UIBarMetrics.default) + if let navbarBackground = navbarBackground { + navbarBackground.setOrientation(toInterfaceOrientation) } } @@ -179,8 +125,16 @@ class WebBrowserViewController: UIViewController, UIWebViewDelegate, UIAlertView } @objc func loadAddress(_ sender: Any, event: UIEvent) { - guard let urlString = addressField?.text, var url = URL(string: urlString) else { - log.debug("Attempting to load invalid URL: \(addressField?.text ?? "nil")") + if let urlString = addressField?.text { + loadUrlString(urlString) + } + } + + func loadUrlString(_ urlString: String, allowSearchRedirect: Bool = true) { + guard var url = URL(string: urlString) else { + if allowSearchRedirect { + loadSearchString(urlString) + } return } if url.scheme == nil { @@ -189,6 +143,12 @@ class WebBrowserViewController: UIViewController, UIWebViewDelegate, UIAlertView let request = URLRequest(url: url) webView.loadRequest(request) } + + func loadSearchString(_ searchString: String) { + if let query = searchString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) { + loadUrlString("google.com/search?q=\(query)", allowSearchRedirect: false) + } + } func updateAddress(_ request: URLRequest) { let url: URL? = request.mainDocumentURL @@ -249,12 +209,13 @@ class WebBrowserViewController: UIViewController, UIWebViewDelegate, UIAlertView func webView(_ webView: UIWebView, didFailLoadWithError error: Error) { UIApplication.shared.isNetworkActivityIndicatorVisible = false updateButtons() - let alert = UIAlertView(title: "Cannot Open Page", - message: error.localizedDescription, - delegate: self, - cancelButtonTitle: "OK", - otherButtonTitles: "") - alert.show() + let alertController = UIAlertController(title: "Cannot Open Page", + message: error.localizedDescription, + preferredStyle: UIAlertControllerStyle.alert) + alertController.addAction(UIAlertAction(title: "OK", + style: UIAlertActionStyle.default, + handler: nil)) + self.present(alertController, animated: true, completion: nil) } private func updateButtons() { diff --git a/ios/keyman/Keyman/Keyman/Keyman Navbar/keyman_logo@3x.png b/ios/keyman/Keyman/Keyman/Keyman Navbar/keyman_logo@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..2b34ddf36192ad38d080cb2e390e240f4414cf6e Binary files /dev/null and b/ios/keyman/Keyman/Keyman/Keyman Navbar/keyman_logo@3x.png differ diff --git a/ios/keyman/Keyman/Keyman/MainViewController.swift b/ios/keyman/Keyman/Keyman/MainViewController.swift index 883b67652273344ce8a7dc268b19a5aae2c1df3e..b0451731b40d2b9d7d163fe16e9732ccf6cfaef5 100644 --- a/ios/keyman/Keyman/Keyman/MainViewController.swift +++ b/ios/keyman/Keyman/Keyman/MainViewController.swift @@ -22,7 +22,7 @@ let dontShowGetStartedKey = "DontShowGetStarted" let launchedFromUrlNotification = NSNotification.Name("LaunchedFromUrlNotification") let urlKey = "url" -class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDelegate, UIAlertViewDelegate { +class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDelegate { private let minTextSize: CGFloat = 9.0 private let maxTextSize: CGFloat = 72.0 private let getStartedViewTag = 7183 @@ -31,6 +31,7 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg var textView: TextView! var textSize: CGFloat = 0.0 + var navbarBackground: KMNavigationBarBackgroundView! private var getStartedVC: GetStartedViewController! private var infoView: InfoViewController! @@ -135,10 +136,6 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg automaticallyAdjustsScrollViewInsets = false let systemFonts = Set(UIFont.familyNames) - let screenRect = UIScreen.main.bounds - let orientation = UIApplication.shared.statusBarOrientation - screenWidth = screenRect.size.width - screenHeight = screenRect.size.height // Setup Keyman Manager & fetch keyboards list Manager.shared.canRemoveDefaultKeyboard = true @@ -169,47 +166,15 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg } // Setup NavigationBar - // TODO: refactor - if UIDevice.current.userInterfaceIdiom == .phone { - let size = CGFloat.maximum(screenRect.width, screenRect.height) - if size > 568.0 { - // Navbar for iPhone 6 & 6 Plus - let image: UIImage - if UIInterfaceOrientationIsPortrait(orientation) { - image = #imageLiteral(resourceName: "navbar-Portrait.png") - } else { - image = #imageLiteral(resourceName: "navbar-Landscape-568h.png") - } - let bgImg = image.resizableImage(withCapInsets: - UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0), resizingMode: .stretch) - navigationController?.navigationBar.setBackgroundImage(bgImg, for: UIBarMetrics.default) - } else if size == 568 { - // Navbar for iPhone and iPod Touch with 4" Display - navigationController?.navigationBar.setBackgroundImage(#imageLiteral(resourceName: "navbar-Portrait.png"), - for: UIBarMetrics.default) - navigationController?.navigationBar.setBackgroundImage(#imageLiteral(resourceName: "navbar-Landscape-568h.png"), - for: UIBarMetrics.compact) - } else if size < 568.0 { - // Navbar for iPhone and iPod Touch with 3.5" Display - navigationController?.navigationBar.setBackgroundImage(#imageLiteral(resourceName: "navbar-Portrait.png"), - for: UIBarMetrics.default) - navigationController?.navigationBar.setBackgroundImage(#imageLiteral(resourceName: "navbar-Landscape.png"), - for: UIBarMetrics.compact) - } - } else { - // Navbar for iPad - if UIInterfaceOrientationIsPortrait(orientation) { - navigationController?.navigationBar.setBackgroundImage( - #imageLiteral(resourceName: "navbar-Portrait.png"), for: UIBarMetrics.default) - } else { - navigationController?.navigationBar.setBackgroundImage( - #imageLiteral(resourceName: "navbar-Landscape.png"), for: UIBarMetrics.default) - } + if let navbar = navigationController?.navigationBar { + navbarBackground = KMNavigationBarBackgroundView() + navbarBackground.addToNavbar(navbar) + navbarBackground.setOrientation(UIApplication.shared.statusBarOrientation) } // Setup Keyman TextView textSize = 16.0 - textView = TextView(frame: screenRect) + textView = TextView(frame: view.frame) textView.setKeymanDelegate(self) textView.viewController = self textView.backgroundColor = bgColor @@ -375,29 +340,10 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg }, completion: nil) } - // TODO: Refactor - if UIDevice.current.userInterfaceIdiom == .phone { - let screenRect = UIScreen.main.bounds - let size = CGFloat.maximum(screenRect.width, screenRect.height) - if size > 568.0 { - // Navbar for iPhone 6 & 6 Plus - let image: UIImage - if UIInterfaceOrientationIsPortrait(orientation) { - image = #imageLiteral(resourceName: "navbar-Portrait.png") - } else { - image = #imageLiteral(resourceName: "navbar-Landscape-568h.png") - } - let bgImg = image.resizableImage(withCapInsets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0), - resizingMode: .stretch) - navigationController?.navigationBar.setBackgroundImage(bgImg, for: UIBarMetrics.default) - } - } else { - if UIInterfaceOrientationIsPortrait(orientation) { - navigationController?.navigationBar.setBackgroundImage(#imageLiteral(resourceName: "navbar-Portrait.png"), for: UIBarMetrics.default) - } else { - navigationController?.navigationBar.setBackgroundImage(#imageLiteral(resourceName: "navbar-Landscape.png"), for: UIBarMetrics.default) - } + if let navbarBackground = navbarBackground { + navbarBackground.setOrientation(toInterfaceOrientation) } + popover?.dismiss(animated: false) _ = dismissDropDownMenu() } @@ -495,7 +441,7 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg for keyboard in keyboards { Manager.shared.addKeyboard(keyboard) - Manager.shared.setKeyboard(keyboard) + _ = Manager.shared.setKeyboard(keyboard) } launchUrl = nil @@ -505,8 +451,7 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg if launchUrl != nil { perform(#selector(self.dismissActivityIndicator), with: nil, afterDelay: 1.0) let error = notification.error - showAlert(withTitle: "Keyboard Download Error", message: error.localizedDescription, - cancelButtonTitle: "OK", otherButtonTitles: nil, tag: -1) + appDelegate.showSimpleAlert(title: "Keyboard Download Error", message: error.localizedDescription) launchUrl = nil } } @@ -850,8 +795,8 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg if let urlString = params["url"] { // Download and set custom keyboard guard let url = URL(string: urlString) else { - showAlert(withTitle: "Custom Keyboard", message: "The keyboard could not be installed: Invalid Url", - cancelButtonTitle: "OK", otherButtonTitles: nil, tag: -1) + appDelegate.showSimpleAlert(title: "Custom Keyboard", + message: "The keyboard could not be installed: Invalid Url") launchUrl = nil return } @@ -863,8 +808,9 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg customKeyboardToDownload = url let title = "Custom Keyboard: \(url.lastPathComponent)" - showAlert(withTitle: title, message: "Would you like to install this keyboard?", - cancelButtonTitle: "Cancel", otherButtonTitles: "Install", tag: 2) + confirmInstall(withTitle: title, message: "Would you like to install this keyboard?", + cancelButtonHandler: showGetStartedIfNeeded, + installButtonHandler: proceedWithCustomKeyboardDownload) } else if let kbID = params["keyboard"], let langID = params["language"] { // Query should include keyboard and language IDs to set the keyboard (first download if not available) guard let keyboard = Manager.shared.apiKeyboardRepository.installableKeyboard(withID: kbID, @@ -874,12 +820,12 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg if Manager.shared.stateForKeyboard(withID: kbID) == .needsDownload { keyboardToDownload = keyboard - showAlert(withTitle: "\(keyboard.languageName): \(keyboard.name)", + confirmInstall(withTitle: "\(keyboard.languageName): \(keyboard.name)", message: "Would you like to install this keyboard?", - cancelButtonTitle: "Cancel", otherButtonTitles: "Install", tag: 0) + installButtonHandler: proceedWithKeyboardDownload) } else { Manager.shared.addKeyboard(keyboard) - Manager.shared.setKeyboard(keyboard) + _ = Manager.shared.setKeyboard(keyboard) } } else { launchUrl = nil @@ -927,7 +873,9 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg let languageName = keyboard.languageName let title = "\(languageName) Font" let msg = "Touch Install to make \(languageName) display correctly in all your apps" - showAlert(withTitle: title, message: msg, cancelButtonTitle: "Cancel", otherButtonTitles: "Install", tag: 1) + confirmInstall(withTitle: title, message: msg, + cancelButtonHandler: handleUserDecisionAboutInstallingProfile, + installButtonHandler: handleUserDecisionAboutInstallingProfile) } else { profileName = nil } @@ -937,55 +885,53 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg textView.becomeFirstResponder() } - private func showAlert(withTitle title: String, message msg: String, cancelButtonTitle cbTitle: String?, - otherButtonTitles obTitles: String?, tag: Int) { + private func confirmInstall(withTitle title: String, message msg: String, + cancelButtonHandler cbHandler: ((UIAlertAction) -> Swift.Void)? = nil, + installButtonHandler installHandler: ((UIAlertAction) -> Swift.Void)?) { dismissGetStartedView(nil) - let alertView = UIAlertView(title: title, message: msg, delegate: self, cancelButtonTitle: cbTitle, - otherButtonTitles: obTitles ?? "") - alertView.tag = tag - alertView.show() + + let alertController = UIAlertController(title: title, message: msg, + preferredStyle: UIAlertControllerStyle.alert) + alertController.addAction(UIAlertAction(title: "Cancel", + style: UIAlertActionStyle.cancel, + handler: cbHandler)) + alertController.addAction(UIAlertAction(title: "Install", + style: UIAlertActionStyle.default, + handler: installHandler)) + + self.present(alertController, animated: true, completion: nil) + } + + private func proceedWithKeyboardDownload(withAction action: UIAlertAction) { + if let keyboard = keyboardToDownload { + Manager.shared.downloadKeyboard(withID: keyboard.id, languageID: keyboard.languageID, isUpdate: false) + } } - private func performAlertButtonClick(withTag tag: Int) { - switch tag { - case 0: - if let keyboard = keyboardToDownload { - Manager.shared.downloadKeyboard(withID: keyboard.id, languageID: keyboard.languageID, isUpdate: false) - } - case 1: - if let profileName = profileName { - checkedProfiles.append(profileName) - let userData = AppDelegate.activeUserDefaults() - userData.set(checkedProfiles, forKey: checkedProfilesKey) - userData.synchronize() + private func handleUserDecisionAboutInstallingProfile(withAction action: UIAlertAction) { + if let profileName = profileName { + checkedProfiles.append(profileName) + let userData = AppDelegate.activeUserDefaults() + userData.set(checkedProfiles, forKey: checkedProfilesKey) + userData.synchronize() + if action.style == .default { UIApplication.shared.openURL(URL(string: "\(baseUri)\(profileName)")!) - self.profileName = nil } - case 2: - if let url = customKeyboardToDownload { - Manager.shared.downloadKeyboard(from: url) - } - default: - break + self.profileName = nil } } - func alertView(_ alertView: UIAlertView, clickedButtonAt buttonIndex: Int) { - if buttonIndex != alertView.cancelButtonIndex { - performAlertButtonClick(withTag: alertView.tag) + private func proceedWithCustomKeyboardDownload(withAction action: UIAlertAction) { + if let url = customKeyboardToDownload { + Manager.shared.downloadKeyboard(from: url) } + showGetStartedIfNeeded(withAction: action) + } - if let profileName = profileName, alertView.tag == 1 { - checkedProfiles.append(profileName) - let userData = AppDelegate.activeUserDefaults() - userData.set(checkedProfiles, forKey: checkedProfilesKey) - userData.synchronize() - self.profileName = nil - } else if alertView.tag == 2 { - if shouldShowGetStarted { - showGetStartedView(nil) - } + private func showGetStartedIfNeeded(withAction action: UIAlertAction) { + if shouldShowGetStarted { + showGetStartedView(nil) } } diff --git a/ios/keyman/Keyman/Settings.bundle/Root.plist b/ios/keyman/Keyman/Settings.bundle/Root.plist index ab5a2c6f63d83bb4248970fa616ba6838afd3b4a..57514b906575b6b4f83a97cc4bc10366c6fff438 100644 --- a/ios/keyman/Keyman/Settings.bundle/Root.plist +++ b/ios/keyman/Keyman/Settings.bundle/Root.plist @@ -6,7 +6,7 @@ DefaultValue - 2.5.2 (build 2.5.120) + 10.0.0 (build 10.0.0) Key version_no Title diff --git a/ios/keymanios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/keymanios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000000000000000000000000000000000..18d981003d68d0546c4804ac2ff47dd97c6e7921 --- /dev/null +++ b/ios/keymanios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/linux/LICENSE.md b/linux/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..1a8c4e35aa9f379a1a60176464b7d0cb7b7ea9d4 --- /dev/null +++ b/linux/LICENSE.md @@ -0,0 +1,4 @@ +The [kmflcomp](./kmflcomp) and [libkmfl](./libkmfl) projects are covered by the [MIT license](./libkmfl/COPYING) + +The [ibus-kmfl](./ibus-kmfl) project is licensed under GNU General Public License as published by the Free Software Foundation; either [version 2 of the License](./ibus-kmfl/COPYING), or (at your option) any later version. +2 files in ibus-kmfl, [kmflutil.c](./ibus-kmfl/src/kmflutil.c) and [kmflutil.h](./ibus-kmfl/src/kmflutil.h) are dual licensed by the MIT license and the GNU General Public License which is described above. They MIT license alone may be chosen for them for their use in other projects. diff --git a/linux/README.md b/linux/README.md index 38e54ed250ad8c1766c7a9258fc8efee328500ff..dc8232027d6475ef8fb9a74fbdef96859ff875ad 100644 --- a/linux/README.md +++ b/linux/README.md @@ -2,11 +2,13 @@ ## Projects - * kmflcomp - KMFL keyboard compiler - * libkmfl - core library - * ibus-kmfl - IBUS integration to use KMFL + * [kmflcomp](./kmflcomp) - KMFL keyboard compiler + * [libkmfl](./libkmfl) - core library + * [ibus-kmfl](./ibus-kmfl) - IBUS integration to use KMFL * scim\_kmfl\_imengine - deprecated SCIM engine to use KMFL + See [license information](./LICENSE.md) about licensing. + ## Linux Requirements/Setup - It is helpful to be using the [packages.sil.org](http://packages.sil.org) repo @@ -134,4 +136,4 @@ Use `Win-space` to switch between keyboards. * Click `Add` to add a keyman keyboard. * Click the 3 dots expander then search for "Other" and click it * The Keyman keyboards should be listed here to choose - \ No newline at end of file + diff --git a/linux/ibus-kmfl/debian/copyright b/linux/ibus-kmfl/debian/copyright index 57a17a3f76978809be9731787ffe8609caf21ab2..825997310d3a7f5916898296d3b56aaf3436b1a8 100644 --- a/linux/ibus-kmfl/debian/copyright +++ b/linux/ibus-kmfl/debian/copyright @@ -3,11 +3,16 @@ Upstream-Name: ibus-kmfl Upstream-Contact: Doug Rintoul Files: * -Copyright: 2004-2016 by SIL Intl +Copyright: 2004-2018 SIL International License: GPL-2+ +Files: src/kmflutil.c + src/kmflutil.h +Copyright: 2009-2018 SIL International +License: GPL-2+ or MIT + Files: debian/* -Copyright: 2004-2016 by SIL Intl +Copyright: 2004-2018 SIL International License: GPL-2+ License: GPL-2+ @@ -28,3 +33,24 @@ License: GPL-2+ On Debian systems, the full text of the GNU General Public License version 2 can be found in the file `/usr/share/common-licenses/GPL-2'. + +License: MIT + 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, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + . + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + . + 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. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/linux/ibus-kmfl/src/engine.c b/linux/ibus-kmfl/src/engine.c index b7e0275b69b9587bac987f6980aa005b4ed57b5e..5b825359d7b37b5d8057aee17379762e09a37406 100644 --- a/linux/ibus-kmfl/src/engine.c +++ b/linux/ibus-kmfl/src/engine.c @@ -100,93 +100,6 @@ static IBusEngineClass *parent_class = NULL; static GHashTable *im_table = NULL; -void output_string(void *contrack, char *ptr) { - KInputContext * ic = (KInputContext *)contrack; - g_debug("DAR: output_string - ic->cmds=%p", ic->cmds); - if (ptr) { - Cmd * cmd = g_new(Cmd, 1); - cmd->opcode=OUTPUT_STRING; - cmd->cmdarg=g_strdup(ptr); - ic->cmds = g_list_append(ic->cmds, cmd); - } -} - -void erase_char(void *contrack) { - KInputContext * ic = (KInputContext *)contrack; - g_debug("DAR: erase_char - ic->cmds=%p", ic->cmds); - Cmd * cmd = g_new(Cmd, 1); - cmd->opcode = ERASE_CHAR; - cmd->cmdarg=NULL; - ic->cmds = g_list_append(ic->cmds, cmd); -} - -void output_char(void *contrack, unsigned char byte) { - if (byte == 8) { - erase_char(contrack); - } else { - char s[2]; - s[0] = byte; - s[1] = '\0'; - output_string(contrack, s); - } -} - -void forward_keyevent(void *contrack, unsigned int key, unsigned int state) -{ - -} - -void output_beep(void *contrack) { - KInputContext * ic = (KInputContext *)contrack; - Cmd * cmd = g_new(Cmd, 1); - cmd->opcode = OUTPUT_BEEP; - cmd->cmdarg=NULL; - ic->cmds = g_list_append(ic->cmds, cmd); -} - -/* - * Create an input context - */ -KInputContext * -kmfl_create_ic(KInputMethod *im) -{ - KInputContext * ic; - g_debug("DAR: kmfl_create_ic"); - ic = g_new(KInputContext, 1); - ic->cmds = NULL; - ic->p_kmsi=kmfl_make_keyboard_instance(ic); - kmfl_attach_keyboard(ic->p_kmsi, im->keyboard_number); - - return ic; -} - - -/* - * Destroy an input context - */ -void -kmfl_destroy_ic(KInputContext *ic) -{ - GList * p; - g_debug("DAR: kmfl_destroy_ic"); - kmfl_detach_keyboard(ic->p_kmsi); - kmfl_delete_keyboard_instance(ic->p_kmsi); - - if (ic->cmds) { - for (p=ic->cmds; p != NULL; p = p->next) { - Cmd * cmd = (Cmd *)p->data; - if (cmd) { - if (cmd->cmdarg) - g_free(cmd->cmdarg); - g_free(cmd); - } - } - g_list_free(ic->cmds); - ic->cmds=NULL; - } - -} - GType ibus_kmfl_engine_get_type (void) { diff --git a/linux/ibus-kmfl/src/kmflutil.c b/linux/ibus-kmfl/src/kmflutil.c index 516df2e3eb7b54ac2f189bb28a4a4242660a8641..a2c21bfae0fc6e86b54b5047dbfeaa2cdcff043e 100644 --- a/linux/ibus-kmfl/src/kmflutil.c +++ b/linux/ibus-kmfl/src/kmflutil.c @@ -3,14 +3,42 @@ /* * KMFL Input Method for IBUS (The Input Bus) * - * Copyright (C) 2009 SIL International + * Copyright (C) 2009-2018 SIL International * - * This library is free software; you can redistribute it and/or + * kmflutil is dual licensed under the MIT or GPL licenses as described below. + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * MIT license + * + * 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, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * 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. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * OR + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * - * This library is distributed in the hope that it will be useful, + * This program 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 * General Public License for more details. @@ -21,6 +49,8 @@ * */ + + #include #include #include @@ -42,10 +72,9 @@ static gchar * get_dirname(const gchar * path) } } -GList * kmfl_get_keyboard_list( const gchar * path) +GList * kmfl_get_keyboard_fromdir( GList *keyboard_list, const gchar * path) { - GList * keyboard_list=NULL; - +// g_message("KMFL: getting from dir: %s", path); DIR *dir = opendir(path); if (dir != NULL) { @@ -55,14 +84,24 @@ GList * kmfl_get_keyboard_list( const gchar * path) gchar * absfn = g_strdup_printf("%s/%s", path, file->d_name); stat(absfn, &filestat); + if (S_ISDIR(filestat.st_mode)) + { + if(strcmp(file->d_name, ".") != 0 && strcmp(file->d_name, "..") != 0) + keyboard_list = kmfl_get_keyboard_fromdir(keyboard_list, absfn); + g_free(absfn); + } // Only .kmfl and .kmn extensions are valid keyboard files - if (S_ISREG(filestat.st_mode) + else if (S_ISREG(filestat.st_mode) && ((g_str_has_suffix(absfn, ".kmfl") && kmfl_check_keyboard(absfn) == 0) || g_str_has_suffix(absfn, ".kmn"))) { keyboard_list=g_list_append(keyboard_list, absfn); } + else + { + g_free(absfn); + } file = readdir(dir); } @@ -71,6 +110,13 @@ GList * kmfl_get_keyboard_list( const gchar * path) return keyboard_list; } +GList * kmfl_get_keyboard_list( const gchar * path) +{ + GList * keyboard_list=NULL; + keyboard_list = kmfl_get_keyboard_fromdir(keyboard_list, path); + return keyboard_list; +} + gchar * kmfl_get_icon_file(KInputMethod * im) { const char * icon_file = kmfl_icon_file(im->keyboard_number); @@ -212,21 +258,29 @@ ibus_kmfl_list_engines (void) gchar *local_keyboard_path; keyboard_list = kmfl_get_keyboard_list("/usr/share/kmfl"); + engines = ibus_kmfl_add_engines(engines, keyboard_list); + g_list_free(keyboard_list); + keyboard_list = kmfl_get_keyboard_list("/usr/share/keyman"); engines = ibus_kmfl_add_engines(engines, keyboard_list); + g_list_free(keyboard_list); + keyboard_list = kmfl_get_keyboard_list("/usr/local/share/keyman"); + engines = ibus_kmfl_add_engines(engines, keyboard_list); g_list_free(keyboard_list); local_keyboard_path= g_strdup_printf("%s/.kmfl", getenv("HOME")); - keyboard_list = kmfl_get_keyboard_list(local_keyboard_path); - engines = ibus_kmfl_add_engines(engines, keyboard_list); - g_free(local_keyboard_path); + g_list_free(keyboard_list); + local_keyboard_path= g_strdup_printf("%s/.local/share/keyman", getenv("HOME")); + keyboard_list = kmfl_get_keyboard_list(local_keyboard_path); + engines = ibus_kmfl_add_engines(engines, keyboard_list); + g_free(local_keyboard_path); g_list_free(keyboard_list); - + return engines; } @@ -280,6 +334,94 @@ void kinput_close_im(KInputMethod * im) g_free(im); } +void output_string(void *contrack, char *ptr) { + KInputContext * ic = (KInputContext *)contrack; + g_debug("DAR: output_string - ic->cmds=%p", ic->cmds); + if (ptr) { + Cmd * cmd = g_new(Cmd, 1); + cmd->opcode=OUTPUT_STRING; + cmd->cmdarg=g_strdup(ptr); + ic->cmds = g_list_append(ic->cmds, cmd); + } +} + +void erase_char(void *contrack) { + KInputContext * ic = (KInputContext *)contrack; + g_debug("DAR: erase_char - ic->cmds=%p", ic->cmds); + Cmd * cmd = g_new(Cmd, 1); + cmd->opcode = ERASE_CHAR; + cmd->cmdarg=NULL; + ic->cmds = g_list_append(ic->cmds, cmd); +} + +void output_char(void *contrack, unsigned char byte) { + if (byte == 8) { + erase_char(contrack); + } else { + char s[2]; + s[0] = byte; + s[1] = '\0'; + output_string(contrack, s); + } +} + +void forward_keyevent(void *contrack, unsigned int key, unsigned int state) +{ + +} + +void output_beep(void *contrack) { + KInputContext * ic = (KInputContext *)contrack; + Cmd * cmd = g_new(Cmd, 1); + cmd->opcode = OUTPUT_BEEP; + cmd->cmdarg=NULL; + ic->cmds = g_list_append(ic->cmds, cmd); +} + + +/* + * Create an input context + */ +KInputContext * +kmfl_create_ic(KInputMethod *im) +{ + KInputContext * ic; + g_debug("DAR: kmfl_create_ic"); + ic = g_new(KInputContext, 1); + ic->cmds = NULL; + ic->p_kmsi=kmfl_make_keyboard_instance(ic); + kmfl_attach_keyboard(ic->p_kmsi, im->keyboard_number); + + return ic; +} + + +/* + * Destroy an input context + */ +void +kmfl_destroy_ic(KInputContext *ic) +{ + GList * p; + g_debug("DAR: kmfl_destroy_ic"); + kmfl_detach_keyboard(ic->p_kmsi); + kmfl_delete_keyboard_instance(ic->p_kmsi); + + if (ic->cmds) { + for (p=ic->cmds; p != NULL; p = p->next) { + Cmd * cmd = (Cmd *)p->data; + if (cmd) { + if (cmd->cmdarg) + g_free(cmd->cmdarg); + g_free(cmd); + } + } + g_list_free(ic->cmds); + ic->cmds=NULL; + } + +} + #ifdef DEBUG #include diff --git a/linux/ibus-kmfl/src/kmflutil.h b/linux/ibus-kmfl/src/kmflutil.h index 3da445aeb90423e5b75452494dc53f85445f0829..3937aa8aa217375b426f75bf218c848ce8aa88aa 100644 --- a/linux/ibus-kmfl/src/kmflutil.h +++ b/linux/ibus-kmfl/src/kmflutil.h @@ -3,14 +3,42 @@ /* * KMFL Input Method for IBUS (The Input Bus) * - * Copyright (C) 2009 SIL International + * Copyright (C) 2009-2018 SIL International * - * This library is free software; you can redistribute it and/or + * kmflutil is dual licensed under the MIT or GPL licenses as described below. + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * MIT license + * + * 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, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * 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. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * OR + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * - * This library is distributed in the hope that it will be useful, + * This program 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 * General Public License for more details. @@ -47,6 +75,7 @@ typedef struct int keyboard_number; gchar * keyboard_filename; gchar * keyboard_icon_filename; + gchar * keyboard_id; gchar * keyboard_name; gchar * keyboard_language; gchar * keyboard_author; @@ -61,6 +90,8 @@ void ibus_kmfl_init (void); GList *ibus_kmfl_list_engines (void); IBusComponent *ibus_kmfl_get_component (void); KInputMethod *kinput_open_im (const gchar * keyboard_filename); +KInputContext *kmfl_create_ic (KInputMethod *im); +void kmfl_destroy_ic (KInputContext *ic); void kinput_close_im (KInputMethod * im); void kmfl_get_keyboard_info (KInputMethod * im); #endif diff --git a/linux/kmflcomp/COPYING b/linux/kmflcomp/COPYING index d60c31a97a544b53039088d14fe9114583c0efc3..4587de8ab2d92f28bd11d013904a7efaa87f3391 100644 --- a/linux/kmflcomp/COPYING +++ b/linux/kmflcomp/COPYING @@ -1,340 +1,19 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the 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 Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. +Copyright (c) 2017 SIL International + +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, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/linux/kmflcomp/ChangeLog b/linux/kmflcomp/ChangeLog index 58a9cecf593275045156fdbd8d8a5ffbd047f10d..e71f61f0124e56712eda8eb9e6791824621daf93 100644 --- a/linux/kmflcomp/ChangeLog +++ b/linux/kmflcomp/ChangeLog @@ -1,3 +1,10 @@ +kmflcomp (10.99.1-1) + + * Change license to MIT as it is being moved into Keyman 11 + * Keyman is now owned by SIL + + -- Doug Rintoul Thu, 17 May 2018 11:43:22 +0700 + kmflcomp (0.9.10-1) * fix bug in processing special stores when special store name is invalid diff --git a/linux/kmflcomp/Makefile.am b/linux/kmflcomp/Makefile.am index c833351d7d9ff8cac4ba78e64d2e05fb6dc473bf..dfdd4d0b2cc041ef3fc7cb311c0bb68b5ea1b33b 100644 --- a/linux/kmflcomp/Makefile.am +++ b/linux/kmflcomp/Makefile.am @@ -5,7 +5,7 @@ SUBDIRS = include src kmfl_compiler -kmflcompdocdir = ${prefix}/doc/kmflcomp +kmflcompdocdir = ${docdir} kmflcompdoc_DATA = \ README\ COPYING\ diff --git a/linux/kmflcomp/configure.ac b/linux/kmflcomp/configure.ac index fc914039fa1696fc755ac0e259ace9a2fce030e7..51d90a4a1e808617c20dcc1eddcbe872695665d2 100644 --- a/linux/kmflcomp/configure.ac +++ b/linux/kmflcomp/configure.ac @@ -14,7 +14,7 @@ AC_PROG_CC AM_PROG_CC_STDC AM_PROG_CC_C_O AC_HEADER_STDC -AM_PROG_LIBTOOL +AC_PROG_LIBTOOL AM_PROG_LEX AC_PROG_YACC AC_YACC_EXPECT diff --git a/linux/kmflcomp/debian/changelog b/linux/kmflcomp/debian/changelog index 441bf47f6960f12a29a5af3f78a4eda90754ffbd..96d2e442c4fecf46777b67931cc0965a89cecfea 100644 --- a/linux/kmflcomp/debian/changelog +++ b/linux/kmflcomp/debian/changelog @@ -1,3 +1,10 @@ +kmflcomp (10.99.1-1) UNRELEASED; urgency=medium + + * Change license to MIT as kmflcomp is being moved into Keyman 11 + * Keyman is now owned by SIL + + -- Daniel Glassey Thu, 17 May 2018 11:39:04 +0700 + kmflcomp (0.9.10-1) unstable; urgency=low * new upstream release diff --git a/linux/kmflcomp/debian/copyright b/linux/kmflcomp/debian/copyright index e1f4b8fc4fe75d101147682dd0076718e89460fc..15a473225097358e08358e12e636ca5eb4353542 100644 --- a/linux/kmflcomp/debian/copyright +++ b/linux/kmflcomp/debian/copyright @@ -3,56 +3,35 @@ Upstream-Name: kmflcomp Upstream-Contact: Doug Rintoul Files: * -Copyright: Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd -License: GPL-2+-KMFL-C - This file is part of the KMFL compiler. - . - The KMFL compiler is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - . - The KMFL compiler 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 General Public License for more details. - . - You should have received a copy of the GNU General Public License - along with the KMFL compiler; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - . - On Debian systems, the full text of the GNU General Public - License version 2 can be found in the file - `/usr/share/common-licenses/GPL-2'. - -Files: src/utfconv.c - include/kmflutfconv.h -Copyright: Copyright (C) 2006 SIL International -License: GPL-2+-KMFL-L - This file is part of the KMFL library. - . - The KMFL library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - . - The KMFL library 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 - General Public License for more details. - . - You should have received a copy of the GNU General Public - License along with the KMFL library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - . - On Debian systems, the full text of the GNU General Public - License version 2 can be found in the file - `/usr/share/common-licenses/GPL-2'. +Copyright: Copyright (C) 2005-2018 SIL International +License: MIT Files: src/yacc.c src/yacc.h Copyright: Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. -License: GPL-2+ +License: GPL-2+ with Bison 2.2 exception + +License: MIT + 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, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + . + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + . + 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. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +License: GPL-2+ with Bison 2.2 exception This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) @@ -71,4 +50,17 @@ License: GPL-2+ On Debian systems, the full text of the GNU General Public License version 2 can be found in the file `/usr/share/common-licenses/GPL-2'. + . + As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + . + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. diff --git a/linux/kmflcomp/include/kmfl.h b/linux/kmflcomp/include/kmfl.h index 42d6bd4ebd93a2d0551bdba2b12037b80ea0513e..68463321330b8cd79842b919018ee2156193bc98 100644 --- a/linux/kmflcomp/include/kmfl.h +++ b/linux/kmflcomp/include/kmfl.h @@ -1,21 +1,25 @@ /* kmfl.h - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd + * Copyright (C) 2005 SIL International * - * This file is part of KMFL compiler. + * This file is part of the KMFL compiler. * - * KMFL compiler is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * 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, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * KMFL compiler 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with KMFL compiler; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * 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. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. * */ diff --git a/linux/kmflcomp/include/kmflcomp.h b/linux/kmflcomp/include/kmflcomp.h index e7a9e49a1d4159c196c111bb9dd4ffc43ef31121..8e6c4e61a811e7c9af6480c0389f47b98beef23e 100644 --- a/linux/kmflcomp/include/kmflcomp.h +++ b/linux/kmflcomp/include/kmflcomp.h @@ -1,21 +1,25 @@ /* kmflcomp.h - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd + * Copyright (C) 2005 SIL International * * This file is part of the KMFL compiler. * - * The KMFL compiler is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * 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, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The KMFL compiler 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with the KMFL compiler; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * 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. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. * */ diff --git a/linux/kmflcomp/include/kmflutfconv.h b/linux/kmflcomp/include/kmflutfconv.h index 112576d1a0fccbe0f22a551a6dbb8d8a69954bba..3d7158f747ffc1275b15084aba71502bf66b77ed 100644 --- a/linux/kmflcomp/include/kmflutfconv.h +++ b/linux/kmflcomp/include/kmflutfconv.h @@ -1,21 +1,25 @@ /* kmflutfconv.h * Copyright (C) 2006 SIL International * - * This file is part of the KMFL library. + * This file is part of the KMFL compiler. * - * The KMFL library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. + * 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, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The KMFL library 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 - * General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public - * License along with the KMFL library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * 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. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. * */ diff --git a/linux/kmflcomp/kmfl_compiler/kmfl_compiler.c b/linux/kmflcomp/kmfl_compiler/kmfl_compiler.c index bc02cddfe9025aa829d36901dd0d50efe4db3897..76a6dc36fb89d9db8520e9fd19866693691c1e1b 100644 --- a/linux/kmflcomp/kmfl_compiler/kmfl_compiler.c +++ b/linux/kmflcomp/kmfl_compiler/kmfl_compiler.c @@ -3,22 +3,8 @@ * * This file is part of KMFL compiler. * - * KMFL compiler is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * KMFL compiler 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with KMFL compiler; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - * */ -const char * VERSION= "0.9.10"; +const char * VERSION= "10.99.1"; #include #include diff --git a/linux/kmflcomp/kmflcomp.prj b/linux/kmflcomp/kmflcomp.prj deleted file mode 100644 index 84cf6a6c8b190aae81060920c96fe035d0523b3a..0000000000000000000000000000000000000000 --- a/linux/kmflcomp/kmflcomp.prj +++ /dev/null @@ -1,115 +0,0 @@ -# Anjuta Version 1.2.1 -Compatibility Level: 1 - - -Compile Keyman-style keyboard layout files to a binary format for use by the KMFL keystroke interpreter. - - - - - - - - - - - - - - - - - -props.file.type=project - -anjuta.version=1.2.1 -anjuta.compatibility.level=1 - -project.name=kmflcomp -project.type=GENERIC -project.target.type=EXECUTABLE -project.version=0.3 -project.author=John Durdin -project.source.target=kmflcomp -project.has.gettext=0 -project.gui.command= -project.programming.language=C -project.excluded.modules=intl - -project.config.extra.modules.before= -project.config.extra.modules.after= -project.config.blocked=0 -project.config.disable.overwriting=1 0 1 0 0 0 0 0 0 - -project.menu.entry=kmflcomp Version 0.3 -project.menu.group=Applications -project.menu.comment=kmflcomp Version 0.3 -project.menu.icon= -project.menu.need.terminal=0 - -project.configure.options= -anjuta.program.arguments= -preferences.build.option.jobs=0 -preferences.build.option.silent=0 -preferences.build.option.autosave=0 -preferences.anjuta.make.options=-k -preferences.make=make -preferences.build.option.keep.going=1 -preferences.build.option.warn.undef=0 -preferences.autoformat.custom.style= -i8 -sc -bli0 -bl0 -cbi0 -ss -preferences.indent.opening=0 -preferences.autoformat.disable=1 -preferences.indent.automatic=1 -preferences.use.tabs=1 -preferences.indent.size=4 -preferences.tabsize=4 -preferences.indent.closing=0 - -module.include.name=include -module.include.type= -module.include.files= - -module.source.name=src -module.source.type= -module.source.files=\ - ConvertUTF.c\ - kmfl_compiler.c\ - lex.l\ - yacc.y\ - compiler.h - -module.pixmap.name=pixmaps -module.pixmap.type= -module.pixmap.files= - -module.data.name=data -module.data.type= -module.data.files= - -module.help.name=help -module.help.type= -module.help.files= - -module.doc.name=doc -module.doc.type= -module.doc.files= - -module.po.files= - -compiler.options.supports= -compiler.options.include.paths=\ - /home/john/Projects/kmflcomp/include/\ - /usr/local/include/libkmfl/ -compiler.options.library.paths= -compiler.options.libraries= -compiler.options.libraries.selected= -compiler.options.defines= -compiler.options.defines.selected= -compiler.options.warning.buttons=0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 -compiler.options.optimize.buttons=1 0 0 0 -compiler.options.other.buttons=1 0 -compiler.options.other.c.flags= -compiler.options.other.l.flags= -compiler.options.other.l.libs= - -project.src.paths= diff --git a/linux/kmflcomp/kmflcomp.pws b/linux/kmflcomp/kmflcomp.pws deleted file mode 100644 index 99be5a89f5369989ed567ece4555cab3bbcfa00c..0000000000000000000000000000000000000000 --- a/linux/kmflcomp/kmflcomp.pws +++ /dev/null @@ -1,41 +0,0 @@ - -[filenumbers] -0=1279 -1=42 -2=5 -3=1 -4=297 -5=1 -6=149 - -[filemarkers] -0=1279, -1= -2= -3= -4= -5= -6= - -[File View] -filter.file.unmatch=*.so *.o *.a *.la -filter.file.ignore.hidden=0 -filter.dir.ignore.hidden=0 - -[executer] -RunInTerminal=true - -[Project State] -clean before build=false - -[Project Tree] -0=0 -1=0:0 - -[Symbol Tree] -0=3 - -[File Tree] -0=0 -1=0:2 -2=0:4 diff --git a/linux/kmflcomp/kmflcomp.rbc b/linux/kmflcomp/kmflcomp.rbc deleted file mode 100644 index c29a3f115e77675cd8a8dedbeab1a7a085b3e3e2..0000000000000000000000000000000000000000 --- a/linux/kmflcomp/kmflcomp.rbc +++ /dev/null @@ -1,53 +0,0 @@ - - - - 1.0 - kmflcomp - 0.3 - - - kmflcomp - 0.3 - 1 - User <Email> - User <Email> - GPL - i386 - /var/tmp/kmflcomp - /usr - %{name}-%{version}.tar.gz - AUTHORS -COPYING -ChangeLog -README -INSTALL -NEWS -TODO - - - - - - - - - False - False - %base% - Applications/System - %{name} - libkmfl - kmflcomp - %anjuta% - %{_bindir}/kmflcomp - - - diff --git a/linux/kmflcomp/src/compiler.h b/linux/kmflcomp/src/compiler.h old mode 100755 new mode 100644 index 5fe78b0fb9590320b0dae0e258d6c11d3429bcd0..5272b875bd6e8c2188d0d9df007adf54e0a8d402 --- a/linux/kmflcomp/src/compiler.h +++ b/linux/kmflcomp/src/compiler.h @@ -1,21 +1,5 @@ /* compiler.h - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd - * - * This file is part of the KMFL compiler. - * - * The KMFL compiler is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The KMFL compiler 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the KMFL compiler; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * Copyright (C) 2005 SIL International * */ diff --git a/linux/kmflcomp/src/kmflcomp.c b/linux/kmflcomp/src/kmflcomp.c index 1a094dc664d02a534b8e87621cf281317f4d1072..b6ba93c160b72e1219a33665a91a6da573404f50 100644 --- a/linux/kmflcomp/src/kmflcomp.c +++ b/linux/kmflcomp/src/kmflcomp.c @@ -1,21 +1,5 @@ /* kmflcomp.c - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd - * - * This file is part of the KMFL compiler. - * - * The KMFL compiler is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The KMFL compiler 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the KMFL compiler; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * Copyright (C) 2005 SIL International * */ diff --git a/linux/kmflcomp/src/lex.c b/linux/kmflcomp/src/lex.c index 26d0bcff30c5f6769eb4bca11646677741e5fe10..46a32ec9565729ab5f92278284aa8f2461698d90 100644 --- a/linux/kmflcomp/src/lex.c +++ b/linux/kmflcomp/src/lex.c @@ -7,8 +7,8 @@ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 34 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 0 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif @@ -53,7 +53,6 @@ typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; -#endif /* ! C99 */ /* Limits of integral types. */ #ifndef INT8_MIN @@ -84,6 +83,8 @@ typedef unsigned int flex_uint32_t; #define UINT32_MAX (4294967295U) #endif +#endif /* ! C99 */ + #endif /* ! FLEXINT_H */ #ifdef __cplusplus @@ -140,7 +141,15 @@ typedef unsigned int flex_uint32_t; /* Size of default input buffer. */ #ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else #define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. @@ -152,7 +161,12 @@ typedef unsigned int flex_uint32_t; typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif -extern int yyleng; +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +extern yy_size_t yyleng; extern FILE *yyin, *yyout; @@ -161,6 +175,7 @@ extern FILE *yyin, *yyout; #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) + #define YY_LINENO_REWIND_TO(ptr) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ @@ -178,18 +193,6 @@ extern FILE *yyin, *yyout; #define unput(c) yyunput( c, (yytext_ptr) ) -/* The following is because we cannot portably get our hands on size_t - * (without autoconf's help, which isn't available because we want - * flex-generated scanners to compile on their own). - * Given that the standard has decreed that size_t exists since 1989, - * I guess we can afford to depend on it. Manoj. - */ - -#ifndef YY_TYPEDEF_YY_SIZE_T -#define YY_TYPEDEF_YY_SIZE_T -typedef size_t yy_size_t; -#endif - #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state @@ -278,7 +281,7 @@ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ -int yyleng; +yy_size_t yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; @@ -306,7 +309,7 @@ static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); -YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ); void *yyalloc (yy_size_t ); void *yyrealloc (void *,yy_size_t ); @@ -336,7 +339,7 @@ void yyfree (void * ); #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) -#define yywrap(n) 1 +#define yywrap() (/*CONSTCOND*/1) #define YY_SKIP_YYWRAP typedef unsigned char YY_CHAR; @@ -350,11 +353,17 @@ extern int yylineno; int yylineno = 1; extern char *yytext; +#ifdef yytext_ptr +#undef yytext_ptr +#endif #define yytext_ptr yytext static yy_state_type yy_get_previous_state (void ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); static int yy_get_next_buffer (void ); +#if defined(__GNUC__) && __GNUC__ >= 3 +__attribute__((__noreturn__)) +#endif static void yy_fatal_error (yyconst char msg[] ); /* Done after the current pattern has been matched and before the @@ -461,7 +470,7 @@ static yyconst flex_int16_t yy_accept[738] = 14, 0, 11, 15, 14, 11, 0 } ; -static yyconst flex_int32_t yy_ec[256] = +static yyconst YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, @@ -493,7 +502,7 @@ static yyconst flex_int32_t yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst flex_int32_t yy_meta[82] = +static yyconst YY_CHAR yy_meta[82] = { 0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, @@ -506,7 +515,7 @@ static yyconst flex_int32_t yy_meta[82] = 5 } ; -static yyconst flex_int16_t yy_base[766] = +static yyconst flex_uint16_t yy_base[766] = { 0, 0, 77, 135, 0, 215, 219, 223, 227, 279, 357, 236, 247, 435, 492, 258, 289, 549, 0, 322, 336, @@ -682,7 +691,7 @@ static yyconst flex_int16_t yy_def[766] = 737, 737, 737, 737, 737 } ; -static yyconst flex_int16_t yy_nxt[2035] = +static yyconst flex_uint16_t yy_nxt[2035] = { 0, 24, 25, 26, 27, 25, 28, 29, 30, 31, 32, 33, 24, 24, 34, 34, 34, 34, 34, 34, 34, @@ -1152,8 +1161,8 @@ int yy_flex_debug = 0; #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *yytext; -#line 1 "lex.l" -#line 2 "lex.l" +#line 1 "../../kmflcomp/src/lex.l" +#line 2 "../../kmflcomp/src/lex.l" /* lex.l: Lex parser for Keyman keyboard source files for kmflcomp compiler */ /* Derived from version written by David Gardner for k_tty */ @@ -1199,7 +1208,7 @@ int yyterminate(void) -#line 1203 "lex.c" +#line 1212 "lex.c" #define INITIAL 0 #define STOR 1 @@ -1227,6 +1236,35 @@ int yyterminate(void) static int yy_init_globals (void ); +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy (void ); + +int yyget_debug (void ); + +void yyset_debug (int debug_flag ); + +YY_EXTRA_TYPE yyget_extra (void ); + +void yyset_extra (YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in (void ); + +void yyset_in (FILE * _in_str ); + +FILE *yyget_out (void ); + +void yyset_out (FILE * _out_str ); + +yy_size_t yyget_leng (void ); + +char *yyget_text (void ); + +int yyget_lineno (void ); + +void yyset_lineno (int _line_number ); + /* Macros after this point can all be overridden by user definitions in * section 1. */ @@ -1239,8 +1277,12 @@ extern int yywrap (void ); #endif #endif +#ifndef YY_NO_UNPUT + static void yyunput (int c,char *buf_ptr ); +#endif + #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ); #endif @@ -1261,7 +1303,12 @@ static int input (void ); /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else #define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ @@ -1269,7 +1316,7 @@ static int input (void ); /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ -#define ECHO fwrite( yytext, yyleng, 1, yyout ) +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, @@ -1280,7 +1327,7 @@ static int input (void ); if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ - int n; \ + size_t n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ @@ -1348,7 +1395,7 @@ extern int yylex (void); /* Code executed at the end of each rule. */ #ifndef YY_BREAK -#define YY_BREAK break; +#define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ @@ -1361,15 +1408,10 @@ extern int yylex (void); */ YY_DECL { - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; -#line 53 "lex.l" - - -#line 1372 "lex.c" - if ( !(yy_init) ) { (yy_init) = 1; @@ -1396,7 +1438,13 @@ YY_DECL yy_load_buffer_state( ); } - while ( 1 ) /* loops until end-of-file is reached */ + { +#line 53 "../../kmflcomp/src/lex.l" + + +#line 1446 "lex.c" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { yy_cp = (yy_c_buf_p); @@ -1413,7 +1461,7 @@ YY_DECL yy_match: do { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; @@ -1455,12 +1503,12 @@ do_action: /* This label is used only to access EOF actions. */ case 1: /* rule 1 can match eol */ YY_RULE_SETUP -#line 55 "lex.l" +#line 55 "../../kmflcomp/src/lex.l" {lineno++;caller=INITIAL;BEGIN(INITIAL);return(TOK_NL);} YY_BREAK case 2: YY_RULE_SETUP -#line 56 "lex.l" +#line 56 "../../kmflcomp/src/lex.l" {/* just ignore carriage returns */}; YY_BREAK case YY_STATE_EOF(INITIAL): @@ -1474,7 +1522,7 @@ case YY_STATE_EOF(BITMAP): case YY_STATE_EOF(LNGCODE): case YY_STATE_EOF(SKIP): case YY_STATE_EOF(NAME): -#line 58 "lex.l" +#line 58 "../../kmflcomp/src/lex.l" { if(done){yyterminate();} else {done=1;lineno++;caller=INITIAL;BEGIN(INITIAL);return(TOK_NL);} @@ -1482,187 +1530,187 @@ case YY_STATE_EOF(NAME): YY_BREAK case 3: YY_RULE_SETUP -#line 63 "lex.l" +#line 63 "../../kmflcomp/src/lex.l" {return TOK_NAME;} YY_BREAK case 4: YY_RULE_SETUP -#line 64 "lex.l" +#line 64 "../../kmflcomp/src/lex.l" {BEGIN(BITMAP);return TOK_BITMAP;} YY_BREAK case 5: YY_RULE_SETUP -#line 65 "lex.l" +#line 65 "../../kmflcomp/src/lex.l" {caller=STOR;BEGIN(STOR);return TOK_HOTKEY;} YY_BREAK case 6: YY_RULE_SETUP -#line 66 "lex.l" +#line 66 "../../kmflcomp/src/lex.l" {BEGIN(KBDVER);return TOK_VERSION;} YY_BREAK case 7: YY_RULE_SETUP -#line 67 "lex.l" +#line 67 "../../kmflcomp/src/lex.l" {BEGIN(LNGCODE);return TOK_LANGUAGE;} YY_BREAK case 8: YY_RULE_SETUP -#line 68 "lex.l" +#line 68 "../../kmflcomp/src/lex.l" {return TOK_LAYOUT;} YY_BREAK case 9: YY_RULE_SETUP -#line 69 "lex.l" +#line 69 "../../kmflcomp/src/lex.l" {return TOK_CAPSOFF;} YY_BREAK case 10: YY_RULE_SETUP -#line 70 "lex.l" +#line 70 "../../kmflcomp/src/lex.l" {return TOK_CAPSON;} YY_BREAK case 11: YY_RULE_SETUP -#line 71 "lex.l" +#line 71 "../../kmflcomp/src/lex.l" {return TOK_CAPSFREE;} YY_BREAK case 12: YY_RULE_SETUP -#line 72 "lex.l" +#line 72 "../../kmflcomp/src/lex.l" {return TOK_COPYRIGHT;} YY_BREAK case 13: YY_RULE_SETUP -#line 73 "lex.l" +#line 73 "../../kmflcomp/src/lex.l" {return TOK_MESSAGE;} YY_BREAK case 14: YY_RULE_SETUP -#line 74 "lex.l" +#line 74 "../../kmflcomp/src/lex.l" {return TOK_MNEMONIC;} YY_BREAK case 15: YY_RULE_SETUP -#line 75 "lex.l" +#line 75 "../../kmflcomp/src/lex.l" {return TOK_ETHNOLOGUE;} YY_BREAK case 16: YY_RULE_SETUP -#line 76 "lex.l" +#line 76 "../../kmflcomp/src/lex.l" {return TOK_AUTHOR;} YY_BREAK case 17: YY_RULE_SETUP -#line 77 "lex.l" +#line 77 "../../kmflcomp/src/lex.l" {return TOK_ANSI;} YY_BREAK case 18: YY_RULE_SETUP -#line 78 "lex.l" +#line 78 "../../kmflcomp/src/lex.l" {return TOK_UNICODE;} YY_BREAK case 19: YY_RULE_SETUP -#line 79 "lex.l" +#line 79 "../../kmflcomp/src/lex.l" {return TOK_ANSI;} YY_BREAK case 20: YY_RULE_SETUP -#line 80 "lex.l" +#line 80 "../../kmflcomp/src/lex.l" {caller=STOR;BEGIN(STOR);return TOK_STORE;} YY_BREAK case 21: YY_RULE_SETUP -#line 81 "lex.l" +#line 81 "../../kmflcomp/src/lex.l" {return TOK_OUTS;} YY_BREAK case 22: YY_RULE_SETUP -#line 82 "lex.l" +#line 82 "../../kmflcomp/src/lex.l" {return TOK_GROUP;} YY_BREAK case 23: YY_RULE_SETUP -#line 83 "lex.l" +#line 83 "../../kmflcomp/src/lex.l" {return TOK_USINGKEYS;} YY_BREAK case 24: YY_RULE_SETUP -#line 84 "lex.l" +#line 84 "../../kmflcomp/src/lex.l" {return TOK_USE;} YY_BREAK case 25: YY_RULE_SETUP -#line 85 "lex.l" +#line 85 "../../kmflcomp/src/lex.l" {return TOK_CONTEXT;} YY_BREAK case 26: YY_RULE_SETUP -#line 86 "lex.l" +#line 86 "../../kmflcomp/src/lex.l" {return TOK_ANY;} YY_BREAK case 27: YY_RULE_SETUP -#line 87 "lex.l" +#line 87 "../../kmflcomp/src/lex.l" {return TOK_NOTANY;} YY_BREAK case 28: YY_RULE_SETUP -#line 88 "lex.l" +#line 88 "../../kmflcomp/src/lex.l" {return TOK_BEEP;} YY_BREAK case 29: YY_RULE_SETUP -#line 89 "lex.l" +#line 89 "../../kmflcomp/src/lex.l" {BEGIN(PLIST);return TOK_INDEX;} YY_BREAK case 30: YY_RULE_SETUP -#line 90 "lex.l" +#line 90 "../../kmflcomp/src/lex.l" {return TOK_NOMATCH;} YY_BREAK case 31: YY_RULE_SETUP -#line 91 "lex.l" +#line 91 "../../kmflcomp/src/lex.l" {return TOK_MATCH;} YY_BREAK case 32: YY_RULE_SETUP -#line 92 "lex.l" +#line 92 "../../kmflcomp/src/lex.l" {return TOK_NUL;} YY_BREAK case 33: YY_RULE_SETUP -#line 93 "lex.l" +#line 93 "../../kmflcomp/src/lex.l" {return TOK_DEADKEY;} YY_BREAK case 34: YY_RULE_SETUP -#line 94 "lex.l" +#line 94 "../../kmflcomp/src/lex.l" {return TOK_DEADKEY;} YY_BREAK case 35: YY_RULE_SETUP -#line 95 "lex.l" +#line 95 "../../kmflcomp/src/lex.l" {return TOK_RTN;} YY_BREAK case 36: YY_RULE_SETUP -#line 96 "lex.l" +#line 96 "../../kmflcomp/src/lex.l" {return TOK_CALL; /* not implemented */} YY_BREAK case 37: YY_RULE_SETUP -#line 97 "lex.l" +#line 97 "../../kmflcomp/src/lex.l" {return TOK_SWITCH;/* (obsolete) */} YY_BREAK case 38: YY_RULE_SETUP -#line 98 "lex.l" +#line 98 "../../kmflcomp/src/lex.l" {return TOK_GT;} YY_BREAK case 39: YY_RULE_SETUP -#line 99 "lex.l" +#line 99 "../../kmflcomp/src/lex.l" {return TOK_PLUS;} YY_BREAK case 40: @@ -1670,18 +1718,18 @@ case 40: (yy_c_buf_p) = yy_cp = yy_bp + 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 100 "lex.l" +#line 100 "../../kmflcomp/src/lex.l" {BEGIN(NAME);return TOK_DOLLAR;} YY_BREAK case 41: YY_RULE_SETUP -#line 103 "lex.l" +#line 103 "../../kmflcomp/src/lex.l" {/* ignore spaces */} YY_BREAK case 42: YY_RULE_SETUP -#line 104 "lex.l" +#line 104 "../../kmflcomp/src/lex.l" {BEGIN(SKIP);} YY_BREAK case 43: @@ -1689,7 +1737,7 @@ case 43: (yy_c_buf_p) = yy_cp = yy_bp + 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 105 "lex.l" +#line 105 "../../kmflcomp/src/lex.l" {BEGIN(PARENS);return(TOK_BRKT);} YY_BREAK case 44: @@ -1697,7 +1745,7 @@ case 44: (yy_c_buf_p) = yy_cp = yy_bp + 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 106 "lex.l" +#line 106 "../../kmflcomp/src/lex.l" {qchar='\'';BEGIN(QUOTE);return(TOK_QM);} YY_BREAK case 45: @@ -1705,71 +1753,71 @@ case 45: (yy_c_buf_p) = yy_cp = yy_bp + 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 107 "lex.l" +#line 107 "../../kmflcomp/src/lex.l" {qchar='"';BEGIN(QUOTE);return(TOK_QM);} YY_BREAK case 46: YY_RULE_SETUP -#line 108 "lex.l" +#line 108 "../../kmflcomp/src/lex.l" {yylval.number=strtol(yytext,NULL,8);return(TOK_NUMBER);} YY_BREAK case 47: YY_RULE_SETUP -#line 109 "lex.l" +#line 109 "../../kmflcomp/src/lex.l" {yylval.number=atoi(yytext+1);return(TOK_NUMBER);} YY_BREAK case 48: YY_RULE_SETUP -#line 110 "lex.l" +#line 110 "../../kmflcomp/src/lex.l" {yylval.number=strtol(yytext+1,NULL,16);return(TOK_NUMBER);} YY_BREAK case 49: YY_RULE_SETUP -#line 111 "lex.l" +#line 111 "../../kmflcomp/src/lex.l" {yylval.number=strtol(yytext+2,NULL,16);return(TOK_NUMBER);} YY_BREAK case 50: YY_RULE_SETUP -#line 112 "lex.l" +#line 112 "../../kmflcomp/src/lex.l" {BEGIN(KEYNAME);return(TOK_SB);} YY_BREAK case 51: YY_RULE_SETUP -#line 113 "lex.l" +#line 113 "../../kmflcomp/src/lex.l" {return(TOK_BEEP);} YY_BREAK case 52: YY_RULE_SETUP -#line 117 "lex.l" +#line 117 "../../kmflcomp/src/lex.l" {return(TOK_DEADKEY);} YY_BREAK case 53: YY_RULE_SETUP -#line 118 "lex.l" +#line 118 "../../kmflcomp/src/lex.l" {return(TOK_DEADKEY);} YY_BREAK case 54: YY_RULE_SETUP -#line 119 "lex.l" +#line 119 "../../kmflcomp/src/lex.l" {return(TOK_OUTS);} YY_BREAK case 55: YY_RULE_SETUP -#line 120 "lex.l" +#line 120 "../../kmflcomp/src/lex.l" {return(TOK_NUL);} YY_BREAK case 56: YY_RULE_SETUP -#line 121 "lex.l" +#line 121 "../../kmflcomp/src/lex.l" {return(TOK_ERROR);} YY_BREAK case 57: YY_RULE_SETUP -#line 125 "lex.l" +#line 125 "../../kmflcomp/src/lex.l" {/* ignore spaces */} YY_BREAK case 58: @@ -1777,36 +1825,37 @@ case 58: (yy_c_buf_p) = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 126 "lex.l" +#line 126 "../../kmflcomp/src/lex.l" {/* ignore comments */} YY_BREAK case 59: /* rule 59 can match eol */ *yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ +YY_LINENO_REWIND_TO(yy_cp - 1); (yy_c_buf_p) = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 127 "lex.l" +#line 127 "../../kmflcomp/src/lex.l" {/* before either EOL */} YY_BREAK case 60: YY_RULE_SETUP -#line 128 "lex.l" +#line 128 "../../kmflcomp/src/lex.l" {return TOK_QM;} YY_BREAK case 61: YY_RULE_SETUP -#line 129 "lex.l" +#line 129 "../../kmflcomp/src/lex.l" {yylval.number=*yytext;return TOK_CHAR;} YY_BREAK case 62: YY_RULE_SETUP -#line 130 "lex.l" +#line 130 "../../kmflcomp/src/lex.l" {yylval.number=*yytext;return TOK_CHAR;} YY_BREAK case 63: YY_RULE_SETUP -#line 131 "lex.l" +#line 131 "../../kmflcomp/src/lex.l" {BEGIN(SKIP);} YY_BREAK @@ -1816,16 +1865,17 @@ case 64: (yy_c_buf_p) = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 135 "lex.l" +#line 135 "../../kmflcomp/src/lex.l" {/* ignore anything after a space */} YY_BREAK case 65: /* rule 65 can match eol */ *yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ +YY_LINENO_REWIND_TO(yy_cp - 1); (yy_c_buf_p) = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 136 "lex.l" +#line 136 "../../kmflcomp/src/lex.l" {/* including comments */} YY_BREAK case 66: @@ -1833,7 +1883,7 @@ case 66: (yy_c_buf_p) = yy_cp = yy_bp + 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 137 "lex.l" +#line 137 "../../kmflcomp/src/lex.l" {qchar='\'';BEGIN(QUOTE);return(TOK_QM);} YY_BREAK case 67: @@ -1841,12 +1891,12 @@ case 67: (yy_c_buf_p) = yy_cp = yy_bp + 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 138 "lex.l" +#line 138 "../../kmflcomp/src/lex.l" {qchar='"';BEGIN(QUOTE);return(TOK_QM);} YY_BREAK case 68: YY_RULE_SETUP -#line 139 "lex.l" +#line 139 "../../kmflcomp/src/lex.l" {yylval.number=*yytext;return TOK_CHAR;} YY_BREAK case 69: @@ -1854,23 +1904,24 @@ case 69: (yy_c_buf_p) = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 140 "lex.l" +#line 140 "../../kmflcomp/src/lex.l" {/* also ignore anything after a comma */} YY_BREAK case 70: /* rule 70 can match eol */ *yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ +YY_LINENO_REWIND_TO(yy_cp - 1); (yy_c_buf_p) = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 141 "lex.l" +#line 141 "../../kmflcomp/src/lex.l" {/* before either EOL */} YY_BREAK case 71: YY_RULE_SETUP -#line 145 "lex.l" +#line 145 "../../kmflcomp/src/lex.l" {/* ignore spaces */} YY_BREAK case 72: @@ -1878,43 +1929,44 @@ case 72: (yy_c_buf_p) = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 146 "lex.l" +#line 146 "../../kmflcomp/src/lex.l" {/* ignore comments */} YY_BREAK case 73: /* rule 73 can match eol */ *yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ +YY_LINENO_REWIND_TO(yy_cp - 1); (yy_c_buf_p) = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 147 "lex.l" +#line 147 "../../kmflcomp/src/lex.l" {/* before either EOL */} YY_BREAK case 74: YY_RULE_SETUP -#line 148 "lex.l" +#line 148 "../../kmflcomp/src/lex.l" {yylval.number=strtoul(yytext,NULL,8);return(TOK_NUMBER);} YY_BREAK case 75: YY_RULE_SETUP -#line 149 "lex.l" +#line 149 "../../kmflcomp/src/lex.l" {yylval.number=strtoul(yytext+1,NULL,10);return(TOK_NUMBER);} YY_BREAK case 76: YY_RULE_SETUP -#line 150 "lex.l" +#line 150 "../../kmflcomp/src/lex.l" {yylval.number=strtoul(yytext+1,NULL,16);return(TOK_NUMBER);} YY_BREAK case 77: YY_RULE_SETUP -#line 151 "lex.l" +#line 151 "../../kmflcomp/src/lex.l" {/* ignore comma separator */} YY_BREAK case 78: YY_RULE_SETUP -#line 155 "lex.l" +#line 155 "../../kmflcomp/src/lex.l" {if (*yytext==qchar) {BEGIN(caller);return(TOK_QM);} else @@ -1925,688 +1977,688 @@ YY_RULE_SETUP case 79: YY_RULE_SETUP -#line 163 "lex.l" +#line 163 "../../kmflcomp/src/lex.l" YY_BREAK case 80: YY_RULE_SETUP -#line 164 "lex.l" +#line 164 "../../kmflcomp/src/lex.l" {BEGIN(caller);return(TOK_BRKT);} YY_BREAK case 81: YY_RULE_SETUP -#line 165 "lex.l" +#line 165 "../../kmflcomp/src/lex.l" {yylval.number=*yytext;return(TOK_CHAR);} YY_BREAK case 82: YY_RULE_SETUP -#line 169 "lex.l" +#line 169 "../../kmflcomp/src/lex.l" {/* ignore */} YY_BREAK case 83: YY_RULE_SETUP -#line 170 "lex.l" +#line 170 "../../kmflcomp/src/lex.l" { return(TOK_COMMA);} YY_BREAK case 84: YY_RULE_SETUP -#line 171 "lex.l" +#line 171 "../../kmflcomp/src/lex.l" { return(TOK_BRKT);} YY_BREAK case 85: YY_RULE_SETUP -#line 172 "lex.l" +#line 172 "../../kmflcomp/src/lex.l" {BEGIN(caller);return(TOK_BRKT);} YY_BREAK case 86: YY_RULE_SETUP -#line 173 "lex.l" +#line 173 "../../kmflcomp/src/lex.l" {yylval.number=*yytext;return(TOK_CHAR);} YY_BREAK case 87: YY_RULE_SETUP -#line 177 "lex.l" +#line 177 "../../kmflcomp/src/lex.l" {yylval.number=*yytext;return(TOK_CHAR);} YY_BREAK case 88: YY_RULE_SETUP -#line 178 "lex.l" +#line 178 "../../kmflcomp/src/lex.l" {BEGIN(caller);} YY_BREAK case 89: YY_RULE_SETUP -#line 182 "lex.l" +#line 182 "../../kmflcomp/src/lex.l" {/* ignore */} YY_BREAK case 90: YY_RULE_SETUP -#line 183 "lex.l" +#line 183 "../../kmflcomp/src/lex.l" {yylval.number=KS_LSHIFT;return(TOK_SHIFT);} YY_BREAK case 91: YY_RULE_SETUP -#line 184 "lex.l" +#line 184 "../../kmflcomp/src/lex.l" {yylval.number=KS_CAPS;return(TOK_SHIFT);} YY_BREAK case 92: YY_RULE_SETUP -#line 185 "lex.l" +#line 185 "../../kmflcomp/src/lex.l" {yylval.number=KS_LCTRL;return(TOK_SHIFT);} YY_BREAK case 93: YY_RULE_SETUP -#line 186 "lex.l" +#line 186 "../../kmflcomp/src/lex.l" {yylval.number=KS_LALT;return(TOK_SHIFT);} YY_BREAK case 94: YY_RULE_SETUP -#line 187 "lex.l" +#line 187 "../../kmflcomp/src/lex.l" {yylval.number=KS_RSHIFT;return(TOK_SHIFT);} YY_BREAK case 95: YY_RULE_SETUP -#line 188 "lex.l" +#line 188 "../../kmflcomp/src/lex.l" {yylval.number=KS_NCAPS;return(TOK_SHIFT);} YY_BREAK case 96: YY_RULE_SETUP -#line 189 "lex.l" +#line 189 "../../kmflcomp/src/lex.l" {yylval.number=KS_RCTRL;return(TOK_SHIFT);} YY_BREAK case 97: YY_RULE_SETUP -#line 190 "lex.l" +#line 190 "../../kmflcomp/src/lex.l" {yylval.number=KS_RALT;return(TOK_SHIFT);} YY_BREAK case 98: YY_RULE_SETUP -#line 191 "lex.l" +#line 191 "../../kmflcomp/src/lex.l" {yylval.number=KS_SHIFT;return(TOK_SHIFT);} YY_BREAK case 99: YY_RULE_SETUP -#line 192 "lex.l" +#line 192 "../../kmflcomp/src/lex.l" {yylval.number=KS_CTRL;return(TOK_SHIFT);} YY_BREAK case 100: YY_RULE_SETUP -#line 193 "lex.l" +#line 193 "../../kmflcomp/src/lex.l" {yylval.number=KS_ALT;return(TOK_SHIFT);} YY_BREAK case 101: YY_RULE_SETUP -#line 195 "lex.l" +#line 195 "../../kmflcomp/src/lex.l" {yylval.number=0x20;return(TOK_RAWKEY);} YY_BREAK case 102: YY_RULE_SETUP -#line 196 "lex.l" +#line 196 "../../kmflcomp/src/lex.l" {yylval.number=0x27;return(TOK_RAWKEY);} YY_BREAK case 103: YY_RULE_SETUP -#line 197 "lex.l" +#line 197 "../../kmflcomp/src/lex.l" {yylval.number=0x30;return(TOK_RAWKEY);} YY_BREAK case 104: YY_RULE_SETUP -#line 198 "lex.l" +#line 198 "../../kmflcomp/src/lex.l" {yylval.number=0x31;return(TOK_RAWKEY);} YY_BREAK case 105: YY_RULE_SETUP -#line 199 "lex.l" +#line 199 "../../kmflcomp/src/lex.l" {yylval.number=0x32;return(TOK_RAWKEY);} YY_BREAK case 106: YY_RULE_SETUP -#line 200 "lex.l" +#line 200 "../../kmflcomp/src/lex.l" {yylval.number=0x33;return(TOK_RAWKEY);} YY_BREAK case 107: YY_RULE_SETUP -#line 201 "lex.l" +#line 201 "../../kmflcomp/src/lex.l" {yylval.number=0x34;return(TOK_RAWKEY);} YY_BREAK case 108: YY_RULE_SETUP -#line 202 "lex.l" +#line 202 "../../kmflcomp/src/lex.l" {yylval.number=0x35;return(TOK_RAWKEY);} YY_BREAK case 109: YY_RULE_SETUP -#line 203 "lex.l" +#line 203 "../../kmflcomp/src/lex.l" {yylval.number=0x36;return(TOK_RAWKEY);} YY_BREAK case 110: YY_RULE_SETUP -#line 204 "lex.l" +#line 204 "../../kmflcomp/src/lex.l" {yylval.number=0x37;return(TOK_RAWKEY);} YY_BREAK case 111: YY_RULE_SETUP -#line 205 "lex.l" +#line 205 "../../kmflcomp/src/lex.l" {yylval.number=0x38;return(TOK_RAWKEY);} YY_BREAK case 112: YY_RULE_SETUP -#line 206 "lex.l" +#line 206 "../../kmflcomp/src/lex.l" {yylval.number=0x39;return(TOK_RAWKEY);} YY_BREAK case 113: YY_RULE_SETUP -#line 207 "lex.l" +#line 207 "../../kmflcomp/src/lex.l" {yylval.number=0x41;return(TOK_RAWKEY);} YY_BREAK case 114: YY_RULE_SETUP -#line 208 "lex.l" +#line 208 "../../kmflcomp/src/lex.l" {yylval.number=0x42;return(TOK_RAWKEY);} YY_BREAK case 115: YY_RULE_SETUP -#line 209 "lex.l" +#line 209 "../../kmflcomp/src/lex.l" {yylval.number=0x43;return(TOK_RAWKEY);} YY_BREAK case 116: YY_RULE_SETUP -#line 210 "lex.l" +#line 210 "../../kmflcomp/src/lex.l" {yylval.number=0x44;return(TOK_RAWKEY);} YY_BREAK case 117: YY_RULE_SETUP -#line 211 "lex.l" +#line 211 "../../kmflcomp/src/lex.l" {yylval.number=0x45;return(TOK_RAWKEY);} YY_BREAK case 118: YY_RULE_SETUP -#line 212 "lex.l" +#line 212 "../../kmflcomp/src/lex.l" {yylval.number=0x46;return(TOK_RAWKEY);} YY_BREAK case 119: YY_RULE_SETUP -#line 213 "lex.l" +#line 213 "../../kmflcomp/src/lex.l" {yylval.number=0x47;return(TOK_RAWKEY);} YY_BREAK case 120: YY_RULE_SETUP -#line 214 "lex.l" +#line 214 "../../kmflcomp/src/lex.l" {yylval.number=0x48;return(TOK_RAWKEY);} YY_BREAK case 121: YY_RULE_SETUP -#line 215 "lex.l" +#line 215 "../../kmflcomp/src/lex.l" {yylval.number=0x49;return(TOK_RAWKEY);} YY_BREAK case 122: YY_RULE_SETUP -#line 216 "lex.l" +#line 216 "../../kmflcomp/src/lex.l" {yylval.number=0x4a;return(TOK_RAWKEY);} YY_BREAK case 123: YY_RULE_SETUP -#line 217 "lex.l" +#line 217 "../../kmflcomp/src/lex.l" {yylval.number=0x4b;return(TOK_RAWKEY);} YY_BREAK case 124: YY_RULE_SETUP -#line 218 "lex.l" +#line 218 "../../kmflcomp/src/lex.l" {yylval.number=0x4c;return(TOK_RAWKEY);} YY_BREAK case 125: YY_RULE_SETUP -#line 219 "lex.l" +#line 219 "../../kmflcomp/src/lex.l" {yylval.number=0x4d;return(TOK_RAWKEY);} YY_BREAK case 126: YY_RULE_SETUP -#line 220 "lex.l" +#line 220 "../../kmflcomp/src/lex.l" {yylval.number=0x4e;return(TOK_RAWKEY);} YY_BREAK case 127: YY_RULE_SETUP -#line 221 "lex.l" +#line 221 "../../kmflcomp/src/lex.l" {yylval.number=0x4f;return(TOK_RAWKEY);} YY_BREAK case 128: YY_RULE_SETUP -#line 222 "lex.l" +#line 222 "../../kmflcomp/src/lex.l" {yylval.number=0x50;return(TOK_RAWKEY);} YY_BREAK case 129: YY_RULE_SETUP -#line 223 "lex.l" +#line 223 "../../kmflcomp/src/lex.l" {yylval.number=0x51;return(TOK_RAWKEY);} YY_BREAK case 130: YY_RULE_SETUP -#line 224 "lex.l" +#line 224 "../../kmflcomp/src/lex.l" {yylval.number=0x52;return(TOK_RAWKEY);} YY_BREAK case 131: YY_RULE_SETUP -#line 225 "lex.l" +#line 225 "../../kmflcomp/src/lex.l" {yylval.number=0x53;return(TOK_RAWKEY);} YY_BREAK case 132: YY_RULE_SETUP -#line 226 "lex.l" +#line 226 "../../kmflcomp/src/lex.l" {yylval.number=0x54;return(TOK_RAWKEY);} YY_BREAK case 133: YY_RULE_SETUP -#line 227 "lex.l" +#line 227 "../../kmflcomp/src/lex.l" {yylval.number=0x55;return(TOK_RAWKEY);} YY_BREAK case 134: YY_RULE_SETUP -#line 228 "lex.l" +#line 228 "../../kmflcomp/src/lex.l" {yylval.number=0x56;return(TOK_RAWKEY);} YY_BREAK case 135: YY_RULE_SETUP -#line 229 "lex.l" +#line 229 "../../kmflcomp/src/lex.l" {yylval.number=0x57;return(TOK_RAWKEY);} YY_BREAK case 136: YY_RULE_SETUP -#line 230 "lex.l" +#line 230 "../../kmflcomp/src/lex.l" {yylval.number=0x58;return(TOK_RAWKEY);} YY_BREAK case 137: YY_RULE_SETUP -#line 231 "lex.l" +#line 231 "../../kmflcomp/src/lex.l" {yylval.number=0x59;return(TOK_RAWKEY);} YY_BREAK case 138: YY_RULE_SETUP -#line 232 "lex.l" +#line 232 "../../kmflcomp/src/lex.l" {yylval.number=0x5a;return(TOK_RAWKEY);} YY_BREAK case 139: YY_RULE_SETUP -#line 233 "lex.l" +#line 233 "../../kmflcomp/src/lex.l" {yylval.number=0x60;return(TOK_RAWKEY);} YY_BREAK case 140: YY_RULE_SETUP -#line 234 "lex.l" +#line 234 "../../kmflcomp/src/lex.l" {yylval.number=0x2c;return(TOK_RAWKEY);} YY_BREAK case 141: YY_RULE_SETUP -#line 235 "lex.l" +#line 235 "../../kmflcomp/src/lex.l" {yylval.number=0x2d;return(TOK_RAWKEY);} YY_BREAK case 142: YY_RULE_SETUP -#line 236 "lex.l" +#line 236 "../../kmflcomp/src/lex.l" {yylval.number=0x2e;return(TOK_RAWKEY);} YY_BREAK case 143: YY_RULE_SETUP -#line 237 "lex.l" +#line 237 "../../kmflcomp/src/lex.l" {yylval.number=0x2f;return(TOK_RAWKEY);} YY_BREAK case 144: YY_RULE_SETUP -#line 238 "lex.l" +#line 238 "../../kmflcomp/src/lex.l" {yylval.number=0x3a;return(TOK_RAWKEY);} YY_BREAK case 145: YY_RULE_SETUP -#line 239 "lex.l" +#line 239 "../../kmflcomp/src/lex.l" {yylval.number=0x3d;return(TOK_RAWKEY);} YY_BREAK case 146: YY_RULE_SETUP -#line 240 "lex.l" +#line 240 "../../kmflcomp/src/lex.l" {yylval.number=0x5b;return(TOK_RAWKEY);} YY_BREAK case 147: YY_RULE_SETUP -#line 241 "lex.l" +#line 241 "../../kmflcomp/src/lex.l" {yylval.number=0x5c;return(TOK_RAWKEY);} YY_BREAK case 148: YY_RULE_SETUP -#line 242 "lex.l" +#line 242 "../../kmflcomp/src/lex.l" {yylval.number=0x5d;return(TOK_RAWKEY);} YY_BREAK case 149: YY_RULE_SETUP -#line 243 "lex.l" +#line 243 "../../kmflcomp/src/lex.l" {yylval.number=0xff08;return(TOK_RAWKEY);} YY_BREAK case 150: YY_RULE_SETUP -#line 244 "lex.l" +#line 244 "../../kmflcomp/src/lex.l" {yylval.number=0xff09;return(TOK_RAWKEY);} YY_BREAK case 151: YY_RULE_SETUP -#line 245 "lex.l" +#line 245 "../../kmflcomp/src/lex.l" {yylval.number=0xff0d;return(TOK_RAWKEY);} YY_BREAK case 152: YY_RULE_SETUP -#line 246 "lex.l" +#line 246 "../../kmflcomp/src/lex.l" {yylval.number=0xff13;return(TOK_RAWKEY);} YY_BREAK case 153: YY_RULE_SETUP -#line 247 "lex.l" +#line 247 "../../kmflcomp/src/lex.l" {yylval.number=0xff14;return(TOK_RAWKEY);} YY_BREAK case 154: YY_RULE_SETUP -#line 248 "lex.l" +#line 248 "../../kmflcomp/src/lex.l" {yylval.number=0xff1b;return(TOK_RAWKEY);} YY_BREAK case 155: YY_RULE_SETUP -#line 249 "lex.l" +#line 249 "../../kmflcomp/src/lex.l" {yylval.number=0xff50;return(TOK_RAWKEY);} YY_BREAK case 156: YY_RULE_SETUP -#line 250 "lex.l" +#line 250 "../../kmflcomp/src/lex.l" {yylval.number=0xff51;return(TOK_RAWKEY);} YY_BREAK case 157: YY_RULE_SETUP -#line 251 "lex.l" +#line 251 "../../kmflcomp/src/lex.l" {yylval.number=0xff52;return(TOK_RAWKEY);} YY_BREAK case 158: YY_RULE_SETUP -#line 252 "lex.l" +#line 252 "../../kmflcomp/src/lex.l" {yylval.number=0xff53;return(TOK_RAWKEY);} YY_BREAK case 159: YY_RULE_SETUP -#line 253 "lex.l" +#line 253 "../../kmflcomp/src/lex.l" {yylval.number=0xff54;return(TOK_RAWKEY);} YY_BREAK case 160: YY_RULE_SETUP -#line 254 "lex.l" +#line 254 "../../kmflcomp/src/lex.l" {yylval.number=0xff55;return(TOK_RAWKEY);} YY_BREAK case 161: YY_RULE_SETUP -#line 255 "lex.l" +#line 255 "../../kmflcomp/src/lex.l" {yylval.number=0xff56;return(TOK_RAWKEY);} YY_BREAK case 162: YY_RULE_SETUP -#line 256 "lex.l" +#line 256 "../../kmflcomp/src/lex.l" {yylval.number=0xff57;return(TOK_RAWKEY);} YY_BREAK case 163: YY_RULE_SETUP -#line 257 "lex.l" +#line 257 "../../kmflcomp/src/lex.l" {yylval.number=0xff63;return(TOK_RAWKEY);} YY_BREAK case 164: YY_RULE_SETUP -#line 258 "lex.l" +#line 258 "../../kmflcomp/src/lex.l" {yylval.number=0xff7f;return(TOK_RAWKEY);} YY_BREAK case 165: YY_RULE_SETUP -#line 259 "lex.l" +#line 259 "../../kmflcomp/src/lex.l" {yylval.number=0xffaa;return(TOK_RAWKEY);} YY_BREAK case 166: YY_RULE_SETUP -#line 260 "lex.l" +#line 260 "../../kmflcomp/src/lex.l" {yylval.number=0xffab;return(TOK_RAWKEY);} YY_BREAK case 167: YY_RULE_SETUP -#line 261 "lex.l" +#line 261 "../../kmflcomp/src/lex.l" {yylval.number=0xffad;return(TOK_RAWKEY);} YY_BREAK case 168: YY_RULE_SETUP -#line 262 "lex.l" +#line 262 "../../kmflcomp/src/lex.l" {yylval.number=0xffae;return(TOK_RAWKEY);} YY_BREAK case 169: YY_RULE_SETUP -#line 263 "lex.l" +#line 263 "../../kmflcomp/src/lex.l" {yylval.number=0xffaf;return(TOK_RAWKEY);} YY_BREAK case 170: YY_RULE_SETUP -#line 264 "lex.l" +#line 264 "../../kmflcomp/src/lex.l" {yylval.number=0xffb0;return(TOK_RAWKEY);} YY_BREAK case 171: YY_RULE_SETUP -#line 265 "lex.l" +#line 265 "../../kmflcomp/src/lex.l" {yylval.number=0xffb1;return(TOK_RAWKEY);} YY_BREAK case 172: YY_RULE_SETUP -#line 266 "lex.l" +#line 266 "../../kmflcomp/src/lex.l" {yylval.number=0xffb2;return(TOK_RAWKEY);} YY_BREAK case 173: YY_RULE_SETUP -#line 267 "lex.l" +#line 267 "../../kmflcomp/src/lex.l" {yylval.number=0xffb3;return(TOK_RAWKEY);} YY_BREAK case 174: YY_RULE_SETUP -#line 268 "lex.l" +#line 268 "../../kmflcomp/src/lex.l" {yylval.number=0xffb4;return(TOK_RAWKEY);} YY_BREAK case 175: YY_RULE_SETUP -#line 269 "lex.l" +#line 269 "../../kmflcomp/src/lex.l" {yylval.number=0xffb5;return(TOK_RAWKEY);} YY_BREAK case 176: YY_RULE_SETUP -#line 270 "lex.l" +#line 270 "../../kmflcomp/src/lex.l" {yylval.number=0xffb6;return(TOK_RAWKEY);} YY_BREAK case 177: YY_RULE_SETUP -#line 271 "lex.l" +#line 271 "../../kmflcomp/src/lex.l" {yylval.number=0xffb7;return(TOK_RAWKEY);} YY_BREAK case 178: YY_RULE_SETUP -#line 272 "lex.l" +#line 272 "../../kmflcomp/src/lex.l" {yylval.number=0xffb8;return(TOK_RAWKEY);} YY_BREAK case 179: YY_RULE_SETUP -#line 273 "lex.l" +#line 273 "../../kmflcomp/src/lex.l" {yylval.number=0xffb9;return(TOK_RAWKEY);} YY_BREAK case 180: YY_RULE_SETUP -#line 274 "lex.l" +#line 274 "../../kmflcomp/src/lex.l" {yylval.number=0xffbe;return(TOK_RAWKEY);} YY_BREAK case 181: YY_RULE_SETUP -#line 275 "lex.l" +#line 275 "../../kmflcomp/src/lex.l" {yylval.number=0xffbf;return(TOK_RAWKEY);} YY_BREAK case 182: YY_RULE_SETUP -#line 276 "lex.l" +#line 276 "../../kmflcomp/src/lex.l" {yylval.number=0xffc0;return(TOK_RAWKEY);} YY_BREAK case 183: YY_RULE_SETUP -#line 277 "lex.l" +#line 277 "../../kmflcomp/src/lex.l" {yylval.number=0xffc1;return(TOK_RAWKEY);} YY_BREAK case 184: YY_RULE_SETUP -#line 278 "lex.l" +#line 278 "../../kmflcomp/src/lex.l" {yylval.number=0xffc2;return(TOK_RAWKEY);} YY_BREAK case 185: YY_RULE_SETUP -#line 279 "lex.l" +#line 279 "../../kmflcomp/src/lex.l" {yylval.number=0xffc3;return(TOK_RAWKEY);} YY_BREAK case 186: YY_RULE_SETUP -#line 280 "lex.l" +#line 280 "../../kmflcomp/src/lex.l" {yylval.number=0xffc4;return(TOK_RAWKEY);} YY_BREAK case 187: YY_RULE_SETUP -#line 281 "lex.l" +#line 281 "../../kmflcomp/src/lex.l" {yylval.number=0xffc5;return(TOK_RAWKEY);} YY_BREAK case 188: YY_RULE_SETUP -#line 282 "lex.l" +#line 282 "../../kmflcomp/src/lex.l" {yylval.number=0xffc6;return(TOK_RAWKEY);} YY_BREAK case 189: YY_RULE_SETUP -#line 283 "lex.l" +#line 283 "../../kmflcomp/src/lex.l" {yylval.number=0xffc7;return(TOK_RAWKEY);} YY_BREAK case 190: YY_RULE_SETUP -#line 284 "lex.l" +#line 284 "../../kmflcomp/src/lex.l" {yylval.number=0xffc8;return(TOK_RAWKEY);} YY_BREAK case 191: YY_RULE_SETUP -#line 285 "lex.l" +#line 285 "../../kmflcomp/src/lex.l" {yylval.number=0xffc9;return(TOK_RAWKEY);} YY_BREAK case 192: YY_RULE_SETUP -#line 286 "lex.l" +#line 286 "../../kmflcomp/src/lex.l" {yylval.number=0xffca;return(TOK_RAWKEY);} YY_BREAK case 193: YY_RULE_SETUP -#line 287 "lex.l" +#line 287 "../../kmflcomp/src/lex.l" {yylval.number=0xffcb;return(TOK_RAWKEY);} YY_BREAK case 194: YY_RULE_SETUP -#line 288 "lex.l" +#line 288 "../../kmflcomp/src/lex.l" {yylval.number=0xffcc;return(TOK_RAWKEY);} YY_BREAK case 195: YY_RULE_SETUP -#line 289 "lex.l" +#line 289 "../../kmflcomp/src/lex.l" {yylval.number=0xffcd;return(TOK_RAWKEY);} YY_BREAK case 196: YY_RULE_SETUP -#line 290 "lex.l" +#line 290 "../../kmflcomp/src/lex.l" {yylval.number=0xffce;return(TOK_RAWKEY);} YY_BREAK case 197: YY_RULE_SETUP -#line 291 "lex.l" +#line 291 "../../kmflcomp/src/lex.l" {yylval.number=0xffcf;return(TOK_RAWKEY);} YY_BREAK case 198: YY_RULE_SETUP -#line 292 "lex.l" +#line 292 "../../kmflcomp/src/lex.l" {yylval.number=0xffd0;return(TOK_RAWKEY);} YY_BREAK case 199: YY_RULE_SETUP -#line 293 "lex.l" +#line 293 "../../kmflcomp/src/lex.l" {yylval.number=0xffd1;return(TOK_RAWKEY);} YY_BREAK case 200: YY_RULE_SETUP -#line 294 "lex.l" +#line 294 "../../kmflcomp/src/lex.l" {yylval.number=0xffd2;return(TOK_RAWKEY);} YY_BREAK case 201: YY_RULE_SETUP -#line 295 "lex.l" +#line 295 "../../kmflcomp/src/lex.l" {yylval.number=0xffd3;return(TOK_RAWKEY);} YY_BREAK case 202: YY_RULE_SETUP -#line 296 "lex.l" +#line 296 "../../kmflcomp/src/lex.l" {yylval.number=0xffd4;return(TOK_RAWKEY);} YY_BREAK case 203: YY_RULE_SETUP -#line 297 "lex.l" +#line 297 "../../kmflcomp/src/lex.l" {yylval.number=0xffd5;return(TOK_RAWKEY);} YY_BREAK case 204: YY_RULE_SETUP -#line 298 "lex.l" +#line 298 "../../kmflcomp/src/lex.l" {yylval.number=0xffe1;return(TOK_RAWKEY);} YY_BREAK case 205: YY_RULE_SETUP -#line 299 "lex.l" +#line 299 "../../kmflcomp/src/lex.l" {yylval.number=0xffe3;return(TOK_RAWKEY);} YY_BREAK case 206: YY_RULE_SETUP -#line 300 "lex.l" +#line 300 "../../kmflcomp/src/lex.l" {yylval.number=0xffe5;return(TOK_RAWKEY);} YY_BREAK case 207: YY_RULE_SETUP -#line 301 "lex.l" +#line 301 "../../kmflcomp/src/lex.l" {yylval.number=0xffe9;return(TOK_RAWKEY);} YY_BREAK case 208: YY_RULE_SETUP -#line 302 "lex.l" +#line 302 "../../kmflcomp/src/lex.l" {yylval.number=0xffff;return(TOK_RAWKEY);} YY_BREAK case 209: YY_RULE_SETUP -#line 303 "lex.l" +#line 303 "../../kmflcomp/src/lex.l" {yylval.number=0x3c;return(TOK_RAWKEY); /* on German kbds only!*/} YY_BREAK case 210: YY_RULE_SETUP -#line 305 "lex.l" +#line 305 "../../kmflcomp/src/lex.l" {yylval.number=text_to_keysym(yytext); if (yylval.number == -1) yyerror("unrecognised raw key"); else return(TOK_XKEYSYM);} YY_BREAK case 211: YY_RULE_SETUP -#line 306 "lex.l" +#line 306 "../../kmflcomp/src/lex.l" { yyerror("unrecognised raw key");} YY_BREAK case 212: YY_RULE_SETUP -#line 307 "lex.l" +#line 307 "../../kmflcomp/src/lex.l" {caller0=caller;caller=KEYNAME;qchar='\'';BEGIN(QUOTE);return(TOK_QM);} YY_BREAK case 213: YY_RULE_SETUP -#line 308 "lex.l" +#line 308 "../../kmflcomp/src/lex.l" {caller0=caller;caller=KEYNAME;qchar='\"';BEGIN(QUOTE);return(TOK_QM);} YY_BREAK case 214: YY_RULE_SETUP -#line 310 "lex.l" +#line 310 "../../kmflcomp/src/lex.l" { if(caller==KEYNAME) caller=caller0; BEGIN(caller);return(TOK_SB); @@ -2616,25 +2668,25 @@ YY_RULE_SETUP case 215: /* rule 215 can match eol */ YY_RULE_SETUP -#line 316 "lex.l" +#line 316 "../../kmflcomp/src/lex.l" {lineno++; /* Join lines */} YY_BREAK case 216: /* rule 216 can match eol */ YY_RULE_SETUP -#line 317 "lex.l" +#line 317 "../../kmflcomp/src/lex.l" {lineno++; /* Join lines */} YY_BREAK case 217: /* rule 217 can match eol */ YY_RULE_SETUP -#line 318 "lex.l" +#line 318 "../../kmflcomp/src/lex.l" {lineno++; /* Join lines */} YY_BREAK case 218: /* rule 218 can match eol */ YY_RULE_SETUP -#line 319 "lex.l" +#line 319 "../../kmflcomp/src/lex.l" {lineno++; /* Join lines */} YY_BREAK case 219: @@ -2642,16 +2694,17 @@ case 219: (yy_c_buf_p) = yy_cp = yy_bp + 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 321 "lex.l" +#line 321 "../../kmflcomp/src/lex.l" {/* ignore, use both /\r and /\n, not to work $ */} YY_BREAK case 220: /* rule 220 can match eol */ *yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ +YY_LINENO_REWIND_TO(yy_bp + 1); (yy_c_buf_p) = yy_cp = yy_bp + 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 322 "lex.l" +#line 322 "../../kmflcomp/src/lex.l" {/* with either CR or CR/LF line ending */} YY_BREAK case 221: @@ -2659,16 +2712,17 @@ case 221: (yy_c_buf_p) = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 323 "lex.l" +#line 323 "../../kmflcomp/src/lex.l" {/* ignore */} YY_BREAK case 222: /* rule 222 can match eol */ *yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ +YY_LINENO_REWIND_TO(yy_cp - 1); (yy_c_buf_p) = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 324 "lex.l" +#line 324 "../../kmflcomp/src/lex.l" {/* ignore */} YY_BREAK case 223: @@ -2676,68 +2730,69 @@ case 223: (yy_c_buf_p) = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 325 "lex.l" +#line 325 "../../kmflcomp/src/lex.l" {/* ignore */} YY_BREAK case 224: /* rule 224 can match eol */ *yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ +YY_LINENO_REWIND_TO(yy_cp - 1); (yy_c_buf_p) = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 326 "lex.l" +#line 326 "../../kmflcomp/src/lex.l" {/* ignore */} YY_BREAK case 225: YY_RULE_SETUP -#line 328 "lex.l" +#line 328 "../../kmflcomp/src/lex.l" {BEGIN(SKIP);} YY_BREAK case 226: YY_RULE_SETUP -#line 330 "lex.l" +#line 330 "../../kmflcomp/src/lex.l" {/* Keyman platform conditional - just drop marker */} YY_BREAK case 227: YY_RULE_SETUP -#line 331 "lex.l" +#line 331 "../../kmflcomp/src/lex.l" {/* Kmfl platform conditional - just drop marker */} YY_BREAK case 228: YY_RULE_SETUP -#line 332 "lex.l" +#line 332 "../../kmflcomp/src/lex.l" {BEGIN(SKIP);} /* Platform Conditional */ YY_BREAK case 229: YY_RULE_SETUP -#line 335 "lex.l" +#line 335 "../../kmflcomp/src/lex.l" {/* ignore everything until nl or EOF */} YY_BREAK case 230: YY_RULE_SETUP -#line 338 "lex.l" +#line 338 "../../kmflcomp/src/lex.l" {fprintf(stderr,"Line %d: Unmatched closing parenthesis\n",lineno);return(TOK_BRKT);} YY_BREAK case 231: YY_RULE_SETUP -#line 339 "lex.l" +#line 339 "../../kmflcomp/src/lex.l" {yylval.number=yytext[0];fprintf(stderr,"Line %d: Unrecognized keyword '%s'\n", (int)lineno, yytext);errcount++;return(TOK_ERROR);} YY_BREAK case 232: YY_RULE_SETUP -#line 341 "lex.l" +#line 341 "../../kmflcomp/src/lex.l" {yylval.number=yytext[0];fprintf(stderr,"Line %d: Unexpected char (%d) `%c'\n", (int)lineno, (int) yytext[0],(char) yytext[0]);errcount++;return(TOK_CHAR);} YY_BREAK case 233: YY_RULE_SETUP -#line 343 "lex.l" +#line 343 "../../kmflcomp/src/lex.l" ECHO; YY_BREAK -#line 2741 "lex.c" +#line 2796 "lex.c" case YY_END_OF_BUFFER: { @@ -2866,6 +2921,7 @@ ECHO; "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ + } /* end of user's declarations */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer @@ -2877,9 +2933,9 @@ ECHO; */ static int yy_get_next_buffer (void) { - register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - register char *source = (yytext_ptr); - register int number_to_move, i; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = (yytext_ptr); + yy_size_t number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) @@ -2908,7 +2964,7 @@ static int yy_get_next_buffer (void) /* Try to read more data. */ /* First move last chars to start of buffer. */ - number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + number_to_move = (yy_size_t) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); @@ -2921,21 +2977,21 @@ static int yy_get_next_buffer (void) else { - int num_to_read = + yy_size_t num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ - YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { - int new_size = b->yy_buf_size * 2; + yy_size_t new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; @@ -2966,7 +3022,7 @@ static int yy_get_next_buffer (void) /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), - (yy_n_chars), (size_t) num_to_read ); + (yy_n_chars), num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } @@ -2990,9 +3046,9 @@ static int yy_get_next_buffer (void) else ret_val = EOB_ACT_CONTINUE_SCAN; - if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + if ((int) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ - yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); @@ -3011,15 +3067,15 @@ static int yy_get_next_buffer (void) static yy_state_type yy_get_previous_state (void) { - register yy_state_type yy_current_state; - register char *yy_cp; + yy_state_type yy_current_state; + char *yy_cp; yy_current_state = (yy_start); yy_current_state += YY_AT_BOL(); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; @@ -3044,10 +3100,10 @@ static int yy_get_next_buffer (void) */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { - register int yy_is_jam; - register char *yy_cp = (yy_c_buf_p); + int yy_is_jam; + char *yy_cp = (yy_c_buf_p); - register YY_CHAR yy_c = 1; + YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; @@ -3062,12 +3118,14 @@ static int yy_get_next_buffer (void) yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 737); - return yy_is_jam ? 0 : yy_current_state; + return yy_is_jam ? 0 : yy_current_state; } - static void yyunput (int c, register char * yy_bp ) +#ifndef YY_NO_UNPUT + + static void yyunput (int c, char * yy_bp ) { - register char *yy_cp; + char *yy_cp; yy_cp = (yy_c_buf_p); @@ -3077,10 +3135,10 @@ static int yy_get_next_buffer (void) if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ - register int number_to_move = (yy_n_chars) + 2; - register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + yy_size_t number_to_move = (yy_n_chars) + 2; + char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; - register char *source = + char *source = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) @@ -3102,6 +3160,8 @@ static int yy_get_next_buffer (void) (yy_c_buf_p) = yy_cp; } +#endif + #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) @@ -3126,7 +3186,7 @@ static int yy_get_next_buffer (void) else { /* need more input */ - int offset = (yy_c_buf_p) - (yytext_ptr); + yy_size_t offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) @@ -3253,7 +3313,7 @@ static void yy_load_buffer_state (void) if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - b->yy_buf_size = size; + b->yy_buf_size = (yy_size_t)size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. @@ -3288,10 +3348,6 @@ static void yy_load_buffer_state (void) yyfree((void *) b ); } -#ifndef __cplusplus -extern int isatty (int ); -#endif /* __cplusplus */ - /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. @@ -3404,7 +3460,7 @@ void yypop_buffer_state (void) */ static void yyensure_buffer_stack (void) { - int num_to_alloc; + yy_size_t num_to_alloc; if (!(yy_buffer_stack)) { @@ -3412,7 +3468,7 @@ static void yyensure_buffer_stack (void) * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ - num_to_alloc = 1; + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); @@ -3429,7 +3485,7 @@ static void yyensure_buffer_stack (void) if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ - int grow_size = 8 /* arbitrary grow size */; + yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc @@ -3496,17 +3552,17 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. - * @param bytes the byte buffer to scan - * @param len the number of bytes in the buffer pointed to by @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ -YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len ) { YY_BUFFER_STATE b; char *buf; yy_size_t n; - int i; + yy_size_t i; /* Get memory for full buffer, including space for trailing EOB's. */ n = _yybytes_len + 2; @@ -3537,7 +3593,7 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) static void yy_fatal_error (yyconst char* msg ) { - (void) fprintf( stderr, "%s\n", msg ); + (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } @@ -3588,7 +3644,7 @@ FILE *yyget_out (void) /** Get the length of the current token. * */ -int yyget_leng (void) +yy_size_t yyget_leng (void) { return yyleng; } @@ -3603,29 +3659,29 @@ char *yyget_text (void) } /** Set the current line number. - * @param line_number + * @param _line_number line number * */ -void yyset_lineno (int line_number ) +void yyset_lineno (int _line_number ) { - yylineno = line_number; + yylineno = _line_number; } /** Set the input stream. This does not discard the current * input buffer. - * @param in_str A readable stream. + * @param _in_str A readable stream. * * @see yy_switch_to_buffer */ -void yyset_in (FILE * in_str ) +void yyset_in (FILE * _in_str ) { - yyin = in_str ; + yyin = _in_str ; } -void yyset_out (FILE * out_str ) +void yyset_out (FILE * _out_str ) { - yyout = out_str ; + yyout = _out_str ; } int yyget_debug (void) @@ -3633,9 +3689,9 @@ int yyget_debug (void) return yy_flex_debug; } -void yyset_debug (int bdebug ) +void yyset_debug (int _bdebug ) { - yy_flex_debug = bdebug ; + yy_flex_debug = _bdebug ; } static int yy_init_globals (void) @@ -3695,7 +3751,8 @@ int yylex_destroy (void) #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) { - register int i; + + int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } @@ -3704,7 +3761,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s ) { - register int n; + int n; for ( n = 0; s[n]; ++n ) ; @@ -3714,11 +3771,12 @@ static int yy_flex_strlen (yyconst char * s ) void *yyalloc (yy_size_t size ) { - return (void *) malloc( size ); + return (void *) malloc( size ); } void *yyrealloc (void * ptr, yy_size_t size ) { + /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter @@ -3731,9 +3789,9 @@ void *yyrealloc (void * ptr, yy_size_t size ) void yyfree (void * ptr ) { - free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" -#line 343 "lex.l" +#line 343 "../../kmflcomp/src/lex.l" diff --git a/linux/kmflcomp/src/memman.c b/linux/kmflcomp/src/memman.c index abf955477ffb77ab84c26b19457befea56b73c36..c3fc9d3ab3ce3be4caeff0aa841377f6358c46db 100644 --- a/linux/kmflcomp/src/memman.c +++ b/linux/kmflcomp/src/memman.c @@ -1,21 +1,5 @@ /* memman.c - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd - * - * This file is part of the KMFL compiler. - * - * The KMFL compiler is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The KMFL compiler 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the KMFL compiler; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * Copyright (C) 2005 SIL International * */ diff --git a/linux/kmflcomp/src/memman.h b/linux/kmflcomp/src/memman.h index ae458ffd6a8d912872abb6cf0a707132cd65d7bb..47dc80448a8035ced37b6598b3c5fbe626d48a46 100644 --- a/linux/kmflcomp/src/memman.h +++ b/linux/kmflcomp/src/memman.h @@ -1,21 +1,5 @@ /* memman.h - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd - * - * This file is part of the KMFL compiler. - * - * The KMFL compiler is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The KMFL compiler 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the KMFL compiler; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * Copyright (C) 2005 SIL International * */ diff --git a/linux/kmflcomp/src/utfconv.c b/linux/kmflcomp/src/utfconv.c index ef7b66e94126b112cb37ccb8a2cd12ee3fa60a2a..312b5640c85af52691fb96297805bf5bf92e93f3 100644 --- a/linux/kmflcomp/src/utfconv.c +++ b/linux/kmflcomp/src/utfconv.c @@ -1,23 +1,7 @@ /* utfconv.c - * Copyright (C) 2006 SIL International - * - * This file is part of the KMFL library. - * - * The KMFL library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * The KMFL library 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with the KMFL library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - * - */ + * Copyright (C) 2006 SIL International + * + */ #include #include "kmflutfconv.h" diff --git a/linux/libkmfl/COPYING b/linux/libkmfl/COPYING index d60c31a97a544b53039088d14fe9114583c0efc3..4587de8ab2d92f28bd11d013904a7efaa87f3391 100644 --- a/linux/libkmfl/COPYING +++ b/linux/libkmfl/COPYING @@ -1,340 +1,19 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the 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 Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. +Copyright (c) 2017 SIL International + +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, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/linux/libkmfl/ChangeLog b/linux/libkmfl/ChangeLog index 37a2e876083fdc1c002331cebfdbfb3e872f7cc9..a218f58328fd39b17095b831c5932a3e60602757 100644 --- a/linux/libkmfl/ChangeLog +++ b/linux/libkmfl/ChangeLog @@ -1,3 +1,10 @@ +libkmfl (10.99.1) + + * Change license to MIT as it is being moved into Keyman 11 + * Keyman is now owned by SIL + + -- Doug Rintoul Thu, 17 May 2018 11:43:22 +0700 + libkmfl (0.9.12) * fix debug messages diff --git a/linux/libkmfl/Makefile.am b/linux/libkmfl/Makefile.am index 5e6683605a01d29c1152210f6625ef8b8e34c092..6d55dfcb33390a56c9f30e414e672412a0dd41d8 100644 --- a/linux/libkmfl/Makefile.am +++ b/linux/libkmfl/Makefile.am @@ -2,7 +2,7 @@ SUBDIRS = include src ACLOCAL_AMFLAGS = -I m4 -libkmfldocdir = ${prefix}/doc/libkmfl +libkmfldocdir = ${docdir} libkmfldoc_DATA = \ README\ COPYING\ diff --git a/linux/libkmfl/debian/changelog b/linux/libkmfl/debian/changelog index 86219e934dacdc36e4b7319226fba7d064405de6..0f4d1252487d84afb3dc8bc9bb6a6a4ba31e7d37 100644 --- a/linux/libkmfl/debian/changelog +++ b/linux/libkmfl/debian/changelog @@ -1,3 +1,10 @@ +libkmfl (10.99.1-1) UNRELEASED; urgency=medium + + * Change license to MIT as libkmfl is being moved into Keyman 11 + * Keyman is now owned by SIL + + -- Daniel Glassey Thu, 17 May 2018 11:39:04 +0700 + libkmfl (0.9.12-1) unstable; urgency=low * fix debug messages diff --git a/linux/libkmfl/debian/copyright b/linux/libkmfl/debian/copyright index bfa97c3c289f5d34f35d592e078192244f027669..75763836b0e89b4c7cbfaff186719a6119dd312b 100644 --- a/linux/libkmfl/debian/copyright +++ b/linux/libkmfl/debian/copyright @@ -3,23 +3,25 @@ Upstream-Name: libkmfl Upstream-Contact: Doug Rintoul Files: * -Copyright: Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd -License: GPL-2+ +Copyright: Copyright (C) 2005-2018 SIL International +License: MIT -License: GPL-2+ - The KMFL library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. +License: MIT + 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, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: . - The KMFL library 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 - General Public License for more details. + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. . - You should have received a copy of the GNU General Public - License along with the KMFL library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - . - On Debian systems, the complete text of the GNU General - Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". + 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. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/linux/libkmfl/include/libkmfl.h b/linux/libkmfl/include/libkmfl.h old mode 100755 new mode 100644 index af64acdc7d9e1b44540738542f7fec523419edf9..cb0a83c272aebe671670fe0d608d206b991428eb --- a/linux/libkmfl/include/libkmfl.h +++ b/linux/libkmfl/include/libkmfl.h @@ -1,22 +1,26 @@ /* libkmfl.h - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd + * Copyright (C) 2005 SIL International * * This file is part of the KMFL library. * - * The KMFL library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * The KMFL library 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with the KMFL library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - * + * 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, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * 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. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * */ // LIBKMFL.H: Header for interpreter for Keyboard Mapping for Linux @@ -26,13 +30,13 @@ #ifdef __cplusplus extern "C" { #endif - + int kmfl_interpret(KMSI *p_kmsi, UINT key, UINT state); int kmfl_load_keyboard(const char *file); -int kmfl_check_keyboard(const char *file); +int kmfl_check_keyboard(const char *file); int kmfl_reload_keyboard(int keyboard_number); -int kmfl_reload_all_keyboards(void); +int kmfl_reload_all_keyboards(void); int kmfl_unload_keyboard(int keyboard_number); int kmfl_unload_all_keyboards(void); @@ -51,14 +55,14 @@ int kmfl_get_header(KMSI *p_kmsi,int hdrID,char *buf,int buflen); void DBGMSG(int debug,const char *fmt,...); void *ERRMSG(const char *fmt,...); -void clear_history(KMSI *p_kmsi); +void clear_history(KMSI *p_kmsi); int deadkey_in_history(KMSI *p_kmsi); -void set_history(KMSI *p_kmsi, ITEM * items, UINT nitems); +void set_history(KMSI *p_kmsi, ITEM * items, UINT nitems); extern int kmfl_debug; #ifdef __cplusplus } -#endif +#endif #endif /* *** end of LIBKMFL.H *** */ diff --git a/linux/libkmfl/libkmfl.prj b/linux/libkmfl/libkmfl.prj deleted file mode 100644 index 0618c4f924f0cbaaef987b042dd0bd635bb5335b..0000000000000000000000000000000000000000 --- a/linux/libkmfl/libkmfl.prj +++ /dev/null @@ -1,116 +0,0 @@ -# Anjuta Version 1.2.1 -Compatibility Level: 1 - - -Keystroke interpreter for KMFL - - - - - - - - - - - - - - - - - -props.file.type=project - -anjuta.version=1.2.1 -anjuta.compatibility.level=1 - -project.name=libkmfl -project.type=GENERIC -project.target.type=DYNAMIC_LIB -project.version=0.3 -project.author=John Durdin -project.source.target=libkmfl -project.has.gettext=0 -project.gui.command= -project.programming.language=C -project.excluded.modules=intl - -project.config.extra.modules.before= -project.config.extra.modules.after= -project.config.blocked=0 -project.config.disable.overwriting=0 0 0 0 0 0 0 0 0 - -project.menu.entry=libkmfl Version 0.3 -project.menu.group=Applications -project.menu.comment=libkmfl Version 0.3 -project.menu.icon= -project.menu.need.terminal=0 - -project.configure.options= -anjuta.program.arguments= -preferences.build.option.jobs=0 -preferences.build.option.silent=0 -preferences.build.option.autosave=0 -preferences.anjuta.make.options=-k -preferences.make=make -preferences.build.option.keep.going=1 -preferences.build.option.warn.undef=0 -preferences.autoformat.custom.style= -i8 -sc -bli0 -bl0 -cbi0 -ss -preferences.indent.opening=0 -preferences.autoformat.disable=1 -preferences.indent.automatic=1 -preferences.use.tabs=1 -preferences.indent.size=4 -preferences.tabsize=4 -preferences.indent.closing=0 - -module.include.name=include -module.include.type= -module.include.files=\ - kmfl.h - -module.source.name=src -module.source.type= -module.source.files=\ - main.c\ - ConvertUTF.c\ - kmfl_interpreter.c\ - kmfl_load_keyboard.c\ - kmfl_messages.c\ - ConvertUTF.h - -module.pixmap.name=pixmaps -module.pixmap.type= -module.pixmap.files= - -module.data.name=data -module.data.type= -module.data.files= - -module.help.name=help -module.help.type= -module.help.files= - -module.doc.name=doc -module.doc.type= -module.doc.files= - -module.po.files= - -compiler.options.supports= -compiler.options.include.paths=\ - $(top_srcdir)/include -compiler.options.library.paths= -compiler.options.libraries= -compiler.options.libraries.selected= -compiler.options.defines= -compiler.options.defines.selected= -compiler.options.warning.buttons=0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 -compiler.options.optimize.buttons=1 0 0 0 -compiler.options.other.buttons=1 0 -compiler.options.other.c.flags= -compiler.options.other.l.flags= -compiler.options.other.l.libs= - -project.src.paths= diff --git a/linux/libkmfl/libkmfl.pws b/linux/libkmfl/libkmfl.pws deleted file mode 100644 index aab0f240a32fbe876afb3bd07fb4e803ce180403..0000000000000000000000000000000000000000 --- a/linux/libkmfl/libkmfl.pws +++ /dev/null @@ -1,59 +0,0 @@ - -[filenumbers] -0=167 -1=222 -2=285 -3=33 -4=1 -5=1 - -[filemarkers] -0= -1= -2= -3= -4= -5= - -[File View] -filter.file.unmatch=*.so *.o *.a *.la -filter.file.ignore.hidden=0 -filter.dir.ignore.hidden=0 - -[executer] -RunInTerminal=true - -[Project State] -clean before build=false - -[replace_text] -0=keyboard_number -1=connection - -[find_text] -0=erase_char -1=delete -2=erase -3=unload_key -4=p_first_instance - -[filelist] -0=/home/doug/Projects/libkmfl-0.3/include/kmfl.h -1=/home/doug/Projects/libkmfl-0.3/src/kmfl_load_keyboard.c -2=/home/doug/Projects/libkmfl-0.3/src/ConvertUTF.c -3=/home/doug/Projects/libkmfl-0.3/src/kmfl_interpreter.c -4=/home/doug/Projects/libkmfl-0.3/src/kmfl_messages.c -5=/home/doug/Projects/libkmfl-0.3/src/main.c - -[Project Tree] -0=0 -1=0:0 -2=0:1 - -[Symbol Tree] -0=0 -1=2 -2=3 - -[File Tree] -0=0 diff --git a/linux/libkmfl/libkmfl.rbc b/linux/libkmfl/libkmfl.rbc deleted file mode 100644 index e126a2b47d5473ec31e56f98502323ff361bc043..0000000000000000000000000000000000000000 --- a/linux/libkmfl/libkmfl.rbc +++ /dev/null @@ -1,73 +0,0 @@ - - - -1.0 -libkmfl -0.3 - - -libkmfl -0.3 -1 -SIL &lt;doug_rintoul@sil.org&gt; -Doug Rintoul &lt;doug_rintoul@sil.org&gt; -GPL -i386 -/var/tmp/libkmfl -/usr -%{name}-%{version}.tar.gz -AUTHORS -COPYING -ChangeLog -README -INSTALL -NEWS -TODO - - - - - - - - -False -False -%base% -User Interface/X -%{name} -%anjuta% -%{_libdir}/libkmfl.so.0.0.0 -%{_libdir}/libkmfl.so.0 - - - -True -False -libs -System Environment/Libraries -Dynamic libraries for %{name} -%anjuta% - - -False -False -devel -Development/Libraries -Development libraries and headers to use %{name} in an application -%anjuta% -%{_includedir}/libkmfl/kmfl.h -%{_libdir}/libkmfl.la -%{_libdir}/libkmfl.a -%{_libdir}/libkmfl.so - - - diff --git a/linux/libkmfl/src/kmfl_interpreter.c b/linux/libkmfl/src/kmfl_interpreter.c index 37e10a23685e0d4fe6794d0ecace658a20d9f2dc..57e8aa69f093c5038b50144c654bb2533c8cd82d 100644 --- a/linux/libkmfl/src/kmfl_interpreter.c +++ b/linux/libkmfl/src/kmfl_interpreter.c @@ -1,22 +1,8 @@ /* kmfl_interpreter.c - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd + * Copyright (C) 2005 SIL International * * This file is part of the KMFL library. * - * The KMFL library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * The KMFL library 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with the KMFL library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - * */ /* diff --git a/linux/libkmfl/src/kmfl_load_keyboard.c b/linux/libkmfl/src/kmfl_load_keyboard.c index 85bf0cbe3927ac366cdf86cb0d20ea1f61286a8d..d9bb670f3ee4db4df6e14ff52129864dc683c3eb 100644 --- a/linux/libkmfl/src/kmfl_load_keyboard.c +++ b/linux/libkmfl/src/kmfl_load_keyboard.c @@ -1,23 +1,9 @@ /* kmfl_load_keyboard.c - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd - * - * This file is part of the KMFL library. - * - * The KMFL library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * The KMFL library 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with the KMFL library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - * - */ + * Copyright (C) 2005 SIL International + * + * This file is part of the KMFL library. + * + */ /* diff --git a/linux/libkmfl/src/kmfl_messages.c b/linux/libkmfl/src/kmfl_messages.c index fb8958a3a601ecc8ec6092921a95cd727da50cc2..033c86613c892906c665af1bb4a5b83bf72b1791 100644 --- a/linux/libkmfl/src/kmfl_messages.c +++ b/linux/libkmfl/src/kmfl_messages.c @@ -1,23 +1,9 @@ /* kmfl_messages.c - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd - * - * This file is part of the KMFL library. - * - * The KMFL library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * The KMFL library 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with the KMFL library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - * - */ + * Copyright (C) 2005 SIL International + * + * This file is part of the KMFL library. + * + */ /* diff --git a/mac/.gitignore b/mac/.gitignore index 1a9f734cb403305c71d6c5a717da8bb1a474fbd2..a162af22df9342cc6e70cfb8a8aeb94e1144305b 100644 --- a/mac/.gitignore +++ b/mac/.gitignore @@ -3,6 +3,7 @@ **/xcuserdata Keyman4MacIM/output/* Keyman4MacIM/Keyman4MacIM/Frameworks/** +Keyman4MacIM/Pods/** Keyman4Mac/Keyman4Mac/Frameworks/** Carthage/** **/build diff --git a/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj b/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj index 129be2825e4a877b8c3076acdba65392f7f30ddb..db38f50e07771cad0a8eff961a8013b8a6a2ba4b 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj +++ b/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 37407275F02D5CDA553EE07E /* libPods-Keyman.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 97064F9FBF9E0D09264AF6C5 /* libPods-Keyman.a */; }; 9800EC5A1C02940300BF0FB5 /* keyman-for-mac-os-license.html in Resources */ = {isa = PBXBuildFile; fileRef = 9800EC591C02940300BF0FB5 /* keyman-for-mac-os-license.html */; }; 9803C9D81B0EFB3B0082A6F9 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9803C9D71B0EFB3B0082A6F9 /* WebKit.framework */; }; 983247281A9EA28F0010B90C /* KeymanEngine4Mac.framework in Copy Files */ = {isa = PBXBuildFile; fileRef = 984C2B211A79DF1B0023F89D /* KeymanEngine4Mac.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -19,7 +20,7 @@ 9836B3741AE5F11D00780482 /* ZipArchive.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9836B36F1AE5F11D00780482 /* ZipArchive.mm */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 984B8F441AF1C3D900E096A8 /* OSKWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 984B8F421AF1C3D900E096A8 /* OSKWindowController.m */; }; 984B8F451AF1C3D900E096A8 /* OSKWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 984B8F431AF1C3D900E096A8 /* OSKWindowController.xib */; }; - 984C2B221A79DF1B0023F89D /* KeymanEngine4Mac.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 984C2B211A79DF1B0023F89D /* KeymanEngine4Mac.framework */; }; + 984C2B221A79DF1B0023F89D /* KeymanEngine4Mac.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 984C2B211A79DF1B0023F89D /* KeymanEngine4Mac.framework */; settings = {ATTRIBUTES = (Required, ); }; }; 9874C3211B536847000BB543 /* info.png in Resources */ = {isa = PBXBuildFile; fileRef = 9874C31E1B536847000BB543 /* info.png */; }; 9874C3221B536847000BB543 /* keyman.png in Resources */ = {isa = PBXBuildFile; fileRef = 9874C31F1B536847000BB543 /* keyman.png */; }; 9874C3231B536847000BB543 /* SideImage.bmp in Resources */ = {isa = PBXBuildFile; fileRef = 9874C3201B536847000BB543 /* SideImage.bmp */; }; @@ -48,10 +49,21 @@ 98FE105E1B4DE8F400525F54 /* NSWindow+SuppMethods.m in Sources */ = {isa = PBXBuildFile; fileRef = 98FE105D1B4DE8F400525F54 /* NSWindow+SuppMethods.m */; }; 98FE10631B4DEE5600525F54 /* KMInfoWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 98FE10611B4DEE5600525F54 /* KMInfoWindowController.m */; }; 98FE10641B4DEE5600525F54 /* KMInfoWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98FE10621B4DEE5600525F54 /* KMInfoWindowController.xib */; }; + E211769D20E182DD00F8065D /* NoContextTestClient.m in Sources */ = {isa = PBXBuildFile; fileRef = E211769C20E182DD00F8065D /* NoContextTestClient.m */; }; + E21176A020E18C5200F8065D /* AppleCompliantTestClient.m in Sources */ = {isa = PBXBuildFile; fileRef = E211769F20E18C5200F8065D /* AppleCompliantTestClient.m */; }; + E211CCF620B600A500505C36 /* KeymanEngine4Mac.framework.dSYM in CopyFiles */ = {isa = PBXBuildFile; fileRef = E211CCF520B600A500505C36 /* KeymanEngine4Mac.framework.dSYM */; }; + E21291A920A4DD680049790C /* Crashlytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E21291A820A4DD680049790C /* Crashlytics.framework */; }; + E21291AB20A4DDE70049790C /* Fabric.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E21291AA20A4DDE70049790C /* Fabric.framework */; }; E21799051FC5B7BC00F2D66A /* KMInputMethodEventHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = E21799041FC5B7BC00F2D66A /* KMInputMethodEventHandler.m */; }; + E218402F20A539E20035AADB /* Crashlytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E21291A820A4DD680049790C /* Crashlytics.framework */; }; + E218403020A53A010035AADB /* Fabric.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E21291AA20A4DDE70049790C /* Fabric.framework */; }; + E21E645820C04EA8000D6274 /* logo.png in Resources */ = {isa = PBXBuildFile; fileRef = E21E645720C04EA7000D6274 /* logo.png */; }; E22020F6200506F300B74FAC /* KMInputMethodSafariClientEventHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = E22020F5200506F300B74FAC /* KMInputMethodSafariClientEventHandler.m */; }; E240F599202DED740000067D /* KMPackage.m in Sources */ = {isa = PBXBuildFile; fileRef = E240F598202DED740000067D /* KMPackage.m */; }; E24C79EA1FFFCC7500D8E46F /* KMInputMethodBrowserClientEventHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = E24C79E91FFFCC7500D8E46F /* KMInputMethodBrowserClientEventHandler.m */; }; + E2585A7D20DD68BA00CBB994 /* KMInputMethodEventHandlerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E2585A7C20DD68BA00CBB994 /* KMInputMethodEventHandlerTests.m */; }; + E2585A7F20DD6C3C00CBB994 /* KMMethodEventHandlerTests.kmx in Resources */ = {isa = PBXBuildFile; fileRef = E2585A7E20DD6C3C00CBB994 /* KMMethodEventHandlerTests.kmx */; }; + E2585A8120DD7CF100CBB994 /* TestAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E2585A8020DD7CF100CBB994 /* TestAppDelegate.m */; }; E27BA9CE2020322000D273E7 /* OCMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E27BA9CD2020322000D273E7 /* OCMock.framework */; }; E27BA9D1202036E200D273E7 /* OCMock.framework.dSYM in CopyFiles */ = {isa = PBXBuildFile; fileRef = E27BA9D0202036E200D273E7 /* OCMock.framework.dSYM */; }; E27BA9D32020D8BF00D273E7 /* SimpleTest.kmx in Resources */ = {isa = PBXBuildFile; fileRef = E27BA9D22020D8BF00D273E7 /* SimpleTest.kmx */; }; @@ -61,6 +73,8 @@ E28914D72024E6220048E71E /* KeymanEngine4Mac.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 984C2B211A79DF1B0023F89D /* KeymanEngine4Mac.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; E28914D92028A78C0048E71E /* OCMock.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = E28914D82028A78C0048E71E /* OCMock.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; E29F22F4201A59B1005EA234 /* KMInputMethodBrowserClientEventHandlerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E29F22F3201A59B1005EA234 /* KMInputMethodBrowserClientEventHandlerTests.m */; }; + E2D5529D20DD8E0200D77CFB /* LegacyTestClient.m in Sources */ = {isa = PBXBuildFile; fileRef = E2D5529C20DD8E0200D77CFB /* LegacyTestClient.m */; }; + E61216E78B7F03FE755687F1 /* libPods-KeymanTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9E7FB3417C46A01721AD32D0 /* libPods-KeymanTests.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -85,6 +99,16 @@ name = "Copy Files"; runOnlyForDeploymentPostprocessing = 0; }; + E211CCF420B5FE7A00505C36 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 16; + files = ( + E211CCF620B600A500505C36 /* KeymanEngine4Mac.framework.dSYM in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; E27BA9CF202036BA00D273E7 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -100,6 +124,10 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 2B51C9B443060BB3B4A1AE8E /* Pods-Keyman.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Keyman.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Keyman/Pods-Keyman.debug.xcconfig"; sourceTree = ""; }; + 750C7C7BCA2917BAF99E6B69 /* Pods-Keyman.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Keyman.release.xcconfig"; path = "Pods/Target Support Files/Pods-Keyman/Pods-Keyman.release.xcconfig"; sourceTree = ""; }; + 8577C0C788461AFE564DDF4F /* Pods-KeymanTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-KeymanTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-KeymanTests/Pods-KeymanTests.debug.xcconfig"; sourceTree = ""; }; + 97064F9FBF9E0D09264AF6C5 /* libPods-Keyman.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Keyman.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 9800EC591C02940300BF0FB5 /* keyman-for-mac-os-license.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "keyman-for-mac-os-license.html"; sourceTree = ""; }; 9803C9D71B0EFB3B0082A6F9 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; 9832472C1A9EABC70010B90C /* KMConfigColumn1CellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KMConfigColumn1CellView.h; path = Keyman4MacIM/KMConfiguration/KMConfigColumn1CellView.h; sourceTree = ""; }; @@ -164,8 +192,17 @@ 98FE10601B4DEE5600525F54 /* KMInfoWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KMInfoWindowController.h; path = Keyman4MacIM/KMInfoWindow/KMInfoWindowController.h; sourceTree = ""; }; 98FE10611B4DEE5600525F54 /* KMInfoWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KMInfoWindowController.m; path = Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m; sourceTree = ""; }; 98FE10621B4DEE5600525F54 /* KMInfoWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = KMInfoWindowController.xib; path = Keyman4MacIM/KMInfoWindow/KMInfoWindowController.xib; sourceTree = ""; }; + 9E7FB3417C46A01721AD32D0 /* libPods-KeymanTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-KeymanTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + E211769B20E1826800F8065D /* NoContextTestClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NoContextTestClient.h; sourceTree = ""; }; + E211769C20E182DD00F8065D /* NoContextTestClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NoContextTestClient.m; sourceTree = ""; }; + E211769E20E18C0B00F8065D /* AppleCompliantTestClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppleCompliantTestClient.h; sourceTree = ""; }; + E211769F20E18C5200F8065D /* AppleCompliantTestClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppleCompliantTestClient.m; sourceTree = ""; }; + E211CCF520B600A500505C36 /* KeymanEngine4Mac.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = KeymanEngine4Mac.framework.dSYM; path = Keyman4MacIM/Frameworks/KeymanEngine4Mac.framework.dSYM; sourceTree = ""; }; + E21291A820A4DD680049790C /* Crashlytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Crashlytics.framework; path = ../../Carthage/Build/Mac/Crashlytics.framework; sourceTree = ""; }; + E21291AA20A4DDE70049790C /* Fabric.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Fabric.framework; path = ../../Carthage/Build/Mac/Fabric.framework; sourceTree = ""; }; E21799031FC5B74D00F2D66A /* KMInputMethodEventHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KMInputMethodEventHandler.h; sourceTree = ""; }; E21799041FC5B7BC00F2D66A /* KMInputMethodEventHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KMInputMethodEventHandler.m; sourceTree = ""; }; + E21E645720C04EA7000D6274 /* logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logo.png; path = Keyman4MacIM/KMAboutWindow/logo.png; sourceTree = SOURCE_ROOT; }; E22020F3200505EF00B74FAC /* KMInputMethodSafariClientEventHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KMInputMethodSafariClientEventHandler.h; sourceTree = ""; }; E22020F5200506F300B74FAC /* KMInputMethodSafariClientEventHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KMInputMethodSafariClientEventHandler.m; sourceTree = ""; }; E22020F920050D6300B74FAC /* KMInputMethodBrowserClientEventHandlerProtected.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KMInputMethodBrowserClientEventHandlerProtected.h; sourceTree = ""; }; @@ -174,6 +211,10 @@ E24C79E91FFFCC7500D8E46F /* KMInputMethodBrowserClientEventHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KMInputMethodBrowserClientEventHandler.m; sourceTree = ""; }; E24C79EB1FFFCE3000D8E46F /* KMInputMethodBrowserClientEventHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KMInputMethodBrowserClientEventHandler.h; sourceTree = ""; }; E24C79EC1FFFEA6B00D8E46F /* KMInputMethodEventHandlerProtected.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KMInputMethodEventHandlerProtected.h; sourceTree = ""; }; + E2585A7C20DD68BA00CBB994 /* KMInputMethodEventHandlerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KMInputMethodEventHandlerTests.m; sourceTree = ""; }; + E2585A7E20DD6C3C00CBB994 /* KMMethodEventHandlerTests.kmx */ = {isa = PBXFileReference; lastKnownFileType = file; path = KMMethodEventHandlerTests.kmx; sourceTree = ""; }; + E2585A8020DD7CF100CBB994 /* TestAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestAppDelegate.m; sourceTree = ""; }; + E2585A8220DD7D3F00CBB994 /* TestAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestAppDelegate.h; sourceTree = ""; }; E27BA9CD2020322000D273E7 /* OCMock.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OCMock.framework; path = ../Carthage/Build/Mac/OCMock.framework; sourceTree = ""; }; E27BA9D0202036E200D273E7 /* OCMock.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = OCMock.framework.dSYM; path = ../Carthage/Build/Mac/OCMock.framework.dSYM; sourceTree = ""; }; E27BA9D22020D8BF00D273E7 /* SimpleTest.kmx */ = {isa = PBXFileReference; lastKnownFileType = file; path = SimpleTest.kmx; sourceTree = ""; }; @@ -181,6 +222,10 @@ E29F22F1201A59B1005EA234 /* KeymanTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KeymanTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; E29F22F3201A59B1005EA234 /* KMInputMethodBrowserClientEventHandlerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KMInputMethodBrowserClientEventHandlerTests.m; sourceTree = ""; }; E29F22F5201A59B2005EA234 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + E2C92D4720B46CEA00742A7D /* KeymanEngine4Mac.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = KeymanEngine4Mac.framework.dSYM; path = Keyman4MacIM/Frameworks/KeymanEngine4Mac.framework.dSYM; sourceTree = ""; }; + E2D5529B20DD8D6100D77CFB /* LegacyTestClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LegacyTestClient.h; sourceTree = ""; }; + E2D5529C20DD8E0200D77CFB /* LegacyTestClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LegacyTestClient.m; sourceTree = ""; }; + FA67C64E3D2743D2BCF46ED1 /* Pods-KeymanTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-KeymanTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-KeymanTests/Pods-KeymanTests.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -189,8 +234,11 @@ buildActionMask = 2147483647; files = ( 98D6DA7B1A799F0B00B09822 /* InputMethodKit.framework in Frameworks */, + E21291AB20A4DDE70049790C /* Fabric.framework in Frameworks */, + E21291A920A4DD680049790C /* Crashlytics.framework in Frameworks */, 984C2B221A79DF1B0023F89D /* KeymanEngine4Mac.framework in Frameworks */, 9803C9D81B0EFB3B0082A6F9 /* WebKit.framework in Frameworks */, + 37407275F02D5CDA553EE07E /* libPods-Keyman.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -198,14 +246,28 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + E218403020A53A010035AADB /* Fabric.framework in Frameworks */, + E218402F20A539E20035AADB /* Crashlytics.framework in Frameworks */, E28914D32024D1B80048E71E /* KeymanEngine4Mac.framework in Frameworks */, E27BA9CE2020322000D273E7 /* OCMock.framework in Frameworks */, + E61216E78B7F03FE755687F1 /* libPods-KeymanTests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 2CDC487CDFFBB26D621D73BD /* Pods */ = { + isa = PBXGroup; + children = ( + 2B51C9B443060BB3B4A1AE8E /* Pods-Keyman.debug.xcconfig */, + 750C7C7BCA2917BAF99E6B69 /* Pods-Keyman.release.xcconfig */, + 8577C0C788461AFE564DDF4F /* Pods-KeymanTests.debug.xcconfig */, + FA67C64E3D2743D2BCF46ED1 /* Pods-KeymanTests.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; 983246EC1A9E8E860010B90C /* KMConfiguration */ = { isa = PBXGroup; children = ( @@ -263,6 +325,7 @@ 9874C31E1B536847000BB543 /* info.png */, 9874C31F1B536847000BB543 /* keyman.png */, 9874C3201B536847000BB543 /* SideImage.bmp */, + E21E645720C04EA7000D6274 /* logo.png */, ); path = Images; sourceTree = ""; @@ -281,12 +344,15 @@ 989C9BFF1A7876DE00A20425 = { isa = PBXGroup; children = ( + E2C92D4720B46CEA00742A7D /* KeymanEngine4Mac.framework.dSYM */, + E211CCF520B600A500505C36 /* KeymanEngine4Mac.framework.dSYM */, E28914D82028A78C0048E71E /* OCMock.framework */, E27BA9D0202036E200D273E7 /* OCMock.framework.dSYM */, 989C9C0A1A7876DE00A20425 /* Keyman4MacIM */, E29F22F2201A59B1005EA234 /* KeymanTests */, 989C9C091A7876DE00A20425 /* Products */, E27BA9CC2020321F00D273E7 /* Frameworks */, + 2CDC487CDFFBB26D621D73BD /* Pods */, ); sourceTree = ""; }; @@ -367,6 +433,8 @@ 98D6DA791A799EE700B09822 /* Frameworks */ = { isa = PBXGroup; children = ( + E21291AA20A4DDE70049790C /* Fabric.framework */, + E21291A820A4DD680049790C /* Crashlytics.framework */, 98D6DA7A1A799F0B00B09822 /* InputMethodKit.framework */, 984C2B211A79DF1B0023F89D /* KeymanEngine4Mac.framework */, 9803C9D71B0EFB3B0082A6F9 /* WebKit.framework */, @@ -411,6 +479,8 @@ isa = PBXGroup; children = ( E27BA9CD2020322000D273E7 /* OCMock.framework */, + 97064F9FBF9E0D09264AF6C5 /* libPods-Keyman.a */, + 9E7FB3417C46A01721AD32D0 /* libPods-KeymanTests.a */, ); name = Frameworks; sourceTree = ""; @@ -418,9 +488,19 @@ E29F22F2201A59B1005EA234 /* KeymanTests */ = { isa = PBXGroup; children = ( + E2585A7E20DD6C3C00CBB994 /* KMMethodEventHandlerTests.kmx */, E27BA9D22020D8BF00D273E7 /* SimpleTest.kmx */, E29F22F3201A59B1005EA234 /* KMInputMethodBrowserClientEventHandlerTests.m */, + E2585A7C20DD68BA00CBB994 /* KMInputMethodEventHandlerTests.m */, E29F22F5201A59B2005EA234 /* Info.plist */, + E2585A8220DD7D3F00CBB994 /* TestAppDelegate.h */, + E2585A8020DD7CF100CBB994 /* TestAppDelegate.m */, + E2D5529B20DD8D6100D77CFB /* LegacyTestClient.h */, + E2D5529C20DD8E0200D77CFB /* LegacyTestClient.m */, + E211769B20E1826800F8065D /* NoContextTestClient.h */, + E211769C20E182DD00F8065D /* NoContextTestClient.m */, + E211769E20E18C0B00F8065D /* AppleCompliantTestClient.h */, + E211769F20E18C5200F8065D /* AppleCompliantTestClient.m */, ); path = KeymanTests; sourceTree = ""; @@ -432,11 +512,14 @@ isa = PBXNativeTarget; buildConfigurationList = 989C9C251A7876DE00A20425 /* Build configuration list for PBXNativeTarget "Keyman" */; buildPhases = ( + D2FF67BB6C749BA6861F5E25 /* [CP] Check Pods Manifest.lock */, E2588F2E1F2644850061C9C4 /* ShellScript */, 989C9C041A7876DE00A20425 /* Sources */, 989C9C051A7876DE00A20425 /* Frameworks */, 989C9C061A7876DE00A20425 /* Resources */, 983247261A9EA1DD0010B90C /* Copy Files */, + E211CCF420B5FE7A00505C36 /* CopyFiles */, + E21291A120A33CA50049790C /* ShellScript */, ); buildRules = ( ); @@ -451,6 +534,7 @@ isa = PBXNativeTarget; buildConfigurationList = E29F22F8201A59B2005EA234 /* Build configuration list for PBXNativeTarget "KeymanTests" */; buildPhases = ( + 3263C54E5ED17882C05003D5 /* [CP] Check Pods Manifest.lock */, E29F22ED201A59B1005EA234 /* Sources */, E29F22EE201A59B1005EA234 /* Frameworks */, E29F22EF201A59B1005EA234 /* Resources */, @@ -521,6 +605,7 @@ 989C9C131A7876DE00A20425 /* Images.xcassets in Resources */, 98E2CEA11A92C39C00AE2455 /* InfoPlist.strings in Resources */, 98BF92491BF0216F0002126A /* logo.png in Resources */, + E21E645820C04EA8000D6274 /* logo.png in Resources */, 9874C3211B536847000BB543 /* info.png in Resources */, 98E672A01B532F5E00DBDE2F /* KMDownloadKBWindowController.xib in Resources */, 984B8F451AF1C3D900E096A8 /* OSKWindowController.xib in Resources */, @@ -540,12 +625,63 @@ buildActionMask = 2147483647; files = ( E27BA9D32020D8BF00D273E7 /* SimpleTest.kmx in Resources */, + E2585A7F20DD6C3C00CBB994 /* KMMethodEventHandlerTests.kmx in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 3263C54E5ED17882C05003D5 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-KeymanTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + D2FF67BB6C749BA6861F5E25 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Keyman-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + E21291A120A33CA50049790C /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if [ \"${CONFIGURATION}\" = \"Release\" ]; then\n if [ \"${FABRIC_API_KEY_KEYMAN4MACIM}\" != \"\" ]; then\nPods/Fabric/upload-symbols -a ${FABRIC_API_KEY_KEYMAN4MACIM} -p mac build/${CONFIGURATION}\n fi\nelse\n Pods/Fabric/upload-symbols -a 68056571ada44ad2d93864380272808ada308b24 -p mac build/${CONFIGURATION}\nfi\n"; + showEnvVarsInLog = 0; + }; E2588F2E1F2644850061C9C4 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -557,7 +693,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "SRC_DIR=\"${PROJECT_DIR}/../KeymanEngine4Mac/build/${CONFIGURATION}\"\nDEST_DIR=\"${PROJECT_DIR}/Keyman4MacIM/Frameworks\"\nFRAMEWORK_NAME=\"KeymanEngine4Mac.framework\"\nSRC_FRAMEWORK_PATH=\"${SRC_DIR}/KeymanEngine4Mac.framework\"\nDEST_FRAMEWORK_PATH=\"${DEST_DIR}/${FRAMEWORK_NAME}\"\nif [[ \"${SRC_DIR}\" == \"${DEST_DIR}\" ]]; then\n exit 0\nfi\n\necho \"Source: ${SRC_FRAMEWORK_PATH}\"\necho \"Dest: ${DEST_FRAMEWORK_PATH}\"\n\nif [ ! -d \"${SRC_FRAMEWORK_PATH}\" ]; then\n if [ ! -d \"${DEST_FRAMEWORK_PATH}\" ]; then\n echo \"Keyman engine framework must be built first!\"\n exit 1\n fi\n exit 0\nfi\n\necho \"Copying Keyman Engine framework from ${SRC_DIR} to ${DEST_DIR}...\"\n\nif [ ! -d \"${DEST_DIR}\" ]; then\n if [ -e \"${DEST_DIR}\" ]; then\n echo \"${DEST_DIR} exists, but it is not a directory!\"\n exit 1\n else\n mkdir -p \"$DEST_DIR\"\n fi\nelif [ -d \"${DEST_FRAMEWORK_PATH}\" ]; then\n rm -rf \"${DEST_FRAMEWORK_PATH}\"\nfi\n\ncp -Rf \"${SRC_FRAMEWORK_PATH}\" \"${DEST_FRAMEWORK_PATH}\""; + shellScript = "SRC_DIR=\"${PROJECT_DIR}/../KeymanEngine4Mac/build/${CONFIGURATION}\"\nDEST_DIR=\"${PROJECT_DIR}/Keyman4MacIM/Frameworks\"\nFRAMEWORK_NAME=\"KeymanEngine4Mac.framework\"\nSRC_FRAMEWORK_PATH=\"${SRC_DIR}/${FRAMEWORK_NAME}\"\nDEST_FRAMEWORK_PATH=\"${DEST_DIR}/${FRAMEWORK_NAME}\"\nif [[ \"${SRC_DIR}\" == \"${DEST_DIR}\" ]]; then\n exit 0\nfi\n\necho \"Source: ${SRC_FRAMEWORK_PATH}\"\necho \"Dest: ${DEST_FRAMEWORK_PATH}\"\n\nif [ ! -d \"${SRC_FRAMEWORK_PATH}\" ]; then\n if [ ! -d \"${DEST_FRAMEWORK_PATH}\" ]; then\n echo \"Keyman engine framework must be built first!\"\n exit 1\n fi\n exit 0\nfi\n\necho \"Copying Keyman Engine framework from ${SRC_DIR} to ${DEST_DIR}...\"\n\nif [ ! -d \"${DEST_DIR}\" ]; then\n if [ -e \"${DEST_DIR}\" ]; then\n echo \"${DEST_DIR} exists, but it is not a directory!\"\n exit 1\n else\n mkdir -p \"$DEST_DIR\"\n fi\nelif [ -d \"${DEST_FRAMEWORK_PATH}\" ]; then\n rm -rf \"${DEST_FRAMEWORK_PATH}\"\nfi\n\ncp -Rf \"${SRC_FRAMEWORK_PATH}\" \"${DEST_FRAMEWORK_PATH}\"\nif [ -e \"${SRC_FRAMEWORK_PATH}.dSYM\" ]; then\n cp -Rf \"${SRC_FRAMEWORK_PATH}.dSYM\" \"${DEST_DIR}\"\nfi"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -599,8 +735,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + E211769D20E182DD00F8065D /* NoContextTestClient.m in Sources */, + E2D5529D20DD8E0200D77CFB /* LegacyTestClient.m in Sources */, E29F22F4201A59B1005EA234 /* KMInputMethodBrowserClientEventHandlerTests.m in Sources */, E28914D52024E3DF0048E71E /* KMInputMethodBrowserClientEventHandler.m in Sources */, + E2585A7D20DD68BA00CBB994 /* KMInputMethodEventHandlerTests.m in Sources */, + E21176A020E18C5200F8065D /* AppleCompliantTestClient.m in Sources */, + E2585A8120DD7CF100CBB994 /* TestAppDelegate.m in Sources */, E28914D62024E4010048E71E /* KMInputMethodEventHandler.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -704,7 +845,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = YES; + COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -724,17 +865,21 @@ }; 989C9C261A7876DE00A20425 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 2B51C9B443060BB3B4A1AE8E /* Pods-Keyman.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "Developer ID Application"; COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 3YE4W86L3G; EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES = "*.nib *.lproj *.framework *.gch *.xcode* *.xcassets (*) .DS_Store CVS .svn .git .hg *.pbproj *.pbxproj"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Keyman4MacIM/Frameworks", + "$(PROJECT_DIR)/../Carthage/Build/Mac/**", ); - HEADER_SEARCH_PATHS = ""; + HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = Keyman4MacIM/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.7; @@ -742,22 +887,26 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = ""; + STRIP_INSTALLED_PRODUCT = YES; }; name = Debug; }; 989C9C271A7876DE00A20425 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 750C7C7BCA2917BAF99E6B69 /* Pods-Keyman.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "Developer ID Application"; COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; DEVELOPMENT_TEAM = 3YE4W86L3G; EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES = "*.nib *.lproj *.framework *.gch *.xcode* *.xcassets (*) .DS_Store CVS .svn .git .hg *.pbproj *.pbxproj"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Keyman4MacIM/Frameworks", + "$(PROJECT_DIR)/../Carthage/Build/Mac/**", ); - HEADER_SEARCH_PATHS = ""; + HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = Keyman4MacIM/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.7; @@ -765,11 +914,13 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = ""; + STRIP_INSTALLED_PRODUCT = YES; }; name = Release; }; E29F22F9201A59B2005EA234 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 8577C0C788461AFE564DDF4F /* Pods-KeymanTests.debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -789,7 +940,10 @@ "$(PROJECT_DIR)/../Carthage/Build/Mac/**", ); GCC_C_LANGUAGE_STANDARD = gnu11; - HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac/**"; + HEADER_SEARCH_PATHS = ( + "$(PROJECT_DIR)/../Carthage/Build/Mac/**", + "$(inherited)", + ); INFOPLIST_FILE = KeymanTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.7; @@ -801,6 +955,7 @@ }; E29F22FA201A59B2005EA234 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = FA67C64E3D2743D2BCF46ED1 /* Pods-KeymanTests.release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; diff --git a/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/xcshareddata/xcschemes/Keyman.xcscheme b/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/xcshareddata/xcschemes/Keyman.xcscheme index 9fd741da12512cad71ccf17b3fac46eaaea3de89..c5b862367d3f49d0f9b7bcc8fe2742e0ec4e35be 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/xcshareddata/xcschemes/Keyman.xcscheme +++ b/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/xcshareddata/xcschemes/Keyman.xcscheme @@ -40,7 +40,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" shouldUseLaunchSchemeArgsEnv = "YES"> + + + + + + diff --git a/mac/Keyman4MacIM/Keyman4MacIM.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/mac/Keyman4MacIM/Keyman4MacIM.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000000000000000000000000000000000..18d981003d68d0546c4804ac2ff47dd97c6e7921 --- /dev/null +++ b/mac/Keyman4MacIM/Keyman4MacIM.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/mac/Keyman4MacIM/Keyman4MacIM/Info.plist b/mac/Keyman4MacIM/Keyman4MacIM/Info.plist index d7c44c45fb9e942eb2c6170a3cf5efeddb66ce6d..3bbe5f5d5b7353234080b41aa495a02c239f3dee 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/Info.plist +++ b/mac/Keyman4MacIM/Keyman4MacIM/Info.plist @@ -50,6 +50,20 @@ CFBundleVersion 10.0.0 + Fabric + + APIKey + 68056571ada44ad2d93864380272808ada308b24 + Kits + + + KitInfo + + KitName + Crashlytics + + + InputMethodConnectionName Keyman_Input_Connection InputMethodServerControllerClass diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.h b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.h index f77887b175f647bb996ea6a7cdb524d769e62d15..adc7343bd6d71a4799873c6e68c627959cc28f80 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.h +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.h @@ -10,7 +10,10 @@ #import "KMInputMethodAppDelegate.h" #import "KMConfigColumn1CellView.h" #import "KMConfigColumn3CellView.h" +#import "KMPackage.h" @interface KMConfigurationWindowController : NSWindowController +- (void)handleRequestToInstallPackage:(KMPackage *) package; + @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m index ab4ffe6def8f05423e29414b02b94a1e65a22711..68de881b899654207ba7e2ed564c9c823a3f4f2e 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m @@ -13,10 +13,13 @@ @property (nonatomic, weak) IBOutlet NSTableView *tableView; @property (nonatomic, weak) IBOutlet WebView *webView; @property (nonatomic, weak) IBOutlet NSButton *alwaysShowOSKCheckBox; +@property (nonatomic, weak) IBOutlet NSButton *useVerboseLoggingCheckBox; +@property (nonatomic, weak) IBOutlet NSTextField *verboseLoggingInfo; @property (nonatomic, strong) NSMutableArray *tableContents; @property (nonatomic, strong) NSTimer *reloadTimer; @property (nonatomic, strong) NSDate *lastReloadDate; @property (nonatomic, strong) NSAlert *deleteAlertView; +@property (nonatomic, strong) NSAlert *confirmKmpInstallAlertView; @end @implementation KMConfigurationWindowController @@ -57,10 +60,9 @@ [self.webView setFrameLoadDelegate:(id)self]; [self.webView.mainFrame loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://help.keyman.com/products/macosx/"]]]; - if (self.AppDelegate.alwaysShowOSK) - [self.alwaysShowOSKCheckBox setState:NSOnState]; - else - [self.alwaysShowOSKCheckBox setState:NSOffState]; + + [self.alwaysShowOSKCheckBox setState:(self.AppDelegate.alwaysShowOSK ? NSOnState : NSOffState)]; + [self.useVerboseLoggingCheckBox setState:(self.AppDelegate.useVerboseLogging ? NSOnState : NSOffState)]; } - (void)setTableView:(NSTableView *)tableView { @@ -371,10 +373,54 @@ - (IBAction)alwaysShowOSKCheckBoxAction:(id)sender { NSButton *checkBox = (NSButton *)sender; - if (checkBox.state == NSOnState) - [self.AppDelegate setAlwaysShowOSK:YES]; - else if (checkBox.state == NSOffState) - [self.AppDelegate setAlwaysShowOSK:NO]; + [self.AppDelegate setAlwaysShowOSK:(checkBox.state == NSOnState)]; +} + +- (IBAction)useVerboseLoggingCheckBoxAction:(id)sender { + NSButton *checkBox = (NSButton *)sender; + BOOL verboseLoggingOn = checkBox.state == NSOnState; + [self.AppDelegate setUseVerboseLogging:verboseLoggingOn]; + [self.verboseLoggingInfo setHidden:!verboseLoggingOn]; +} + +- (void)handleRequestToInstallPackage:(KMPackage *) package { + NSString *infoFmt = NSLocalizedString(@"Do you want the Keyman Input Method to install this Package?\rFile: %@", @"Alert informative text when user double-clicks a KMP file. Parameter is the name of the KMP file."); + [self.confirmKmpInstallAlertView setInformativeText:[NSString localizedStringWithFormat:infoFmt, package.getOrigKmpFilename]]; + + if ([self.AppDelegate debugMode]) { + NSLog(@"Asking user to confirm installation of %@...", package.getOrigKmpFilename); + NSLog(@"KMP - temp file name: %@", package.getTempKmpFilename); + } + + [self.confirmKmpInstallAlertView beginSheetModalForWindow:self.window + modalDelegate:self + didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) + contextInfo:(__bridge void *)(package)]; +} + +- (void)installPackageFile:(NSString *)kmpFile { + // kmpFile could be a temp file (in fact, it always is!), so don't display the name. + + if ([self.AppDelegate debugMode]) { + NSLog(@"KMP - Ready to unzip/install Package File: %@", kmpFile); + } + + BOOL didUnzip = [self.AppDelegate unzipFile:kmpFile]; + + if (!didUnzip) { + NSAlert *failure = [[NSAlert alloc] init]; + [failure addButtonWithTitle:NSLocalizedString(@"OK", @"Alert button")]; + [failure setMessageText:NSLocalizedString(@"Failed to unzip Keyman Package!", @"Alert message when user double-clicks a KMP file that cannot be unzipped.")]; + [failure setIcon:[[NSBundle mainBundle] imageForResource:@"logo.png"]]; + [failure setAlertStyle:NSWarningAlertStyle]; + [failure beginSheetModalForWindow:self.window + modalDelegate:self + didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) + contextInfo:nil]; + } + else if ([self.AppDelegate debugMode]) { + NSLog(@"Completed installation of KMP file."); + } } - (void)startTimer { @@ -431,37 +477,67 @@ [_deleteAlertView addButtonWithTitle:@"OK"]; [_deleteAlertView addButtonWithTitle:@"Cancel"]; [_deleteAlertView setAlertStyle:NSWarningAlertStyle]; + [_deleteAlertView setIcon:[[NSBundle mainBundle] imageForResource:@"logo.png"]]; } return _deleteAlertView; } +- (NSAlert *)confirmKmpInstallAlertView { + if (_confirmKmpInstallAlertView == nil) { + _confirmKmpInstallAlertView = [[NSAlert alloc] init]; + [_confirmKmpInstallAlertView addButtonWithTitle:NSLocalizedString(@"Yes", @"Alert button")]; + [_confirmKmpInstallAlertView addButtonWithTitle:NSLocalizedString(@"No", @"Alert button")]; + [_confirmKmpInstallAlertView setMessageText:NSLocalizedString(@"Install Keyman Package?", @"Alert message text when user double-clicks a KMP file.")]; + [_confirmKmpInstallAlertView setAlertStyle:NSInformationalAlertStyle]; + [_confirmKmpInstallAlertView setIcon:[[NSBundle mainBundle] imageForResource:@"logo.png"]]; + } + + return _confirmKmpInstallAlertView; +} + - (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { - if (returnCode == NSAlertFirstButtonReturn) { - // OK - NSNumber *n = (__bridge NSNumber *)contextInfo; - NSInteger index = [n integerValue]; - NSString *path2Remove = nil; - NSString *kmxFilePath = [self kmxFilePathAtIndex:index]; - if (kmxFilePath == nil) { - kmxFilePath = [self kmxFilePathAtIndex:index+1]; - path2Remove = [[self keyboardsPath] stringByAppendingPathComponent:[self packageFolderFromPath:kmxFilePath]]; - } - else { - path2Remove = kmxFilePath; + if ([self.AppDelegate debugMode]) { + NSLog(@"User responded to NSAlert"); + } + if (alert == _deleteAlertView) { + if (returnCode == NSAlertFirstButtonReturn) { // OK + [self deleteFileAtIndex:(__bridge NSNumber *)contextInfo]; } - NSError *error; - [[NSFileManager defaultManager] removeItemAtPath:path2Remove error:&error]; - if (error == nil) { - [self performSelector:@selector(timerAction:) withObject:nil afterDelay:1.0]; + _deleteAlertView = nil; + } + else if (alert == _confirmKmpInstallAlertView) { + KMPackage *package = (__bridge KMPackage *)contextInfo; + if ([self.AppDelegate debugMode]) { + NSLog(@"KMP - Temp file: %@", package.getTempKmpFilename); + } + if (returnCode == NSAlertFirstButtonReturn) { // Yes + [self installPackageFile: package.getTempKmpFilename]; } + + [package releaseTempKMPFile]; + _confirmKmpInstallAlertView = nil; + } + // else, just a message - nothing to do. +} + +- (void)deleteFileAtIndex:(NSNumber *) n { + NSInteger index = [n integerValue]; + NSString *path2Remove = nil; + NSString *kmxFilePath = [self kmxFilePathAtIndex:index]; + if (kmxFilePath == nil) { + kmxFilePath = [self kmxFilePathAtIndex:index+1]; + path2Remove = [[self keyboardsPath] stringByAppendingPathComponent:[self packageFolderFromPath:kmxFilePath]]; } - else if (returnCode == NSAlertSecondButtonReturn) { - // Cancel + else { + path2Remove = kmxFilePath; } - _deleteAlertView = nil; + NSError *error; + [[NSFileManager defaultManager] removeItemAtPath:path2Remove error:&error]; + if (error == nil) { + [self performSelector:@selector(timerAction:) withObject:nil afterDelay:1.0]; + } } - @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/preferences.xib b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/preferences.xib index 1aad31feb3ff4a8f04206fe6a69540b5d564fde8..433ff81340aaf31a93ff3a0d57713e575ae7f848 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/preferences.xib +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/preferences.xib @@ -1,22 +1,26 @@ - - + + - - + + + + + + - - + + @@ -49,11 +53,11 @@ - + - + @@ -156,7 +160,7 @@ + + @@ -248,59 +272,59 @@ - + + + + -YnBsaXN0MDDUAQIDBAUGPj9YJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoK4HCBMU -GR4fIyQsLzI4O1UkbnVsbNUJCgsMDQ4PEBESVk5TU2l6ZVYkY2xhc3NcTlNJbWFnZUZsYWdzVk5TUmVw +YnBsaXN0MDDUAQIDBAUGPT5YJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoK4HCBMU +GR4fIyQrLjE3OlUkbnVsbNUJCgsMDQ4PEBESVk5TU2l6ZVYkY2xhc3NcTlNJbWFnZUZsYWdzVk5TUmVw c1dOU0NvbG9ygAKADRIgwwAAgAOAC1Z7MSwgMX3SFQoWGFpOUy5vYmplY3RzoReABIAK0hUKGh2iGxyA -BYAGgAkQANIgCiEiXxAUTlNUSUZGUmVwcmVzZW50YXRpb26AB4AITxEIdE1NACoAAAAKAAAADgEAAAMA -AAABAAEAAAEBAAMAAAABAAEAAAECAAMAAAACAAgACAEDAAMAAAABAAEAAAEGAAMAAAABAAEAAAERAAQA -AAABAAAACAESAAMAAAABAAEAAAEVAAMAAAABAAIAAAEWAAMAAAABAAEAAAEXAAQAAAABAAAAAgEcAAMA -AAABAAEAAAFSAAMAAAABAAEAAAFTAAMAAAACAAEAAYdzAAcAAAe8AAAAuAAAAAAAAAe8YXBwbAIgAABt -bnRyR1JBWVhZWiAH0AACAA4ADAAAAABhY3NwQVBQTAAAAABub25lAAAAAAAAAAAAAAAAAAAAAAAA9tYA -AQAAAADTLWFwcGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVk -ZXNjAAAAwAAAAG9kc2NtAAABMAAABi5jcHJ0AAAHYAAAADh3dHB0AAAHmAAAABRrVFJDAAAHrAAAAA5k -ZXNjAAAAAAAAABVHZW5lcmljIEdyYXkgUHJvZmlsZQAAAAAAAAAAAAAAFUdlbmVyaWMgR3JheSBQcm9m -aWxlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbWx1YwAAAAAA -AAAeAAAADHNrU0sAAAAqAAABeGRhREsAAAA0AAABomNhRVMAAAAsAAAB1nB0QlIAAAAqAAACAnVrVUEA -AAAsAAACLGZyRlUAAAAqAAACWGh1SFUAAAAuAAACgnpoVFcAAAAQAAACsG5iTk8AAAAsAAACwGNzQ1oA -AAAkAAAC7GhlSUwAAAAgAAADEGl0SVQAAAAuAAADMHJvUk8AAAAkAAADXmRlREUAAAA6AAADgmtvS1IA -AAAYAAADvHN2U0UAAAAuAAAD1HpoQ04AAAAQAAAEAmphSlAAAAAWAAAEEmVsR1IAAAAkAAAEKHB0UE8A -AAA4AAAETG5sTkwAAAAqAAAEhGVzRVMAAAAoAAAErnRoVEgAAAAkAAAE1nRyVFIAAAAiAAAE+mZpRkkA -AAAsAAAFHGhySFIAAAA6AAAFSHBsUEwAAAA2AAAFgnJ1UlUAAAAmAAAFuGFyRUcAAAAoAAAF3mVuVVMA -AAAoAAAGBgBWAWEAZQBvAGIAZQBjAG4A/QAgAHMAaQB2AP0AIABwAHIAbwBmAGkAbABHAGUAbgBlAHIA -ZQBsACAAZwByAOUAdABvAG4AZQBiAGUAcwBrAHIAaQB2AGUAbABzAGUAUABlAHIAZgBpAGwAIABkAGUA -IABnAHIAaQBzACAAZwBlAG4A6AByAGkAYwBQAGUAcgBmAGkAbAAgAEMAaQBuAHoAYQAgAEcAZQBuAOkA -cgBpAGMAbwQXBDAEMwQwBDsETAQ9BDgEOQAgBD8EQAQ+BEQEMAQ5BDsAIABHAHIAYQB5AFAAcgBvAGYA -aQBsACAAZwDpAG4A6QByAGkAcQB1AGUAIABnAHIAaQBzAMEAbAB0AGEAbADhAG4AbwBzACAAcwB6APwA -cgBrAGUAIABwAHIAbwBmAGkAbJAadShwcJaOgnJfaWPPj/AARwBlAG4AZQByAGkAcwBrACAAZwByAOUA -dABvAG4AZQBwAHIAbwBmAGkAbABPAGIAZQBjAG4A/QAgAWEAZQBkAP0AIABwAHIAbwBmAGkAbAXkBegF -1QXkBdkF3AAgAEcAcgBhAHkAIAXbBdwF3AXZAFAAcgBvAGYAaQBsAG8AIABnAHIAaQBnAGkAbwAgAGcA -ZQBuAGUAcgBpAGMAbwBQAHIAbwBmAGkAbAAgAGcAcgBpACAAZwBlAG4AZQByAGkAYwBBAGwAbABnAGUA -bQBlAGkAbgBlAHMAIABHAHIAYQB1AHMAdAB1AGYAZQBuAC0AUAByAG8AZgBpAGzHfLwYACAARwByAGEA -eQAg1QS4XNMMx3wARwBlAG4AZQByAGkAcwBrACAAZwByAOUAcwBrAGEAbABlAHAAcgBvAGYAaQBsZm6Q -GnBwXqZjz4/wZYdO9k4AgiwwsDDsMKQw1zDtMNUwoTCkMOsDkwO1A70DuQO6A8wAIAPAA8EDvwPGA68D -uwAgA7MDugPBA7kAUABlAHIAZgBpAGwAIABnAGUAbgDpAHIAaQBjAG8AIABkAGUAIABjAGkAbgB6AGUA -bgB0AG8AcwBBAGwAZwBlAG0AZQBlAG4AIABnAHIAaQBqAHMAcAByAG8AZgBpAGUAbABQAGUAcgBmAGkA -bAAgAGcAcgBpAHMAIABnAGUAbgDpAHIAaQBjAG8OQg4bDiMORA4fDiUOTA4qDjUOQA4XDjIOFw4xDkgO -Jw5EDhsARwBlAG4AZQBsACAARwByAGkAIABQAHIAbwBmAGkAbABpAFkAbABlAGkAbgBlAG4AIABoAGEA -cgBtAGEAYQBwAHIAbwBmAGkAaQBsAGkARwBlAG4AZQByAGkBDQBrAGkAIABwAHIAbwBmAGkAbAAgAHMA -aQB2AGkAaAAgAHQAbwBuAG8AdgBhAFUAbgBpAHcAZQByAHMAYQBsAG4AeQAgAHAAcgBvAGYAaQBsACAA -cwB6AGEAcgBvAVsAYwBpBB4EMQRJBDgEOQAgBEEENQRABEsEOQAgBD8EQAQ+BEQEOAQ7BEwGRQZEBkEA -IAYqBjkGMQZKBkEAIABHAHIAYQB5ACAGJwZEBjkGJwZFAEcAZQBuAGUAcgBpAGMAIABHAHIAYQB5ACAA -UAByAG8AZgBpAGwAZQAAdGV4dAAAAABDb3B5cmlnaHQgMjAwNyBBcHBsZSBJbmMuLCBhbGwgcmlnaHRz -IHJlc2VydmVkLgBYWVogAAAAAAAA81EAAQAAAAEWzGN1cnYAAAAAAAAAAQHNAADSJSYnKFokY2xhc3Nu -YW1lWCRjbGFzc2VzXxAQTlNCaXRtYXBJbWFnZVJlcKMpKitfEBBOU0JpdG1hcEltYWdlUmVwWk5TSW1h -Z2VSZXBYTlNPYmplY3TSJSYtLldOU0FycmF5oi0r0iUmMDFeTlNNdXRhYmxlQXJyYXmjMC0r0zM0CjU2 -N1dOU1doaXRlXE5TQ29sb3JTcGFjZUQwIDAAEAOADNIlJjk6V05TQ29sb3KiOSvSJSY8PVdOU0ltYWdl -ojwrXxAPTlNLZXllZEFyY2hpdmVy0UBBVHJvb3SAAQAIABEAGgAjAC0AMgA3AEYATABXAF4AZQByAHkA -gQCDAIUAigCMAI4AlQCaAKUApwCpAKsAsACzALUAtwC5ALsAwADXANkA2wlTCVgJYwlsCX8JgwmWCaEJ -qgmvCbcJugm/Cc4J0gnZCeEJ7gnzCfUJ9wn8CgQKBwoMChQKFwopCiwKMQAAAAAAAAIBAAAAAAAAAEIA -AAAAAAAAAAAAAAAAAAozA +BYAGgAkQANIgCiEiXxAUTlNUSUZGUmVwcmVzZW50YXRpb26AB4AITxEIjE1NACoAAAAKAAAAEAEAAAMA +AAABAAEAAAEBAAMAAAABAAEAAAECAAMAAAACAAgACAEDAAMAAAABAAEAAAEGAAMAAAABAAEAAAEKAAMA +AAABAAEAAAERAAQAAAABAAAACAESAAMAAAABAAEAAAEVAAMAAAABAAIAAAEWAAMAAAABAAEAAAEXAAQA +AAABAAAAAgEcAAMAAAABAAEAAAEoAAMAAAABAAIAAAFSAAMAAAABAAEAAAFTAAMAAAACAAEAAYdzAAcA +AAe8AAAA0AAAAAAAAAe8YXBwbAIgAABtbnRyR1JBWVhZWiAH0AACAA4ADAAAAABhY3NwQVBQTAAAAABu +b25lAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWFwcGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVkZXNjAAAAwAAAAG9kc2NtAAABMAAABi5jcHJ0AAAHYAAAADh3 +dHB0AAAHmAAAABRrVFJDAAAHrAAAAA5kZXNjAAAAAAAAABVHZW5lcmljIEdyYXkgUHJvZmlsZQAAAAAA +AAAAAAAAFUdlbmVyaWMgR3JheSBQcm9maWxlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAbWx1YwAAAAAAAAAeAAAADHNrU0sAAAAqAAABeGRhREsAAAA0AAABomNhRVMA +AAAsAAAB1nB0QlIAAAAqAAACAnVrVUEAAAAsAAACLGZyRlUAAAAqAAACWGh1SFUAAAAuAAACgnpoVFcA +AAAQAAACsG5iTk8AAAAsAAACwGNzQ1oAAAAkAAAC7GhlSUwAAAAgAAADEGl0SVQAAAAuAAADMHJvUk8A +AAAkAAADXmRlREUAAAA6AAADgmtvS1IAAAAYAAADvHN2U0UAAAAuAAAD1HpoQ04AAAAQAAAEAmphSlAA +AAAWAAAEEmVsR1IAAAAkAAAEKHB0UE8AAAA4AAAETG5sTkwAAAAqAAAEhGVzRVMAAAAoAAAErnRoVEgA +AAAkAAAE1nRyVFIAAAAiAAAE+mZpRkkAAAAsAAAFHGhySFIAAAA6AAAFSHBsUEwAAAA2AAAFgnJ1UlUA +AAAmAAAFuGFyRUcAAAAoAAAF3mVuVVMAAAAoAAAGBgBWAWEAZQBvAGIAZQBjAG4A/QAgAHMAaQB2AP0A +IABwAHIAbwBmAGkAbABHAGUAbgBlAHIAZQBsACAAZwByAOUAdABvAG4AZQBiAGUAcwBrAHIAaQB2AGUA +bABzAGUAUABlAHIAZgBpAGwAIABkAGUAIABnAHIAaQBzACAAZwBlAG4A6AByAGkAYwBQAGUAcgBmAGkA +bAAgAEMAaQBuAHoAYQAgAEcAZQBuAOkAcgBpAGMAbwQXBDAEMwQwBDsETAQ9BDgEOQAgBD8EQAQ+BEQE +MAQ5BDsAIABHAHIAYQB5AFAAcgBvAGYAaQBsACAAZwDpAG4A6QByAGkAcQB1AGUAIABnAHIAaQBzAMEA +bAB0AGEAbADhAG4AbwBzACAAcwB6APwAcgBrAGUAIABwAHIAbwBmAGkAbJAadShwcJaOgnJfaWPPj/AA +RwBlAG4AZQByAGkAcwBrACAAZwByAOUAdABvAG4AZQBwAHIAbwBmAGkAbABPAGIAZQBjAG4A/QAgAWEA +ZQBkAP0AIABwAHIAbwBmAGkAbAXkBegF1QXkBdkF3AAgAEcAcgBhAHkAIAXbBdwF3AXZAFAAcgBvAGYA +aQBsAG8AIABnAHIAaQBnAGkAbwAgAGcAZQBuAGUAcgBpAGMAbwBQAHIAbwBmAGkAbAAgAGcAcgBpACAA +ZwBlAG4AZQByAGkAYwBBAGwAbABnAGUAbQBlAGkAbgBlAHMAIABHAHIAYQB1AHMAdAB1AGYAZQBuAC0A +UAByAG8AZgBpAGzHfLwYACAARwByAGEAeQAg1QS4XNMMx3wARwBlAG4AZQByAGkAcwBrACAAZwByAOUA +cwBrAGEAbABlAHAAcgBvAGYAaQBsZm6QGnBwXqZjz4/wZYdO9k4AgiwwsDDsMKQw1zDtMNUwoTCkMOsD +kwO1A70DuQO6A8wAIAPAA8EDvwPGA68DuwAgA7MDugPBA7kAUABlAHIAZgBpAGwAIABnAGUAbgDpAHIA +aQBjAG8AIABkAGUAIABjAGkAbgB6AGUAbgB0AG8AcwBBAGwAZwBlAG0AZQBlAG4AIABnAHIAaQBqAHMA +cAByAG8AZgBpAGUAbABQAGUAcgBmAGkAbAAgAGcAcgBpAHMAIABnAGUAbgDpAHIAaQBjAG8OQg4bDiMO +RA4fDiUOTA4qDjUOQA4XDjIOFw4xDkgOJw5EDhsARwBlAG4AZQBsACAARwByAGkAIABQAHIAbwBmAGkA +bABpAFkAbABlAGkAbgBlAG4AIABoAGEAcgBtAGEAYQBwAHIAbwBmAGkAaQBsAGkARwBlAG4AZQByAGkB +DQBrAGkAIABwAHIAbwBmAGkAbAAgAHMAaQB2AGkAaAAgAHQAbwBuAG8AdgBhAFUAbgBpAHcAZQByAHMA +YQBsAG4AeQAgAHAAcgBvAGYAaQBsACAAcwB6AGEAcgBvAVsAYwBpBB4EMQRJBDgEOQAgBEEENQRABEsE +OQAgBD8EQAQ+BEQEOAQ7BEwGRQZEBkEAIAYqBjkGMQZKBkEAIABHAHIAYQB5ACAGJwZEBjkGJwZFAEcA +ZQBuAGUAcgBpAGMAIABHAHIAYQB5ACAAUAByAG8AZgBpAGwAZQAAdGV4dAAAAABDb3B5cmlnaHQgMjAw +NyBBcHBsZSBJbmMuLCBhbGwgcmlnaHRzIHJlc2VydmVkLgBYWVogAAAAAAAA81EAAQAAAAEWzGN1cnYA +AAAAAAAAAQHNAADSJSYnKFokY2xhc3NuYW1lWCRjbGFzc2VzXxAQTlNCaXRtYXBJbWFnZVJlcKMnKSpa +TlNJbWFnZVJlcFhOU09iamVjdNIlJiwtV05TQXJyYXmiLCrSJSYvMF5OU011dGFibGVBcnJheaMvLCrT +MjMKNDU2V05TV2hpdGVcTlNDb2xvclNwYWNlRDAgMAAQA4AM0iUmODlXTlNDb2xvcqI4KtIlJjs8V05T +SW1hZ2WiOypfEA9OU0tleWVkQXJjaGl2ZXLRP0BUcm9vdIABAAgAEQAaACMALQAyADcARgBMAFcAXgBl +AHIAeQCBAIMAhQCKAIwAjgCVAJoApQCnAKkAqwCwALMAtQC3ALkAuwDAANcA2QDbCWsJcAl7CYQJlwmb +CaYJrwm0CbwJvwnECdMJ1wneCeYJ8wn4CfoJ/AoBCgkKDAoRChkKHAouCjEKNgAAAAAAAAIBAAAAAAAA +AEEAAAAAAAAAAAAAAAAAAAo4A - - - diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.m index 7373535fd46ca55aa202cc9476e071509513d5a4..524b59b73ba84c00a72e4d5ced19b09d8c642f15 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.m @@ -3,7 +3,7 @@ // Keyman4MacIM // // Created by Serkan Kurt on 18/05/2015. -// Copyright (c) 2017 SIL International. All rights reserved. +// Copyright (c) 2018 SIL International. All rights reserved. // #import "KMDownloadKBWindowController.h" @@ -23,11 +23,42 @@ [super windowDidLoad]; [self.webView setFrameLoadDelegate:(id)self]; + [self.webView setGroupName:@"KMDownloadKB"]; + [self.webView setPolicyDelegate:(id)self]; NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]; NSString *url = [NSString stringWithFormat:@"https://keyman.com/go/macos/10.0/download-keyboards/?version=%@", version]; - NSLog(@"KMDownloadKBWindowController opening url = %@, version = '%@'", url, version); + if (self.AppDelegate.debugMode) + NSLog(@"KMDownloadKBWindowController opening url = %@, version = '%@'", url, version); [self.webView.mainFrame loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]]; } +- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener { + NSString* url = [[request URL] description]; + if (self.AppDelegate.debugMode) + NSLog(@"decidePolicyForNavigationAction, navigating to %@", url); + + if ([request.URL.absoluteString startsWith:@"keyman:"]) { + if ([request.URL.absoluteString startsWith:@"keyman:link?url="]) + { + [listener ignore]; + url = [request.URL.absoluteString substringFromIndex:[@"keyman:link?url=" length]]; + if (self.AppDelegate.debugMode) + NSLog(@"Opening URL in default browser: %@", url); + [[NSWorkspace sharedWorkspace] openURL: [[NSURL alloc] initWithString:url]]; + } + else { + if (self.AppDelegate.debugMode) + NSLog(@"Farming out download to app delegate."); + [listener ignore]; + [self.AppDelegate processURL:url]; + } + } + else + { + if (self.AppDelegate.debugMode) + NSLog(@"Normal navigation in webview."); + [listener use]; + } +} @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.xib b/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.xib index fffbef769b72aaec0d6b7cdf8f13120e34fd15ae..5377f29425d1b999794deffca70a00b9b742e007 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.xib +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.xib @@ -1,9 +1,10 @@ - - + + - - + + + @@ -14,8 +15,8 @@ - - + + diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m index 22e5a788327d38323a62b84a1a48e9f78c33b7e0..bc7200bdcec5f5ee7e909fa26068d6bc5798819b 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m @@ -112,15 +112,26 @@ ""; NSString *pBodyFormat = @"

%@


"; - NSArray *kbs = [self.infoDict objectForKey:kKeyboard]; NSMutableString *kbsStr = [NSMutableString stringWithString:@""]; + NSArray *kbs = [[self AppDelegate] keyboardNamesFromFolder:self.packagePath]; if (kbs != nil && kbs.count) { - for (NSArray *kb in kbs) { - [kbsStr appendString:[NSString stringWithFormat:pBodyFormat, [kb objectAtIndex:0]]]; + for (NSArray *kbName in kbs) { + [kbsStr appendString:[NSString stringWithFormat:pBodyFormat, kbName]]; } } else { - kbsStr = [NSMutableString stringWithString:@"


"]; + // This was the old logic (prior to fixing issue #994). Keeping as fallback, though + // it's unlikely to be useful/needed. + kbs = [self.infoDict objectForKey:kKeyboard]; + + if (kbs != nil && kbs.count) { + for (NSArray *kb in kbs) { + [kbsStr appendString:[NSString stringWithFormat:pBodyFormat, [kb objectAtIndex:0]]]; + } + } + else { + kbsStr = [NSMutableString stringWithString:@"


"]; + } } NSArray *fonts = [self.infoDict objectForKey:kFont]; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.xib b/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.xib index fbc9aaac5dc2b371cc1bb47f3aa8ed0409948561..ed3e50a4cbe2b54279c63736e14b17310279a84b 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.xib +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.xib @@ -1,8 +1,9 @@ - - + + - + + @@ -17,25 +18,27 @@ - + - + - + + + - - + + diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputController.m index 671005a3a25158e7f6b900a40a93f9caad1b40a3..e5f4db5f1e303085e6a63500e4ea4ba2e97667ba 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputController.m @@ -15,6 +15,7 @@ @implementation KMInputController KMInputMethodEventHandler* _eventHandler; +NSMutableArray *servers; - (KMInputMethodAppDelegate *)AppDelegate { return (KMInputMethodAppDelegate *)[NSApp delegate]; @@ -22,18 +23,24 @@ KMInputMethodEventHandler* _eventHandler; - (id)initWithServer:(IMKServer *)server delegate:(id)delegate client:(id)inputClient { + if ([self.AppDelegate debugMode]) { + NSLog(@"Initializing Keyman Input Method with server: %@", server); + } + self = [super initWithServer:server delegate:delegate client:inputClient]; if (self) { + servers = [[NSMutableArray alloc] initWithCapacity:2]; self.AppDelegate.inputController = self; - if (self.AppDelegate.kvk != nil && self.AppDelegate.alwaysShowOSK) + if (self.AppDelegate.kvk != nil && self.AppDelegate.alwaysShowOSK) { [self.AppDelegate showOSK]; + } } return self; } - (NSUInteger)recognizedEvents:(id)sender { - return (NSKeyDownMask | NSLeftMouseDownMask | NSLeftMouseUpMask); + return (NSEventMaskKeyDown); } - (BOOL)handleEvent:(NSEvent *)event client:(id)sender { @@ -47,27 +54,35 @@ KMInputMethodEventHandler* _eventHandler; } - (void)activateServer:(id)sender { - [sender overrideKeyboardWithKeyboardNamed:@"com.apple.keylayout.US"]; - - if (_eventHandler != nil) { - [_eventHandler deactivate]; - } - - NSRunningApplication *currApp = [[NSWorkspace sharedWorkspace] frontmostApplication]; - NSString *clientAppId = [currApp bundleIdentifier]; - if ([self.AppDelegate debugMode]) - NSLog(@"New active app %@", clientAppId); - - // Most things in Safari work well using the normal way, but Google Docs doesn't. - if ([clientAppId isEqual: @"com.apple.Safari"]) { - _eventHandler = [[KMInputMethodSafariClientEventHandler alloc] init]; - } - else if ([clientAppId isEqual: @"org.mozilla.firefox"] || - [clientAppId isEqual: @"com.google.Chrome"]) { - _eventHandler = [[KMInputMethodBrowserClientEventHandler alloc] init]; + @synchronized(servers) { + [sender overrideKeyboardWithKeyboardNamed:@"com.apple.keylayout.US"]; + + [self.AppDelegate wakeUpWith:sender]; + [servers addObject:sender]; + + if (_eventHandler != nil) { + [_eventHandler deactivate]; + } + + NSRunningApplication *currApp = [[NSWorkspace sharedWorkspace] frontmostApplication]; + NSString *clientAppId = [currApp bundleIdentifier]; + if ([self.AppDelegate debugMode]) { + NSLog(@"New active app %@", clientAppId); + NSLog(@"sender %@", sender); + } + + // Most things in Safari work well using the normal way, but Google Docs doesn't. + if ([clientAppId isEqual: @"com.apple.Safari"]) { + _eventHandler = [[KMInputMethodSafariClientEventHandler alloc] init]; + } + else if ([clientAppId isEqual: @"org.mozilla.firefox"] || + [clientAppId isEqual: @"com.google.Chrome"]) { + _eventHandler = [[KMInputMethodBrowserClientEventHandler alloc] init]; + } + else { + _eventHandler = [[KMInputMethodEventHandler alloc] initWithClient:clientAppId]; + } } - else - _eventHandler = [[KMInputMethodEventHandler alloc] initWithClient:clientAppId]; } - (void)deactivateServer:(id)sender { @@ -76,13 +91,32 @@ KMInputMethodEventHandler* _eventHandler; NSLog(@"sender: %@", sender); NSLog(@"***"); } - // Seems like we ought to do this, but it appears there is a timing issue that - // sometimes causes the deactivate to happen AFTER the new activateServer event, - // thereby clobbering the newly created event handler. -// if (_eventHandler != nil) { -// [_eventHandler deactivate]; -// _eventHandler = nil; -// } + @synchronized(servers) { + for (int i = 0; i < servers.count; i++) { + if (servers[i] == sender) { + [servers removeObjectAtIndex:i]; + break; + } + } + if (servers.count == 0) { + if ([self.AppDelegate debugMode]) { + NSLog(@"No known active server for Keyman IM. Starting countdown to sleep..."); + } + [self performSelector:@selector(timerAction:) withObject:sender afterDelay:0.7]; + } + } +} + +- (void)timerAction:(id)lastServer { + @synchronized(servers) { + if (servers.count == 0) { + if (_eventHandler != nil) { + [_eventHandler deactivate]; + _eventHandler = nil; + } + [self.AppDelegate sleepFollowingDeactivationOfServer:lastServer]; + } + } } /* @@ -135,6 +169,8 @@ KMInputMethodEventHandler* _eventHandler; - (void)menuAction:(id)sender { NSMenuItem *mItem = [sender objectForKey:kIMKCommandMenuItemName]; NSInteger itag = mItem.tag; + if ([self.AppDelegate debugMode]) + NSLog(@"Keyman menu clicked - tag: %lu", itag); if (itag == 2) { // Using `showConfigurationWindow` instead of `showPreferences:` because `showPreferences:` is missing in // High Sierra (10.13.1 - 10.13.3). See: https://bugreport.apple.com/web/?problemID=35422518 @@ -169,7 +205,10 @@ KMInputMethodEventHandler* _eventHandler; kvk = [[KVKFile alloc] initWithFilePath:kvkFilePath]; } [self.AppDelegate setKvk:kvk]; - [self.AppDelegate setKeyboardName:[kmxInfo objectForKey:kKMKeyboardNameKey]]; + NSString *keyboardName = [kmxInfo objectForKey:kKMKeyboardNameKey]; + if ([self.AppDelegate debugMode]) + NSLog(@"Selected keyboard from menu: %@", keyboardName); + [self.AppDelegate setKeyboardName:keyboardName]; [self.AppDelegate setKeyboardIcon:[kmxInfo objectForKey:kKMKeyboardIconKey]]; [self.AppDelegate setContextBuffer:nil]; [self.AppDelegate setSelectedKeyboard:path]; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h index 9874e32c56fcc649551a085acd3c4c4dd2f5d3a8..4fc27105ea283ecacc533f915ec175c54761a99e 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h @@ -20,6 +20,8 @@ #import "NSWindow+SuppMethods.h" #import "NSString+SuppMethods.h" +typedef void(^PostEventCallback)(CGEventRef eventToPost); + extern NSString *const kKMSelectedKeyboardKey; extern NSString *const kKMActiveKeyboardsKey; extern NSString *const kKeymanKeyboardDownloadCompletedNotification; @@ -42,7 +44,12 @@ extern NSString *const kReadMeFile; extern NSString *const kVersion; extern NSString *const kWebSite; -@interface KMInputMethodAppDelegate : NSObject { +@interface KMInputMethodAppDelegate : NSObject +#define USE_ALERT_SHOW_HELP_TO_FORCE_EASTER_EGG_CRASH_FROM_ENGINE 1 +#ifdef USE_ALERT_SHOW_HELP_TO_FORCE_EASTER_EGG_CRASH_FROM_ENGINE + +#endif +{ IBOutlet NSMenu *_menu; } @@ -56,6 +63,9 @@ extern NSString *const kWebSite; @property (nonatomic, strong) NSMutableArray *activeKeyboards; @property (nonatomic, strong) NSMutableString *contextBuffer; @property (nonatomic, assign) NSEventModifierFlags currentModifierFlags; +@property (nonatomic, assign) CFMachPortRef lowLevelEventTap; +@property (nonatomic, assign) CFRunLoopSourceRef runLoopEventSrc; +@property (nonatomic, assign) BOOL sleeping; @property (nonatomic, assign) BOOL contextChangingEventDetected; @property (nonatomic, strong) OSKWindowController *oskWindow; @property (nonatomic, strong) NSString *keyboardName; @@ -73,6 +83,7 @@ extern NSString *const kWebSite; @property (nonatomic, strong) NSMutableData *receivedData; @property (nonatomic, assign) NSUInteger expectedBytes; @property (nonatomic, assign) BOOL alwaysShowOSK; +@property (nonatomic, assign) BOOL useVerboseLogging; @property (nonatomic, assign) BOOL useNullChar; @property (nonatomic, assign) BOOL debugMode; @@ -81,20 +92,25 @@ extern NSString *const kWebSite; - (void)showAboutWindow; - (void)showOSK; - (void)showConfigurationWindow; +- (void)sleepFollowingDeactivationOfServer:(id)lastServer; +- (void)wakeUpWith:(id)newServer; - (void)handleKeyEvent:(NSEvent *)event; - (BOOL)unzipFile:(NSString *)filePath; - (NSWindowController *)downloadKBWindow_; - (NSWindowController *)aboutWindow_; - (NSWindowController *)infoWindow_; - (NSWindowController *)kbHelpWindow_; +- (void)processURL:(NSString*)rawUrl; - (NSString *)kmxFilePathAtIndex:(NSUInteger)index; - (NSString *)packagePathAtIndex:(NSUInteger)index; - (NSInteger)indexForPackageFolder:(NSString *)packageFolder; - (NSString *)packageFolderFromPath:(NSString *)path; - (NSString *)packageNameFromFolder:(NSString *)packageFolder; +- (NSArray *)keyboardNamesFromFolder:(NSString *)packageFolder; - (NSDictionary *)infoDictionaryFromFile:(NSString *)infoFile; - (NSString *)kvkFilePathFromFilename:(NSString *)kvkFilename; - (NSString *)oskWindowTitle; +- (void)postKeyboardEventWithSource: (CGEventSourceRef)source code:(CGKeyCode) virtualKey postCallback:(PostEventCallback)postEvent; @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m index 70c1a10ad4d1de41b686079eed403b751ac63002..335d2f2bedec6d39642534669d41a5c56f592e51 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m @@ -19,10 +19,13 @@ #import "KMConfigurationWindowController.h" #import "KMDownloadKBWindowController.h" #import "ZipArchive.h" +#import +#import NSString *const kKMSelectedKeyboardKey = @"KMSelectedKeyboardKey"; NSString *const kKMActiveKeyboardsKey = @"KMActiveKeyboardsKey"; NSString *const kKMAlwaysShowOSKKey = @"KMAlwaysShowOSKKey"; +NSString *const kKMUseVerboseLogging = @"KMUseVerboseLogging"; NSString *const kKeymanKeyboardDownloadCompletedNotification = @"kKeymanKeyboardDownloadCompletedNotification"; NSString *const kPackage = @"[Package]"; @@ -60,48 +63,78 @@ typedef enum { @synthesize contextBuffer = _contextBuffer; @synthesize alwaysShowOSK = _alwaysShowOSK; +id _lastServerWithOSKShowing = nil; + - (id)init { self = [super init]; if (self) { #ifdef DEBUG + // If debugging, we'll turn it on by default, regardless of setting. If developer + // really wants it off, they can either change this line of code temporarily or + // go to the config screen and turn it off explicitly. _debugMode = YES; #else - _debugMode = NO; + _debugMode = self.useVerboseLogging; #endif [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:@selector(handleURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL]; - CFMachPortRef lowLevelEventTap = CGEventTapCreate(kCGAnnotatedSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly, NSFlagsChangedMask | NSLeftMouseDown | NSLeftMouseUp, (CGEventTapCallBack)eventTapFunction, nil); + self.lowLevelEventTap = CGEventTapCreate(kCGAnnotatedSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly, NSFlagsChangedMask | NSLeftMouseDown | NSLeftMouseUp, (CGEventTapCallBack)eventTapFunction, nil); - if (!lowLevelEventTap) + if (!self.lowLevelEventTap) { NSLog(@"Can't tap into low level events!"); - else - CFRelease(lowLevelEventTap); + } + else { + CFRelease(self.lowLevelEventTap); + } - CFRunLoopSourceRef runLoopEventSrc = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, lowLevelEventTap, 0); + self.runLoopEventSrc = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, self.lowLevelEventTap, 0); CFRunLoopRef runLoop = CFRunLoopGetCurrent(); - if (runLoopEventSrc && runLoop) { - CFRunLoopAddSource(runLoop, runLoopEventSrc, kCFRunLoopDefaultMode); + if (self.runLoopEventSrc && runLoop) { + CFRunLoopAddSource(runLoop, self.runLoopEventSrc, kCFRunLoopDefaultMode); } } return self; } +-(void)applicationDidFinishLaunching:(NSNotification *)aNotification { + [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"NSApplicationCrashOnExceptions": @YES }]; + [[Fabric sharedSDK] setDebug: self.debugMode]; + [Fabric with:@[[Crashlytics class]]]; +} + +#ifdef USE_ALERT_SHOW_HELP_TO_FORCE_EASTER_EGG_CRASH_FROM_ENGINE +- (BOOL)alertShowHelp:(NSAlert *)alert { + NSLog(@"Crashlytics - KME: Got call to force crash from engine"); + [[Crashlytics sharedInstance] crash]; + NSLog(@"Crashlytics - KME: should not have gotten this far!"); + return NO; +} +#endif + - (void)handleURLEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAppleEventDescriptor*)replyEvent { - NSMutableString *urlStr = [NSMutableString stringWithString:[[event paramDescriptorForKeyword:keyDirectObject] stringValue]]; + + [self processURL:[[event paramDescriptorForKeyword:keyDirectObject] stringValue]]; +} + +- (void)processURL:(NSString*)rawUrl { + NSMutableString *urlStr = [NSMutableString stringWithString:rawUrl]; [urlStr replaceOccurrencesOfString:@"keyman:" withString:@"keyman/" options:0 range:NSMakeRange(0, 7)]; NSURL *url = [NSURL URLWithString:urlStr]; - if (_debugMode) + if (self.debugMode) NSLog(@"url = %@", url); if ([url.lastPathComponent isEqualToString:@"download"]) { - if (_connection != nil) + if (_connection != nil) { + if (self.debugMode) + NSLog(@"Already downloading a keyboard."); return; + } NSURL *downloadUrl; NSArray *params = [[url query] componentsSeparatedByString:@"&"]; @@ -157,12 +190,72 @@ typedef enum { return (KMInputMethodAppDelegate *)[NSApp delegate]; } +-(void) sleepFollowingDeactivationOfServer:(id)lastServer { + if ([self debugMode]) { + NSLog(@"Keyman no longer active IM."); + } + self.sleeping = YES; + if ([self.oskWindow.window isVisible]) { + if ([self debugMode]) { + NSLog(@"Hiding OSK."); + } + // Storing this ensures that if the deactivation is temporary, resulting from dropping down a menu, + // the OSK will re-display when that client application re-activates. + _lastServerWithOSKShowing = lastServer; + [self.oskWindow.window setIsVisible:NO]; + } + if (self.lowLevelEventTap) { + if ([self debugMode]) { + NSLog(@"Disabling event tap..."); + } + CGEventTapEnable(self.lowLevelEventTap, NO); + } +} + +-(void) wakeUpWith:(id)newServer { + self.sleeping = NO; + if (self.lowLevelEventTap && !CGEventTapIsEnabled(self.lowLevelEventTap)) { + if ([self debugMode]) { + NSLog(@"Keyman is now the active IM. Re-enabling event tap..."); + } + CGEventTapEnable(self.lowLevelEventTap, YES); + } + // See note in sleepFollowingDeactivationOfServer. + if (_kvk != nil && (_alwaysShowOSK || _lastServerWithOSKShowing == newServer)) { + [self showOSK]; + } +} + CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) { KMInputMethodAppDelegate *appDelegate = [KMInputMethodAppDelegate AppDelegate]; if (appDelegate != nil) { + if (type == kCGEventTapDisabledByTimeout || type == kCGEventTapDisabledByUserInput) { + // kCGEventTapDisabledByUserInput most likely means we're "sleeping", in which case we want it to stay + // diabled until we get the wake-up call. + if (!appDelegate.sleeping) { + // REVIEW: We might need to consider putting in some kind of counter/flag to ensure that the very next + // event is not another disable so we don't end up in an endless cycle. + NSLog(@"Event tap disabled by %@! Attempting to restart...", (type == kCGEventTapDisabledByTimeout ? @"timeout" : @"user")); + CGEventTapEnable(appDelegate.lowLevelEventTap, YES); + if (!CGEventTapIsEnabled(appDelegate.lowLevelEventTap)) { + if (appDelegate.runLoopEventSrc) { // This should always be true + CFRunLoopRef runLoop = CFRunLoopGetCurrent(); + if (runLoop) { + CFRunLoopRemoveSource(runLoop, appDelegate.runLoopEventSrc, kCFRunLoopDefaultMode); + } + appDelegate.runLoopEventSrc = nil; + } + appDelegate.lowLevelEventTap = nil; + } + } + return event; + } + NSEvent* sysEvent = [NSEvent eventWithCGEvent:event]; - if (appDelegate.debugMode) - NSLog(@"System Event: %@", sysEvent); + // Too many of these to be useful for most debugging sessions, but we'll keep this around to be + // un-commented when needed. + //if (appDelegate.debugMode) + // NSLog(@"System Event: %@", sysEvent); switch (type) { case kCGEventFlagsChanged: @@ -192,6 +285,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef - (KMEngine *)kme { if (_kme == nil) { _kme = [[KMEngine alloc] initWithKMX:nil contextBuffer:self.contextBuffer]; + [_kme setDebugMode:self.debugMode]; } return _kme; @@ -228,12 +322,27 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef [userData synchronize]; } +- (void)setUseVerboseLogging:(BOOL)useVerboseLogging { + NSLog(@"Turning verbose logging %@", useVerboseLogging ? @"on." : @"off."); + _debugMode = useVerboseLogging; + if (_kme != nil) + [_kme setUseVerboseLogging:useVerboseLogging]; + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + [userData setBool:useVerboseLogging forKey:kKMUseVerboseLogging]; + [userData synchronize]; +} + - (BOOL)alwaysShowOSK { NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; _alwaysShowOSK = [userData boolForKey:kKMAlwaysShowOSKKey]; return _alwaysShowOSK; } +- (BOOL)useVerboseLogging { + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + return [userData boolForKey:kKMUseVerboseLogging]; +} + - (NSString *)keyboardsPath { if (_keyboardsPath == nil) { NSString *documentDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; @@ -374,6 +483,22 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef return packageName; } +- (NSArray *)keyboardNamesFromFolder:(NSString *)packageFolder { + NSMutableArray *kbNames = [[NSMutableArray alloc] initWithCapacity:0];; + for (NSString *kmxFile in [self KMXFilesAtPath:packageFolder]) { + NSDictionary * infoDict = [KMXFile infoDictionaryFromFilePath:kmxFile]; + if (infoDict != nil) { + NSString *name = [infoDict objectForKey:kKMKeyboardNameKey]; + if (name != nil && [name length]) { + if (self.debugMode) + NSLog(@"Adding keyboard name: %@", name); + [kbNames addObject:name]; + } + } + } + return kbNames; +} + - (NSDictionary *)infoDictionaryFromFile:(NSString *)infoFile { NSMutableDictionary *infoDict = [NSMutableDictionary dictionaryWithCapacity:0]; NSMutableArray *files = [NSMutableArray arrayWithCapacity:0]; @@ -731,7 +856,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef } - (void)showConfigurationWindow { - if (_debugMode) + if (self.debugMode) NSLog(@"Showing config window..."); [self.configWindow.window centerInParent]; [self.configWindow.window makeKeyAndOrderFront:nil]; @@ -756,7 +881,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef - (NSWindowController *)configWindow { if (_configWindow.window == nil) { - if (_debugMode) + if (self.debugMode) NSLog(@"Creating config window..."); _configWindow = [[KMConfigurationWindowController alloc] initWithWindowNibName:@"preferences"]; } @@ -924,6 +1049,25 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef [_oskWindow.oskView handleKeyEvent:event]; } +extern const CGKeyCode kProcessPendingBuffer; + +// This could more easily and logically be done in the input method, but this +// allows us to override the norma behavior for unit testing, where there is no +// active event loop to post to. +- (void)postKeyboardEventWithSource: (CGEventSourceRef)source code:(CGKeyCode) virtualKey postCallback:(PostEventCallback)postEvent{ + + CGEventRef ev = CGEventCreateKeyboardEvent (source, virtualKey, true); //down + if (postEvent) + postEvent(ev); + CFRelease(ev); + if (virtualKey != kProcessPendingBuffer) { // special 0xFF code is not a real key-press, so no "up" is needed + ev = CGEventCreateKeyboardEvent (source, virtualKey, false); //up + if (postEvent) + postEvent(ev); + CFRelease(ev); + } +} + - (BOOL)unzipFile:(NSString *)filePath { BOOL didUnzip = NO; NSString *fileName = filePath.lastPathComponent; @@ -931,7 +1075,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef ZipArchive *za = [[ZipArchive alloc] init]; if ([za UnzipOpenFile:filePath]) { NSString *destFolder = [self.keyboardsPath stringByAppendingPathComponent:folderName]; - if (_debugMode) { + if (self.debugMode) { NSLog(@"Unzipping %@ to %@", filePath, destFolder); if ([[NSFileManager defaultManager] fileExistsAtPath:destFolder]) NSLog(@"The destiination folder already exists. Overwriting..."); @@ -941,19 +1085,19 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef } if (didUnzip) { - if (_debugMode) + if (self.debugMode) NSLog(@"Unzipped file: %@", filePath); NSString * keyboardFolderPath = [self.keyboardsPath stringByAppendingPathComponent:folderName]; [self installFontsAtPath:keyboardFolderPath]; for (NSString *kmxFile in [self KMXFilesAtPath:keyboardFolderPath]) { - if (_debugMode) + if (self.debugMode) NSLog(@"Adding keyboard to list of active keyboards: %@", kmxFile); [self.activeKeyboards addObject:kmxFile]; } [self saveActiveKeyboards]; } else { - if (_debugMode) { + if (self.debugMode) { NSLog(@"Failed to unzip file: %@", filePath); } } diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodBrowserClientEventHandler.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodBrowserClientEventHandler.m index b23cd117e59169a233f4945073e1757a3cdf343d..fb29380d2e18bfb30b729a7b0da89bd8aae6a3b5 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodBrowserClientEventHandler.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodBrowserClientEventHandler.m @@ -101,7 +101,7 @@ NSUInteger _failuresToRetrieveExpectedContext; _failuresToRetrieveExpectedContext = NSUIntegerMax; if (self.clientSelectionCanChangeUnexpectedly) { - self.cannnotTrustSelectionLength = YES; + self.clientCanProvideSelectionInfo = Unreliable; self.clientSelectionCanChangeUnexpectedly = NO; // This isn't true (it can change unexpectedly), but we can't get the context, so we pretend/hope it won't. } } diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m index e69821305c68967c87910dc124e6400faaf235f7..cbaa1e1c069a5c15f577f61e25113274840be406 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m @@ -8,6 +8,7 @@ #import "KMInputMethodEventHandler.h" #import "KMInputMethodEventHandlerProtected.h" #include /* For kVK_ constants. */ +#import @implementation KMInputMethodEventHandler @@ -19,6 +20,9 @@ NSMutableString* _pendingBuffer; NSUInteger _numberOfPostedDeletesToExpect = 0; CGKeyCode _keyCodeOfOriginalEvent; CGEventSourceRef _sourceFromOriginalEvent = nil; +NSMutableString* _easterEggForCrashlytics = nil; +NSString* const kEasterEggText = @"Crashlytics force now"; +NSString* const kEasterEggKmxName = @"EnglishSpanish.kmx"; NSRange _previousSelRange; @@ -28,7 +32,7 @@ NSRange _previousSelRange; if (self) { _previousSelRange = NSMakeRange(NSNotFound, NSNotFound); _clientSelectionCanChangeUnexpectedly = flagClientSelectionCanChangeUnexpectedly; - _cannnotTrustSelectionLength = NO; + _clientCanProvideSelectionInfo = Unknown; _legacyMode = NO; _contextOutOfDate = YES; if (legacy) { @@ -40,13 +44,21 @@ NSRange _previousSelRange; // This is the public initializer. - (instancetype)initWithClient:(NSString *)clientAppId { + // TODO: Pages and Keynote (and possibly lots of other undiscovered apps that are otherwise compliant + // with Apple's IM faramework) have a problem in that if the user selects a different font (or other + // formatting) and then types a sequence that causes characters to be added to the document and then + // subsequently replaced, the replacement causes the formatting decision to be forgotten. This can be + // "fixed" by treating them as legacy apps, but it causes other problems. BOOL legacy = ([clientAppId isEqual: @"com.github.atom"] || [clientAppId isEqual: @"com.collabora.libreoffice-free"] || + [clientAppId isEqual: @"org.libreoffice.script"] || [clientAppId isEqual: @"com.axosoft.gitkraken"] || [clientAppId isEqual: @"org.sil.app.builder.scripture.ScriptureAppBuilder"] || [clientAppId isEqual: @"org.sil.app.builder.reading.ReadingAppBuilder"] || [clientAppId isEqual: @"org.sil.app.builder.dictionary.DictionaryAppBuilder"] || - [clientAppId isEqual: @"com.microsoft.Word"] + [clientAppId isEqual: @"com.microsoft.Word"] || + [clientAppId isEqual: @"org.openoffice.script"] || + [clientAppId isEqual: @"com.adobe.InDesign"] /*||[clientAppId isEqual: @"ro.sync.exml.Oxygen"] - Oxygen has worse problems */); // We used to default to NO, so these were the obvious exceptions. But then we realized that @@ -59,6 +71,14 @@ NSRange _previousSelRange; // _clientSelectionCanChangeUnexpectedly = YES; // } + // In Xcode, if Keyman is the active IM and is in "debugMode" and "English plus Spanish" is the current keyboard and you type "Crashlytics force now", it will force a simulated crash to test reporting to fabric.io. + if ([self.AppDelegate debugMode] && [clientAppId isEqual: @"com.apple.dt.Xcode"]) { + NSLog(@"Crashlytics - Preparing to detect Easter egg."); + _easterEggForCrashlytics = [[NSMutableString alloc] init]; + } + else + _easterEggForCrashlytics = nil; + // For the Atom editor, this isn't really true (the context CAN change unexpectedly), but we can't get // the context, so we pretend/hope it won't. BOOL selectionCanChangeUnexpectedly = (![clientAppId isEqual: @"com.github.atom"]); @@ -82,6 +102,8 @@ NSRange _previousSelRange; NSLog(@" _keyCodeOfOriginalEvent = %hu", _keyCodeOfOriginalEvent); } _numberOfPostedDeletesToExpect = 0; + // If _sourceFromOriginalEvent != nil, we should probably attempt to release and clear it. + // [self dealloc] _pendingBuffer = nil; _keyCodeOfOriginalEvent = 0; } @@ -155,33 +177,54 @@ NSRange _previousSelRange; return self.AppDelegate.contextBuffer; } +- (NSRange)getSelectionRangefromClient:(id)client { + switch (_clientCanProvideSelectionInfo) { + case Unknown: + if ([client respondsToSelector:@selector(selectedRange)]) { + NSRange selRange = [client selectedRange]; + if (selRange.location != NSNotFound || selRange.length != NSNotFound) { + _clientCanProvideSelectionInfo = Yes; + if ([self.AppDelegate debugMode]) { + NSLog(@"Client can provide selection info."); + NSLog(@"selRange.location: %lu", (unsigned long)selRange.location); + NSLog(@"selRange.length: %lu", (unsigned long)selRange.length); + } + return selRange; + } + } + _clientCanProvideSelectionInfo = No; + // REVIEW: For now, if the client reports its location as "not found", we're stuck assuming that we're + // still in the same location in the context. This may be totally untrue, but if the client can't report + // its location, we have nothing else to go on. + _clientSelectionCanChangeUnexpectedly = NO; + if ([self.AppDelegate debugMode]) + NSLog(@"Client can NOT provide selection info!"); + // fall through + case No: + return NSMakeRange(NSNotFound, NSNotFound); + case Yes: + case Unreliable: + { + NSRange selRange = [client selectedRange]; + if ([self.AppDelegate debugMode]) { + NSLog(@"selRange.location: %lu", (unsigned long)selRange.location); + } + return selRange; + } + } +} + - (void)updateContextBuffer:(id)sender { if ([self.AppDelegate debugMode]) { NSLog(@"*** updateContextBuffer ***"); NSLog(@"sender: %@", sender); } - NSRange selRange = ([sender respondsToSelector:@selector(selectedRange)]) ? - [sender selectedRange] : - NSMakeRange(NSNotFound, NSNotFound); - - NSUInteger len; - if ([self.AppDelegate debugMode]) { - NSLog(@"selRange.location: %lu", (unsigned long)selRange.location); - } - - if (selRange.location == NSNotFound) { - // REVIEW: For now, if the client always reports its location as "not found", we're stuck assuming that we're - // still in the same location in the context. This may be totally untrue, but if the client can't report - // its location, we have nothing else to go on. (It won't matter anyway if the client also fails to report - // its context.) - _clientSelectionCanChangeUnexpectedly = NO; - len = _previousSelRange.length; - } - else { - len = selRange.location; - } + NSRange selRange = [self getSelectionRangefromClient: sender]; + // Since client can't tell us the actual current position, we assume the previously known location in the context. + // (It won't matter anyway if the client also fails to report its context.) + NSUInteger len = (_clientCanProvideSelectionInfo != Yes) ? _previousSelRange.length : selRange.location; NSString *preBuffer = [self getLimitedContextFrom:sender at:len]; // REVIEW: If there is ever a situation where preBuffer gets some text but the client reports its @@ -244,6 +287,11 @@ NSRange _previousSelRange; } - (void)updateContextBufferIfNeeded:(id)client { + // REVIEW: if self.AppDelegate.lowLevelEventTap == nil under what circumstances might we be able to safely + // re-get the context? (Probably clientCanProvideSelectionInfo would need to be true, and it would only + // actually be useful if client respondsToSelector:@selector(attributedSubstringFromRange:), but even then + // we'd only want to do it if we have actually moved from our previous location. Otherwise, we wouldn't be + // able to handle dead keys correctly.) if (self.AppDelegate.contextChangingEventDetected) { if (!_contextOutOfDate && [self.AppDelegate debugMode]) { @@ -261,10 +309,40 @@ NSRange _previousSelRange; BOOL deleteBackPosted = NO; NSArray *actions = nil; if (![self willDeleteNullChar]) { - NSEvent *eventWithOriginalModifierFlags = [NSEvent keyEventWithType:event.type location:event.locationInWindow modifierFlags:self.AppDelegate.currentModifierFlags timestamp:event.timestamp windowNumber:event.windowNumber context:event.context characters:event.characters charactersIgnoringModifiers:event.charactersIgnoringModifiers isARepeat:event.isARepeat keyCode:event.keyCode]; - actions = [self.kme processEvent:eventWithOriginalModifierFlags]; - if (actions.count == 0) + if (self.AppDelegate.lowLevelEventTap != nil) { + NSEvent *eventWithOriginalModifierFlags = [NSEvent keyEventWithType:event.type location:event.locationInWindow modifierFlags:self.AppDelegate.currentModifierFlags timestamp:event.timestamp windowNumber:event.windowNumber context:event.context characters:event.characters charactersIgnoringModifiers:event.charactersIgnoringModifiers isARepeat:event.isARepeat keyCode:event.keyCode]; + actions = [self.kme processEvent:eventWithOriginalModifierFlags]; + } + else { + // Depending on the client app and the keyboard, using the passed-in event as it is should work okay. + // Keyboards that depend on chirality support will not work. And command-key actions that change the + // context might go undetected in some apps, resulting in errant behavior for subsequent typing. + actions = [self.kme processEvent:event]; + } + if (actions.count == 0) { + if (_easterEggForCrashlytics != nil) { + NSString * kmxName = [[self.kme.kmx filePath] lastPathComponent]; + NSLog(@"Crashlytics - KMX name: %@", kmxName); + if ([kmxName isEqualToString:kEasterEggKmxName]) { + NSUInteger len = [_easterEggForCrashlytics length]; + NSLog(@"Crashlytics - Processing character(s): %@", [event characters]); + if ([[event characters] characterAtIndex:0] == [kEasterEggText characterAtIndex:len]) { + NSString *characterToAdd = [kEasterEggText substringWithRange:NSMakeRange(len, 1)]; + NSLog(@"Crashlytics - Adding character to Easter Egg code string: %@", characterToAdd); + [_easterEggForCrashlytics appendString:characterToAdd]; + if ([_easterEggForCrashlytics isEqualToString:kEasterEggText]) { + NSLog(@"Crashlytics - Forcing crash now with API Key: %@", [[Crashlytics sharedInstance] APIKey]); + [[Crashlytics sharedInstance] crash]; + } + } + else if (len > 0) { + NSLog(@"Crashlytics - Clearing Easter Egg code string."); + [_easterEggForCrashlytics setString:@""]; + } + } + } return NO; + } } else return NO; @@ -296,8 +374,7 @@ NSRange _previousSelRange; if (nc > 0) { if ([self.AppDelegate debugMode]) NSLog(@"nc = %lu", nc); - NSRange selRange = [sender selectedRange]; - NSUInteger pos = selRange.location; + NSUInteger pos = [self getSelectionRangefromClient:sender].location; if (pos >= nc && pos != NSNotFound) { if ([self.AppDelegate debugMode]) { NSLog(@"Replacement index = %lu", pos - nc); @@ -378,19 +455,26 @@ NSRange _previousSelRange; NSLog(@"Processing final posted delete-back..."); self.willDeleteNullChar = NO; - if (_legacyMode && _pendingBuffer != nil && _pendingBuffer.length > 0) { - if ([self.AppDelegate debugMode]) - NSLog(@"Posting special code to tell IM to insert characters from pending buffer."); - [self performSelector:@selector(initiatePendingBufferProcessing:) withObject:client afterDelay:0.1]; + if (_legacyMode) { + if (_pendingBuffer != nil && _pendingBuffer.length > 0) { + if ([self.AppDelegate debugMode]) + NSLog(@"Posting special code to tell IM to insert characters from pending buffer."); + [self performSelector:@selector(initiatePendingBufferProcessing:) withObject:client afterDelay:0.1]; + } } else { - if ([self.AppDelegate debugMode]) { - NSLog(@"Re-posting original (unhandled) code: %d", (int)_keyCodeOfOriginalEvent); + if (!_sourceFromOriginalEvent) { + NSLog(@"----- If not legacy mode, _sourceFromOriginalEvent should be retained until original code is posted -----"); + } + else { + if ([self.AppDelegate debugMode]) { + NSLog(@"Re-posting original (unhandled) code: %d", (int)_keyCodeOfOriginalEvent); + } + [self postKeyPressToFrontProcess:_keyCodeOfOriginalEvent from:_sourceFromOriginalEvent]; + _keyCodeOfOriginalEvent = 0; + CFRelease(_sourceFromOriginalEvent); + _sourceFromOriginalEvent = nil; } - [self postKeyPressToFrontProcess:_keyCodeOfOriginalEvent from:_sourceFromOriginalEvent]; - _keyCodeOfOriginalEvent = 0; - CFRelease(_sourceFromOriginalEvent); - _sourceFromOriginalEvent = nil; } *updateEngineContext = NO; } @@ -405,13 +489,7 @@ NSRange _previousSelRange; /*if (event.type == NSKeyDown) [self.AppDelegate handleKeyEvent:event];*/ - if (event.type == NSLeftMouseDown || event.type == NSLeftMouseUp ) { - _contextOutOfDate = YES; - return NO; - } - else if (event.type != NSKeyDown) - return NO; // We ignore NSLeftMouseDragged events (because we'll eventually get a mouse-up). - else if ((event.modifierFlags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand) { + if ((event.modifierFlags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand) { [self handleCommand:event]; return NO; // We let the client app handle all Command-key events. } @@ -438,7 +516,8 @@ NSRange _previousSelRange; if ([self.AppDelegate debugMode]) { NSLog(@"sender type = %@", NSStringFromClass([sender class])); - NSLog(@"sender selection range location = %lu", [sender selectedRange].location); + if (_clientCanProvideSelectionInfo == Yes) + NSLog(@"sender selection range location = %lu", [self getSelectionRangefromClient:sender].location); } BOOL handled = [self handleKeymanEngineActions:event in: sender]; @@ -449,10 +528,9 @@ NSRange _previousSelRange; if ([self.AppDelegate debugMode]) NSLog(@"Deleted %li null characters from context buffer", nc); // This can presumably only happen if a previous event resulted in a chain of - // actions that had a Q_BACK not followed by a Q_STR (assuming that can happen). - // REVIEW: Need to test this scenario in Atom and Googe Docs in Safari + // actions that had a Q_BACK not followed by a Q_STR. self.willDeleteNullChar = YES; - [self postDeleteBack:nc for:event]; + [self postDeleteBacks:nc for:event]; _keyCodeOfOriginalEvent = event.keyCode; return YES; @@ -488,18 +566,18 @@ NSRange _previousSelRange; break; default: - { - // NOTE: Although ch is usually the same as keyCode, when the option key is depressed (and - // perhaps in some other cases) it may not be (keyCode can be 0). Likewise, the option key - // can generate more than one character in event.characters. - unichar ch = [event.characters characterAtIndex:0]; - if (keyCode < 0x33 || (ch >= 0x2A && ch <= 0x39)) { // Main keys, Numpad char range, normal punctuation - charactersToAppend = event.characters; - } - else { - // Other keys + { + // NOTE: Although ch is usually the same as keyCode, when the option key is depressed (and + // perhaps in some other cases) it may not be (keyCode can be 0). Likewise, the option key + // can generate more than one character in event.characters. + unichar ch = [event.characters characterAtIndex:0]; + if (keyCode < 0x33 || (ch >= 0x2A && ch <= 0x39)) { // Main keys, Numpad char range, normal punctuation + charactersToAppend = event.characters; + } + else { + // Other keys + } } - } break; } if (charactersToAppend != nil) { @@ -524,25 +602,22 @@ NSRange _previousSelRange; else NSLog(@"contextBuffer = \"%@\"", self.contextBuffer.length?[self.contextBuffer codeString]:@"{empty}"); NSLog(@"kme.contextBuffer = \"%@\"", self.kme.contextBuffer.length?[self.kme.contextBuffer codeString]:@"{empty}"); - NSRange range = [sender selectedRange]; - NSLog(@"sender.selectedRange.location = %lu", range.location); - if (_cannnotTrustSelectionLength) - NSLog(@"The following cannot be trusted and will be ignored:"); - NSLog(@"sender.selectedRange.length = %lu", range.length); + if (_clientCanProvideSelectionInfo == Yes) { + NSRange range = [self getSelectionRangefromClient:sender]; // This call (in debug) reports location to Console + NSLog(@"sender.selectedRange.length = %lu", range.length); + } NSLog(@"***"); } - // Seems we can't do it this way because (at least for "legacy mode" apps) the selection range doesn't get - // updated until after we return from this method. - // if (_legacyMode) - // _previousSelRange = [sender selectedRange]; + // Note: Although this would seem to be the obvious place to set _previousSelRange (in legacy mode), we can't + // because the selection range doesn't get updated until after we return from this method. return handled; } - (BOOL)deleteBack:(NSUInteger)n in:(id) client for:(NSEvent *) event { if ([self.AppDelegate debugMode]) NSLog(@"Attempting to back-delete %li characters.", n); - NSRange selectedRange = [client selectedRange]; + NSRange selectedRange = [self getSelectionRangefromClient:client]; NSInteger pos = selectedRange.location; if (!_legacyMode) [self deleteBack:n at: pos in: client]; @@ -643,8 +718,8 @@ NSRange _previousSelRange; if (pos >= n) { // n is now the number of delete-backs we need to post (plus one more if there is selected text) if ([self.AppDelegate debugMode]) { - NSLog(@"Legacy mode: calling postDeleteBack"); - if (_cannnotTrustSelectionLength) + NSLog(@"Legacy mode: calling postDeleteBacks"); + if (_clientCanProvideSelectionInfo == No || _clientCanProvideSelectionInfo == Unreliable) NSLog(@"Cannot trust client to report accurate selection length - assuming no selection."); } @@ -658,9 +733,9 @@ NSRange _previousSelRange; @throw exception; } - if (!_cannnotTrustSelectionLength && selectedRange.length > 0) + if (_clientCanProvideSelectionInfo == Yes && selectedRange.length > 0) n++; // First delete-back will delete the existing selection. - [self postDeleteBack:n for:event]; + [self postDeleteBacks:n for:event]; CFRelease(_sourceFromOriginalEvent); _sourceFromOriginalEvent = nil; @@ -685,22 +760,19 @@ NSRange _previousSelRange; CFRelease(keyUpEvent); } -- (void)postDeleteBack:(NSUInteger)count for:(NSEvent *) event { +- (void)postDeleteBacks:(NSUInteger)count for:(NSEvent *) event { _numberOfPostedDeletesToExpect = count; - CGEventRef ev; + _sourceFromOriginalEvent = CGEventCreateSourceFromEvent([event CGEvent]); for (int db = 0; db < count; db++) { - if ([self.AppDelegate debugMode]) + if ([self.AppDelegate debugMode]) { NSLog(@"Posting a delete (down/up) at kCGHIDEventTap."); - - ev = CGEventCreateKeyboardEvent (_sourceFromOriginalEvent, kVK_Delete, true);//delete-back down - CGEventPost(kCGHIDEventTap, ev); - CFRelease(ev); - ev = CGEventCreateKeyboardEvent (_sourceFromOriginalEvent, kVK_Delete, false); //delete-back up - CGEventPost(kCGHIDEventTap, ev); - CFRelease(ev); + } + [self.AppDelegate postKeyboardEventWithSource:_sourceFromOriginalEvent code:kVK_Delete postCallback:^(CGEventRef eventToPost) { + CGEventPost(kCGHIDEventTap, eventToPost); + }]; } } @@ -712,15 +784,18 @@ NSRange _previousSelRange; ProcessSerialNumber psn; GetFrontProcess(&psn); - CGEventRef event = CGEventCreateKeyboardEvent(source, code, true); - CGEventPostToPSN(&psn, event); - CFRelease(event); - - if (code != kProcessPendingBuffer) { // special 0xFF code is not a real key-press, so no "up" is needed - event = CGEventCreateKeyboardEvent(source, code, false); - CGEventPostToPSN(&psn, event); - CFRelease(event); + if ([self.AppDelegate debugMode]) { + if (code == kProcessPendingBuffer) { + NSLog(@"Posting code to tell Keyman to process characters in pending buffer."); + } + else { + NSLog(@"Posting a keypress (down/up) to the 'front process' for the %hu key.", code); + } } + + [self.AppDelegate postKeyboardEventWithSource:source code:code postCallback:^(CGEventRef eventToPost) { + CGEventPostToPSN((ProcessSerialNumberPtr)&psn, eventToPost); + }]; } @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandlerProtected.h b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandlerProtected.h index 9cd4c6affc03f114c473100a49a4403c49887f05..5ce208947ed84b4106a33dc35a7853326904ab76 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandlerProtected.h +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandlerProtected.h @@ -9,6 +9,13 @@ #ifndef KMInputMethodEventHandlerProtected_h #define KMInputMethodEventHandlerProtected_h +typedef NS_ENUM(NSInteger, ClientCapability) { + Unknown, + Yes, + No, + Unreliable +}; + @interface KMInputMethodEventHandler () //@property (nonatomic) NSMutableDictionary *kbData; //@property (nonatomic) NSDictionary *kmModes; @@ -25,7 +32,7 @@ // checking at the start of the event processing to see if we're probably still in the same place where we // left off previously. @property (assign) BOOL clientSelectionCanChangeUnexpectedly; // REVIEW: Maybe we can get notification from these clients by handling mouseDownOnCharacterIndex. -@property (assign) BOOL cannnotTrustSelectionLength; +@property (assign) ClientCapability clientCanProvideSelectionInfo; - (instancetype)initWithLegacyMode:(BOOL)legacy clientSelectionCanChangeUnexpectedly:(BOOL) flagClientSelectionCanChangeUnexpectedly; - (void)handleCommand:(NSEvent *)event; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardHelpWindow/KMKeyboardHelpWindowController.xib b/mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardHelpWindow/KMKeyboardHelpWindowController.xib index 2c92af90573b1cf8fd27d095f843048fe08beb8d..446f8cb23d0ccbffcc25055fdc765b4e666b38f9 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardHelpWindow/KMKeyboardHelpWindowController.xib +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardHelpWindow/KMKeyboardHelpWindowController.xib @@ -1,9 +1,10 @@ - - + + - - + + + @@ -14,23 +15,25 @@ - - + + - + + Presentation: +
@@ -52,7 +53,7 @@ - + @@ -79,7 +80,7 @@ - + @@ -96,7 +97,7 @@
-
+

diff --git a/windows/src/developer/TIKE/xml/layoutbuilder/skflag.png b/windows/src/developer/TIKE/xml/layoutbuilder/skflag.png index 6855a537e9e1ac27c1e6832f0817855f26b5f459..f279af54094edc7b2114beee01f7d4002ecfaea0 100644 Binary files a/windows/src/developer/TIKE/xml/layoutbuilder/skflag.png and b/windows/src/developer/TIKE/xml/layoutbuilder/skflag.png differ diff --git a/windows/src/developer/TIKE/xml/layoutbuilder/template-basic.js b/windows/src/developer/TIKE/xml/layoutbuilder/template-basic.keyman-touch-layout similarity index 100% rename from windows/src/developer/TIKE/xml/layoutbuilder/template-basic.js rename to windows/src/developer/TIKE/xml/layoutbuilder/template-basic.keyman-touch-layout diff --git a/windows/src/developer/TIKE/xml/layoutbuilder/template-latin.js b/windows/src/developer/TIKE/xml/layoutbuilder/template-latin.keyman-touch-layout similarity index 100% rename from windows/src/developer/TIKE/xml/layoutbuilder/template-latin.js rename to windows/src/developer/TIKE/xml/layoutbuilder/template-latin.keyman-touch-layout diff --git a/windows/src/developer/TIKE/xml/layoutbuilder/template-traditional.js b/windows/src/developer/TIKE/xml/layoutbuilder/template-traditional.keyman-touch-layout similarity index 100% rename from windows/src/developer/TIKE/xml/layoutbuilder/template-traditional.js rename to windows/src/developer/TIKE/xml/layoutbuilder/template-traditional.keyman-touch-layout diff --git a/windows/src/developer/TIKE/xml/project/distribution.xsl b/windows/src/developer/TIKE/xml/project/distribution.xsl index 3f63086896fbd2737a525d0e889d4d34d461ed68..4bb87723a9966fe23b22aa4d4088b78937bf0e38 100644 --- a/windows/src/developer/TIKE/xml/project/distribution.xsl +++ b/windows/src/developer/TIKE/xml/project/distribution.xsl @@ -3,12 +3,10 @@ -
-
+
+
-

Distribution - header_distrib.png -

+

Distribution