From 807dd7c6be5d382749df9ccd3e05c8d7b149b20d Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Tue, 24 Apr 2018 13:24:55 +0700 Subject: [PATCH 001/356] Adds JS warnings in case of bad defaultKeyOutput parameters. --- web/source/kmwosk.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/web/source/kmwosk.ts b/web/source/kmwosk.ts index 198d08632a..c29cfa1c77 100644 --- a/web/source/kmwosk.ts +++ b/web/source/kmwosk.ts @@ -1002,14 +1002,18 @@ if(!window['keyman']['initialized']) { } // Hereafter, we refer to keyCodes. } else if(checkCodes) { - if(n >= osk.keyCodes['K_0'] && n <= osk.keyCodes['K_9']) { // The number keys. - ch = codesUS[keyShiftState][0][n-osk.keyCodes['K_0']]; - } else if(n >=osk.keyCodes['K_A'] && n <= osk.keyCodes['K_Z']) { // The base letter keys - ch = String.fromCharCode(n+(keyShiftState?0:32)); // 32 is the offset from uppercase to lowercase. - } else if(n >= osk.keyCodes['K_COLON'] && n <= osk.keyCodes['K_BKQUOTE']) { - ch = codesUS[keyShiftState][1][n-osk.keyCodes['K_COLON']]; - } else if(n >= osk.keyCodes['K_LBRKT'] && n <= osk.keyCodes['K_QUOTE']) { - ch = codesUS[keyShiftState][2][n-osk.keyCodes['K_LBRKT']]; + try { + if(n >= osk.keyCodes['K_0'] && n <= osk.keyCodes['K_9']) { // The number keys. + ch = codesUS[keyShiftState][0][n-osk.keyCodes['K_0']]; + } else if(n >=osk.keyCodes['K_A'] && n <= osk.keyCodes['K_Z']) { // The base letter keys + ch = String.fromCharCode(n+(keyShiftState?0:32)); // 32 is the offset from uppercase to lowercase. + } else if(n >= osk.keyCodes['K_COLON'] && n <= osk.keyCodes['K_BKQUOTE']) { + ch = codesUS[keyShiftState][1][n-osk.keyCodes['K_COLON']]; + } else if(n >= osk.keyCodes['K_LBRKT'] && n <= osk.keyCodes['K_QUOTE']) { + ch = codesUS[keyShiftState][2][n-osk.keyCodes['K_LBRKT']]; + } + } catch (e) { + console.error("Error detected with default mapping for key: code = " + n + ", shift state = " + (keyShiftState == 1 ? 'shift' : 'default')); } } return ch; -- GitLab From 859c20eb129ce2cb4fb1503129e78f5354739254 Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Tue, 24 Apr 2018 13:28:29 +0700 Subject: [PATCH 002/356] Added shift-state warning. --- web/source/kmwosk.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/source/kmwosk.ts b/web/source/kmwosk.ts index c29cfa1c77..89828f8d09 100644 --- a/web/source/kmwosk.ts +++ b/web/source/kmwosk.ts @@ -910,6 +910,8 @@ if(!window['keyman']['initialized']) { } else if (keyShiftState == osk.modifierCodes['SHIFT']) { checkCodes = true; keyShiftState = 1; // It's used as an index. + } else { + console.warn("KMW only defines default key output for the 'default' and 'shift' layers!"); } // If this was triggered by the OSK -or- if it was triggered within a touch-aliased DIV element. @@ -1001,7 +1003,7 @@ if(!window['keyman']['initialized']) { ch=String.kmwFromCharCode(codePoint); } // Hereafter, we refer to keyCodes. - } else if(checkCodes) { + } else if(checkCodes) { // keyShiftState can only be '1' or '2'. try { if(n >= osk.keyCodes['K_0'] && n <= osk.keyCodes['K_9']) { // The number keys. ch = codesUS[keyShiftState][0][n-osk.keyCodes['K_0']]; -- GitLab From cfdb2b6591804b30ccf716b7d542a402e7e03a94 Mon Sep 17 00:00:00 2001 From: darcywong00 Date: Tue, 24 Apr 2018 13:41:23 +0700 Subject: [PATCH 003/356] Hide system OSK when resuming Keyman app This handles all transitions where an external app/dialog using the system OSK returns to the Keyman app such as resuming: * from WebBrowserActivity * from Android Oreo's "Add to dictionary" dialog --- .../main/java/com/tavultesoft/kmapro/MainActivity.java | 5 +++++ .../java/com/tavultesoft/kmapro/WebBrowserActivity.java | 9 --------- .../src/main/java/com/tavultesoft/kmea/KMKeyboard.java | 5 +++++ .../src/main/java/com/tavultesoft/kmea/KMManager.java | 6 ++++++ android/history.md | 3 +++ 5 files changed, 19 insertions(+), 9 deletions(-) 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 92eb652fc1..a5b128cf33 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(); 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 139806dced..bb9a8c0ef4 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 @@ -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/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java index a65235f92a..0690f88dbd 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 @@ -168,6 +168,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); 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 4cceec811d..b2293cf9d8 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 @@ -257,6 +257,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; diff --git a/android/history.md b/android/history.md index fbdd7170ee..de5ae196bc 100644 --- a/android/history.md +++ b/android/history.md @@ -1,5 +1,8 @@ # Keyman for Android +## 2018-04-24 10.0.376 beta +* Hide system OSK when resuming Keyman app (#711) + ## 2018-03-22 10.0.373 beta * Initial beta release of Keyman for Android 10.0 -- GitLab From fe9f648a403efa5c02035754fb5e26ebf2332f25 Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Tue, 24 Apr 2018 13:59:56 +0700 Subject: [PATCH 004/356] Fixes display of longpress special keys. --- web/source/kmwosk.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web/source/kmwosk.ts b/web/source/kmwosk.ts index 198d08632a..eab9ac7dfc 100644 --- a/web/source/kmwosk.ts +++ b/web/source/kmwosk.ts @@ -759,13 +759,17 @@ if(!window['keyman']['initialized']) { var i, idx = e.id.split('-'), baseId = idx[idx.length-1], - layer = e['key'] && e['key']['layer'] ? e['key']['layer'] : (idx.length > 1 ? idx[0] : ''); + layer = e['key'] && e['key']['layer'] ? e['key']['layer'] : (idx.length > 1 ? idx[0] : ''), + sp = e['key'] && e['key']['sp']; if(typeof e.subKeys != 'undefined' && e.subKeys.length > 0 && (e.subKeys[0].id != baseId || e.subKeys[0].layer != layer)) { var eCopy={'id':baseId,'layer':'','key':undefined}; if(layer != '') { eCopy['layer'] = layer; } + if(sp) { + eCopy['sp'] = sp; + } for(i = 0; i < e.childNodes.length; i++) { if(osk.hasClass(e.childNodes[i],'kmw-key-text')) break; } -- GitLab From e582632c97cc66d1f943e5998d9df84e5cd126d5 Mon Sep 17 00:00:00 2001 From: darcywong00 Date: Tue, 24 Apr 2018 16:25:08 +0700 Subject: [PATCH 005/356] Disable text suggestions in app text field --- android/KMAPro/kMAPro/src/main/res/layout/activity_main.xml | 4 ++-- android/history.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/android/KMAPro/kMAPro/src/main/res/layout/activity_main.xml b/android/KMAPro/kMAPro/src/main/res/layout/activity_main.xml index eb7a1cbb60..a9779e37c6 100644 --- a/android/KMAPro/kMAPro/src/main/res/layout/activity_main.xml +++ b/android/KMAPro/kMAPro/src/main/res/layout/activity_main.xml @@ -13,10 +13,10 @@ android:layout_height="wrap_content" android:layout_alignParentTop="true" android:ems="10" - android:inputType="textMultiLine" + android:inputType="textMultiLine|textNoSuggestions" android:hint="@string/textview_hint" android:gravity="top" - android:scrollbars="vertical" > + android:scrollbars="vertical"> diff --git a/android/history.md b/android/history.md index de5ae196bc..f3f593365c 100644 --- a/android/history.md +++ b/android/history.md @@ -1,7 +1,7 @@ # Keyman for Android ## 2018-04-24 10.0.376 beta -* Hide system OSK when resuming Keyman app (#711) +* Hide system OSK when resuming Keyman app. Disable text suggestions (#711) ## 2018-03-22 10.0.373 beta * Initial beta release of Keyman for Android 10.0 -- GitLab From 0f464ec44d1436a6fd98f6697e1f08c6b8607126 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 25 Apr 2018 07:37:36 +0700 Subject: [PATCH 006/356] Add version history for 10.0 beta releases for Desktop and Developer --- windows/src/desktop/history.md | 11 ++++++++++- windows/src/developer/history.md | 9 +++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/windows/src/desktop/history.md b/windows/src/desktop/history.md index 85b0019cba..34c58b7e07 100644 --- a/windows/src/desktop/history.md +++ b/windows/src/desktop/history.md @@ -1,7 +1,16 @@ # Keyman Desktop Version History +## 2018-04-12 10.0.1057.0 beta +* Fix for backspace in legacy mode breaking SMP characters (#729) + +## 2018-03-31 10.0.1056.0 beta +* No changes in Keyman Desktop + +## 2018-03-22 10.0.1055.0 beta +* Offline help updates are synchronised with help.keyman.com in the correct version (#695) + ## 2018-03-22 10.0.1054.0 beta -Initial beta release of Keyman Desktop 10 +* Initial beta release of Keyman Desktop 10 ## 10.0 alpha * Keyman Desktop moved to open source (#121) diff --git a/windows/src/developer/history.md b/windows/src/developer/history.md index cf422ddfc7..b63b3ae872 100644 --- a/windows/src/developer/history.md +++ b/windows/src/developer/history.md @@ -1,5 +1,14 @@ # Keyman Developer Version History +## 2018-04-12 10.0.1057.0 beta +* No changes in Keyman Developer + +## 2018-03-31 10.0.1056.0 beta +* Web compiler was not escaping quote character in v10.0 keyboards (#719) + +## 2018-03-22 10.0.1055.0 beta +* No changes in Keyman Developer + ## 2018-03-22 10.0.1054.0 beta * Initial beta release of Keyman Developer 10 -- GitLab From c249c792d7cf9cea706383775a2278c8145d723c Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Wed, 25 Apr 2018 08:36:15 +0700 Subject: [PATCH 007/356] Minor tweaks and housekeeping. --- web/history.md | 3 +++ web/unit_tests/CI.conf.js | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/web/history.md b/web/history.md index bb137bc1f5..43f0e10d42 100644 --- a/web/history.md +++ b/web/history.md @@ -1,5 +1,8 @@ # KeymanWeb Version History +## 2018-04-25 10.0.86 beta +* Fixes display of popup keys representing modifiers and other special characters. (#698) + ## 2018-03-22 10.0.83 beta * Initial beta for KeymanWeb v 10.0. diff --git a/web/unit_tests/CI.conf.js b/web/unit_tests/CI.conf.js index 040a821f3a..c65b7a18a5 100644 --- a/web/unit_tests/CI.conf.js +++ b/web/unit_tests/CI.conf.js @@ -66,7 +66,7 @@ module.exports = function(config) { var CURRENT_IOS_LAUNCHERS = { bs_iphoneX: { - device: 'iPhone X', + device: 'iPhone 8 Plus', // Ideally, we'd use 'iPhone X', but BrowserStack's version is being problematic lately. real_mobile: false, os: 'ios', os_version: '11.0' -- GitLab From e53bf7fcaf4279459eafb6ebba6b0ea9de34ccaa Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Wed, 25 Apr 2018 12:46:45 +0700 Subject: [PATCH 008/356] Properly escapes ' and \ as popup keys. --- ios/build.sh | 1 + .../Classes/KeymanWebViewController.swift | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/ios/build.sh b/ios/build.sh index 11aa500d0e..4f96ec5f83 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/Classes/KeymanWebViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift index 5ebf8d786c..713f70c10d 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift @@ -78,7 +78,21 @@ extension KeymanWebViewController { // FIXME: text is unused in the JS func executePopupKey(id: String, text: String) { - webView.evaluateJavaScript("executePopupKey('\(id)','\(text)');", completionHandler: nil) + //var escapedText: String; + // 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.. Date: Wed, 25 Apr 2018 12:52:53 +0700 Subject: [PATCH 009/356] Minor housekeeping for the PR. --- .../KMEI/KeymanEngine/Classes/KeymanWebViewController.swift | 1 - ios/history.md | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift index 713f70c10d..736b32d692 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift @@ -78,7 +78,6 @@ extension KeymanWebViewController { // FIXME: text is unused in the JS func executePopupKey(id: String, text: String) { - //var escapedText: String; // Text must be checked for ', ", and \ characters; they must be escaped properly! do { let encodingArray = [ text ]; diff --git a/ios/history.md b/ios/history.md index f9a2798d06..ac80c9d424 100644 --- a/ios/history.md +++ b/ios/history.md @@ -1,5 +1,8 @@ # Keyman for iPhone and iPad Version History +## 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 -- GitLab From 925efe893d6c83a34035aad20acd159fb93a992b Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 25 Apr 2018 14:09:56 +0700 Subject: [PATCH 010/356] Rewrite all context help links to match Developer 10.0 help paths and identifiers; update language help to track keywords more reliably --- windows/src/developer/TIKE/Tike.dpr | 3 +- windows/src/developer/TIKE/Tike.dproj | 1 + .../developer/TIKE/child/UfrmBitmapEditor.pas | 15 +- .../src/developer/TIKE/child/UfrmDebug.pas | 10 + .../developer/TIKE/child/UfrmDebugStatus.pas | 12 +- .../src/developer/TIKE/child/UfrmEditor.pas | 8 + .../developer/TIKE/child/UfrmKeymanWizard.pas | 8 + .../developer/TIKE/child/UfrmOSKEditor.pas | 9 + .../TIKE/child/UfrmPackageEditor.pas | 8 + .../developer/TIKE/child/UfrmTestKeyboard.pas | 9 + .../TIKE/debug/UfrmDebugStatus_CallStack.pas | 10 + .../TIKE/debug/UfrmDebugStatus_Child.pas | 3 +- .../TIKE/debug/UfrmDebugStatus_Deadkeys.pas | 14 +- .../TIKE/debug/UfrmDebugStatus_Elements.pas | 10 +- .../TIKE/debug/UfrmDebugStatus_Key.pas | 9 + .../TIKE/debug/UfrmDebugStatus_RegTest.pas | 8 + .../src/developer/TIKE/debug/UfrmKeyTest.pas | 11 +- .../TIKE/debug/UfrmSelectSystemKeyboard.pas | 10 +- .../developer/TIKE/dialogs/UfrmAboutTike.pas | 9 + .../TIKE/dialogs/UfrmBitmapEditorText.pas | 10 +- .../TIKE/dialogs/UfrmKeyboardFonts.pas | 10 + .../TIKE/dialogs/UfrmMustIncludeDebug.pas | 13 +- .../src/developer/TIKE/dialogs/UfrmNew.pas | 9 + .../TIKE/dialogs/UfrmNewFileDetails.pas | 10 + .../developer/TIKE/dialogs/UfrmOptions.pas | 9 + .../dialogs/UfrmRegressionTestFailure.pas | 11 +- .../developer/TIKE/dialogs/UfrmSelectKey.pas | 10 + .../dialogs/UfrmVisualKeyboardImportKMX.pas | 7 + ...n.Developer.UI.UfrmSelectBCP47Language.pas | 9 +- .../languages/UfrmSelectWindowsLanguages.pas | 10 + .../TIKE/dockforms/UfrmCharacterMapDock.pas | 10 + .../Keyman.Developer.System.HelpTopics.pas | 51 ++ windows/src/developer/TIKE/help/kwhelp.pas | 73 ++- windows/src/developer/TIKE/help/webhelp.pas | 5 +- .../main/UframeOnScreenKeyboardEditor.pas | 9 + .../developer/TIKE/main/UframeTextEditor.pas | 91 ++-- .../TIKE/main/UfrmCharacterIdentifier.pas | 14 + .../TIKE/main/UfrmDownloadProgress.pas | 10 + windows/src/developer/TIKE/main/UfrmHelp.pas | 78 ++- windows/src/developer/TIKE/main/UfrmMain.pas | 17 +- .../src/developer/TIKE/main/UfrmMessages.pas | 11 +- .../src/developer/TIKE/main/UfrmStartup.pas | 9 + windows/src/developer/TIKE/main/UfrmTike.pas | 28 +- .../oskbuilder/UframeTouchLayoutBuilder.pas | 8 + .../developer/TIKE/project/UfrmProject.pas | 12 +- .../developer/TIKE/xml/help/contexthelp.xml | 480 +++--------------- windows/src/developer/TIKE/xml/help/help.xsl | 26 +- .../developer/TIKE/xml/project/elements.xsl | 2 +- .../developer/TIKE/xml/project/keyboards.xsl | 12 +- .../developer/TIKE/xml/project/packages.xsl | 4 +- .../developer/TIKE/xml/project/welcome.xsl | 3 +- .../UfrmVisualKeyboardExportHTMLParams.pas | 9 + 52 files changed, 680 insertions(+), 557 deletions(-) create mode 100644 windows/src/developer/TIKE/help/Keyman.Developer.System.HelpTopics.pas diff --git a/windows/src/developer/TIKE/Tike.dpr b/windows/src/developer/TIKE/Tike.dpr index 794be230ad..0136c859cd 100644 --- a/windows/src/developer/TIKE/Tike.dpr +++ b/windows/src/developer/TIKE/Tike.dpr @@ -263,7 +263,8 @@ uses Keyman.System.KMXFileLanguages in '..\..\global\delphi\keyboards\Keyman.System.KMXFileLanguages.pas', Keyman.System.LanguageCodeUtils in '..\..\global\delphi\general\Keyman.System.LanguageCodeUtils.pas', Keyman.System.RegExGroupHelperRSP19902 in '..\..\global\delphi\general\Keyman.System.RegExGroupHelperRSP19902.pas', - Keyman.System.UpdateCheckResponse in '..\..\global\delphi\general\Keyman.System.UpdateCheckResponse.pas'; + Keyman.System.UpdateCheckResponse in '..\..\global\delphi\general\Keyman.System.UpdateCheckResponse.pas', + Keyman.Developer.System.HelpTopics in 'help\Keyman.Developer.System.HelpTopics.pas'; {$R *.RES} {$R ICONS.RES} diff --git a/windows/src/developer/TIKE/Tike.dproj b/windows/src/developer/TIKE/Tike.dproj index 98bfd962b6..fc3de23643 100644 --- a/windows/src/developer/TIKE/Tike.dproj +++ b/windows/src/developer/TIKE/Tike.dproj @@ -503,6 +503,7 @@ + Cfg_2 diff --git a/windows/src/developer/TIKE/child/UfrmBitmapEditor.pas b/windows/src/developer/TIKE/child/UfrmBitmapEditor.pas index 6d023edbf3..bfb7e37f0d 100644 --- a/windows/src/developer/TIKE/child/UfrmBitmapEditor.pas +++ b/windows/src/developer/TIKE/child/UfrmBitmapEditor.pas @@ -35,8 +35,8 @@ type procedure FormCreate(Sender: TObject); private procedure FrameModified(Sender: TObject); - protected + function GetHelpTopic: string; override; function DoOpenFile: Boolean; override; function DoSaveFile: Boolean; override; function GetFileNameFilter: string; override; @@ -48,7 +48,13 @@ type implementation -uses Clipbrd, UfrmMain, UfrmMessages; +uses + Clipbrd, + + Keyman.Developer.System.HelpTopics, + + UfrmMain, + UfrmMessages; {$R *.DFM} @@ -78,6 +84,11 @@ begin Result := 'Bitmap files (*.bmp)|*.bmp|All files (*.*)|*.*'; end; +function TfrmBitmapEditor.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_BitmapEditor; +end; + function TfrmBitmapEditor.DoOpenFile: Boolean; begin RefreshOptions; diff --git a/windows/src/developer/TIKE/child/UfrmDebug.pas b/windows/src/developer/TIKE/child/UfrmDebug.pas index 56ff0ed17f..c16362cbed 100644 --- a/windows/src/developer/TIKE/child/UfrmDebug.pas +++ b/windows/src/developer/TIKE/child/UfrmDebug.pas @@ -199,6 +199,9 @@ type procedure WMUSERUpdateForceKeyboard(var Message: TMessage); message WM_USER_UpdateForceKeyboard; // I4767 procedure UpdateCharacterGrid; // I4808 + protected + function GetHelpTopic: string; override; + public function CanChangeANSITest: Boolean; property ANSITest: Boolean read FANSITest write SetANSITest; @@ -261,6 +264,8 @@ implementation {$R *.DFM} uses + Keyman.Developer.System.HelpTopics, + ActiveX, dmActionsKeyboardEditor, dmActionsMain, @@ -1304,6 +1309,11 @@ begin Result := debugkeyboard; end; +function TfrmDebug.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_Debug; +end; + function TfrmDebug.GetStatusText: string; begin Result := frmKeymanDeveloper.barStatus.Panels[1].Text; diff --git a/windows/src/developer/TIKE/child/UfrmDebugStatus.pas b/windows/src/developer/TIKE/child/UfrmDebugStatus.pas index dbe9b67985..e3585510e3 100644 --- a/windows/src/developer/TIKE/child/UfrmDebugStatus.pas +++ b/windows/src/developer/TIKE/child/UfrmDebugStatus.pas @@ -60,6 +60,8 @@ type procedure SetDebugForm(const Value: TfrmDebug); procedure SetDisplayFont(const Value: TFont); + protected + function GetHelpTopic: string; override; public property DebugForm: TfrmDebug read FDebugForm write SetDebugForm; @@ -72,12 +74,11 @@ type property RegTest: TfrmDebugStatus_RegTest read FRegTest; end; -//var -// frmDebugStatus: TfrmDebugStatus; - implementation uses + Keyman.Developer.System.HelpTopics, + UfrmMain; {$R *.dfm} @@ -108,6 +109,11 @@ begin FRegTest.Visible := True; end; +function TfrmDebugStatus.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_DebugStatus; +end; + procedure TfrmDebugStatus.SetDebugForm(const Value: TfrmDebug); var FDebugKeyboard: TDebugKeyboard; diff --git a/windows/src/developer/TIKE/child/UfrmEditor.pas b/windows/src/developer/TIKE/child/UfrmEditor.pas index da39b589f0..cf1806abe0 100644 --- a/windows/src/developer/TIKE/child/UfrmEditor.pas +++ b/windows/src/developer/TIKE/child/UfrmEditor.pas @@ -86,6 +86,7 @@ type function GetTextFileFormat: TTextFileFormat; protected + function GetHelpTopic: string; override; function DoSaveFile: Boolean; override; function DoOpenFile: Boolean; override; function GetFileNameFilter: string; override; @@ -116,6 +117,8 @@ type implementation uses + Keyman.Developer.System.HelpTopics, + CharacterDragObject, CharMapDropTool, ClipBrd, @@ -328,6 +331,11 @@ begin Result := 'Keyboard definitions (*.kmn)|*.kmn|HTML files (*.htm, *.html)|*.htm?|XML files (*.xml)|*.xml|Text files (*.txt)|*.txt|All files (*.*)|*.*'; end; +function TfrmEditor.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_Editor; +end; + function TfrmEditor.GetTextFileFormat: TTextFileFormat; begin Result := FEditorFrame.TextFileFormat; diff --git a/windows/src/developer/TIKE/child/UfrmKeymanWizard.pas b/windows/src/developer/TIKE/child/UfrmKeymanWizard.pas index 4829a31646..df9c0c4230 100644 --- a/windows/src/developer/TIKE/child/UfrmKeymanWizard.pas +++ b/windows/src/developer/TIKE/child/UfrmKeymanWizard.pas @@ -466,6 +466,7 @@ type procedure OrderDetailsPanels; protected + function GetHelpTopic: string; override; procedure FocusTab; @@ -548,6 +549,8 @@ uses System.Math, System.Win.ComObj, + Keyman.Developer.System.HelpTopics, + CharacterDragObject, CharacterInfo, CharMapDropTool, @@ -1824,6 +1827,11 @@ begin end; end; +function TfrmKeymanWizard.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_KeyboardEditor; +end; + function TfrmKeymanWizard.GetIsDebugVisible: Boolean; begin Result := panDebugHost.Visible; diff --git a/windows/src/developer/TIKE/child/UfrmOSKEditor.pas b/windows/src/developer/TIKE/child/UfrmOSKEditor.pas index b1934385e2..ad98a071e2 100644 --- a/windows/src/developer/TIKE/child/UfrmOSKEditor.pas +++ b/windows/src/developer/TIKE/child/UfrmOSKEditor.pas @@ -31,6 +31,7 @@ type frameOSK: TframeOnScreenKeyboardEditor; procedure OSKModified(Sender: TObject); protected + function GetHelpTopic: string; override; function GetFileNameFilter: string; override; function GetDefaultExt: string; override; @@ -44,6 +45,9 @@ type implementation +uses + Keyman.Developer.System.HelpTopics; + {$R *.dfm} { TfrmOSKEditor } @@ -91,4 +95,9 @@ begin Result := 'On Screen Keyboard Files (*.kvk)|*.kvk'; end; +function TfrmOSKEditor.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_OSKEditor; +end; + end. diff --git a/windows/src/developer/TIKE/child/UfrmPackageEditor.pas b/windows/src/developer/TIKE/child/UfrmPackageEditor.pas index 6cb4acf833..d0bd2b4398 100644 --- a/windows/src/developer/TIKE/child/UfrmPackageEditor.pas +++ b/windows/src/developer/TIKE/child/UfrmPackageEditor.pas @@ -251,6 +251,7 @@ type State: TProjectLogState); protected + function GetHelpTopic: string; override; function DoOpenFile: Boolean; override; function DoSaveFile: Boolean; override; function GetFileNameFilter: string; override; @@ -273,6 +274,8 @@ type implementation uses + Keyman.Developer.System.HelpTopics, + CharMapDropTool, CharMapInsertMode, CompilePackageInstaller, @@ -462,6 +465,11 @@ begin Result := 'Package source files (*.kps)|*.kps|All files (*.*)|*.*'; end; +function TfrmPackageEditor.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_PackageEditor; +end; + function TfrmPackageEditor.DoOpenFile: Boolean; begin Result := True; diff --git a/windows/src/developer/TIKE/child/UfrmTestKeyboard.pas b/windows/src/developer/TIKE/child/UfrmTestKeyboard.pas index e4ed741208..f193dc7c7a 100644 --- a/windows/src/developer/TIKE/child/UfrmTestKeyboard.pas +++ b/windows/src/developer/TIKE/child/UfrmTestKeyboard.pas @@ -93,6 +93,8 @@ type procedure SaveFont; procedure FocusTestWindow; procedure ShowEditControl; + protected + function GetHelpTopic: string; override; public procedure Reload; property KeyboardName: string read FKeyboardName write SetKeyboardName; @@ -102,6 +104,8 @@ type implementation uses + Keyman.Developer.System.HelpTopics, + KeymanDeveloperUtils, kmxfile, UfrmMessages, @@ -430,6 +434,11 @@ begin end; +function TfrmTestKeyboard.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_TestKeyboard; +end; + { Debug menu } diff --git a/windows/src/developer/TIKE/debug/UfrmDebugStatus_CallStack.pas b/windows/src/developer/TIKE/debug/UfrmDebugStatus_CallStack.pas index 7d64331e72..66cbb6934c 100644 --- a/windows/src/developer/TIKE/debug/UfrmDebugStatus_CallStack.pas +++ b/windows/src/developer/TIKE/debug/UfrmDebugStatus_CallStack.pas @@ -34,6 +34,9 @@ type function SetEditorCursorLine(ALine: Integer): Boolean; { Call stack functions } + protected + function GetHelpTopic: string; override; + public { Public declarations } procedure CallStackPush(rule: TDebugEventRuleData); @@ -44,6 +47,8 @@ type implementation uses + Keyman.Developer.System.HelpTopics, + UKeyBitmap; {$R *.dfm} @@ -88,6 +93,11 @@ begin end; end; +function TfrmDebugStatus_CallStack.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_DebugStatus_CallStack; +end; + procedure TfrmDebugStatus_CallStack.lbCallStackDblClick(Sender: TObject); var rule: TDebugEventRuleData; diff --git a/windows/src/developer/TIKE/debug/UfrmDebugStatus_Child.pas b/windows/src/developer/TIKE/debug/UfrmDebugStatus_Child.pas index 63980ddba3..fb98471794 100644 --- a/windows/src/developer/TIKE/debug/UfrmDebugStatus_Child.pas +++ b/windows/src/developer/TIKE/debug/UfrmDebugStatus_Child.pas @@ -52,7 +52,8 @@ type implementation -uses UfrmDebugStatus; +uses + UfrmDebugStatus; {$R *.dfm} diff --git a/windows/src/developer/TIKE/debug/UfrmDebugStatus_Deadkeys.pas b/windows/src/developer/TIKE/debug/UfrmDebugStatus_Deadkeys.pas index 14daf760cb..9de347b2af 100644 --- a/windows/src/developer/TIKE/debug/UfrmDebugStatus_Deadkeys.pas +++ b/windows/src/developer/TIKE/debug/UfrmDebugStatus_Deadkeys.pas @@ -32,6 +32,10 @@ type private { Deadkey functions } procedure ClearDeadKeys; + + protected + function GetHelpTopic: string; override; + public procedure UpdateDeadkeyDisplay(deadkeys: TList); procedure DeselectDeadkeys; @@ -39,7 +43,10 @@ type implementation -uses UfrmDebugStatus; +uses + Keyman.Developer.System.HelpTopics, + + UfrmDebugStatus; {$R *.dfm} @@ -54,6 +61,11 @@ begin lbDeadkeysClick(lbDeadkeys); end; +function TfrmDebugStatus_DeadKeys.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_DebugStatus_DeadKeys; +end; + procedure TfrmDebugStatus_DeadKeys.lbDeadkeysClick(Sender: TObject); begin if lbDeadKeys.ItemIndex < 0 diff --git a/windows/src/developer/TIKE/debug/UfrmDebugStatus_Elements.pas b/windows/src/developer/TIKE/debug/UfrmDebugStatus_Elements.pas index aaca9d0704..d6e5c15e57 100644 --- a/windows/src/developer/TIKE/debug/UfrmDebugStatus_Elements.pas +++ b/windows/src/developer/TIKE/debug/UfrmDebugStatus_Elements.pas @@ -53,9 +53,8 @@ type function GetStoreDisplayWidth(Element: TXStringElement): Integer; procedure ResizeStoreGrid; -// procedure RefreshOptions; - protected + function GetHelpTopic: string; override; procedure DisplayFontChanged; override; public procedure UpdateStores(Event: TDebugEvent); @@ -65,6 +64,8 @@ type implementation uses + Keyman.Developer.System.HelpTopics, + KeymanDeveloperOptions, UfrmDebugStatus; @@ -322,6 +323,11 @@ begin lvElements.Repaint; end; +function TfrmDebugStatus_Elements.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_DebugStatus_Elements; +end; + function TfrmDebugStatus_Elements.GetStoreDisplayWidth(Element: TXStringElement): Integer; var p1, p2, p3: WideString; diff --git a/windows/src/developer/TIKE/debug/UfrmDebugStatus_Key.pas b/windows/src/developer/TIKE/debug/UfrmDebugStatus_Key.pas index 3f14496410..6a6df47f37 100644 --- a/windows/src/developer/TIKE/debug/UfrmDebugStatus_Key.pas +++ b/windows/src/developer/TIKE/debug/UfrmDebugStatus_Key.pas @@ -47,6 +47,8 @@ type FRegTest: TRegressionTest; // I4809 FUIStatus: TDebugUIStatus; // I4809 procedure SetUIStatus(const Value: TDebugUIStatus); // I4809 + protected + function GetHelpTopic: string; override; public procedure ClearLog; // I4809 procedure ShowKey(key: PAIDebugKeyInfo); @@ -56,6 +58,8 @@ type implementation uses + Keyman.Developer.System.HelpTopics, + KeyNames, UKeyBitmap; @@ -80,6 +84,11 @@ begin FRegTest.Free; // I4809 end; +function TfrmDebugStatus_Key.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_DebugStatus_Key +end; + procedure TfrmDebugStatus_Key.panKeyPaint(Sender: TObject); begin panKey.Canvas.Brush.Color := clWindow; // I4816 diff --git a/windows/src/developer/TIKE/debug/UfrmDebugStatus_RegTest.pas b/windows/src/developer/TIKE/debug/UfrmDebugStatus_RegTest.pas index b689e0f88b..eec964320e 100644 --- a/windows/src/developer/TIKE/debug/UfrmDebugStatus_RegTest.pas +++ b/windows/src/developer/TIKE/debug/UfrmDebugStatus_RegTest.pas @@ -77,6 +77,7 @@ type procedure BatchRegTest; protected + function GetHelpTopic: string; override; procedure DebugKeyboardChanged; override; public @@ -94,6 +95,8 @@ type implementation uses + Keyman.Developer.System.HelpTopics, + debugDeadkeys, KeyNames, TextFileFormat, @@ -388,4 +391,9 @@ begin FreeAndNil(FRegTest); end; +function TfrmDebugStatus_RegTest.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_DebugStatus_RegTest; +end; + end. diff --git a/windows/src/developer/TIKE/debug/UfrmKeyTest.pas b/windows/src/developer/TIKE/debug/UfrmKeyTest.pas index 334e701610..9ffd367cce 100644 --- a/windows/src/developer/TIKE/debug/UfrmKeyTest.pas +++ b/windows/src/developer/TIKE/debug/UfrmKeyTest.pas @@ -58,6 +58,7 @@ type FLastActiveControl: TWinControl; procedure WMKey(var Msg: TMsg); protected + function GetHelpTopic: string; override; public function ShowModal: Integer; override; end; @@ -66,7 +67,10 @@ function FormatKeyName(Shift, Key: Integer): string; implementation -uses UfrmMain, KeyNames, UfrmMDIChild, CharMapInsertMode, CharMapDropTool; +uses + Keyman.Developer.System.HelpTopics, + +UfrmMain, KeyNames, UfrmMDIChild, CharMapInsertMode, CharMapDropTool; {$R *.DFM} @@ -366,6 +370,11 @@ begin GetCharMapDropTool.InsertToControl(FLastActiveControl, FormatKeyName(FLastShift, FLastKey), cmimCode); end; +function TfrmKeyTest.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_KeyTest; +end; + function TfrmKeyTest.ShowModal: Integer; begin FLastActiveControl := Screen.ActiveControl; diff --git a/windows/src/developer/TIKE/debug/UfrmSelectSystemKeyboard.pas b/windows/src/developer/TIKE/debug/UfrmSelectSystemKeyboard.pas index bd74e8e0e5..d4d918b8b0 100644 --- a/windows/src/developer/TIKE/debug/UfrmSelectSystemKeyboard.pas +++ b/windows/src/developer/TIKE/debug/UfrmSelectSystemKeyboard.pas @@ -54,7 +54,8 @@ type function GetSystemKeyboardName: string; procedure SetSystemKeyboardName(Value: string); procedure InvalidateCell(ACol, ARow: Integer); - { Private declarations } + protected + function GetHelpTopic: string; override; public { Public declarations } property SystemKeyboardName: string read GetSystemKeyboardName write SetSystemKeyboardName; @@ -71,6 +72,8 @@ function GetSystemKeyboardIndex(keyboardlist: TStrings; id: string): Integer; implementation uses + Keyman.Developer.System.HelpTopics, + ErrorControlledRegistry, RegistryKeys, utilstr; @@ -155,6 +158,11 @@ begin end; end; +function TfrmSelectSystemKeyboard.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_SelectSystemKeyboard; +end; + function TfrmSelectSystemKeyboard.GetSystemKeyboardName: string; begin Result := gridKeyboards.Cells[2, gridKeyboards.Row]; diff --git a/windows/src/developer/TIKE/dialogs/UfrmAboutTike.pas b/windows/src/developer/TIKE/dialogs/UfrmAboutTike.pas index 20e27dfcc6..8b3151711e 100644 --- a/windows/src/developer/TIKE/dialogs/UfrmAboutTike.pas +++ b/windows/src/developer/TIKE/dialogs/UfrmAboutTike.pas @@ -50,6 +50,8 @@ type procedure imgKeymanClick(Sender: TObject); private FOnIconClick: TNotifyEvent; + protected + function GetHelpTopic: string; override; public property OnIconClick: TNotifyEvent read FOnIconClick write FOnIconClick; end; @@ -59,6 +61,8 @@ implementation uses VCL.Themes, + Keyman.Developer.System.HelpTopics, + KeymanVersion, onlineconstants, Upload_Settings, @@ -84,6 +88,11 @@ begin TUtilExecute.URL(lblWebsite.Caption); // I3349 end; +function TfrmAboutTike.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_About; +end; + procedure TfrmAboutTike.imgKeymanClick(Sender: TObject); begin if ((GetKeyState(VK_SHIFT) and $8000) = $8000) and diff --git a/windows/src/developer/TIKE/dialogs/UfrmBitmapEditorText.pas b/windows/src/developer/TIKE/dialogs/UfrmBitmapEditorText.pas index 857b6957aa..ca98784908 100644 --- a/windows/src/developer/TIKE/dialogs/UfrmBitmapEditorText.pas +++ b/windows/src/developer/TIKE/dialogs/UfrmBitmapEditorText.pas @@ -59,7 +59,8 @@ type procedure SetInsertFont(const Value: TFont); procedure DrawPreview; procedure SetDisplayQuality(const Value: TClearTypeDisplayQuality); - { Private declarations } + protected + function GetHelpTopic: string; override; public { Public declarations } property DisplayQuality: TClearTypeDisplayQuality read FDisplayQuality write SetDisplayQuality; @@ -72,6 +73,8 @@ type implementation uses + Keyman.Developer.System.HelpTopics, + UFixFontDialogBold, UframeBitmapEditor; @@ -126,6 +129,11 @@ begin DrawPreview; end; +function TfrmBitmapEditorText.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_BitmapEditorText; +end; + function TfrmBitmapEditorText.GetInsertText: WideString; begin Result := editText.Text; diff --git a/windows/src/developer/TIKE/dialogs/UfrmKeyboardFonts.pas b/windows/src/developer/TIKE/dialogs/UfrmKeyboardFonts.pas index 71a3a2b32f..8c5bc103c2 100644 --- a/windows/src/developer/TIKE/dialogs/UfrmKeyboardFonts.pas +++ b/windows/src/developer/TIKE/dialogs/UfrmKeyboardFonts.pas @@ -72,6 +72,8 @@ type FControls: array[TKeyboardFont] of TKeyboardFontControl; function GetFontInfo(Index: TKeyboardFont): TKeyboardFontInfo; procedure SetFontInfo(Index: TKeyboardFont; const Value: TKeyboardFontInfo); + protected + function GetHelpTopic: string; override; public { Public declarations } property FontInfo[Index: TKeyboardFont]: TKeyboardFontInfo read GetFontInfo write SetFontInfo; @@ -79,6 +81,9 @@ type implementation +uses + Keyman.Developer.System.HelpTopics; + {$R *.dfm} procedure TfrmKeyboardFonts.cmdOKClick(Sender: TObject); @@ -125,6 +130,11 @@ begin //Result.Filename := IncludeTrailingPathDelimiter(FControls[Index].PathEdit.Text) + FControls[Index].FilenameEdit.Text; end; +function TfrmKeyboardFonts.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_KeyboardFonts; +end; + procedure TfrmKeyboardFonts.SetFontInfo(Index: TKeyboardFont; const Value: TKeyboardFontInfo); begin FControls[Index].NameCombo.Enabled := Value.Enabled; diff --git a/windows/src/developer/TIKE/dialogs/UfrmMustIncludeDebug.pas b/windows/src/developer/TIKE/dialogs/UfrmMustIncludeDebug.pas index 3e9afde16c..28ccce4ba4 100644 --- a/windows/src/developer/TIKE/dialogs/UfrmMustIncludeDebug.pas +++ b/windows/src/developer/TIKE/dialogs/UfrmMustIncludeDebug.pas @@ -33,14 +33,18 @@ type chkAutoRecompile: TCheckBox; procedure cmdOKClick(Sender: TObject); private - { Private declarations } + protected + function GetHelpTopic: string; override; public { Public declarations } end; implementation -uses KeymanDeveloperOptions; +uses + Keyman.Developer.System.HelpTopics, + + KeymanDeveloperOptions; {$R *.DFM} @@ -56,4 +60,9 @@ begin ModalResult := mrYes; end; +function TfrmMustIncludeDebug.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_MustIncludeDebug; +end; + end. diff --git a/windows/src/developer/TIKE/dialogs/UfrmNew.pas b/windows/src/developer/TIKE/dialogs/UfrmNew.pas index 43b3252810..93d62b187f 100644 --- a/windows/src/developer/TIKE/dialogs/UfrmNew.pas +++ b/windows/src/developer/TIKE/dialogs/UfrmNew.pas @@ -72,6 +72,8 @@ type function GetAddToProject: Boolean; function GetFileName: string; function GetDefaultExt: string; + protected + function GetHelpTopic: string; override; public property FileType: TKMFileType read GetFileType; property AddToProject: Boolean read GetAddToProject; @@ -81,6 +83,8 @@ type implementation uses + Keyman.Developer.System.HelpTopics, + Project, shlobj, utilsystem; @@ -249,6 +253,11 @@ begin Result := ftOther; end; +function TfrmNew.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_New; +end; + procedure TfrmNew.mnuShowIconsClick(Sender: TObject); begin lvItems.ViewStyle := vsIcon; diff --git a/windows/src/developer/TIKE/dialogs/UfrmNewFileDetails.pas b/windows/src/developer/TIKE/dialogs/UfrmNewFileDetails.pas index 4226ef1032..c9a70d6eee 100644 --- a/windows/src/developer/TIKE/dialogs/UfrmNewFileDetails.pas +++ b/windows/src/developer/TIKE/dialogs/UfrmNewFileDetails.pas @@ -55,6 +55,8 @@ type procedure EnableControls; function GetFileName: string; procedure SetBaseFileName(Value: string); + protected + function GetHelpTopic: string; override; public property FileName: string read GetFileName; property FileType: TKMFileType read FFileType write SetFileType; @@ -65,6 +67,9 @@ implementation uses ShlObj, + + Keyman.Developer.System.HelpTopics, + utilsystem; {$R *.DFM} @@ -150,5 +155,10 @@ begin Result := Result + FDefaultExt; end; +function TfrmNewFileDetails.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_NewFileDetails; +end; + end. diff --git a/windows/src/developer/TIKE/dialogs/UfrmOptions.pas b/windows/src/developer/TIKE/dialogs/UfrmOptions.pas index 35f43cdc95..57f0b8cae5 100644 --- a/windows/src/developer/TIKE/dialogs/UfrmOptions.pas +++ b/windows/src/developer/TIKE/dialogs/UfrmOptions.pas @@ -156,6 +156,8 @@ type procedure RefreshColourPanels; {$ENDIF} { Private declarations } + protected + function GetHelpTopic: string; override; public { Public declarations } end; @@ -165,6 +167,8 @@ implementation {$R *.DFM} uses + Keyman.Developer.System.HelpTopics, + JvDockControlForm, OnlineConstants, RedistFiles, @@ -318,6 +322,11 @@ begin FQuotedFont.Free; end; +function TfrmOptions.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_Options; +end; + procedure TfrmOptions.cmdOKClick(Sender: TObject); var i: Integer; diff --git a/windows/src/developer/TIKE/dialogs/UfrmRegressionTestFailure.pas b/windows/src/developer/TIKE/dialogs/UfrmRegressionTestFailure.pas index b8b33b3d77..2b3c1ead60 100644 --- a/windows/src/developer/TIKE/dialogs/UfrmRegressionTestFailure.pas +++ b/windows/src/developer/TIKE/dialogs/UfrmRegressionTestFailure.pas @@ -45,7 +45,8 @@ type procedure SetActualString(Value: WideString); procedure SetExpectedString(Value: WideString); procedure SetTestName(Value: string); - { Private declarations } + protected + function GetHelpTopic: string; override; public { Public declarations } property TestName: string read FTestName write SetTestName; @@ -56,10 +57,18 @@ type implementation +uses + Keyman.Developer.System.HelpTopics; + {$R *.DFM} { TfrmRegressionTestFailure } +function TfrmRegressionTestFailure.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_RegressionTestFailure; +end; + procedure TfrmRegressionTestFailure.SetActualString(Value: WideString); begin FActualString := Value; diff --git a/windows/src/developer/TIKE/dialogs/UfrmSelectKey.pas b/windows/src/developer/TIKE/dialogs/UfrmSelectKey.pas index de59ba08e7..72089b4195 100644 --- a/windows/src/developer/TIKE/dialogs/UfrmSelectKey.pas +++ b/windows/src/developer/TIKE/dialogs/UfrmSelectKey.pas @@ -33,6 +33,8 @@ type FVKey: Word; FShiftState: TExtShiftState; FDistinguishLeftRight: Boolean; + protected + function GetHelpTopic: string; override; public property VKey: Word read FVKey; property ShiftState: TExtShiftState read FShiftState; @@ -41,6 +43,9 @@ type implementation +uses + Keyman.Developer.System.HelpTopics; + {$R *.DFM} procedure TfrmSelectKey.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); @@ -67,5 +72,10 @@ begin ModalResult := mrOk; end; +function TfrmSelectKey.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_SelectKey; +end; + end. diff --git a/windows/src/developer/TIKE/dialogs/UfrmVisualKeyboardImportKMX.pas b/windows/src/developer/TIKE/dialogs/UfrmVisualKeyboardImportKMX.pas index 21adf7d9ff..05e516868a 100644 --- a/windows/src/developer/TIKE/dialogs/UfrmVisualKeyboardImportKMX.pas +++ b/windows/src/developer/TIKE/dialogs/UfrmVisualKeyboardImportKMX.pas @@ -66,6 +66,7 @@ type procedure Validate102Key; procedure SetStatus(const msg: string); protected + function GetHelpTopic: string; override; procedure WndProc(var Message: TMessage); override; public property FileName: WideString read FFileName write FFileName; @@ -77,6 +78,7 @@ type implementation uses + Keyman.Developer.System.HelpTopics, keyman32_int, KeymanDeveloperUtils, kmxfileconsts, @@ -494,6 +496,11 @@ begin end; +function TfrmVisualKeyboardImportKMX.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_VisualKeyboardImportKMX; +end; + function TfrmVisualKeyboardImportKMX.GetKeyboardKeys: Boolean; var ki: TKeyboardInfo; diff --git a/windows/src/developer/TIKE/dialogs/languages/Keyman.Developer.UI.UfrmSelectBCP47Language.pas b/windows/src/developer/TIKE/dialogs/languages/Keyman.Developer.UI.UfrmSelectBCP47Language.pas index c7ecaed9a2..5caba5f6b7 100644 --- a/windows/src/developer/TIKE/dialogs/languages/Keyman.Developer.UI.UfrmSelectBCP47Language.pas +++ b/windows/src/developer/TIKE/dialogs/languages/Keyman.Developer.UI.UfrmSelectBCP47Language.pas @@ -52,7 +52,8 @@ type function GetLanguageID: string; function GetLanguageName: string; procedure RefreshPreview; - { Private declarations } + protected + function GetHelpTopic: string; override; public { Public declarations } property LanguageID: string read GetLanguageID; @@ -62,6 +63,7 @@ type implementation uses + Keyman.Developer.System.HelpTopics, Keyman.System.KMXFileLanguages, utilexecute; @@ -81,6 +83,11 @@ begin FreeAndNil(tag); end; +function TfrmSelectBCP47Language.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_SelectBCP47Language; +end; + function TfrmSelectBCP47Language.GetLanguageID: string; begin Result := tag.Tag; diff --git a/windows/src/developer/TIKE/dialogs/languages/UfrmSelectWindowsLanguages.pas b/windows/src/developer/TIKE/dialogs/languages/UfrmSelectWindowsLanguages.pas index 9c8c8169ca..bc7eaf2d8b 100644 --- a/windows/src/developer/TIKE/dialogs/languages/UfrmSelectWindowsLanguages.pas +++ b/windows/src/developer/TIKE/dialogs/languages/UfrmSelectWindowsLanguages.pas @@ -37,6 +37,8 @@ type function GetLanguageNames(Index: Integer): WideString; function GetLanguages(Index: Integer): Integer; { Private declarations } + protected + function GetHelpTopic: string; override; public { Public declarations } procedure RemoveLanguage(ID: Integer); @@ -47,6 +49,9 @@ type implementation +uses + Keyman.Developer.System.HelpTopics; + {$R *.dfm} procedure TfrmSelectWindowsLanguages.FormCreate(Sender: TObject); @@ -58,6 +63,11 @@ begin lbLanguages.Items.AddObject(CWindowsLanguages[i].Name, Pointer(CWindowsLanguages[i].ID)); end; +function TfrmSelectWindowsLanguages.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_SelectWindowsLanguages; +end; + function TfrmSelectWindowsLanguages.GetLanguageCount: Integer; begin Result := lbLanguages.SelCount; diff --git a/windows/src/developer/TIKE/dockforms/UfrmCharacterMapDock.pas b/windows/src/developer/TIKE/dockforms/UfrmCharacterMapDock.pas index f3ef292a87..7088bb04df 100644 --- a/windows/src/developer/TIKE/dockforms/UfrmCharacterMapDock.pas +++ b/windows/src/developer/TIKE/dockforms/UfrmCharacterMapDock.pas @@ -11,6 +11,8 @@ type TfrmCharacterMapDock = class(TTikeDockForm) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); + protected + function GetHelpTopic: string; override; public procedure RefreshOptions; end; @@ -23,6 +25,8 @@ implementation {$R *.dfm} uses + Keyman.Developer.System.HelpTopics, + RegistryKeys, UfrmMain; @@ -33,6 +37,7 @@ begin frmCharacterMapNew.BorderStyle := bsNone; frmCharacterMapNew.Parent := Self; frmCharacterMapNew.Visible := True; + frmCharacterMapNew.HelpKeyword := SHelpTopic_Context_CharacterMap; frmCharacterMapNew.OnCancelFocus := frmKeymanDeveloper.CharMapCancelFocus; frmCharacterMapNew.OnInsertCode := frmKeymanDeveloper.CharMapInsertCode; @@ -46,6 +51,11 @@ begin FreeAndNil(frmCharacterMapNew); end; +function TfrmCharacterMapDock.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_CharacterMap; +end; + procedure TfrmCharacterMapDock.RefreshOptions; begin frmCharacterMapNew.Reload; diff --git a/windows/src/developer/TIKE/help/Keyman.Developer.System.HelpTopics.pas b/windows/src/developer/TIKE/help/Keyman.Developer.System.HelpTopics.pas new file mode 100644 index 0000000000..79758556cc --- /dev/null +++ b/windows/src/developer/TIKE/help/Keyman.Developer.System.HelpTopics.pas @@ -0,0 +1,51 @@ +unit Keyman.Developer.System.HelpTopics; + +interface + +const + SHelpTopic_Context_About = 'context/about-tike'; + SHelpTopic_Context_BitmapEditorText = 'context/keyboard-editor#toc-icon-tab'; + SHelpTopic_Context_CharacterMap = 'context/character-map'; + SHelpTopic_Context_CharacterIdentifier = 'context/character-identifier'; + SHelpTopic_Context_Debug = 'context/debug'; + SHelpTopic_Context_DebugStatus = 'context/debug#toc-state'; + SHelpTopic_Context_DebugStatus_CallStack = 'context/debug#toc-call-stack'; + SHelpTopic_Context_DebugStatus_DeadKeys = 'context/debug#toc-deadkeys'; + SHelpTopic_Context_DebugStatus_Elements = 'context/debug#toc-elements'; + SHelpTopic_Context_DebugStatus_Key = 'context/debug#toc-state'; + SHelpTopic_Context_DebugStatus_RegTest = 'context/debug#toc-regression-testing'; + SHelpTopic_Context_DownloadProgress = 'context/download-progress'; + SHelpTopic_Context_Help = 'context/help'; + SHelpTopic_Context_KeyTest = 'context/key-test'; + SHelpTopic_Context_KeyboardFonts = 'context/keyboard-fonts'; + SHelpTopic_Context_Messages = 'context/messages'; + SHelpTopic_Context_MustIncludeDebug = 'context/must-include-debug'; + SHelpTopic_Context_New = 'context/new'; + SHelpTopic_Context_NewFileDetails = 'context/new-file-details'; + SHelpTopic_Context_OnScreenKeyboardEditor = 'context/keyboard-editor#toc-on-screen-tab'; + SHelpTopic_Context_Options = 'context/options'; + SHelpTopic_Context_Project = 'context/project'; + SHelpTopic_Context_RegressionTestFailure = 'context/debug#toc-regression-testing'; + SHelpTopic_Context_SelectBCP47Language = 'context/select-bcp47-language'; + SHelpTopic_Context_SelectKey = 'context/keyboard-editor#toc-layout-tab'; + SHelpTopic_Context_SelectSystemKeyboard = 'context/select-system-keyboard'; + SHelpTopic_Context_SelectWindowsLanguages = 'context/select-windows-languages'; + SHelpTopic_Context_Startup = 'context/startup'; + SHelpTopic_Context_TextEditor = 'context/editor'; + SHelpTopic_Context_VisualKeyboardImportKMX = 'context/keyboard-editor#toc-on-screen-tab'; + SHelpTopic_Context_VisualKeyboardExportHtmlParams = 'context/keyboard-editor#toc-on-screen-tab'; + + SHelpTopic_Context_Editor = 'context/editor'; + SHelpTopic_Context_PackageEditor = 'context/package-editor'; + SHelpTopic_Context_OSKEditor = 'context/keyboard-editor#toc-on-screen-tab'; + SHelpTopic_Context_BitmapEditor = 'context/keyboard-editor#toc-icon-tab'; + SHelpTopic_Context_KeyboardEditor = 'context/keyboard-editor'; + SHelpTopic_Context_TouchLayoutBuilder = 'context/keyboard-editor#toc-touch-layout-tab'; + SHelpTopic_Context_TestKeyboard = 'context/debug#toc-test-mode'; + + // For all .kmn language reference topics, prefix with this path: + SHelpTopic_LanguageReference_Prefix = 'language/reference/'; + SHelpTopic_LanguageGuide_Prefix = 'language/guide/'; +implementation + +end. diff --git a/windows/src/developer/TIKE/help/kwhelp.pas b/windows/src/developer/TIKE/help/kwhelp.pas index 8a2a857d7f..35837b1095 100644 --- a/windows/src/developer/TIKE/help/kwhelp.pas +++ b/windows/src/developer/TIKE/help/kwhelp.pas @@ -24,21 +24,24 @@ unit kwhelp; interface -function HelpKeyword(txt: string): string; -function IsValidHelpToken(var token: WideString): Boolean; +function IsValidHelpToken(var token: WideString; HelpOnSyntacticElements: Boolean): Boolean; implementation -uses SysUtils; +uses + System.SysUtils, + + Keyman.Developer.System.HelpTopics; type THelpArray = record Word: string; - Topic: string; // if not specified, then will default to "reference/.html" + Topic: string; // if not specified, then will default to "[guide|reference]/" + Guide: Boolean; // if true, uses SLanguageGuide else SLanguageReference end; const - HelpArray: array[0..68] of THelpArray = ( // I4840 + HelpArray: array[0..73] of THelpArray = ( // I4840 (Word: 'BITMAP' ), (Word: 'begin' ), (Word: 'COPYRIGHT' ), @@ -115,27 +118,16 @@ const (Word: 'shift'; Topic: 'caps' ), {32}(Word: 'frees'; Topic: 'caps' ), -{1} (Word: 'c'; Topic: '_struct_comments' ) - ); +{1} (Word: 'c'; Topic: 'comments'; Guide: True ), -function HelpKeyword(txt: string): string; -var - i: Integer; -begin - for i := 0 to High(HelpArray) do - begin - if SameText(txt, HelpArray[i].Word) then - begin - if HelpArray[i].Topic = '' then txt := 'reference_'+LowerCase(HelpArray[i].Word) else txt := 'reference_'+LowerCase(HelpArray[i].Topic); // I4677 // I4841 - Result := txt; - Exit; - end; - end; - - Result := 'reference__keywordsbytype'; // I4677 // I4841 -end; +{3} (Word: '*virtual-key'; Topic: 'virtual-keys'; Guide: True ), + (Word: '*character'; Topic: 'strings'; Guide: True ), + (Word: '*string'; Topic: 'strings'; Guide: True ), + (Word: '*constant'; Topic: 'constants'; Guide: True ), + (Word: '*compile-target'; Topic: 'compile-targets'; Guide: True ) + ); -function IsValidHelpToken(var token: WideString): Boolean; +function IsValidHelpToken(var token: WideString; HelpOnSyntacticElements: Boolean): Boolean; var i: Integer; begin @@ -149,16 +141,41 @@ begin if (Length(token) > 2) and ((token[1] = 'c') or (token[1] = 'C')) and ((token[2] < #33) or (token[2] = #160)) then begin token := 'c'; + end + else if HelpOnSyntacticElements then + begin + if Copy(token, 1, 1) = '[' then + begin + token := '*virtual-key'; + end + else if SameText(Copy(token, 1, 2), 'U+') or SameText(Copy(token, 1, 1), 'd') or SameText(Copy(token, 1, 1), 'x') then + begin + token := '*character'; + end + else if (token <> '') and CharInSet(token[1], ['''', '"']) then + begin + token := '*string'; + end + else if Copy(token, 1, 1) = '$' then + begin + if SameText(token, '$keyman:') or SameText(token, '$keymanonly:') or SameText(token, '$keyman:') or + SameText(token, '$kmfl:') or SameText(token, '$weaver:') + then token := '*compile-target' + else token := '*constant'; + end; end; for i := 0 to High(HelpArray) do begin if WideSameText(HelpArray[i].Word, token) then begin - if HelpArray[i].Topic <> '' then token := LowerCase(HelpArray[i].Topic) - else token := LowerCase(HelpArray[i].Word); - Result := True; - Exit; + if HelpArray[i].Topic <> '' + then token := LowerCase(HelpArray[i].Topic) + else token := LowerCase(HelpArray[i].Word); + if HelpArray[i].Guide + then token := SHelpTopic_LanguageGuide_Prefix + token + else token := SHelpTopic_LanguageReference_Prefix + token; + Exit(True); end; end; diff --git a/windows/src/developer/TIKE/help/webhelp.pas b/windows/src/developer/TIKE/help/webhelp.pas index 15da2d0b5e..cc8b5bb50a 100644 --- a/windows/src/developer/TIKE/help/webhelp.pas +++ b/windows/src/developer/TIKE/help/webhelp.pas @@ -37,6 +37,7 @@ type implementation uses + System.StrUtils, System.SysUtils, utilexecute; @@ -45,6 +46,8 @@ constructor TWebHookHelpSystem.Create(aRootWebPath: string); begin inherited Create; FRootWebPath := aRootWebPath; + if (FRootWebPath <> '') and (FRootWebPath[Length(FRootWebPath)] <> '/') then + FRootWebPath := FRootWebPath + '/'; end; function TWebHookHelpSystem.HelpContext(aContextId: DWord): Boolean; @@ -64,7 +67,7 @@ begin begin for i := 1 to Length(aTopic) do if aTopic[i] = '\' then aTopic[i] := '/'; if aTopic[1] = '/' then Delete(aTopic, 1, 1); - s := FRootWebPath + aTopic + '.php'; + s := FRootWebPath + aTopic; end else s := FRootWebPath; diff --git a/windows/src/developer/TIKE/main/UframeOnScreenKeyboardEditor.pas b/windows/src/developer/TIKE/main/UframeOnScreenKeyboardEditor.pas index 81fedb2ae5..935405b7a2 100644 --- a/windows/src/developer/TIKE/main/UframeOnScreenKeyboardEditor.pas +++ b/windows/src/developer/TIKE/main/UframeOnScreenKeyboardEditor.pas @@ -182,6 +182,8 @@ type function DoesKeyboardSupportXMLVisualKeyboard: Boolean; function TransferDesignToSource: Boolean; function TransferSourceToDesign(ASilent: Boolean): Boolean; // I4057 + protected + function GetHelpTopic: string; override; public procedure Load; procedure Save; @@ -202,6 +204,8 @@ implementation uses Xml.Xmldom, + Keyman.Developer.System.HelpTopics, + CharacterInfo, CharMapInsertMode, ExtShiftState, @@ -1240,6 +1244,11 @@ begin end; end; +function TframeOnScreenKeyboardEditor.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_OnScreenKeyboardEditor; +end; + function TframeOnScreenKeyboardEditor.GetHTMLExportParams(FFileName: string; var FFolders, FGraphical: Boolean): Boolean; begin diff --git a/windows/src/developer/TIKE/main/UframeTextEditor.pas b/windows/src/developer/TIKE/main/UframeTextEditor.pas index bf68e2c782..033d4579d8 100644 --- a/windows/src/developer/TIKE/main/UframeTextEditor.pas +++ b/windows/src/developer/TIKE/main/UframeTextEditor.pas @@ -132,10 +132,11 @@ type function GetCharFont: TFont; function GetCodeFont: TFont; procedure SetTextFileFormat(const Value: TTextFileFormat); - function UpdateHelp(token: WideString): Boolean; + function GetSelectedTokens(var token, prevtoken: WideString; var x, tx: Integer): Boolean; + protected + function GetHelpTopic: string; override; public { Public declarations } - procedure GetHelpTopic(var s: string); override; procedure UpdateParColour(par: Integer; LineType: TParColourLineType); procedure SetFocus; override; @@ -143,8 +144,6 @@ type procedure FindErrorByOffset(offset: Integer); // I4083 function OffsetToLine(Offset: Integer): Integer; // I4083 - function GetHelpToken: WideString; - procedure EditFind; procedure EditFindNext; procedure EditReplace; @@ -173,6 +172,9 @@ type implementation uses + Keyman.Developer.System.HelpTopics, + + dmActionsMain, dmActionsTextEditor, CharacterInfo, CharMapDropTool, @@ -385,6 +387,7 @@ begin begin TextFileFormat := tffUTF8; memo.SetTextBuf(''); + UpdateSelectedToken; end; memo.Modified := False; finally @@ -451,6 +454,7 @@ begin TextFileFormat := tffUTF16 else TextFileFormat := tffANSI; + UpdateSelectedToken; memo.Modified := False; finally FLoading := False; @@ -658,6 +662,7 @@ begin memo.SelLine := SelLine; memo.SelCol := SelCol; memo.ScrollInView; + UpdateSelectedToken; finally FLoading := False; end; @@ -843,56 +848,60 @@ begin {$ENDIF} end; -function TframeTextEditor.GetHelpToken: WideString; + +function TframeTextEditor.GetHelpTopic: string; var x, tx: Integer; - prevtoken: WideString; + token, prevtoken: WideString; begin - x := memo.SelCol+1; + if FEditorFormat <> efKMN then + Exit(SHelpTopic_Context_TextEditor); - if EditorFormat = efKMN - then Result := GetTokenAtCursor(memo.LinesArray[memo.SelLine], x, tx, prevtoken) - else Result := ''; + if not GetSelectedTokens(token, prevtoken, x, tx) then + Exit(SHelpTopic_Context_TextEditor); - if not IsValidHelpToken(Result) then - begin - Result := prevtoken; - if not IsValidHelpToken(Result) then Result := ''; - end; + if not IsValidHelpToken(token, False) then + if IsValidHelpToken(prevtoken, False) then + token := prevtoken + else if not IsValidHelpToken(token, True) then + Exit(SHelpTopic_Context_TextEditor); + + Result := token; end; -procedure TframeTextEditor.GetHelpTopic(var s: string); +procedure TframeTextEditor.tmrUpdateSelectedTokenTimer(Sender: TObject); +var + prevtoken, token: WideString; + tx, x: Integer; begin - if FEditorFormat <> efKMN then Exit; + tmrUpdateSelectedToken.Enabled := False; + + if not GetSelectedTokens(token, prevtoken, x, tx) then Exit; + + if (EditorFormat <> efKMN) and (memo.SelText = '') then + token := FormatUnicode(token); + + UpdateCharacterMap(False, token, x, tx, memo.SelText <> ''); // I4807 - s := memo.SelText; - if s = '' then + if EditorFormat = efKMN then begin -{$IFDEF USE_PLUSMEMO} - memo.Delimiters := [#9, ' ', '.', ',', ';', ':', '=', '<', '>', '(', ')']; -{$ENDIF} - s := memo.CurrentWord; - end; + if not IsValidHelpToken(token, False) then + if IsValidHelpToken(prevtoken, False) then + token := prevtoken + else if not IsValidHelpToken(token, True) then + Exit; - s := kwhelp.HelpKeyword(s); -end; + HelpKeyword := token; -function TframeTextEditor.UpdateHelp(token: WideString): Boolean; -begin - Result := False; - if not IsValidHelpToken(token) then Exit; - if Assigned(frmHelp) and frmHelp.Showing then frmHelp.LoadHelp(token, 'KMN'); - Result := True; + if Assigned(frmHelp) and frmHelp.Showing then + frmHelp.QueueRefresh; + end; end; -procedure TframeTextEditor.tmrUpdateSelectedTokenTimer(Sender: TObject); +function TframeTextEditor.GetSelectedTokens(var token, prevtoken: WideString; var x, tx: Integer): Boolean; var - prevtoken, token: WideString; - tx, x: Integer; ch: WideString; begin - tmrUpdateSelectedToken.Enabled := False; - x := memo.SelCol+1; if EditorFormat = efKMN then // I4807 @@ -922,19 +931,17 @@ begin else begin ch := memo.GetTextPart(memo.SelStart-1, memo.SelStart); - if ch = '' then Exit; + if ch = '' then Exit(False); if Uni_IsSurrogate2(ch[1]) then ch := memo.GetTextPart(memo.SelStart-2, memo.SelStart) else if Uni_IsSurrogate1(ch[1]) then ch := memo.GetTextPart(memo.SelStart-1, memo.SelStart+1); - token := FormatUnicode(ch); + token := ch; //FormatUnicode(ch); end; - UpdateCharacterMap(False, token, x, tx, memo.SelText <> ''); // I4807 - if EditorFormat = efKMN then - if not UpdateHelp(token) then UpdateHelp(prevtoken); + Result := True; end; procedure TframeTextEditor.TntFormDestroy(Sender: TObject); diff --git a/windows/src/developer/TIKE/main/UfrmCharacterIdentifier.pas b/windows/src/developer/TIKE/main/UfrmCharacterIdentifier.pas index d96e40b51c..f7d9978aa9 100644 --- a/windows/src/developer/TIKE/main/UfrmCharacterIdentifier.pas +++ b/windows/src/developer/TIKE/main/UfrmCharacterIdentifier.pas @@ -68,6 +68,8 @@ type procedure FontSizeChanged(Sender: TObject); procedure UpdateFont; procedure CancelFocus; + protected + function GetHelpTopic: string; override; public property Chars: string read FChars write SetChars; property OnCancelFocus: TNotifyEvent read FOnCancelFocus write FOnCancelFocus; @@ -79,6 +81,8 @@ var implementation uses + Keyman.Developer.System.HelpTopics, + UfrmCharacterMapNew, Unicode; @@ -291,6 +295,7 @@ end; procedure TfrmCharacterIdentifier.FormActivate(Sender: TObject); begin + inherited; RefreshFonts; end; @@ -302,6 +307,8 @@ end; procedure TfrmCharacterIdentifier.FormCreate(Sender: TObject); begin + inherited; + FDrawChar := TCleartypeDrawCharacter.Create; FFontName := frmCharacterMapNew.CharMapFontName; frmCharacterMapNew.OnFontSizeChanged := FontSizeChanged; @@ -314,6 +321,7 @@ end; procedure TfrmCharacterIdentifier.FormDestroy(Sender: TObject); begin + inherited; if Assigned(frmCharacterMapNew) then frmCharacterMapNew.OnFontSizeChanged := nil; FreeAndNil(FDrawChar); @@ -321,9 +329,15 @@ end; procedure TfrmCharacterIdentifier.FormResize(Sender: TObject); begin + inherited; AdjustPanes; end; +function TfrmCharacterIdentifier.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_CharacterIdentifier; +end; + procedure TfrmCharacterIdentifier.AdjustPanes; var h: Integer; diff --git a/windows/src/developer/TIKE/main/UfrmDownloadProgress.pas b/windows/src/developer/TIKE/main/UfrmDownloadProgress.pas index e5ffffa4e3..a4b9958f84 100644 --- a/windows/src/developer/TIKE/main/UfrmDownloadProgress.pas +++ b/windows/src/developer/TIKE/main/UfrmDownloadProgress.pas @@ -40,6 +40,8 @@ type FCallback: TDownloadProgressCallback; FCancel: Boolean; procedure WMUserFormShown(var Message: TMessage); message WM_USER_FormShown; + protected + function GetHelpTopic: string; override; public procedure HTTPCheckCancel(Sender: THTTPUploader; var Cancel: Boolean); @@ -51,6 +53,9 @@ type implementation +uses + Keyman.Developer.System.HelpTopics; + {$R *.dfm} procedure TfrmDownloadProgress.cmdCancelClick(Sender: TObject); @@ -59,6 +64,11 @@ begin FCancel := True; end; +function TfrmDownloadProgress.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_DownloadProgress; +end; + procedure TfrmDownloadProgress.HTTPCheckCancel(Sender: THTTPUploader; var Cancel: Boolean); begin Cancel := FCancel; diff --git a/windows/src/developer/TIKE/main/UfrmHelp.pas b/windows/src/developer/TIKE/main/UfrmHelp.pas index 5e5d30331b..0320d360f0 100644 --- a/windows/src/developer/TIKE/main/UfrmHelp.pas +++ b/windows/src/developer/TIKE/main/UfrmHelp.pas @@ -64,6 +64,7 @@ type procedure webKeyDown(Sender: TObject; var Key: Word; ScanCode: Word; Shift: TShiftState); private + FRefreshQueued: Boolean; FHelpControl: TWinControl; FStandardTemplatePath: WideString; FDocumentLoaded: Boolean; @@ -74,8 +75,11 @@ type procedure AddUnmatchedContext(FormName, ControlName: string); procedure DeleteMatchedContext(FormName, ControlName: string); procedure TransformXMLToHTML; + protected + function GetHelpTopic: string; override; public procedure LoadHelp(ControlName, FormName: string); + procedure QueueRefresh; end; var @@ -86,6 +90,8 @@ implementation {$R *.dfm} uses + Keyman.Developer.System.HelpTopics, + MSHTML_TLB, RedistFiles, RegistryKeys, @@ -133,33 +139,48 @@ end; procedure TfrmHelp.actHelpContextRefreshUpdate(Sender: TObject); var FormName, ControlName: string; + o: TComponent; begin if not FDocumentLoaded then Exit; - FormName := ''; - ControlName := ''; - if Screen.ActiveControl <> FHelpControl then - begin - if Screen.ActiveControl = nil then - else + if (Screen.ActiveControl <> FHelpControl) or FRefreshQueued then + try + FormName := ''; + ControlName := ''; + + if Screen.ActiveControl <> nil then begin - FHelpControl := Screen.ActiveControl; - if FHelpControl is TCustomForm then FormName := (FHelpControl as TCustomForm).ClassName + // Don't get help document focus + if (Screen.ActiveControl = Self) or (Screen.ActiveControl.Owner = Self) then + begin + if not FRefreshQueued then + Exit; + end + else + FHelpControl := Screen.ActiveControl; + + if FHelpControl is TTIKEForm then + FormName := (FHelpControl as TTIKEForm).HelpTopic + else if FHelpControl is TCustomForm then + FormName := FHelpControl.ClassName else begin - if FHelpControl.Owner <> nil then + o := FHelpControl.Owner; + while not (o is TTIKEForm) and (o <> nil) do + o := o.Owner; + + if o is TTIKEForm then + FormName := (o as TTIKEForm).HelpTopic + else if FHelpControl.Owner <> nil then FormName := FHelpControl.Owner.ClassName; - ControlName := FHelpControl.Name; - end; - if (ControlName = 'memo') and (FormName = 'TframeTextEditor') then - begin - ControlName := (FHelpControl.Owner as TframeTextEditor).GetHelpToken; - FormName := 'KMN'; + ControlName := FHelpControl.Name; end; end; LoadHelp(ControlName, FormName); + finally + FRefreshQueued := False; end; end; @@ -200,6 +221,11 @@ begin end; end; +procedure TfrmHelp.QueueRefresh; +begin + FRefreshQueued := True; +end; + procedure TfrmHelp.FormCreate(Sender: TObject); begin inherited; @@ -276,21 +302,28 @@ begin web.Navigate(FTempFile.Name); // + 'contexthelp.xml'); end; +function TfrmHelp.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_Help; +end; + procedure TfrmHelp.webBeforeNavigate2(ASender: TObject; const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData, Headers: OleVariant; var Cancel: WordBool); var - FormName: string; + frm: TTIKEForm; begin if Copy(URL, 1, 5) = 'help:' then begin Cancel := True; - if FHelpControl is TCustomForm then FormName := (FHelpControl as TCustomForm).ClassName - else if FHelpControl.Owner <> nil then FormName := FHelpControl.Owner.ClassName - else FormName := ''; - if FormName = '' - then frmKeymanDeveloper.HelpTopic('index') - else frmKeymanDeveloper.HelpTopic('context_'+Copy(FormName,2,MAXINT)); + + if FHelpControl is TTikeForm then frm := FHelpControl as TTikeForm + else if FHelpControl.Owner is TTikeForm then frm := FHelpControl.Owner as TTikeForm + else frm := nil; + + if frm <> nil + then frmKeymanDeveloper.HelpTopic(frm.HelpTopic) + else frmKeymanDeveloper.HelpTopic('index') end; end; @@ -298,6 +331,7 @@ procedure TfrmHelp.webDocumentComplete(ASender: TObject; const pDisp: IDispatch; var URL: OleVariant); begin FDocumentLoaded := True; + QueueRefresh; end; procedure TfrmHelp.webGetDropTarget2(Sender: TCustomEmbeddedWB; diff --git a/windows/src/developer/TIKE/main/UfrmMain.pas b/windows/src/developer/TIKE/main/UfrmMain.pas index 9ddd603100..b8693479fc 100644 --- a/windows/src/developer/TIKE/main/UfrmMain.pas +++ b/windows/src/developer/TIKE/main/UfrmMain.pas @@ -377,7 +377,8 @@ type function OpenTestWindow(FFileName: string): TfrmTikeChild; function OpenFile(FFileName: string; FCloseNewFile: Boolean): TfrmTikeChild; - procedure HelpTopic(s: string); + procedure HelpTopic(s: string); overload; + procedure HelpTopic(Sender: TTIKEForm); overload; property ChildWindows: TChildWindowList read FChildWindows; property CharMapSettings: TCharMapSettings read FCharMapSettings; @@ -760,9 +761,12 @@ begin FInOnHelp := True; try s := PChar(Data); - frm := GetParentForm(Screen.ActiveControl, False); - if frm is TTikeForm then - (frm as TTikeForm).GetHelpTopic(s); + if s = '' then + begin + frm := GetParentForm(Screen.ActiveControl, False); + if frm is TTikeForm then + s := (frm as TTikeForm).HelpTopic; + end; if s <> '' then mHHelp.HelpTopic(s); finally @@ -1032,6 +1036,11 @@ begin DoForm(frmCharacterIdentifier); // I4807 end; +procedure TfrmKeymanDeveloper.HelpTopic(Sender: TTIKEForm); +begin + HelpTopic(Sender.HelpTopic); +end; + function TfrmKeymanDeveloper.OpenTestWindow(FFileName: string): TfrmTikeChild; var i: Integer; diff --git a/windows/src/developer/TIKE/main/UfrmMessages.pas b/windows/src/developer/TIKE/main/UfrmMessages.pas index 6eb4deb76d..e8bcc0124c 100644 --- a/windows/src/developer/TIKE/main/UfrmMessages.pas +++ b/windows/src/developer/TIKE/main/UfrmMessages.pas @@ -33,7 +33,8 @@ interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, - StdCtrls, ExtCtrls, CaptionPanel, Menus, Contnrs, UfrmTikeDock, UfrmTike; + StdCtrls, ExtCtrls, CaptionPanel, Menus, Contnrs, UfrmTikeDock, UfrmTike, + JvComponentBase, JvDockControlForm; type TMessageItem = class @@ -69,6 +70,7 @@ type function GetSelLine: Integer; procedure SetSelLine(Value: Integer); protected + function GetHelpTopic: string; override; property SelLine: Integer read GetSelLine write SetSelLine; public procedure RefreshOptions; @@ -91,6 +93,8 @@ function CompilerMessage(line: Integer; msgcode: LongWord; text: PAnsiChar): Int implementation uses + Keyman.Developer.System.HelpTopics, + UfrmMain, UfrmMDIEditor, dmActionsMain, @@ -254,6 +258,11 @@ begin end; +function TfrmMessages.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_Messages; +end; + function TfrmMessages.GetSelLine: Integer; var i, x, n: Integer; diff --git a/windows/src/developer/TIKE/main/UfrmStartup.pas b/windows/src/developer/TIKE/main/UfrmStartup.pas index b401b750fc..87608fd9de 100644 --- a/windows/src/developer/TIKE/main/UfrmStartup.pas +++ b/windows/src/developer/TIKE/main/UfrmStartup.pas @@ -65,6 +65,7 @@ type procedure WMUserFormShown(var Message: TMessage); message WM_USER_FORMSHOWN; procedure AppMinimize(Sender: TObject); protected + function GetHelpTopic: string; override; procedure WndProc(var Message: TMessage); override; end; @@ -80,6 +81,9 @@ implementation uses Dialogs, + + Keyman.Developer.System.HelpTopics, + OnlineConstants, UfrmMain, utilexecute, @@ -190,6 +194,11 @@ begin PostMessage(Handle, WM_USER_FormShown, 0, 0); end; +function TfrmStartup.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_Startup; +end; + procedure ForceShowStartup(Parent: TForm); begin // Show the startup dialog in a subsequent display (used from About dialog) diff --git a/windows/src/developer/TIKE/main/UfrmTike.pas b/windows/src/developer/TIKE/main/UfrmTike.pas index 0125a14390..5168d70e1b 100644 --- a/windows/src/developer/TIKE/main/UfrmTike.pas +++ b/windows/src/developer/TIKE/main/UfrmTike.pas @@ -39,27 +39,21 @@ type procedure WMUserFormShown(var Message: TMessage); message WM_USER_FormShown; // I4873 protected procedure FormShown; virtual; // I4873 + function GetHelpTopic: string; virtual; public { Public declarations } - procedure GetHelpTopic(var s: string); virtual; + property HelpTopic: string read GetHelpTopic; end; implementation {$R *.dfm} -type - TFormHelper = class helper for Forms.TCustomForm // I4822 - private - procedure RestoreDesignClientSize; - end; - procedure TTikeForm.FormCreate(Sender: TObject); begin - RestoreDesignClientSize; // I4822 inherited; HelpContext := 0; - HelpKeyword := 'context_'+Copy(ClassName, 2, MAXINT); // I4677 // I4841 + HelpKeyword := HelpTopic; // 'context/'+Copy(ClassName, 2, MAXINT); // I4677 // I4841 end; procedure TTikeForm.FormShow(Sender: TObject); // I4873 @@ -71,8 +65,9 @@ procedure TTikeForm.FormShown; // I4873 begin end; -procedure TTikeForm.GetHelpTopic(var s: string); +function TTikeForm.GetHelpTopic: string; begin + Result := ''; end; procedure TTikeForm.WMUserFormShown(var Message: TMessage); // I4873 @@ -80,17 +75,4 @@ begin FormShown; end; - - -{ TFormHelper } - -procedure TFormHelper.RestoreDesignClientSize; // I4822 -begin -(* if BorderStyle in [bsSingle, bsDialog] then - begin - if Self.FClientWidth > 0 then ClientWidth := Self.FClientWidth; - if Self.FClientHeight > 0 then ClientHeight := Self.FClientHeight; - end; *) -end; - end. diff --git a/windows/src/developer/TIKE/oskbuilder/UframeTouchLayoutBuilder.pas b/windows/src/developer/TIKE/oskbuilder/UframeTouchLayoutBuilder.pas index ccc007c941..41ad431a64 100644 --- a/windows/src/developer/TIKE/oskbuilder/UframeTouchLayoutBuilder.pas +++ b/windows/src/developer/TIKE/oskbuilder/UframeTouchLayoutBuilder.pas @@ -84,6 +84,7 @@ type procedure SetupModifierKeysForImportedLayout; { Private declarations } protected + function GetHelpTopic: string; override; procedure CopyToClipboard; procedure CutToClipboard; @@ -126,6 +127,8 @@ uses xmlintf, xmldoc, + Keyman.Developer.System.HelpTopics, + KeymanDeveloperOptions, VKeys, OnScreenKeyboardData, @@ -679,6 +682,11 @@ begin end; end; +function TframeTouchLayoutBuilder.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_TouchLayoutBuilder; +end; + function TframeTouchLayoutBuilder.GetLayoutJS: string; var doc: IHTMLDocument2; diff --git a/windows/src/developer/TIKE/project/UfrmProject.pas b/windows/src/developer/TIKE/project/UfrmProject.pas index 9f0f2a160a..96927dc6a9 100644 --- a/windows/src/developer/TIKE/project/UfrmProject.pas +++ b/windows/src/developer/TIKE/project/UfrmProject.pas @@ -113,6 +113,8 @@ type procedure EditFileExternal(FileName: WideString); function DoNavigate(URL: WideString): Boolean; procedure ClearMessages; + protected + function GetHelpTopic: string; override; public procedure SetFocus; override; procedure SetGlobalProject; @@ -123,6 +125,9 @@ implementation uses Winapi.ShellApi, ComObj, + + Keyman.Developer.System.HelpTopics, + dmActionsMain, KeymanDeveloperOptions, kmnProjectFile, @@ -627,6 +632,11 @@ begin web.Go(bstrUrl); end; +function TfrmProject.GetHelpTopic: string; +begin + Result := SHelpTopic_Context_Project; +end; + function TfrmProject.GetIEVersionString: WideString; begin with TRegistryErrorControlled.Create do // I2890 @@ -683,7 +693,7 @@ function TfrmProject.webShowHelpRequest(Sender: TObject; HWND: NativeUInt; pszHelpFile: PWideChar; uCommand, dwData: Integer; ptMouse: TPoint; var pDispatchObjectHit: IDispatch): HRESULT; begin - frmKeymanDeveloper.HelpTopic('context_frmProject'); + frmKeymanDeveloper.HelpTopic(Self); Result := S_OK; end; diff --git a/windows/src/developer/TIKE/xml/help/contexthelp.xml b/windows/src/developer/TIKE/xml/help/contexthelp.xml index d3c872eddd..319829ab77 100644 --- a/windows/src/developer/TIKE/xml/help/contexthelp.xml +++ b/windows/src/developer/TIKE/xml/help/contexthelp.xml @@ -1,7 +1,7 @@  -
+

The Change option allows the editing of the icon filename.

@@ -15,7 +15,8 @@

The toolbox allows for the changing of the colours, addition of text and shapes. It also allows for the moving of the icon around the button and also a preview of the button is displayed.

-
+ +

If selected, then the visual keyboard will only be used if the current underlying layout is active.

@@ -42,274 +43,72 @@

Allows the user to enter text to be displayed on the selected key.

-
- + + +

The Filter allows a user to reduce the number of characters displayed in the character map. The standard filter options used are by font name or block name.

- +

The Character Map Grid displays each character in a square, with a visual representation of the character and the Unicode value displayed at the bottom of the square. Each font group is divided into a block headed by the font name.

-
- - - - -

To create a folder on the Start menu when the keyboard package is installed.

-
- -

The uninstall shortcut will be added automatically to the shortcut menu list when the package is installed.

-
- -

Addins can be added to be distributed with the install process by checking the required options.

-
- -

To add additional files to the keyboard package to be distributed. If you need to include fonts or documentation, put them into a package and include the package in this list. Do not include fonts or documentation directly.

-
- - -

Compiling the product takes all the files you have selected and compresses them into a single Windows Installer .msi file.

-

This option will check for errors an missing files. The success of the compiling will be displayed at the bottom of the screen.

-
- -

To delete the selected shortcut menu item.

-
- - -

Allows for the insertion of the copyright symbol.

-
- -

This option allows for the installation of the package on to the computer when compiling has been completed.

-
- -

To add a new menu item to the list of shortcuts in the folder on the Start menu created during installation.

-
- -

This option opens the source folder of the selected file.

-
- -

To open an editor to make changes to the selected file.

-
- -

This option allows the user to remove a selected file from the distribution list.

-
- -

To select an existing branding file.

-
- -

This option allows for the uploading of the keyboard package onto the Tavultesoft website.

-
- -

The destination path will always be created under Program Files. The actual name of the Program Files folder may vary from computer to computer and language to language, but the installer will manage that automatically.

-
- -

The location of the selected file.

-
- -

Read Only. Shows information about the type of file selected.

-
- -

The name of the developer of the keyboard to displayed as part of the keyboard package details when installed.

-
- -

Copyright details for the keyboard are displayed when the keyboard is installed. They can also be viewed in Keyman Configuration.

-
- -

The email address of the developer to allow the user to contact them if required.

-
- -

The name of the keyboard package to be displayed in many locations after installation and on the Tavultesoft website for downloading.

-
- -

The version number allows for users to see if they have the latest version of the keyboard. Version numbers should be in major.minor.patch format, where major,minor and patch are all numbers. Other formats are not valid. Also important information when upgrading a keyboard package.

-
- -

Displays a website address for the users to visit to view more information on the keyboard package.

-
- -

You can choose to run a program after installation. This can be a program in the package or another program such as WordPad to display a Readme file. Enclose the program name in quotation marks and use $INSTALLDIR\ as a prefix to reference the installed file location.

-
- -

Output Path and File name

-

Displays the output path and filename of the file when the package is compiled.

-
- -

The text to be displayed for the selected file as a menu item in the Start up folder that is created when the package is installed.

-
- - -

Start Menu Path

-

Enter the path for the start menu folder to be created on installation.

-
- -

If you need to include fonts or documentation, put them into a package and include the package in this list. Do not include fonts or documentation directly. If you are not using the Keyman Desktop user interface, then include all the files for your application here as well.

-

The distribution editor does not allow you to create multiple folders for your application. You can export the distribution source file created in this editor to a WiX source file (.wxs) and extend it there.

-
- -

Read Only. Shows further information about the selected file, for example what the file is used for in the keyboard package.

-
- - -
- -

The Toolbox allows for the editing of an existing icon or the creation of a new icon. The user cane change colours, add shapes and text. Use the move buttons to move the image on the icon and also displays a preview of the icon.

-
-
-
- -

This option selects the action that will occur when a user selects an item from one of the menus or toolbars.

-
- - -

The drop down list allows the user to select the type of menu item to be added.

-

The options available in the list are dependent on the location of the menu item:

-

Text

-

Graphics

-

Separator

-

Keyboards List

-
- -

This option allows for the addition of a new menu item to one of the menu locations.

-
- -

This option allows for the deletion of an existing menu item.

-
- -

This option allows for the selection of font attributes for the caption text to be displayed in the menu.

-
- -

This option allows for the importing of a graphic file to be used as an icon in the list to the left of the menu item.

-
- -

This option allows for the moving of menu items down a list or move buttons across to the right on a toolbar.

-
- -

This option allows the user to move an existing menu item to another location. It gives the user the a drop down list to choose the new location.

-
- -

This option allows for the moving of menu items up a list or move buttons across to the left on a toolbar.

-
- -

The text to be displayed in the menu. A hotkey can also be assigned by placing an ampersand & symbol before the letter to be used in the caption

-
- -

This option allows for the assigning of a hotkey for the menu item. A hotkey can also be assigned by placing an ampersand & symbol before the letter to be used in the caption, but a different hotkey can be assigned by using this option.

-
- -

The location of the menu item gives the user the choice of placing the item in one of four locations

-

Tool Tray Left Button Menu

-

Tool Tray Right Button Menu

-

On Screen Keyboard Toolbar

-

On Screen Keyboard Context Menu

-
- -
- - -

Reset the selected string back to its original value.

-
- -

To set all strings back to original values.

-
- - - - -

A description of the string.

-
- -
- -

This option allows the use of the default keyman template, an existing template or Blank Customisation.

-
-
-
- - -

Use the value $INSTALLDIR to refer to the install path of your application. Don't forget to surround the program path in double quotes.

-
- -

Use the value $INSTALLDIR to refer to the install path of your application. Don't forget to surround the program path in double quotes.

-
- -

The standard controller file name is keyman.exe. Use another executable name here if you wish to write your own controller application for your product. Please review the Keyman COM API documentation for details. Use the values $INSTALLDIR and $ENGINEDIR to reference the installation folder and Keyman Engine folders respectively. Read the Keyman COM API documentation for more information.

-
- -

Use the value $INSTALLDIR to refer to the install path of your application. Don't forget to surround the program path in double quotes.

-
- -

The name of the keyboard package is displayed on the website or when installed. It should be a descriptive name, in any language, but remember that some applications may use a font that does not include the language you are writing the keyboard name in. Don't include a version number, help information or hotkey in the name.

-
- -

The number of days a user can use the product on trial before buying the software.

-
- -

Use the value $INSTALLDIR to refer to the install path of your application. Don't forget to surround the program path in double quotes.

-
- -

You can make changes to the Keyman Desktop user interface on the User Interface tab. The image and XML files will automatically be included in the installer when you select this branding file as the product licence option in the Distribution Editor, and kmshell.exe and related files will be included when the product is compiled.

-
- -

You can create your own application, displaying your own splash screen, configuration, help and about dialogs, as well as any additional functionality that you want. You will need to include the appropriate files in the Distribution Editor when you select this branding file as the product licence option.

-
- -
- -

This option allows for the displaying of a welcome screen when the keyboard is opened. It can be used to inform the user of the features and uses of the keyboard.

-
- -

The Splash screen can be turned on or off. If the option is unchecked a warning message will be displayed to warn that the image will be deleted and to have a copy of the file. The Splash screen can be turned off using Keyman Configuration.

-
- -

This option allows for the importing of a file to be used for the Splash screen.

-
- -

Splash Screen file name

-

Displays the filename of the file selected as the Splash screen image.

-
- -

This option allows for the adjustment of the height of the welcome screen.

-
- -

This option allows for the adjustment of the width of the welcome screen.

-
-
-
- -

The Delete option allows for the removing of a file from the user interface.

-
- -

This option allows for the user interface element for example a graphic to be opened in the default external editor for the file type to make editing changes.

-
- -

The Export option allows for the exporting of a file from the user interface for example a graphic, this will allow it to be used for another keyboard package.

-
- -

The Import option allows for the importing of a file for the user interface for example a graphic, this will allow it to be used for more than one keyboard package.

-
- -

This option will display a list of recommended and optional programs to allow the selection of the required editor for the selected file to be edited.

-
- -

This option will allow for the previewing of the customisation made to the user interface.

-
-
- -
- -

The name of the keyboard is displayed in Keyman Configuration, in the tray menu and in many other places. It should be a descriptive name, in any language, but remember that some applications may use a font that does not include the language you are writing the keyboard name in. Don't include a version number, help information or hotkey in the name.

-
-
-
+ + +

The name of the keyboard is displayed in Keyman Configuration, in the tray menu and in many other places. It should be a descriptive + name, in any language, but remember that some applications may use a font that does not include the language you are writing the + keyboard name in. Don't include a version number, help information or hotkey in the name.

+ +

This corresponds to the following source line:

+
store(&name) 'My Keyboard'
+
+ +

Your keyboard should be either Unicode or Codepage based. Most keyboards today will be Unicode. If you are designing in the source editor, + you can create a keyboard that is includes both Unicode and Codepage (or "ANSI") rules.

+ +

This corresponds to either of the following source lines:

+
+ begin ANSI > use(main)
+ begin Unicode > use(main) +
+
+ +

Copyright details for the keyboard are displayed when the keyboard is installed. They can also be viewed in Keyman Configuration.

+ +

This corresponds to the following source line:

+
store(&copyright) '© 2006 My Company'
+
+ +

The message provides some additional information to a user of your keyboard, when they install the keyboard.

+ +

This corresponds to the following source line:

+
store(&message) 'Here is a message about a keyboard'
+
+ +

In this field, enter information about the keyboard for your own reference. These comments will only be visible in the + source file, and not to users of your keyboard.

+ +

The comments are placed at the top of the source file, e.g.:

+
+ c Version 1.2 - fixed a bug with the 'k' key
+ c Version 1.1 - improved matching on vowels
+ c Version 1.0 - initial version +
+
+ +

To select another key in the keyboard, either:

+
    +
  • Click on the key with the mouse, or
  • +
  • Press and release the Ctrl key to choose with the keyboard
  • +
+
+ @@ -427,20 +226,21 @@
-
- + +

TIKE Debugger

Debug information must be included in the compile keyboard before the debugger process can be started. From the Keyboard menu select Include Debug Information. The debug information will display the error sources when compiling.

The debugger can be used without the debug information by clicking on Test without debugger.

-
- + + +

Enter the name for your new keyboard. Click on the Browse button to change the location of the new keyboard.

-
+

You can include an image file that will be displayed to the left of the install details when the package is installed. This image should be 140 pixels wide and 250 pixels high.

@@ -464,6 +264,19 @@

This allows for the insertion of a copyright symbol if needed.

+ +

A readme file can be a text file (ANSI, UTF-8, or UTF-16), or an HTML file (recommended). Other file types are also acceptable, + but the package installer will load the file in a separate program.

+
+ +

You can include an image file that will be displayed to the left of the install details when the package is + installed. This image should be 140 pixels wide and 250 pixels high.

+
+ +

You should try installing your package on your system before distributing it, to ensure that all files are + installed correctly. If you can, try installing your package on several different machines.

+
+ @@ -555,143 +368,10 @@

This option allows the user to enter details and other additional information about the selected file.

-
- - -
- -

The name of the keyboard is displayed in Keyman Configuration, in the tray menu and in many other places. It should be a descriptive - name, in any language, but remember that some applications may use a font that does not include the language you are writing the - keyboard name in. Don't include a version number, help information or hotkey in the name.

- -

This corresponds to the following source line:

-
store(&name) 'My Keyboard'
-
- -

Your keyboard should be either Unicode or Codepage based. Most keyboards today will be Unicode. If you are designing in the source editor, - you can create a keyboard that is includes both Unicode and Codepage (or "ANSI") rules.

- -

This corresponds to either of the following source lines:

-
- begin ANSI > use(main)
- begin Unicode > use(main) -
-
- -

Copyright details for the keyboard are displayed when the keyboard is installed. They can also be viewed in Keyman Configuration.

- -

This corresponds to the following source line:

-
store(&copyright) '© 2006 My Company'
-
- -

The message provides some additional information to a user of your keyboard, when they install the keyboard.

- -

This corresponds to the following source line:

-
store(&message) 'Here is a message about a keyboard'
-
- -

In this field, enter information about the keyboard for your own reference. These comments will only be visible in the - source file, and not to users of your keyboard.

- -

The comments are placed at the top of the source file, e.g.:

-
- c Version 1.2 - fixed a bug with the 'k' key
- c Version 1.1 - improved matching on vowels
- c Version 1.0 - initial version -
-
- -

To select another key in the keyboard, either:

-
    -
  • Click on the key with the mouse, or
  • -
  • Press and release the Ctrl key to choose with the keyboard
  • -
-
-
- - -
- -

A readme file can be a text file (ANSI, UTF-8, or UTF-16), or an HTML file (recommended). Other file types are also acceptable, - but the package installer will load the file in a separate program.

-
- -

You can include an image file that will be displayed to the left of the install details when the package is - installed. This image should be 140 pixels wide and 250 pixels high.

-
- -

You should try installing your package on your system before distributing it, to ensure that all files are - installed correctly. If you can, try installing your package on several different machines.

-
-
- - -
- -

You can make changes to the Keyman Desktop user interface on the User Interface tab. The image and XML files will - automatically be included in the installer when you select this branding file as the product licence option in the - Distribution Editor, and kmshell.exe and related files will be included when the product is compiled. -

-
- -

You can create your own application, displaying your own splash screen, configuration, help and about dialogs, as well - as any additional functionality that you want. You will need to include the appropriate files in the Distribution Editor - when you select this branding file as the product licence option. -

-
- -

- The standard controller file name is keyman.exe. Use another executable name here if you wish to write your own - controller application for your product. Please review the Keyman COM API documentation for details. Use the values - $INSTALLDIR and $ENGINEDIR to reference the installation folder and Keyman Engine folders respectively. Read the - Keyman COM API documentation for more information. -

-
- -

Use the value $INSTALLDIR to refer to the install path of your application. Don't forget to surround the program - path in double quotes.

-
- -

Use the value $INSTALLDIR to refer to the install path of your application. Don't forget to surround the program - path in double quotes.

-
- -

Use the value $INSTALLDIR to refer to the install path of your application. Don't forget to surround the program - path in double quotes.

-
-
- -
- -

- If you need to include fonts or documentation, put them into a package and include the package in - this list. Do not include fonts or documentation directly. If you are not using the Keyman Desktop user interface, - then include all the files for your application here as well. -

-

- The distribution editor does not allow you to create multiple folders for your application. You can export the distribution - source file created in this editor to a WiX source file (.wxs) and extend it there. -

-
- -

The destination path will always be created under Program Files. The actual name of the Program Files folder may vary from - computer to computer and language to language, but the installer will manage that automatically.

-
- -

You can choose to run a program after installation. This can be - a program in the package or another program such as WordPad to display a Readme file. Enclose the program name in quotation marks - and use $INSTALLDIR\ as a prefix to reference the installed file location.

-
- -

Building the product takes all the files you have selected and compiles them into a single product file.

-
- -

You should try installing your product on your system before distributing it, to ensure that all - files are installed correctly. If you can, try installing your product on several different machines.

-

If you are a registered user of Keyman Developer Professional, then you have access to a free product - validation service from Tavultesoft. Tavultesoft will review your product's installer, user interface, and - integration and provide feedback on issues and resolution of these issues. Simply upload your product to the - Tavultesoft website and click the Request Validation link on the site.

+ + + +

The Project Manager allows you to manage all the files related to a keyboard layout in a single location.

\ No newline at end of file diff --git a/windows/src/developer/TIKE/xml/help/help.xsl b/windows/src/developer/TIKE/xml/help/help.xsl index 482f69ae57..aa58b648bc 100644 --- a/windows/src/developer/TIKE/xml/help/help.xsl +++ b/windows/src/developer/TIKE/xml/help/help.xsl @@ -4,6 +4,8 @@ + + Help diff --git a/android/history.md b/android/history.md index f3f593365c..4963e65d47 100644 --- a/android/history.md +++ b/android/history.md @@ -1,5 +1,8 @@ # Keyman for Android +## 2018-04-26 10.0.379 beta +* Fix OSK missing some keys on older Android configurations (#304) + ## 2018-04-24 10.0.376 beta * Hide system OSK when resuming Keyman app. Disable text suggestions (#711) -- GitLab From d1dadcc38139dafca141fe9dd444671295a6da44 Mon Sep 17 00:00:00 2001 From: darcywong00 Date: Thu, 26 Apr 2018 14:38:20 +0700 Subject: [PATCH 012/356] Revert to original background-color styling --- android/KMEA/app/src/main/assets/keyboard.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/KMEA/app/src/main/assets/keyboard.html b/android/KMEA/app/src/main/assets/keyboard.html index 6cc577670e..c8a6471726 100644 --- a/android/KMEA/app/src/main/assets/keyboard.html +++ b/android/KMEA/app/src/main/assets/keyboard.html @@ -241,7 +241,7 @@ -- GitLab From 827d532265a43429e9609c5cd70622948a92c047 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Thu, 26 Apr 2018 15:28:51 -0400 Subject: [PATCH 013/356] [Mac] Issue 175: Solved compatibility problem with Open Office --- .../Keyman4MacIM/KMInputMethodAppDelegate.m | 6 +- .../KMInputMethodBrowserClientEventHandler.m | 2 +- .../Keyman4MacIM/KMInputMethodEventHandler.m | 93 +++++++++++-------- .../KMInputMethodEventHandlerProtected.h | 9 +- 4 files changed, 69 insertions(+), 41 deletions(-) diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m index 70c1a10ad4..e8c064f4af 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m @@ -161,8 +161,10 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef KMInputMethodAppDelegate *appDelegate = [KMInputMethodAppDelegate AppDelegate]; if (appDelegate != nil) { 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 aound to be + // un-commented when needed. + //if (appDelegate.debugMode) + // NSLog(@"System Event: %@", sysEvent); switch (type) { case kCGEventFlagsChanged: diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodBrowserClientEventHandler.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodBrowserClientEventHandler.m index b23cd117e5..fb29380d2e 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 e69821305c..baf49a1213 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m @@ -28,7 +28,7 @@ NSRange _previousSelRange; if (self) { _previousSelRange = NSMakeRange(NSNotFound, NSNotFound); _clientSelectionCanChangeUnexpectedly = flagClientSelectionCanChangeUnexpectedly; - _cannnotTrustSelectionLength = NO; + _clientCanProvideSelectionInfo = Unknown; _legacyMode = NO; _contextOutOfDate = YES; if (legacy) { @@ -46,7 +46,8 @@ NSRange _previousSelRange; [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: @"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 @@ -155,33 +156,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 @@ -296,8 +318,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); @@ -438,7 +459,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]; @@ -524,25 +546,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]; @@ -644,7 +663,7 @@ NSRange _previousSelRange; // 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) + if (_clientCanProvideSelectionInfo == No || _clientCanProvideSelectionInfo == Unreliable) NSLog(@"Cannot trust client to report accurate selection length - assuming no selection."); } @@ -658,7 +677,7 @@ 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]; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandlerProtected.h b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandlerProtected.h index 9cd4c6affc..5ce208947e 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; -- GitLab From aec583ad16a0312e8a010d49eef054c45242b6da Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 27 Apr 2018 08:41:59 +0700 Subject: [PATCH 014/356] Fixes sillsdev/keyman-issues#5609, fixes #631 - use-after-free arising from RSP-20457 (workaround) --- .../developer/TIKE/project/kmnProjectFile.pas | 9 +- .../member_mutation.dpr | 10 + .../member_mutation.dproj | 583 ++++++++++++++++++ .../member_mutation.res | Bin 0 -> 96 bytes .../mutation_test.pas | 116 ++++ 5 files changed, 717 insertions(+), 1 deletion(-) create mode 100644 windows/src/test/manual-tests/rsp-20547 string-use-after-free-in-param/member_mutation.dpr create mode 100644 windows/src/test/manual-tests/rsp-20547 string-use-after-free-in-param/member_mutation.dproj create mode 100644 windows/src/test/manual-tests/rsp-20547 string-use-after-free-in-param/member_mutation.res create mode 100644 windows/src/test/manual-tests/rsp-20547 string-use-after-free-in-param/mutation_test.pas diff --git a/windows/src/developer/TIKE/project/kmnProjectFile.pas b/windows/src/developer/TIKE/project/kmnProjectFile.pas index e2f7149788..4831969ff5 100644 --- a/windows/src/developer/TIKE/project/kmnProjectFile.pas +++ b/windows/src/developer/TIKE/project/kmnProjectFile.pas @@ -304,8 +304,15 @@ begin end; function TkmnProjectFile.GetTargetFilename: string; +var + FTempFileVersion: string; begin - Result := OwnerProject.GetTargetFilename(OutputFileName, FileName, FileVersion); + // https://github.com/keymanapp/keyman/issues/631 + // This appears to be a Delphi compiler bug (RSP-20457) + // Workaround is to make a copy of the parameter locally + // which fixes the reference counting. + FTempFileVersion := FileVersion; + Result := OwnerProject.GetTargetFilename(OutputFileName, FileName, FTempFileVersion); end; procedure TkmnProjectFile.GetFileParameters; diff --git a/windows/src/test/manual-tests/rsp-20547 string-use-after-free-in-param/member_mutation.dpr b/windows/src/test/manual-tests/rsp-20547 string-use-after-free-in-param/member_mutation.dpr new file mode 100644 index 0000000000..de58a3fec1 --- /dev/null +++ b/windows/src/test/manual-tests/rsp-20547 string-use-after-free-in-param/member_mutation.dpr @@ -0,0 +1,10 @@ +program member_mutation; + +{$APPTYPE CONSOLE} + +uses + mutation_test in 'mutation_test.pas'; + +begin + Run; +end. diff --git a/windows/src/test/manual-tests/rsp-20547 string-use-after-free-in-param/member_mutation.dproj b/windows/src/test/manual-tests/rsp-20547 string-use-after-free-in-param/member_mutation.dproj new file mode 100644 index 0000000000..5a5f4c24a0 --- /dev/null +++ b/windows/src/test/manual-tests/rsp-20547 string-use-after-free-in-param/member_mutation.dproj @@ -0,0 +1,583 @@ + + + {EFBB98A8-665E-4009-A781-953F9780E9DF} + 18.4 + None + member_mutation.dpr + True + Debug + Win32 + 1 + Console + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + RESTComponents;FireDAC;FireDACSqliteDriver;soaprtl;FireDACIBDriver;soapmidas;FireDACCommon;RESTBackendComponents;soapserver;CloudService;FireDACCommonDriver;inet;$(DCC_UsePackage) + System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) + member_mutation + + + DBXSqliteDriver;bindcompdbx;IndyIPCommon;DBXInterBaseDriver;IndyIPServer;IndySystem;tethering;fmxFireDAC;bindcompfmx;FireDACPgDriver;inetdb;DbxCommonDriver;fmx;fmxdae;xmlrtl;fmxobj;rtl;DbxClientDriver;CustomIPTransport;dbexpress;IndyCore;bindcomp;dsnap;IndyIPClient;dbxcds;bindengine;DBXMySQLDriver;dsnapxml;FireDACMySQLDriver;dbrtl;inetdbxpress;IndyProtocols;FireDACCommonODBC;fmxase;$(DCC_UsePackage) + true + + + DBXSqliteDriver;bindcompdbx;IndyIPCommon;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;vclFireDAC;IndySystem;tethering;svnui;mbColorLibD10;dsnapcon;FireDACADSDriver;scFontCombo;DCPdelphi2009;FireDACMSAccDriver;fmxFireDAC;vclimg;Jcl;vcltouch;JvCore;vcldb;bindcompfmx;svn;FireDACPgDriver;inetdb;DbxCommonDriver;fmx;fmxdae;xmlrtl;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;IndyIPClient;bindcompvcl;EmbeddedWebBrowser_XE;VCLRESTComponents;dbxcds;VclSmp;JvDocking;adortl;JclVcl;vclie;bindengine;DBXMySQLDriver;dsnapxml;FireDACMySQLDriver;dbrtl;inetdbxpress;IndyProtocols;keyman_components;FireDACCommonODBC;fmxase;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + Debug + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + true + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + + + DBXSqliteDriver;bindcompdbx;IndyIPCommon;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;vclFireDAC;IndySystem;tethering;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;vclimg;Jcl;vcltouch;vcldb;bindcompfmx;FireDACPgDriver;inetdb;DbxCommonDriver;fmx;fmxdae;xmlrtl;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;IndyIPClient;bindcompvcl;VCLRESTComponents;dbxcds;VclSmp;adortl;JclVcl;vclie;bindengine;DBXMySQLDriver;dsnapxml;FireDACMySQLDriver;dbrtl;inetdbxpress;IndyProtocols;FireDACCommonODBC;fmxase;$(DCC_UsePackage) + true + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + false + c:\projects\fastmm4;$(DCC_UnitSearchPath) + 1033 + (None) + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + + MainSource + + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + + + + Delphi.Personality.12 + Application + + + + member_mutation.dpr + + + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + + + member_mutation.exe + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + 1 + + + Contents\MacOS + 1 + + + Contents\MacOS + 0 + + + + + classes + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\armeabi + 1 + + + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + + + res\values + 1 + + + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + Contents\MacOS + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\ + 1 + + + + + Contents + 1 + + + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + + + + + + + + + False + True + False + + + 12 + + + + + diff --git a/windows/src/test/manual-tests/rsp-20547 string-use-after-free-in-param/member_mutation.res b/windows/src/test/manual-tests/rsp-20547 string-use-after-free-in-param/member_mutation.res new file mode 100644 index 0000000000000000000000000000000000000000..743599575b02e97248bade49ed2e3eabafe25a0a GIT binary patch literal 96 zcmZQzU|>)H;{X347|28cOhBFu5dZ(r#Sp;Y!{Epe!r;c>&k)4m3uHM0X?F%!AS)QE O%YcEC1!e#vkO2UW7YiT& literal 0 HcmV?d00001 diff --git a/windows/src/test/manual-tests/rsp-20547 string-use-after-free-in-param/mutation_test.pas b/windows/src/test/manual-tests/rsp-20547 string-use-after-free-in-param/mutation_test.pas new file mode 100644 index 0000000000..3ea83771f1 --- /dev/null +++ b/windows/src/test/manual-tests/rsp-20547 string-use-after-free-in-param/mutation_test.pas @@ -0,0 +1,116 @@ +unit mutation_test; + +interface + +uses + Winapi.Windows, + System.SysUtils; + +procedure Run; + +// Define this to see how the memory referenced by (C) is freed twice +{$DEFINE LOG_MEMORY_OPERATIONS} + +type + TMutatedMember = class + private + FMutatedMember: string; + function DoMutation: string; + public + constructor Create; + // Using register calling convention, we need 3 parameters. For + // stdcall, only 2 parameters are required. + procedure DoNothing(A, B, C: string); + end; + +implementation + +{$IFDEF LOG_MEMORY_OPERATIONS} +procedure LogMemoryOperations; forward; +{$ENDIF} + +constructor TMutatedMember.Create; +begin + FMutatedMember := '0.0'; +end; + +function TMutatedMember.DoMutation: string; +begin + FMutatedMember := '1.0'; + Result := ''; +end; + +procedure TMutatedMember.DoNothing(A, B, C: string); +begin + // On exiting this function, C is freed a second time, which causes an + // EInvalidPointer. + + // In this simple repro, if we were to reference C, then we wouldn't get an + // exception. So to demonstrate the issue in a minimal way, we won't reference C. + // In our more complex scenario, C is referenced in the function and still + // causes the same double-free at function exit. + + // If we examine pstrrec(cardinal(C)-$c) in a debugger, we can see that refCnt + // is 0 on entry (breakpoint on ). Contrast to pstrrec(cardinal(B)-$c) + // which shows a (correct) refCnt of 1. +end; + +procedure Run; +var + mm: TMutatedMember; +begin +{$IFDEF LOG_MEMORY_OPERATIONS} + LogMemoryOperations; +{$ENDIF} + + mm := TMutatedMember.Create; + try + // As far as I can tell, this call pushes FMutatedMember onto the stack but + // doesn't increase refCnt here. Then mm.DoMutation frees the string out + // underneath it (replacing it with '1.0') and the passed parameter now refers + // to invalid memory, resulting in a double-free of the string + mm.DoNothing(mm.DoMutation, 'ignored', mm.FMutatedMember); + finally + mm.Free; + end; +end; + +{$IFDEF LOG_MEMORY_OPERATIONS} +var + DefaultMM, LoggedAllocsAndFrees: TMemoryManagerEx; + +function LoggedGetMem(Size: NativeInt): Pointer; +var + b: array[0..64] of char; +begin + Result := DefaultMM.GetMem(Size); + Winapi.Windows.wsprintf(b, 'GetMem(%x) = %x', Size, Cardinal(Result)); + OutputDebugString(b); +end; + +function LoggedFreeMem(P: Pointer): Integer; +var + b: array[0..64] of char; +begin + Result := DefaultMM.FreeMem(P); + Winapi.Windows.wsprintf(b, 'FreeMem(%x) = %x', Cardinal(P), Result); + OutputDebugString(b); +end; + +function LoggedReallocMem(P: Pointer; Size: NativeInt): Pointer; +begin + Result := DefaultMM.ReallocMem(P, Size); +end; + +procedure LogMemoryOperations; +begin + GetMemoryManager(DefaultMM); + Move(DefaultMM, LoggedAllocsAndFrees, sizeof(TMemoryManagerEx)); + LoggedAllocsAndFrees.GetMem := @LoggedGetMem; + LoggedAllocsAndFrees.FreeMem := @LoggedFreeMem; + LoggedAllocsAndFrees.ReallocMem := @LoggedReallocMem; + SetMemoryManager(LoggedAllocsAndFrees); +end; +{$ENDIF} + +end. -- GitLab From 30cdf441e0eaf7ddc100b88d7d19cdafa027baf1 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 27 Apr 2018 10:39:55 +0700 Subject: [PATCH 015/356] Fixes #718 - context and index are not valid in the output of a match or nomatch rule --- windows/src/developer/kmcmpdll/Compiler.cpp | 28 +++++++++++++++++++-- windows/src/developer/kmcmpdll/Compiler.rc | 1 + windows/src/global/inc/Comperr.h | 1 + 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/windows/src/developer/kmcmpdll/Compiler.cpp b/windows/src/developer/kmcmpdll/Compiler.cpp index 2bcb1aef8b..c0dbdb8ae1 100644 --- a/windows/src/developer/kmcmpdll/Compiler.cpp +++ b/windows/src/developer/kmcmpdll/Compiler.cpp @@ -604,6 +604,21 @@ DWORD ProcessBeginLine(PFILE_KEYBOARD fk, PWSTR p) return CERR_None; } +DWORD ValidateMatchNomatchOutput(PWSTR p) { + while (p) { + if (*p == UC_SENTINEL) { + switch (*(p + 1)) { + case CODE_CONTEXT: + case CODE_CONTEXTEX: + case CODE_INDEX: + return CERR_ContextAndIndexInvalidInMatchNomatch; + } + } + p = incxstr(p); + } + return CERR_None; +} + DWORD ParseLine(PFILE_KEYBOARD fk, PWSTR str) { PWSTR p, q, pp; @@ -748,7 +763,12 @@ DWORD ParseLine(PFILE_KEYBOARD fk, PWSTR str) return msg; } - gp = &fk->dpGroupArray[fk->currentGroup]; + if ((msg = ValidateMatchNomatchOutput(buf)) != CERR_None) { + delete buf; + return msg; + } + + gp = &fk->dpGroupArray[fk->currentGroup]; gp->dpMatch = new WCHAR[wcslen(buf) + 1]; wcscpy_s(gp->dpMatch, wcslen(buf)+1, buf); // I3481 @@ -781,6 +801,11 @@ DWORD ParseLine(PFILE_KEYBOARD fk, PWSTR str) return msg; } + if ((msg = ValidateMatchNomatchOutput(buf)) != CERR_None) { + delete buf; + return msg; + } + gp = &fk->dpGroupArray[fk->currentGroup]; gp->dpNoMatch = new WCHAR[wcslen(buf) + 1]; @@ -807,7 +832,6 @@ DWORD ParseLine(PFILE_KEYBOARD fk, PWSTR str) //********************************************************************************************************************** - DWORD ProcessGroupLine(PFILE_KEYBOARD fk, PWSTR p) { PFILE_GROUP gp; diff --git a/windows/src/developer/kmcmpdll/Compiler.rc b/windows/src/developer/kmcmpdll/Compiler.rc index e8550bb57c..1f9ee98481 100644 --- a/windows/src/developer/kmcmpdll/Compiler.rc +++ b/windows/src/developer/kmcmpdll/Compiler.rc @@ -202,6 +202,7 @@ BEGIN CERR_ContextExHasInvalidOffset "context() statement has offset out of range" CERR_90FeatureOnlyEmbedCSS "Embedding CSS requires store(&version) '9.0'" CERR_90FeatureOnlyTargets "&TARGETS system store requires store(&version) '9.0'" + CERR_ContextAndIndexInvalidInMatchNomatch "context and index statements cannot be used in a match or nomatch statement" CWARN_PlatformNotInTargets "The specified platform is not a target platform" END diff --git a/windows/src/global/inc/Comperr.h b/windows/src/global/inc/Comperr.h index 27544418a6..91db923a19 100644 --- a/windows/src/global/inc/Comperr.h +++ b/windows/src/global/inc/Comperr.h @@ -136,6 +136,7 @@ #define CERR_ContextExHasInvalidOffset 0x0000405F #define CERR_90FeatureOnlyEmbedCSS 0x00004060 #define CERR_90FeatureOnlyTargets 0x00004061 +#define CERR_ContextAndIndexInvalidInMatchNomatch 0x00004062 #define CWARN_TooManyWarnings 0x00002080 #define CWARN_OldVersion 0x00002081 -- GitLab From b44ce5edda2a4644405d79866006da231b887c65 Mon Sep 17 00:00:00 2001 From: darcywong00 Date: Fri, 27 Apr 2018 11:39:38 +0700 Subject: [PATCH 016/356] Fixes #786 Fixed call for finishing activity when cancelling keyboard download dialog --- .../main/java/com/tavultesoft/kmea/ConfirmDialogFragment.java | 2 +- android/history.md | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) 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 68f41ca769..adcb739be1 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/history.md b/android/history.md index f3f593365c..18dd5b58bc 100644 --- a/android/history.md +++ b/android/history.md @@ -1,5 +1,8 @@ # Keyman for Android +## 2018-04-30 10.0.379 beta +* Fixed app crash when cancelling Keyboard download dialog (#786) + ## 2018-04-24 10.0.376 beta * Hide system OSK when resuming Keyman app. Disable text suggestions (#711) -- GitLab From de28a41025f8621bb84d9c9c46e8d097664729fc Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 30 Apr 2018 08:09:40 +0700 Subject: [PATCH 017/356] Fix loop in test for match and nomatch validity --- windows/src/developer/kmcmpdll/Compiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/src/developer/kmcmpdll/Compiler.cpp b/windows/src/developer/kmcmpdll/Compiler.cpp index c0dbdb8ae1..4be6f3d605 100644 --- a/windows/src/developer/kmcmpdll/Compiler.cpp +++ b/windows/src/developer/kmcmpdll/Compiler.cpp @@ -605,7 +605,7 @@ DWORD ProcessBeginLine(PFILE_KEYBOARD fk, PWSTR p) } DWORD ValidateMatchNomatchOutput(PWSTR p) { - while (p) { + while (p && *p) { if (*p == UC_SENTINEL) { switch (*(p + 1)) { case CODE_CONTEXT: -- GitLab From 06e5efdba3b1ce678a3c0071b7054ac848a12e94 Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Mon, 30 Apr 2018 10:21:39 +0700 Subject: [PATCH 018/356] Mostly fixes chiral AltGr emulation detection. --- web/source/kmwosk.ts | 31 +- .../resources/keyboards/khmer_angkor.js | 871 +++++++++--------- 2 files changed, 462 insertions(+), 440 deletions(-) diff --git a/web/source/kmwosk.ts b/web/source/kmwosk.ts index ff4fa9fdcf..f43ebc0594 100644 --- a/web/source/kmwosk.ts +++ b/web/source/kmwosk.ts @@ -3094,10 +3094,27 @@ if(!window['keyman']['initialized']) { * @return {boolean} */ osk.emulatesAltGr = function(keyLabels) { - var layers = keyLabels ? keyLabels : osk.layers; + var activeKeyboard = keymanweb.keyboardManager.activeKeyboard; + if(activeKeyboard == null || activeKeyboard['KV'] == null) { + return false; + } + + var layers = keyLabels ? keyLabels : activeKeyboard['KV']['KLS']; + + var unshiftedEmulationLayer = layers[osk.getLayerId(osk.modifierCodes['LCTRL'] | osk.modifierCodes['LALT'])]; + var shiftedEmulationLayer = layers[osk.getLayerId(osk.modifierCodes['SHIFT'] | osk.modifierCodes['LCTRL'] | osk.modifierCodes['LALT'])]; + + // buildDefaultLayout ensures that these are aliased to the original modifier set being emulated. + // As a result, we can directly test for reference equality. + if(unshiftedEmulationLayer != layers[osk.getLayerId(osk.modifierCodes['RALT'])]) { + return false; + } + + if(shiftedEmulationLayer != layers[osk.getLayerId(osk.modifierCodes['RALT'] | osk.modifierCodes('SHIFT'))]) { + return false; + } - return !(layers[osk.getLayerId(osk.modifierCodes['LCTRL'] | osk.modifierCodes['LALT'])] || - layers[osk.getLayerId(osk.modifierCodes['SHIFT'] | osk.modifierCodes['LCTRL'] | osk.modifierCodes['LALT'])]); + return true; } /** @@ -3127,7 +3144,9 @@ if(!window['keyman']['initialized']) { var kmw10Plus = !(typeof keyLabels == 'undefined' || !keyLabels); if(!kmw10Plus) { - keyLabels = osk.processLegacyDefinitions(PVK['BK']); + // Save the processed key label information to the keyboard's general data. + // Makes things more efficient elsewhere and for reloading after keyboard swaps. + keyLabels = PVK['KLS'] = osk.processLegacyDefinitions(PVK['BK']); } // Identify key labels (e.g. *Shift*) that require the special OSK font @@ -3143,7 +3162,9 @@ if(!window['keyman']['initialized']) { // Automatic AltGr emulation if the 'leftctrl-leftalt' layer is otherwise undefined. if(osk.emulatesAltGr(keyLabels) && validIdList.indexOf('rightalt') != -1) { validIdList.push('leftctrl-leftalt'); + validIdList.push('leftctrl-leftalt-shift'); keyLabels['leftctrl-leftalt'] = keyLabels['rightalt']; + keyLabels['leftctrl-leftalt-shift'] = keyLabels['rightalt-shift']; } // For desktop devices, we must create all layers, even if invalid. @@ -3158,6 +3179,8 @@ if(!window['keyman']['initialized']) { } } + // This ensures all 'valid' layers are at the front of the layer array and managed by the main loop below. + // 'invalid' layers aren't handled by the loop and thus remain blank after it. var idList = validIdList.concat(invalidIdList); if(kmw10Plus && formFactor != 'desktop') { // KLS exists, so we know the exact layer set. diff --git a/web/unit_tests/resources/keyboards/khmer_angkor.js b/web/unit_tests/resources/keyboards/khmer_angkor.js index aa5115b9f9..b82e41e235 100644 --- a/web/unit_tests/resources/keyboards/khmer_angkor.js +++ b/web/unit_tests/resources/keyboards/khmer_angkor.js @@ -17,7 +17,6 @@ function Keyboard_khmer_angkor() this.KV.KLS={ "rightalt": ["‍","‌","@","៑","$","€","៙","៚","*","{","}","≈","៎","","","","ៜ","៝","ឯ","ឫ","ឨ","[","]","ឦ","ឱ","ឰ","ឩ","ឳ","\\","","","","+","-","×","÷",":","‘","’","ឝ","៘","៖","ៈ","","","","","","","<",">","","","ឞ",";","៓",",",".","/","","","","","",""], "rightalt-shift": ["","៱","៲","៳","៴","៵","៶","៷","៸","៹","៰","","","","","","᧠","᧡","᧢","᧣","᧤","᧥","᧦","᧧","᧨","᧩","᧪","᧫","","","","","᧬","᧭","᧮","᧯","᧰","᧱","᧲","᧳","᧴","᧵","᧶","","","","","","","᧷","᧸","᧹","᧺","᧻","᧼","᧽","᧾","᧿","","","","","","",""], - "leftctrl-leftalt": ["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","‍"], "default": ["«","១","២","៣","៤","៥","៦","៧","៨","៩","០","ឥ","ឲ","","","","ឆ","ឹ","េ","រ","ត","យ","ុ","ិ","ោ","ផ","ៀ","ឪ","ឮ","","","","ា","ស","ដ","ថ","ង","ហ","្","ក","ល","ើ","់","","","","","","","ឋ","ខ","ច","វ","ប","ន","ម","ុំ","។","៊","","","","","","​"], "shift": ["»","!","ៗ","\"","៛","%","៍","័","៏","(",")","៌","=","","","","ឈ","ឺ","ែ","ឬ","ទ","ួ","ូ","ី","ៅ","ភ","ឿ","ឧ","ឭ","","","","ាំ","ៃ","ឌ","ធ","អ","ះ","ញ","គ","ឡ","ោះ","៉","","","","","","","ឍ","ឃ","ជ","េះ","ព","ណ","ំ","ុះ","៕","?","","","","",""," "] }; @@ -36,7 +35,7 @@ function Keyboard_khmer_angkor() })(this.KV.KLS); this.KH=''; this.KM=0; - this.KBVER="1.0"; + this.KBVER="1.0.3"; this.KMBM=modCodes.RALT | modCodes.SHIFT /* 0x0018 */; this.KVKD="T_17D2_1780 T_17D2_1781 T_17D2_1782 T_17D2_1783 T_17D2_1784 T_17D2_1785 T_17D2_1786 T_17D2_1787 T_17D2_1788 T_17D2_1789 T_17D2_178A T_17D2_178B T_17D2_178C T_17D2_178D T_17D2_178E T_17D2_178F T_17D2_1790 T_17D2_1791 T_17D2_1792 T_17D2_1793 T_17D2_1794 T_17D2_1795 T_17D2_1796 T_17D2_1797 T_17D2_1798 T_17D2_1799 T_17D2_179A T_17D2_179B T_17D2_179C T_17D2_179D T_17D2_179E T_17D2_179F T_17D2_17A0 T_17D2_17A1 T_17D2_17A2 U_0030 U_0031 U_0032 U_0033 U_0034 U_0035 U_0036 U_0037 U_0038 U_0039"; this.KVKL={ @@ -1527,683 +1526,683 @@ function Keyboard_khmer_angkor() this.s_c_combo_SA="បយលមនញងរវអ"; this.s_c_combo_QA="ឆឈបផតទ"; this.s_c_combo_HA="វឣ"; - this.s64="touch"; - this.s65="web"; - this.KVER="10.0.700.0"; + this.s61="touch"; + this.s62="web"; + this.KVER="10.0.1057.0"; this.gs=function(t,e) { return this.g_main(t,e); }; this.g_main=function(t,e) { var k=KeymanWeb,r=0,m=0; - if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKSP /* 0x08 */)&&k.KFCM(2,t,['្',{t:'a',a:this.s_c_out}])&&k.KIFS(31,this.s64,t)) { // Line 316 + if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKSP /* 0x08 */)&&k.KFCM(2,t,['្',{t:'a',a:this.s_c_out}])&&k.KIFS(31,this.s61,t)) { // Line 313 r=m=1; k.KDC(2,t); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKSP /* 0x08 */)&&k.KFCM(2,t,['្',{t:'a',a:this.s_c_out}])&&k.KIFS(31,this.s65,t)) { // Line 317 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKSP /* 0x08 */)&&k.KFCM(2,t,['្',{t:'a',a:this.s_c_out}])&&k.KIFS(31,this.s62,t)) { // Line 314 r=m=1; k.KDC(2,t); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKSP /* 0x08 */)&&k.KFCM(2,t,[{t:'a',a:this.s_v_combo_N},'ំ'])) { // Line 246 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKSP /* 0x08 */)&&k.KFCM(2,t,[{t:'a',a:this.s_v_combo_N},'ំ'])) { // Line 243 r=m=1; k.KDC(2,t); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKSP /* 0x08 */)&&k.KFCM(2,t,[{t:'a',a:this.s_v_combo_R},'ះ'])) { // Line 247 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKSP /* 0x08 */)&&k.KFCM(2,t,[{t:'a',a:this.s_v_combo_R},'ះ'])) { // Line 244 r=m=1; k.KDC(2,t); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_K /* 0x4B */)) { // Line 209 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_K /* 0x4B */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឝ"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_B /* 0x42 */)) { // Line 209 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_B /* 0x42 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឞ"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_QUOTE /* 0xDE */)) { // Line 210 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_QUOTE /* 0xDE */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"ៈ"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_I /* 0x49 */)) { // Line 211 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_I /* 0x49 */)) { // Line 208 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឦ"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_LBRKT /* 0xDB */)) { // Line 211 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_LBRKT /* 0xDB */)) { // Line 208 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឩ"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_R /* 0x52 */)) { // Line 211 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_R /* 0x52 */)) { // Line 208 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឫ"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_E /* 0x45 */)) { // Line 211 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_E /* 0x45 */)) { // Line 208 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឯ"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_P /* 0x50 */)) { // Line 211 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_P /* 0x50 */)) { // Line 208 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឰ"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_O /* 0x4F */)) { // Line 211 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_O /* 0x4F */)) { // Line 208 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឱ"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_RBRKT /* 0xDD */)) { // Line 211 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_RBRKT /* 0xDD */)) { // Line 208 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឳ"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_T /* 0x54 */)) { // Line 211 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_T /* 0x54 */)) { // Line 208 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឨ"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_EQUAL /* 0xBB */)) { // Line 212 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_EQUAL /* 0xBB */)) { // Line 209 r=m=1; k.KDC(0,t); k.KO(-1,t,"៎"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_3 /* 0x33 */)) { // Line 212 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_3 /* 0x33 */)) { // Line 209 r=m=1; k.KDC(0,t); k.KO(-1,t,"៑"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_W /* 0x57 */)) { // Line 212 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_W /* 0x57 */)) { // Line 209 r=m=1; k.KDC(0,t); k.KO(-1,t,"៝"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_Q /* 0x51 */)) { // Line 212 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_Q /* 0x51 */)) { // Line 209 r=m=1; k.KDC(0,t); k.KO(-1,t,"ៜ"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_QUOTE /* 0xDE */)) { // Line 212 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_QUOTE /* 0xDE */)) { // Line 209 r=m=1; k.KDC(0,t); k.KO(-1,t,"ៈ"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_COLON /* 0xBA */)) { // Line 214 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_COLON /* 0xBA */)) { // Line 211 r=m=1; k.KDC(0,t); k.KO(-1,t,"៖"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_L /* 0x4C */)) { // Line 214 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_L /* 0x4C */)) { // Line 211 r=m=1; k.KDC(0,t); k.KO(-1,t,"៘"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_7 /* 0x37 */)) { // Line 214 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_7 /* 0x37 */)) { // Line 211 r=m=1; k.KDC(0,t); k.KO(-1,t,"៚"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_M /* 0x4D */)) { // Line 214 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_M /* 0x4D */)) { // Line 211 r=m=1; k.KDC(0,t); k.KO(-1,t,"៓"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_6 /* 0x36 */)) { // Line 214 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_6 /* 0x36 */)) { // Line 211 r=m=1; k.KDC(0,t); k.KO(-1,t,"៙"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_X /* 0x58 */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_X /* 0x58 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,">"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_BKSLASH /* 0xDC */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_BKSLASH /* 0xDC */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"\\"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_S /* 0x53 */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_S /* 0x53 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"-"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_8 /* 0x38 */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_8 /* 0x38 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"*"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_COMMA /* 0xBC */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_COMMA /* 0xBC */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,","); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_D /* 0x44 */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_D /* 0x44 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"×"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_A /* 0x41 */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_A /* 0x41 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"+"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_PERIOD /* 0xBE */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_PERIOD /* 0xBE */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"."); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_C /* 0x43 */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_C /* 0x43 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"#"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_V /* 0x56 */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_V /* 0x56 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"&"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_SLASH /* 0xBF */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_SLASH /* 0xBF */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"/"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_Y /* 0x59 */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_Y /* 0x59 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"["); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_U /* 0x55 */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_U /* 0x55 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"]"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_BKQUOTE /* 0xC0 */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_BKQUOTE /* 0xC0 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"‍"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_1 /* 0x31 */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_1 /* 0x31 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"‌"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_9 /* 0x39 */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_9 /* 0x39 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"{"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_F /* 0x46 */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_F /* 0x46 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"÷"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_G /* 0x47 */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_G /* 0x47 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,":"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_HYPHEN /* 0xBD */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_HYPHEN /* 0xBD */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"≈"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_H /* 0x48 */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_H /* 0x48 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"‘"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_J /* 0x4A */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_J /* 0x4A */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"’"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_N /* 0x4E */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_N /* 0x4E */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,";"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_0 /* 0x30 */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_0 /* 0x30 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"}"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_Z /* 0x5A */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_Z /* 0x5A */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"<"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_2 /* 0x32 */)) { // Line 215 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_2 /* 0x32 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"@"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_4 /* 0x34 */)) { // Line 216 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_4 /* 0x34 */)) { // Line 213 r=m=1; k.KDC(0,t); k.KO(-1,t,"$"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_5 /* 0x35 */)) { // Line 216 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_5 /* 0x35 */)) { // Line 213 r=m=1; k.KDC(0,t); k.KO(-1,t,"€"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_2 /* 0x32 */)) { // Line 218 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_2 /* 0x32 */)) { // Line 215 r=m=1; k.KDC(0,t); k.KO(-1,t,"៲"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_1 /* 0x31 */)) { // Line 218 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_1 /* 0x31 */)) { // Line 215 r=m=1; k.KDC(0,t); k.KO(-1,t,"៱"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_0 /* 0x30 */)) { // Line 218 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_0 /* 0x30 */)) { // Line 215 r=m=1; k.KDC(0,t); k.KO(-1,t,"៰"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_3 /* 0x33 */)) { // Line 218 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_3 /* 0x33 */)) { // Line 215 r=m=1; k.KDC(0,t); k.KO(-1,t,"៳"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_6 /* 0x36 */)) { // Line 218 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_6 /* 0x36 */)) { // Line 215 r=m=1; k.KDC(0,t); k.KO(-1,t,"៶"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_7 /* 0x37 */)) { // Line 218 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_7 /* 0x37 */)) { // Line 215 r=m=1; k.KDC(0,t); k.KO(-1,t,"៷"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_8 /* 0x38 */)) { // Line 218 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_8 /* 0x38 */)) { // Line 215 r=m=1; k.KDC(0,t); k.KO(-1,t,"៸"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_9 /* 0x39 */)) { // Line 218 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_9 /* 0x39 */)) { // Line 215 r=m=1; k.KDC(0,t); k.KO(-1,t,"៹"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_5 /* 0x35 */)) { // Line 218 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_5 /* 0x35 */)) { // Line 215 r=m=1; k.KDC(0,t); k.KO(-1,t,"៵"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_4 /* 0x34 */)) { // Line 218 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_4 /* 0x34 */)) { // Line 215 r=m=1; k.KDC(0,t); k.KO(-1,t,"៴"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_E /* 0x45 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_E /* 0x45 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧢"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_F /* 0x46 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_F /* 0x46 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧯"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_A /* 0x41 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_A /* 0x41 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧬"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_D /* 0x44 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_D /* 0x44 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧮"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_C /* 0x43 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_C /* 0x43 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧹"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_QUOTE /* 0xDE */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_QUOTE /* 0xDE */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧶"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_G /* 0x47 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_G /* 0x47 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧰"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_RBRKT /* 0xDD */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_RBRKT /* 0xDD */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧫"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_LBRKT /* 0xDB */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_LBRKT /* 0xDB */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧪"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_H /* 0x48 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_H /* 0x48 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧱"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_PERIOD /* 0xBE */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_PERIOD /* 0xBE */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧿"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_I /* 0x49 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_I /* 0x49 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧧"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_J /* 0x4A */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_J /* 0x4A */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧲"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_K /* 0x4B */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_K /* 0x4B */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧳"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_L /* 0x4C */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_L /* 0x4C */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧴"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_COMMA /* 0xBC */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_COMMA /* 0xBC */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧾"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_M /* 0x4D */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_M /* 0x4D */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧽"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_N /* 0x4E */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_N /* 0x4E */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧼"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_COLON /* 0xBA */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_COLON /* 0xBA */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧵"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_Z /* 0x5A */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_Z /* 0x5A */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧷"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_Y /* 0x59 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_Y /* 0x59 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧥"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_X /* 0x58 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_X /* 0x58 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧸"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_O /* 0x4F */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_O /* 0x4F */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧨"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_W /* 0x57 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_W /* 0x57 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧡"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_V /* 0x56 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_V /* 0x56 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧺"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_U /* 0x55 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_U /* 0x55 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧦"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_P /* 0x50 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_P /* 0x50 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧩"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_Q /* 0x51 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_Q /* 0x51 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧠"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_R /* 0x52 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_R /* 0x52 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧣"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_S /* 0x53 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_S /* 0x53 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧭"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_T /* 0x54 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_T /* 0x54 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧤"); } - else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_B /* 0x42 */)) { // Line 219 + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_B /* 0x42 */)) { // Line 216 r=m=1; k.KDC(0,t); k.KO(-1,t,"᧻"); } - else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_SPACE /* 0x20 */)) { // Line 220 + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_SPACE /* 0x20 */)) { // Line 217 r=m=1; k.KDC(0,t); k.KO(-1,t,"‍"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x10C)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x10C)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ឌ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x10D)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x10D)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ឍ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x10E)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x10E)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ណ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x10F)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x10F)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ត"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x10A)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x10A)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ដ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x109)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x109)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ញ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x108)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x108)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ឈ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x107)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x107)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ជ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x106)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x106)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ឆ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x105)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x105)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ច"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x122)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x122)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្អ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x104)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x104)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ង"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x103)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x103)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ឃ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x102)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x102)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្គ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x111)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x111)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ទ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x101)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x101)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ខ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x100)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x100)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ក"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x112)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x112)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ធ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x113)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x113)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ន"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x114)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x114)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ប"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x115)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x115)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ផ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x110)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x110)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ថ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x10B)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x10B)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ឋ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x116)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x116)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ព"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x121)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x121)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ឡ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x117)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x117)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ភ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x120)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x120)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ហ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x11F)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x11F)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ស"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x11E)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x11E)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ឞ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x11D)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x11D)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ឝ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x118)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x118)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ម"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x11C)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x11C)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្វ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x119)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x119)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្យ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x11A)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x11A)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្រ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x11B)) { // Line 312 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x11B)) { // Line 309 r=m=1; k.KDC(0,t); k.KO(-1,t,"្ល"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_SPACE /* 0x20 */)) { // Line 220 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_SPACE /* 0x20 */)) { // Line 217 r=m=1; k.KDC(0,t); k.KO(-1,t," "); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_SPACE /* 0x20 */)) { // Line 220 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_SPACE /* 0x20 */)) { // Line 217 r=m=1; k.KDC(0,t); k.KO(-1,t,"​"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_1 /* 0x31 */)) { // Line 215 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_1 /* 0x31 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"!"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(3,t,[{t:'a',a:this.s_c_combo_QA},'្','អ'])) { // Line 261 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(3,t,[{t:'a',a:this.s_c_combo_QA},'្','អ'])) { // Line 258 r=m=1; k.KDC(3,t); k.KIO(-1,this.s_c_combo_QA,1,t); k.KO(-1,t,"្អ៉"); k.KB(t); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(3,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO}])) { // Line 262 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(3,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO}])) { // Line 259 r=m=1; k.KDC(3,t); k.KO(-1,t,"ល្"); @@ -2211,7 +2210,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៉"); k.KB(t); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(3,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO}])) { // Line 263 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(3,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO}])) { // Line 260 r=m=1; k.KDC(3,t); k.KO(-1,t,"ម្"); @@ -2219,7 +2218,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៉"); k.KB(t); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(3,t,['ស','្',{t:'a',a:this.s_c_combo_SA}])) { // Line 264 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(3,t,['ស','្',{t:'a',a:this.s_c_combo_SA}])) { // Line 261 r=m=1; k.KDC(3,t); k.KO(-1,t,"ស្"); @@ -2227,129 +2226,129 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៉"); k.KB(t); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(3,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ'])) { // Line 265 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(3,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ'])) { // Line 262 r=m=1; k.KDC(3,t); k.KIO(-1,this.s_c_combo_HA,1,t); k.KO(-1,t,"្ហ៉"); k.KB(t); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(3,t,['អ','្','ង'])) { // Line 266 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(3,t,['អ','្','ង'])) { // Line 263 r=m=1; k.KDC(3,t); k.KO(-1,t,"អ្ង៉"); k.KB(t); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(3,t,['អ','្','វ'])) { // Line 267 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(3,t,['អ','្','វ'])) { // Line 264 r=m=1; k.KDC(3,t); k.KO(-1,t,"អ្វ៉"); k.KB(t); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(1,t,[{t:'a',a:this.s_c_shifter}])) { // Line 236 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(1,t,[{t:'a',a:this.s_c_shifter}])) { // Line 233 r=m=1; k.KDC(1,t); k.KIO(-1,this.s_c_shifter,1,t); k.KB(t); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(1,t,[{t:'a',a:this.s_shiftable_c_1st}])) { // Line 256 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(1,t,[{t:'a',a:this.s_shiftable_c_1st}])) { // Line 253 r=m=1; k.KDC(1,t); k.KIO(-1,this.s_shiftable_c_1st,1,t); k.KO(-1,t,"៉"); k.KB(t); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)) { // Line 213 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)) { // Line 210 r=m=1; k.KDC(0,t); k.KO(-1,t,"៉"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_3 /* 0x33 */)) { // Line 215 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_3 /* 0x33 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"\""); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_4 /* 0x34 */)) { // Line 216 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_4 /* 0x34 */)) { // Line 213 r=m=1; k.KDC(0,t); k.KO(-1,t,"៛"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_5 /* 0x35 */)) { // Line 215 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_5 /* 0x35 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"%"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_7 /* 0x37 */)) { // Line 212 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_7 /* 0x37 */)) { // Line 209 r=m=1; k.KDC(0,t); k.KO(-1,t,"័"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(2,t,['្',{t:'a',a:this.s_c_out}])) { // Line 235 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(2,t,['្',{t:'a',a:this.s_c_out}])) { // Line 232 r=m=1; k.KDC(2,t); k.KO(-1,t,"្"); k.KIO(-1,this.s_c_out,2,t); k.KB(t); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(1,t,[{t:'a',a:this.s_v_gen}])) { // Line 232 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(1,t,[{t:'a',a:this.s_v_gen}])) { // Line 229 r=m=1; k.KDC(1,t); k.KIO(-1,this.s_v_gen,1,t); k.KB(t); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(1,t,[{t:'a',a:this.s_v_pseudo}])) { // Line 233 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(1,t,[{t:'a',a:this.s_v_pseudo}])) { // Line 230 r=m=1; k.KDC(1,t); k.KIO(-1,this.s_v_pseudo,1,t); k.KB(t); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(1,t,[{t:'a',a:this.s_c_shifter}])) { // Line 234 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_QUOTE /* 0xDE */)&&k.KFCM(1,t,[{t:'a',a:this.s_c_shifter}])) { // Line 231 r=m=1; k.KDC(1,t); k.KIO(-1,this.s_c_shifter,1,t); k.KB(t); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_QUOTE /* 0xDE */)) { // Line 212 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_QUOTE /* 0xDE */)) { // Line 209 r=m=1; k.KDC(0,t); k.KO(-1,t,"់"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_9 /* 0x39 */)) { // Line 215 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_9 /* 0x39 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"("); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_0 /* 0x30 */)) { // Line 215 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_0 /* 0x30 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,")"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_8 /* 0x38 */)) { // Line 212 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_8 /* 0x38 */)) { // Line 209 r=m=1; k.KDC(0,t); k.KO(-1,t,"៏"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_EQUAL /* 0xBB */)) { // Line 215 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_EQUAL /* 0xBB */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"="); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_COMMA /* 0xBC */)) { // Line 227 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_COMMA /* 0xBC */)) { // Line 224 r=m=1; k.KDC(0,t); k.KO(-1,t,"ុំ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_HYPHEN /* 0xBD */)) { // Line 211 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_HYPHEN /* 0xBD */)) { // Line 208 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឥ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_PERIOD /* 0xBE */)) { // Line 214 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_PERIOD /* 0xBE */)) { // Line 211 r=m=1; k.KDC(0,t); k.KO(-1,t,"។"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_SLASH /* 0xBF */)&&k.KFCM(3,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO}])) { // Line 271 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_SLASH /* 0xBF */)&&k.KFCM(3,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO}])) { // Line 268 r=m=1; k.KDC(3,t); k.KO(-1,t,"ល្"); @@ -2357,7 +2356,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៊"); k.KB(t); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_SLASH /* 0xBF */)&&k.KFCM(3,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO}])) { // Line 272 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_SLASH /* 0xBF */)&&k.KFCM(3,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO}])) { // Line 269 r=m=1; k.KDC(3,t); k.KO(-1,t,"ម្"); @@ -2365,380 +2364,380 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៊"); k.KB(t); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_SLASH /* 0xBF */)&&k.KFCM(1,t,[{t:'a',a:this.s_c_shifter}])) { // Line 236 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_SLASH /* 0xBF */)&&k.KFCM(1,t,[{t:'a',a:this.s_c_shifter}])) { // Line 233 r=m=1; k.KDC(1,t); k.KIO(-1,this.s_c_shifter,1,t); k.KB(t); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_SLASH /* 0xBF */)&&k.KFCM(1,t,[{t:'a',a:this.s_shiftable_c_2nd}])) { // Line 257 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_SLASH /* 0xBF */)&&k.KFCM(1,t,[{t:'a',a:this.s_shiftable_c_2nd}])) { // Line 254 r=m=1; k.KDC(1,t); k.KIO(-1,this.s_shiftable_c_2nd,1,t); k.KO(-1,t,"៊"); k.KB(t); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_SLASH /* 0xBF */)) { // Line 213 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_SLASH /* 0xBF */)) { // Line 210 r=m=1; k.KDC(0,t); k.KO(-1,t,"៊"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_0 /* 0x30 */)) { // Line 217 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_0 /* 0x30 */)) { // Line 214 r=m=1; k.KDC(0,t); k.KO(-1,t,"០"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_1 /* 0x31 */)) { // Line 217 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_1 /* 0x31 */)) { // Line 214 r=m=1; k.KDC(0,t); k.KO(-1,t,"១"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_2 /* 0x32 */)) { // Line 217 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_2 /* 0x32 */)) { // Line 214 r=m=1; k.KDC(0,t); k.KO(-1,t,"២"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_3 /* 0x33 */)) { // Line 217 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_3 /* 0x33 */)) { // Line 214 r=m=1; k.KDC(0,t); k.KO(-1,t,"៣"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_4 /* 0x34 */)) { // Line 217 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_4 /* 0x34 */)) { // Line 214 r=m=1; k.KDC(0,t); k.KO(-1,t,"៤"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_5 /* 0x35 */)) { // Line 217 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_5 /* 0x35 */)) { // Line 214 r=m=1; k.KDC(0,t); k.KO(-1,t,"៥"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_6 /* 0x36 */)) { // Line 217 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_6 /* 0x36 */)) { // Line 214 r=m=1; k.KDC(0,t); k.KO(-1,t,"៦"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_7 /* 0x37 */)) { // Line 217 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_7 /* 0x37 */)) { // Line 214 r=m=1; k.KDC(0,t); k.KO(-1,t,"៧"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_8 /* 0x38 */)) { // Line 217 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_8 /* 0x38 */)) { // Line 214 r=m=1; k.KDC(0,t); k.KO(-1,t,"៨"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_9 /* 0x39 */)) { // Line 217 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_9 /* 0x39 */)) { // Line 214 r=m=1; k.KDC(0,t); k.KO(-1,t,"៩"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_COLON /* 0xBA */)) { // Line 226 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_COLON /* 0xBA */)) { // Line 223 r=m=1; k.KDC(0,t); k.KO(-1,t,"ោះ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_COLON /* 0xBA */)) { // Line 210 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_COLON /* 0xBA */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"ើ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_COMMA /* 0xBC */)) { // Line 228 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_COMMA /* 0xBC */)) { // Line 225 r=m=1; k.KDC(0,t); k.KO(-1,t,"ុះ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_EQUAL /* 0xBB */)) { // Line 211 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_EQUAL /* 0xBB */)) { // Line 208 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឲ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_PERIOD /* 0xBE */)) { // Line 214 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_PERIOD /* 0xBE */)) { // Line 211 r=m=1; k.KDC(0,t); k.KO(-1,t,"៕"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_SLASH /* 0xBF */)) { // Line 215 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_SLASH /* 0xBF */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"?"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_2 /* 0x32 */)) { // Line 214 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_2 /* 0x32 */)) { // Line 211 r=m=1; k.KDC(0,t); k.KO(-1,t,"ៗ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_A /* 0x41 */)) { // Line 224 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_A /* 0x41 */)) { // Line 221 r=m=1; k.KDC(0,t); k.KO(-1,t,"ាំ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_B /* 0x42 */)) { // Line 209 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_B /* 0x42 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ព"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_C /* 0x43 */)) { // Line 209 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_C /* 0x43 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ជ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_D /* 0x44 */)) { // Line 209 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_D /* 0x44 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឌ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_E /* 0x45 */)) { // Line 210 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_E /* 0x45 */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"ែ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_F /* 0x46 */)) { // Line 209 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_F /* 0x46 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ធ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_G /* 0x47 */)) { // Line 209 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_G /* 0x47 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"អ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_H /* 0x48 */)&&k.KFCM(1,t,['ះ'])) { // Line 240 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_H /* 0x48 */)&&k.KFCM(1,t,['ះ'])) { // Line 237 r=m=1; k.KDC(1,t); k.KO(-1,t,"ៈ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_H /* 0x48 */)&&k.KFCM(1,t,['ៈ'])) { // Line 241 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_H /* 0x48 */)&&k.KFCM(1,t,['ៈ'])) { // Line 238 r=m=1; k.KDC(1,t); k.KO(-1,t,"ះ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_H /* 0x48 */)) { // Line 210 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_H /* 0x48 */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"ះ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_I /* 0x49 */)) { // Line 210 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_I /* 0x49 */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"ី"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_J /* 0x4A */)) { // Line 209 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_J /* 0x4A */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ញ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_K /* 0x4B */)) { // Line 209 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_K /* 0x4B */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"គ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_L /* 0x4C */)) { // Line 209 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_L /* 0x4C */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឡ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_M /* 0x4D */)) { // Line 210 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_M /* 0x4D */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"ំ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_N /* 0x4E */)) { // Line 209 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_N /* 0x4E */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ណ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_O /* 0x4F */)) { // Line 210 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_O /* 0x4F */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"ៅ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_P /* 0x50 */)) { // Line 209 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_P /* 0x50 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ភ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_Q /* 0x51 */)) { // Line 209 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_Q /* 0x51 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឈ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_R /* 0x52 */)) { // Line 211 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_R /* 0x52 */)) { // Line 208 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឬ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_S /* 0x53 */)) { // Line 210 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_S /* 0x53 */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"ៃ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_T /* 0x54 */)) { // Line 209 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_T /* 0x54 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ទ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_U /* 0x55 */)) { // Line 210 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_U /* 0x55 */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"ូ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_V /* 0x56 */)) { // Line 225 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_V /* 0x56 */)) { // Line 222 r=m=1; k.KDC(0,t); k.KO(-1,t,"េះ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_W /* 0x57 */)) { // Line 210 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_W /* 0x57 */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឺ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_X /* 0x58 */)) { // Line 209 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_X /* 0x58 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឃ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_Y /* 0x59 */)) { // Line 210 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_Y /* 0x59 */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"ួ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_Z /* 0x5A */)) { // Line 209 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_Z /* 0x5A */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឍ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_LBRKT /* 0xDB */)) { // Line 210 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_LBRKT /* 0xDB */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"ៀ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKSLASH /* 0xDC */)) { // Line 211 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKSLASH /* 0xDC */)) { // Line 208 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឮ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_RBRKT /* 0xDD */)) { // Line 211 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_RBRKT /* 0xDD */)) { // Line 208 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឪ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_6 /* 0x36 */)) { // Line 212 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_6 /* 0x36 */)) { // Line 209 r=m=1; k.KDC(0,t); k.KO(-1,t,"៍"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_HYPHEN /* 0xBD */)) { // Line 212 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_HYPHEN /* 0xBD */)) { // Line 209 r=m=1; k.KDC(0,t); k.KO(-1,t,"៌"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKQUOTE /* 0xC0 */)) { // Line 215 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKQUOTE /* 0xC0 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"«"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_A /* 0x41 */)) { // Line 210 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_A /* 0x41 */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"ា"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_B /* 0x42 */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_B /* 0x42 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ប"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_C /* 0x43 */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_C /* 0x43 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ច"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_D /* 0x44 */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_D /* 0x44 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ដ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_E /* 0x45 */)) { // Line 210 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_E /* 0x45 */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"េ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_F /* 0x46 */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_F /* 0x46 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ថ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_G /* 0x47 */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_G /* 0x47 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ង"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_H /* 0x48 */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_H /* 0x48 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ហ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_I /* 0x49 */)) { // Line 210 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_I /* 0x49 */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"ិ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_J /* 0x4A */)) { // Line 212 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_J /* 0x4A */)) { // Line 209 r=m=1; k.KDC(0,t); k.KO(-1,t,"្"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_K /* 0x4B */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_K /* 0x4B */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ក"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_L /* 0x4C */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_L /* 0x4C */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ល"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_M /* 0x4D */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_M /* 0x4D */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ម"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_N /* 0x4E */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_N /* 0x4E */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ន"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_O /* 0x4F */)) { // Line 210 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_O /* 0x4F */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"ោ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_P /* 0x50 */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_P /* 0x50 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ផ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_Q /* 0x51 */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_Q /* 0x51 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឆ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_R /* 0x52 */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_R /* 0x52 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"រ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_S /* 0x53 */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_S /* 0x53 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ស"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_T /* 0x54 */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_T /* 0x54 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ត"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_U /* 0x55 */)&&k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_1st},'ា','ំ'])) { // Line 251 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_U /* 0x55 */)&&k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_1st},'ា','ំ'])) { // Line 248 r=m=1; k.KDC(3,t); k.KIO(-1,this.s_shiftable_c_1st,1,t); @@ -2746,7 +2745,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_U /* 0x55 */)&&k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_2nd},'ា','ំ'])) { // Line 252 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_U /* 0x55 */)&&k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_2nd},'ា','ំ'])) { // Line 249 r=m=1; k.KDC(3,t); k.KIO(-1,this.s_shiftable_c_2nd,1,t); @@ -2754,52 +2753,52 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_U /* 0x55 */)) { // Line 210 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_U /* 0x55 */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"ុ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_V /* 0x56 */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_V /* 0x56 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"វ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_W /* 0x57 */)) { // Line 210 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_W /* 0x57 */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឹ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_X /* 0x58 */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_X /* 0x58 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ខ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_Y /* 0x59 */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_Y /* 0x59 */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"យ"); } - else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_Z /* 0x5A */)) { // Line 209 + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_Z /* 0x5A */)) { // Line 206 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឋ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_LBRKT /* 0xDB */)) { // Line 210 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_LBRKT /* 0xDB */)) { // Line 207 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឿ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_BKSLASH /* 0xDC */)) { // Line 211 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_BKSLASH /* 0xDC */)) { // Line 208 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឭ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_RBRKT /* 0xDD */)) { // Line 211 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_RBRKT /* 0xDD */)) { // Line 208 r=m=1; k.KDC(0,t); k.KO(-1,t,"ឧ"); } - else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_BKQUOTE /* 0xC0 */)) { // Line 215 + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_BKQUOTE /* 0xC0 */)) { // Line 212 r=m=1; k.KDC(0,t); k.KO(-1,t,"»"); @@ -2813,7 +2812,7 @@ function Keyboard_khmer_angkor() }; this.g_normalise=function(t,e) { var k=KeymanWeb,r=1,m=0; - if(k.KFCM(7,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','ុ','ំ','ា','ំ'])) { // Line 422 + if(k.KFCM(7,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','ុ','ំ','ា','ំ'])) { // Line 419 m=1; k.KDC(7,t); k.KIO(-1,this.s_c_combo_QA,1,t); @@ -2822,7 +2821,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(7,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'ុ','ំ','ា','ំ'])) { // Line 427 + else if(k.KFCM(7,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'ុ','ំ','ា','ំ'])) { // Line 424 m=1; k.KDC(7,t); k.KO(-1,t,"ល"); @@ -2832,7 +2831,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(7,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'ុ','ំ','ា','ំ'])) { // Line 432 + else if(k.KFCM(7,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'ុ','ំ','ា','ំ'])) { // Line 429 m=1; k.KDC(7,t); k.KO(-1,t,"ម"); @@ -2842,7 +2841,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(7,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'ុ','ំ','ា','ំ'])) { // Line 437 + else if(k.KFCM(7,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'ុ','ំ','ា','ំ'])) { // Line 434 m=1; k.KDC(7,t); k.KO(-1,t,"ស"); @@ -2852,7 +2851,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(7,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','ុ','ំ','ា','ំ'])) { // Line 442 + else if(k.KFCM(7,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','ុ','ំ','ា','ំ'])) { // Line 439 m=1; k.KDC(7,t); k.KIO(-1,this.s_c_combo_HA,1,t); @@ -2861,7 +2860,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(7,t,['អ','្','ង','ុ','ំ','ា','ំ'])) { // Line 447 + else if(k.KFCM(7,t,['អ','្','ង','ុ','ំ','ា','ំ'])) { // Line 444 m=1; k.KDC(7,t); k.KO(-1,t,"អ"); @@ -2870,7 +2869,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(7,t,['អ','្','វ','ុ','ំ','ា','ំ'])) { // Line 452 + else if(k.KFCM(7,t,['អ','្','វ','ុ','ំ','ា','ំ'])) { // Line 449 m=1; k.KDC(7,t); k.KO(-1,t,"អ"); @@ -2879,7 +2878,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(7,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'ុ','ំ','ា','ំ'])) { // Line 459 + else if(k.KFCM(7,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'ុ','ំ','ា','ំ'])) { // Line 456 m=1; k.KDC(7,t); k.KO(-1,t,"ល"); @@ -2889,7 +2888,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(7,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'ុ','ំ','ា','ំ'])) { // Line 464 + else if(k.KFCM(7,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'ុ','ំ','ា','ំ'])) { // Line 461 m=1; k.KDC(7,t); k.KO(-1,t,"ម"); @@ -2899,7 +2898,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['្','ដ',{t:'a',a:this.s_v_combo_N},'ំ','្','រ'])) { // Line 393 + else if(k.KFCM(6,t,['្','ដ',{t:'a',a:this.s_v_combo_N},'ំ','្','រ'])) { // Line 390 m=1; k.KDC(6,t); k.KO(-1,t,"្ត"); @@ -2908,7 +2907,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_v_combo_N,3,t); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['្','ដ',{t:'a',a:this.s_v_combo_R},'ះ','្','រ'])) { // Line 394 + else if(k.KFCM(6,t,['្','ដ',{t:'a',a:this.s_v_combo_R},'ះ','្','រ'])) { // Line 391 m=1; k.KDC(6,t); k.KO(-1,t,"្ត"); @@ -2917,7 +2916,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_v_combo_R,3,t); k.KO(-1,t,"ះ"); } - else if(k.KFCM(6,t,['្','រ',{t:'a',a:this.s_v_combo_N},'ំ','្','ដ'])) { // Line 397 + else if(k.KFCM(6,t,['្','រ',{t:'a',a:this.s_v_combo_N},'ំ','្','ដ'])) { // Line 394 m=1; k.KDC(6,t); k.KO(-1,t,"្ត"); @@ -2926,7 +2925,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_v_combo_N,3,t); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['្','រ',{t:'a',a:this.s_v_combo_R},'ះ','្','ដ'])) { // Line 398 + else if(k.KFCM(6,t,['្','រ',{t:'a',a:this.s_v_combo_R},'ះ','្','ដ'])) { // Line 395 m=1; k.KDC(6,t); k.KO(-1,t,"្ត"); @@ -2935,7 +2934,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_v_combo_R,3,t); k.KO(-1,t,"ះ"); } - else if(k.KFCM(6,t,['្','រ',{t:'a',a:this.s_v_combo_N},'ំ','្',{t:'a',a:this.s_subcons}])) { // Line 403 + else if(k.KFCM(6,t,['្','រ',{t:'a',a:this.s_v_combo_N},'ំ','្',{t:'a',a:this.s_subcons}])) { // Line 400 m=1; k.KDC(6,t); k.KO(-1,t,"្"); @@ -2945,7 +2944,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_v_combo_N,3,t); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['្','រ',{t:'a',a:this.s_v_combo_R},'ះ','្',{t:'a',a:this.s_subcons}])) { // Line 404 + else if(k.KFCM(6,t,['្','រ',{t:'a',a:this.s_v_combo_R},'ះ','្',{t:'a',a:this.s_subcons}])) { // Line 401 m=1; k.KDC(6,t); k.KO(-1,t,"្"); @@ -2955,7 +2954,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_v_combo_R,3,t); k.KO(-1,t,"ះ"); } - else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','ុ','ា','ំ'])) { // Line 420 + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','ុ','ា','ំ'])) { // Line 417 m=1; k.KDC(6,t); k.KIO(-1,this.s_c_combo_QA,1,t); @@ -2964,7 +2963,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'ុ','ា','ំ'])) { // Line 425 + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'ុ','ា','ំ'])) { // Line 422 m=1; k.KDC(6,t); k.KO(-1,t,"ល"); @@ -2974,7 +2973,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'ុ','ា','ំ'])) { // Line 430 + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'ុ','ា','ំ'])) { // Line 427 m=1; k.KDC(6,t); k.KO(-1,t,"ម"); @@ -2984,7 +2983,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'ុ','ា','ំ'])) { // Line 435 + else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'ុ','ា','ំ'])) { // Line 432 m=1; k.KDC(6,t); k.KO(-1,t,"ស"); @@ -2994,7 +2993,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','ុ','ា','ំ'])) { // Line 440 + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','ុ','ា','ំ'])) { // Line 437 m=1; k.KDC(6,t); k.KIO(-1,this.s_c_combo_HA,1,t); @@ -3003,7 +3002,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['អ','្','ង','ុ','ា','ំ'])) { // Line 445 + else if(k.KFCM(6,t,['អ','្','ង','ុ','ា','ំ'])) { // Line 442 m=1; k.KDC(6,t); k.KO(-1,t,"អ"); @@ -3012,7 +3011,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['អ','្','វ','ុ','ា','ំ'])) { // Line 450 + else if(k.KFCM(6,t,['អ','្','វ','ុ','ា','ំ'])) { // Line 447 m=1; k.KDC(6,t); k.KO(-1,t,"អ"); @@ -3021,7 +3020,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'ុ','ា','ំ'])) { // Line 457 + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'ុ','ា','ំ'])) { // Line 454 m=1; k.KDC(6,t); k.KO(-1,t,"ល"); @@ -3031,7 +3030,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'ុ','ា','ំ'])) { // Line 462 + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'ុ','ា','ំ'])) { // Line 459 m=1; k.KDC(6,t); k.KO(-1,t,"ម"); @@ -3041,7 +3040,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'៊',{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo}])) { // Line 484 + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'៊',{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo}])) { // Line 481 m=1; k.KDC(6,t); k.KO(-1,t,"ល"); @@ -3051,7 +3050,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_v_gen,5,t); k.KIO(-1,this.s_v_pseudo,6,t); } - else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'៊',{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo}])) { // Line 485 + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'៊',{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo}])) { // Line 482 m=1; k.KDC(6,t); k.KO(-1,t,"ម"); @@ -3061,7 +3060,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_v_gen,5,t); k.KIO(-1,this.s_v_pseudo,6,t); } - else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','៉','ា','ំ'])) { // Line 518 + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','៉','ា','ំ'])) { // Line 515 m=1; k.KDC(6,t); k.KIO(-1,this.s_c_combo_QA,1,t); @@ -3070,7 +3069,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'៉','ា','ំ'])) { // Line 519 + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'៉','ា','ំ'])) { // Line 516 m=1; k.KDC(6,t); k.KO(-1,t,"ល"); @@ -3080,7 +3079,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'៉','ា','ំ'])) { // Line 520 + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'៉','ា','ំ'])) { // Line 517 m=1; k.KDC(6,t); k.KO(-1,t,"ម"); @@ -3090,7 +3089,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'៉','ា','ំ'])) { // Line 521 + else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'៉','ា','ំ'])) { // Line 518 m=1; k.KDC(6,t); k.KO(-1,t,"ស"); @@ -3100,7 +3099,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','៉','ា','ំ'])) { // Line 522 + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','៉','ា','ំ'])) { // Line 519 m=1; k.KDC(6,t); k.KIO(-1,this.s_c_combo_HA,1,t); @@ -3109,7 +3108,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['អ','្','ង','៉','ា','ំ'])) { // Line 523 + else if(k.KFCM(6,t,['អ','្','ង','៉','ា','ំ'])) { // Line 520 m=1; k.KDC(6,t); k.KO(-1,t,"អ"); @@ -3118,7 +3117,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['អ','្','វ','៉','ា','ំ'])) { // Line 524 + else if(k.KFCM(6,t,['អ','្','វ','៉','ា','ំ'])) { // Line 521 m=1; k.KDC(6,t); k.KO(-1,t,"អ"); @@ -3127,7 +3126,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','ា','ុ','ំ'])) { // Line 531 + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','ា','ុ','ំ'])) { // Line 528 m=1; k.KDC(6,t); k.KIO(-1,this.s_c_combo_QA,1,t); @@ -3136,7 +3135,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','ុ','ំ','ា'])) { // Line 532 + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','ុ','ំ','ា'])) { // Line 529 m=1; k.KDC(6,t); k.KIO(-1,this.s_c_combo_QA,1,t); @@ -3145,7 +3144,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'ា','ុ','ំ'])) { // Line 534 + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'ា','ុ','ំ'])) { // Line 531 m=1; k.KDC(6,t); k.KO(-1,t,"ល"); @@ -3155,7 +3154,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'ុ','ំ','ា'])) { // Line 535 + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'ុ','ំ','ា'])) { // Line 532 m=1; k.KDC(6,t); k.KO(-1,t,"ល"); @@ -3165,7 +3164,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'ា','ុ','ំ'])) { // Line 537 + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'ា','ុ','ំ'])) { // Line 534 m=1; k.KDC(6,t); k.KO(-1,t,"ម"); @@ -3175,7 +3174,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'ុ','ំ','ា'])) { // Line 538 + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'ុ','ំ','ា'])) { // Line 535 m=1; k.KDC(6,t); k.KO(-1,t,"ម"); @@ -3185,7 +3184,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'ា','ុ','ំ'])) { // Line 540 + else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'ា','ុ','ំ'])) { // Line 537 m=1; k.KDC(6,t); k.KO(-1,t,"ស"); @@ -3195,7 +3194,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'ុ','ំ','ា'])) { // Line 541 + else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'ុ','ំ','ា'])) { // Line 538 m=1; k.KDC(6,t); k.KO(-1,t,"ស"); @@ -3205,7 +3204,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','ា','ុ','ំ'])) { // Line 543 + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','ា','ុ','ំ'])) { // Line 540 m=1; k.KDC(6,t); k.KIO(-1,this.s_c_combo_HA,1,t); @@ -3214,7 +3213,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','ុ','ំ','ា'])) { // Line 544 + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','ុ','ំ','ា'])) { // Line 541 m=1; k.KDC(6,t); k.KIO(-1,this.s_c_combo_HA,1,t); @@ -3223,7 +3222,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['អ','្','ង','ា','ុ','ំ'])) { // Line 546 + else if(k.KFCM(6,t,['អ','្','ង','ា','ុ','ំ'])) { // Line 543 m=1; k.KDC(6,t); k.KO(-1,t,"អ"); @@ -3232,7 +3231,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['អ','្','ង','ុ','ំ','ា'])) { // Line 547 + else if(k.KFCM(6,t,['អ','្','ង','ុ','ំ','ា'])) { // Line 544 m=1; k.KDC(6,t); k.KO(-1,t,"អ"); @@ -3241,7 +3240,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['អ','្','វ','ា','ុ','ំ'])) { // Line 549 + else if(k.KFCM(6,t,['អ','្','វ','ា','ុ','ំ'])) { // Line 546 m=1; k.KDC(6,t); k.KO(-1,t,"អ"); @@ -3250,7 +3249,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['អ','្','វ','ុ','ំ','ា'])) { // Line 550 + else if(k.KFCM(6,t,['អ','្','វ','ុ','ំ','ា'])) { // Line 547 m=1; k.KDC(6,t); k.KO(-1,t,"អ"); @@ -3259,7 +3258,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ុ"); k.KO(-1,t,"ា"); } - else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'ា','ុ','ំ'])) { // Line 557 + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'ា','ុ','ំ'])) { // Line 554 m=1; k.KDC(6,t); k.KO(-1,t,"ល"); @@ -3269,7 +3268,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'ុ','ំ','ា'])) { // Line 558 + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'ុ','ំ','ា'])) { // Line 555 m=1; k.KDC(6,t); k.KO(-1,t,"ល"); @@ -3279,7 +3278,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'ា','ុ','ំ'])) { // Line 560 + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'ា','ុ','ំ'])) { // Line 557 m=1; k.KDC(6,t); k.KO(-1,t,"ម"); @@ -3289,7 +3288,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'ុ','ំ','ា'])) { // Line 561 + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'ុ','ំ','ា'])) { // Line 558 m=1; k.KDC(6,t); k.KO(-1,t,"ម"); @@ -3299,28 +3298,28 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','េ','ុ','ី'])) { // Line 569 + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','េ','ុ','ី'])) { // Line 566 m=1; k.KDC(6,t); k.KIO(-1,this.s_c_combo_QA,1,t); k.KO(-1,t,"្"); k.KO(-1,t,"អ៊ើ"); } - else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','ុ','េ','ី'])) { // Line 570 + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','ុ','េ','ី'])) { // Line 567 m=1; k.KDC(6,t); k.KIO(-1,this.s_c_combo_QA,1,t); k.KO(-1,t,"្"); k.KO(-1,t,"អ៊ើ"); } - else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','៉','េ','ី'])) { // Line 571 + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','៉','េ','ី'])) { // Line 568 m=1; k.KDC(6,t); k.KIO(-1,this.s_c_combo_QA,1,t); k.KO(-1,t,"្"); k.KO(-1,t,"អ៊ើ"); } - else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'េ','ុ','ី'])) { // Line 573 + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'េ','ុ','ី'])) { // Line 570 m=1; k.KDC(6,t); k.KO(-1,t,"ល"); @@ -3328,7 +3327,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_c_1st_combo_LO,3,t); k.KO(-1,t,"៊ើ"); } - else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'ុ','េ','ី'])) { // Line 574 + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'ុ','េ','ី'])) { // Line 571 m=1; k.KDC(6,t); k.KO(-1,t,"ល"); @@ -3336,7 +3335,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_c_1st_combo_LO,3,t); k.KO(-1,t,"៊ើ"); } - else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'៉','េ','ី'])) { // Line 575 + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'៉','េ','ី'])) { // Line 572 m=1; k.KDC(6,t); k.KO(-1,t,"ល"); @@ -3344,7 +3343,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_c_1st_combo_LO,3,t); k.KO(-1,t,"៊ើ"); } - else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'េ','ុ','ី'])) { // Line 577 + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'េ','ុ','ី'])) { // Line 574 m=1; k.KDC(6,t); k.KO(-1,t,"ម"); @@ -3352,7 +3351,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_c_1st_combo_MO,3,t); k.KO(-1,t,"៊ើ"); } - else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'ុ','េ','ី'])) { // Line 578 + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'ុ','េ','ី'])) { // Line 575 m=1; k.KDC(6,t); k.KO(-1,t,"ម"); @@ -3360,7 +3359,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_c_1st_combo_MO,3,t); k.KO(-1,t,"៊ើ"); } - else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'៉','េ','ី'])) { // Line 579 + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'៉','េ','ី'])) { // Line 576 m=1; k.KDC(6,t); k.KO(-1,t,"ម"); @@ -3368,7 +3367,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_c_1st_combo_MO,3,t); k.KO(-1,t,"៊ើ"); } - else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'េ','ុ','ី'])) { // Line 581 + else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'េ','ុ','ី'])) { // Line 578 m=1; k.KDC(6,t); k.KO(-1,t,"ស"); @@ -3376,7 +3375,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_c_combo_SA,3,t); k.KO(-1,t,"៊ើ"); } - else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'ុ','េ','ី'])) { // Line 582 + else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'ុ','េ','ី'])) { // Line 579 m=1; k.KDC(6,t); k.KO(-1,t,"ស"); @@ -3384,7 +3383,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_c_combo_SA,3,t); k.KO(-1,t,"៊ើ"); } - else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'៉','េ','ី'])) { // Line 583 + else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'៉','េ','ី'])) { // Line 580 m=1; k.KDC(6,t); k.KO(-1,t,"ស"); @@ -3392,70 +3391,70 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_c_combo_SA,3,t); k.KO(-1,t,"៊ើ"); } - else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','េ','ុ','ី'])) { // Line 585 + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','េ','ុ','ី'])) { // Line 582 m=1; k.KDC(6,t); k.KIO(-1,this.s_c_combo_HA,1,t); k.KO(-1,t,"្"); k.KO(-1,t,"ហ៊ើ"); } - else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','ុ','េ','ី'])) { // Line 586 + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','ុ','េ','ី'])) { // Line 583 m=1; k.KDC(6,t); k.KIO(-1,this.s_c_combo_HA,1,t); k.KO(-1,t,"្"); k.KO(-1,t,"ហ៊ើ"); } - else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','៉','េ','ី'])) { // Line 587 + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','៉','េ','ី'])) { // Line 584 m=1; k.KDC(6,t); k.KIO(-1,this.s_c_combo_HA,1,t); k.KO(-1,t,"្"); k.KO(-1,t,"ហ៊ើ"); } - else if(k.KFCM(6,t,['អ','្','ង','េ','ុ','ី'])) { // Line 589 + else if(k.KFCM(6,t,['អ','្','ង','េ','ុ','ី'])) { // Line 586 m=1; k.KDC(6,t); k.KO(-1,t,"អ"); k.KO(-1,t,"្"); k.KO(-1,t,"ង៊ើ"); } - else if(k.KFCM(6,t,['អ','្','ង','ុ','េ','ី'])) { // Line 590 + else if(k.KFCM(6,t,['អ','្','ង','ុ','េ','ី'])) { // Line 587 m=1; k.KDC(6,t); k.KO(-1,t,"អ"); k.KO(-1,t,"្"); k.KO(-1,t,"ង៊ើ"); } - else if(k.KFCM(6,t,['អ','្','ង','៉','េ','ី'])) { // Line 591 + else if(k.KFCM(6,t,['អ','្','ង','៉','េ','ី'])) { // Line 588 m=1; k.KDC(6,t); k.KO(-1,t,"អ"); k.KO(-1,t,"្"); k.KO(-1,t,"ង៊ើ"); } - else if(k.KFCM(6,t,['អ','្','វ','េ','ុ','ី'])) { // Line 593 + else if(k.KFCM(6,t,['អ','្','វ','េ','ុ','ី'])) { // Line 590 m=1; k.KDC(6,t); k.KO(-1,t,"អ"); k.KO(-1,t,"្"); k.KO(-1,t,"វ៊ើ"); } - else if(k.KFCM(6,t,['អ','្','វ','ុ','េ','ី'])) { // Line 594 + else if(k.KFCM(6,t,['អ','្','វ','ុ','េ','ី'])) { // Line 591 m=1; k.KDC(6,t); k.KO(-1,t,"អ"); k.KO(-1,t,"្"); k.KO(-1,t,"វ៊ើ"); } - else if(k.KFCM(6,t,['អ','្','វ','៉','េ','ី'])) { // Line 595 + else if(k.KFCM(6,t,['អ','្','វ','៉','េ','ី'])) { // Line 592 m=1; k.KDC(6,t); k.KO(-1,t,"អ"); k.KO(-1,t,"្"); k.KO(-1,t,"វ៊ើ"); } - else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'េ','ុ','ី'])) { // Line 603 + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'េ','ុ','ី'])) { // Line 600 m=1; k.KDC(6,t); k.KO(-1,t,"ល"); @@ -3463,7 +3462,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_c_2nd_combo_LO,3,t); k.KO(-1,t,"៉ើ"); } - else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'ុ','េ','ី'])) { // Line 604 + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'ុ','េ','ី'])) { // Line 601 m=1; k.KDC(6,t); k.KO(-1,t,"ល"); @@ -3471,7 +3470,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_c_2nd_combo_LO,3,t); k.KO(-1,t,"៉ើ"); } - else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'៊','េ','ី'])) { // Line 605 + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'៊','េ','ី'])) { // Line 602 m=1; k.KDC(6,t); k.KO(-1,t,"ល"); @@ -3479,7 +3478,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_c_2nd_combo_LO,3,t); k.KO(-1,t,"៉ើ"); } - else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'េ','ុ','ី'])) { // Line 607 + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'េ','ុ','ី'])) { // Line 604 m=1; k.KDC(6,t); k.KO(-1,t,"ម"); @@ -3487,7 +3486,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_c_2nd_combo_MO,3,t); k.KO(-1,t,"៉ើ"); } - else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'ុ','េ','ី'])) { // Line 608 + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'ុ','េ','ី'])) { // Line 605 m=1; k.KDC(6,t); k.KO(-1,t,"ម"); @@ -3495,7 +3494,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_c_2nd_combo_MO,3,t); k.KO(-1,t,"៉ើ"); } - else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'៊','េ','ី'])) { // Line 609 + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'៊','េ','ី'])) { // Line 606 m=1; k.KDC(6,t); k.KO(-1,t,"ម"); @@ -3503,7 +3502,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_c_2nd_combo_MO,3,t); k.KO(-1,t,"៉ើ"); } - else if(k.KFCM(5,t,[{t:'a',a:this.s_c_shifter},{t:'a',a:this.s_v_combo_N},'ំ','្',{t:'a',a:this.s_subcons}])) { // Line 384 + else if(k.KFCM(5,t,[{t:'a',a:this.s_c_shifter},{t:'a',a:this.s_v_combo_N},'ំ','្',{t:'a',a:this.s_subcons}])) { // Line 381 m=1; k.KDC(5,t); k.KO(-1,t,"្"); @@ -3512,7 +3511,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_v_combo_N,2,t); k.KO(-1,t,"ំ"); } - else if(k.KFCM(5,t,[{t:'a',a:this.s_c_shifter},{t:'a',a:this.s_v_combo_R},'ះ','្',{t:'a',a:this.s_subcons}])) { // Line 385 + else if(k.KFCM(5,t,[{t:'a',a:this.s_c_shifter},{t:'a',a:this.s_v_combo_R},'ះ','្',{t:'a',a:this.s_subcons}])) { // Line 382 m=1; k.KDC(5,t); k.KO(-1,t,"្"); @@ -3521,7 +3520,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_v_combo_R,2,t); k.KO(-1,t,"ះ"); } - else if(k.KFCM(5,t,['្','ដ',{t:'a',a:this.s_v_any},'្','រ'])) { // Line 392 + else if(k.KFCM(5,t,['្','ដ',{t:'a',a:this.s_v_any},'្','រ'])) { // Line 389 m=1; k.KDC(5,t); k.KO(-1,t,"្ត"); @@ -3529,7 +3528,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"រ"); k.KIO(-1,this.s_v_any,3,t); } - else if(k.KFCM(5,t,['្','រ',{t:'a',a:this.s_v_any},'្','ដ'])) { // Line 396 + else if(k.KFCM(5,t,['្','រ',{t:'a',a:this.s_v_any},'្','ដ'])) { // Line 393 m=1; k.KDC(5,t); k.KO(-1,t,"្ត"); @@ -3537,7 +3536,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"រ"); k.KIO(-1,this.s_v_any,3,t); } - else if(k.KFCM(5,t,['្','រ',{t:'a',a:this.s_c_shifter},'្',{t:'a',a:this.s_subcons}])) { // Line 400 + else if(k.KFCM(5,t,['្','រ',{t:'a',a:this.s_c_shifter},'្',{t:'a',a:this.s_subcons}])) { // Line 397 m=1; k.KDC(5,t); k.KO(-1,t,"្"); @@ -3546,7 +3545,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"រ"); k.KIO(-1,this.s_c_shifter,3,t); } - else if(k.KFCM(5,t,['្','រ',{t:'a',a:this.s_v_any},'្',{t:'a',a:this.s_subcons}])) { // Line 402 + else if(k.KFCM(5,t,['្','រ',{t:'a',a:this.s_v_any},'្',{t:'a',a:this.s_subcons}])) { // Line 399 m=1; k.KDC(5,t); k.KO(-1,t,"្"); @@ -3555,7 +3554,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"រ"); k.KIO(-1,this.s_v_any,3,t); } - else if(k.KFCM(5,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','ុ',{t:'a',a:this.s_v_above}])) { // Line 419 + else if(k.KFCM(5,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','ុ',{t:'a',a:this.s_v_above}])) { // Line 416 m=1; k.KDC(5,t); k.KIO(-1,this.s_c_combo_QA,1,t); @@ -3563,7 +3562,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"អ៊"); k.KIO(-1,this.s_v_above,5,t); } - else if(k.KFCM(5,t,[{t:'a',a:this.s_c_combo_QA},'្','អ',{t:'a',a:this.s_v_above},'ុ'])) { // Line 421 + else if(k.KFCM(5,t,[{t:'a',a:this.s_c_combo_QA},'្','អ',{t:'a',a:this.s_v_above},'ុ'])) { // Line 418 m=1; k.KDC(5,t); k.KIO(-1,this.s_c_combo_QA,1,t); @@ -3571,7 +3570,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"អ៊"); k.KIO(-1,this.s_v_above,4,t); } - else if(k.KFCM(5,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'ុ',{t:'a',a:this.s_v_above}])) { // Line 424 + else if(k.KFCM(5,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'ុ',{t:'a',a:this.s_v_above}])) { // Line 421 m=1; k.KDC(5,t); k.KO(-1,t,"ល"); @@ -3580,7 +3579,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៊"); k.KIO(-1,this.s_v_above,5,t); } - else if(k.KFCM(5,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},{t:'a',a:this.s_v_above},'ុ'])) { // Line 426 + else if(k.KFCM(5,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},{t:'a',a:this.s_v_above},'ុ'])) { // Line 423 m=1; k.KDC(5,t); k.KO(-1,t,"ល"); @@ -3589,7 +3588,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៊"); k.KIO(-1,this.s_v_above,4,t); } - else if(k.KFCM(5,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'ុ',{t:'a',a:this.s_v_above}])) { // Line 429 + else if(k.KFCM(5,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'ុ',{t:'a',a:this.s_v_above}])) { // Line 426 m=1; k.KDC(5,t); k.KO(-1,t,"ម"); @@ -3598,7 +3597,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៊"); k.KIO(-1,this.s_v_above,5,t); } - else if(k.KFCM(5,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},{t:'a',a:this.s_v_above},'ុ'])) { // Line 431 + else if(k.KFCM(5,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},{t:'a',a:this.s_v_above},'ុ'])) { // Line 428 m=1; k.KDC(5,t); k.KO(-1,t,"ម"); @@ -3607,7 +3606,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៊"); k.KIO(-1,this.s_v_above,4,t); } - else if(k.KFCM(5,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'ុ',{t:'a',a:this.s_v_above}])) { // Line 434 + else if(k.KFCM(5,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'ុ',{t:'a',a:this.s_v_above}])) { // Line 431 m=1; k.KDC(5,t); k.KO(-1,t,"ស"); @@ -3616,7 +3615,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៊"); k.KIO(-1,this.s_v_above,5,t); } - else if(k.KFCM(5,t,['ស','្',{t:'a',a:this.s_c_combo_SA},{t:'a',a:this.s_v_above},'ុ'])) { // Line 436 + else if(k.KFCM(5,t,['ស','្',{t:'a',a:this.s_c_combo_SA},{t:'a',a:this.s_v_above},'ុ'])) { // Line 433 m=1; k.KDC(5,t); k.KO(-1,t,"ស"); @@ -3625,7 +3624,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៊"); k.KIO(-1,this.s_v_above,4,t); } - else if(k.KFCM(5,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','ុ',{t:'a',a:this.s_v_above}])) { // Line 439 + else if(k.KFCM(5,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','ុ',{t:'a',a:this.s_v_above}])) { // Line 436 m=1; k.KDC(5,t); k.KIO(-1,this.s_c_combo_HA,1,t); @@ -3633,7 +3632,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ហ៊"); k.KIO(-1,this.s_v_above,5,t); } - else if(k.KFCM(5,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ',{t:'a',a:this.s_v_above},'ុ'])) { // Line 441 + else if(k.KFCM(5,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ',{t:'a',a:this.s_v_above},'ុ'])) { // Line 438 m=1; k.KDC(5,t); k.KIO(-1,this.s_c_combo_HA,1,t); @@ -3641,7 +3640,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ហ៊"); k.KIO(-1,this.s_v_above,4,t); } - else if(k.KFCM(5,t,['អ','្','ង','ុ',{t:'a',a:this.s_v_above}])) { // Line 444 + else if(k.KFCM(5,t,['អ','្','ង','ុ',{t:'a',a:this.s_v_above}])) { // Line 441 m=1; k.KDC(5,t); k.KO(-1,t,"អ"); @@ -3649,7 +3648,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ង៊"); k.KIO(-1,this.s_v_above,5,t); } - else if(k.KFCM(5,t,['អ','្','ង',{t:'a',a:this.s_v_above},'ុ'])) { // Line 446 + else if(k.KFCM(5,t,['អ','្','ង',{t:'a',a:this.s_v_above},'ុ'])) { // Line 443 m=1; k.KDC(5,t); k.KO(-1,t,"អ"); @@ -3657,7 +3656,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ង៊"); k.KIO(-1,this.s_v_above,4,t); } - else if(k.KFCM(5,t,['អ','្','វ','ុ',{t:'a',a:this.s_v_above}])) { // Line 449 + else if(k.KFCM(5,t,['អ','្','វ','ុ',{t:'a',a:this.s_v_above}])) { // Line 446 m=1; k.KDC(5,t); k.KO(-1,t,"អ"); @@ -3665,7 +3664,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"វ៊"); k.KIO(-1,this.s_v_above,5,t); } - else if(k.KFCM(5,t,['អ','្','វ',{t:'a',a:this.s_v_above},'ុ'])) { // Line 451 + else if(k.KFCM(5,t,['អ','្','វ',{t:'a',a:this.s_v_above},'ុ'])) { // Line 448 m=1; k.KDC(5,t); k.KO(-1,t,"អ"); @@ -3673,7 +3672,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"វ៊"); k.KIO(-1,this.s_v_above,4,t); } - else if(k.KFCM(5,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'ុ',{t:'a',a:this.s_v_above}])) { // Line 456 + else if(k.KFCM(5,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'ុ',{t:'a',a:this.s_v_above}])) { // Line 453 m=1; k.KDC(5,t); k.KO(-1,t,"ល"); @@ -3682,7 +3681,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៉"); k.KIO(-1,this.s_v_above,5,t); } - else if(k.KFCM(5,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},{t:'a',a:this.s_v_above},'ុ'])) { // Line 458 + else if(k.KFCM(5,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},{t:'a',a:this.s_v_above},'ុ'])) { // Line 455 m=1; k.KDC(5,t); k.KO(-1,t,"ល"); @@ -3691,7 +3690,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៉"); k.KIO(-1,this.s_v_above,4,t); } - else if(k.KFCM(5,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'ុ',{t:'a',a:this.s_v_above}])) { // Line 461 + else if(k.KFCM(5,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'ុ',{t:'a',a:this.s_v_above}])) { // Line 458 m=1; k.KDC(5,t); k.KO(-1,t,"ម"); @@ -3700,7 +3699,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៉"); k.KIO(-1,this.s_v_above,5,t); } - else if(k.KFCM(5,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},{t:'a',a:this.s_v_above},'ុ'])) { // Line 463 + else if(k.KFCM(5,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},{t:'a',a:this.s_v_above},'ុ'])) { // Line 460 m=1; k.KDC(5,t); k.KO(-1,t,"ម"); @@ -3709,7 +3708,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៉"); k.KIO(-1,this.s_v_above,4,t); } - else if(k.KFCM(5,t,[{t:'a',a:this.s_shiftable_c_1st},'ុ','ំ','ា','ំ'])) { // Line 471 + else if(k.KFCM(5,t,[{t:'a',a:this.s_shiftable_c_1st},'ុ','ំ','ា','ំ'])) { // Line 468 m=1; k.KDC(5,t); k.KIO(-1,this.s_shiftable_c_1st,1,t); @@ -3717,7 +3716,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(5,t,[{t:'a',a:this.s_shiftable_c_2nd},'ុ','ំ','ា','ំ'])) { // Line 478 + else if(k.KFCM(5,t,[{t:'a',a:this.s_shiftable_c_2nd},'ុ','ំ','ា','ំ'])) { // Line 475 m=1; k.KDC(5,t); k.KIO(-1,this.s_shiftable_c_2nd,1,t); @@ -3725,7 +3724,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(5,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'៊',{t:'a',a:this.s_v_above}])) { // Line 482 + else if(k.KFCM(5,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO},'៊',{t:'a',a:this.s_v_above}])) { // Line 479 m=1; k.KDC(5,t); k.KO(-1,t,"ល"); @@ -3734,7 +3733,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៉"); k.KIO(-1,this.s_v_above,5,t); } - else if(k.KFCM(5,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'៊',{t:'a',a:this.s_v_above}])) { // Line 483 + else if(k.KFCM(5,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO},'៊',{t:'a',a:this.s_v_above}])) { // Line 480 m=1; k.KDC(5,t); k.KO(-1,t,"ម"); @@ -3743,7 +3742,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៉"); k.KIO(-1,this.s_v_above,5,t); } - else if(k.KFCM(5,t,['្',{t:'a',a:this.s_shiftable_c_2nd},'៊',{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo}])) { // Line 493 + else if(k.KFCM(5,t,['្',{t:'a',a:this.s_shiftable_c_2nd},'៊',{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo}])) { // Line 490 m=1; k.KDC(5,t); k.KO(-1,t,"្"); @@ -3752,7 +3751,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_v_gen,4,t); k.KIO(-1,this.s_v_pseudo,5,t); } - else if(k.KFCM(5,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','៉',{t:'a',a:this.s_v_above}])) { // Line 511 + else if(k.KFCM(5,t,[{t:'a',a:this.s_c_combo_QA},'្','អ','៉',{t:'a',a:this.s_v_above}])) { // Line 508 m=1; k.KDC(5,t); k.KIO(-1,this.s_c_combo_QA,1,t); @@ -3760,7 +3759,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"អ៊"); k.KIO(-1,this.s_v_above,5,t); } - else if(k.KFCM(5,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'៉',{t:'a',a:this.s_v_above}])) { // Line 512 + else if(k.KFCM(5,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO},'៉',{t:'a',a:this.s_v_above}])) { // Line 509 m=1; k.KDC(5,t); k.KO(-1,t,"ល"); @@ -3769,7 +3768,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៊"); k.KIO(-1,this.s_v_above,5,t); } - else if(k.KFCM(5,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'៉',{t:'a',a:this.s_v_above}])) { // Line 513 + else if(k.KFCM(5,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO},'៉',{t:'a',a:this.s_v_above}])) { // Line 510 m=1; k.KDC(5,t); k.KO(-1,t,"ម"); @@ -3778,7 +3777,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៊"); k.KIO(-1,this.s_v_above,5,t); } - else if(k.KFCM(5,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'៉',{t:'a',a:this.s_v_above}])) { // Line 514 + else if(k.KFCM(5,t,['ស','្',{t:'a',a:this.s_c_combo_SA},'៉',{t:'a',a:this.s_v_above}])) { // Line 511 m=1; k.KDC(5,t); k.KO(-1,t,"ស"); @@ -3787,7 +3786,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៊"); k.KIO(-1,this.s_v_above,5,t); } - else if(k.KFCM(5,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','៉',{t:'a',a:this.s_v_above}])) { // Line 515 + else if(k.KFCM(5,t,[{t:'a',a:this.s_c_combo_HA},'្','ហ','៉',{t:'a',a:this.s_v_above}])) { // Line 512 m=1; k.KDC(5,t); k.KIO(-1,this.s_c_combo_HA,1,t); @@ -3795,7 +3794,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ហ៊"); k.KIO(-1,this.s_v_above,5,t); } - else if(k.KFCM(5,t,['អ','្','ង','៉',{t:'a',a:this.s_v_above}])) { // Line 516 + else if(k.KFCM(5,t,['អ','្','ង','៉',{t:'a',a:this.s_v_above}])) { // Line 513 m=1; k.KDC(5,t); k.KO(-1,t,"អ"); @@ -3803,7 +3802,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ង៊"); k.KIO(-1,this.s_v_above,5,t); } - else if(k.KFCM(5,t,['អ','្','វ','៉',{t:'a',a:this.s_v_above}])) { // Line 517 + else if(k.KFCM(5,t,['អ','្','វ','៉',{t:'a',a:this.s_v_above}])) { // Line 514 m=1; k.KDC(5,t); k.KO(-1,t,"អ"); @@ -3811,20 +3810,20 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"វ៊"); k.KIO(-1,this.s_v_above,5,t); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_c_shifter},{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo},{t:'a',a:this.s_c_shifter}])) { // Line 353 + else if(k.KFCM(4,t,[{t:'a',a:this.s_c_shifter},{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo},{t:'a',a:this.s_c_shifter}])) { // Line 350 m=1; k.KDC(4,t); k.KIO(-1,this.s_v_gen,2,t); k.KIO(-1,this.s_v_pseudo,3,t); k.KIO(-1,this.s_c_shifter,4,t); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo},{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo}])) { // Line 365 + else if(k.KFCM(4,t,[{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo},{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo}])) { // Line 362 m=1; k.KDC(4,t); k.KIO(-1,this.s_v_gen,3,t); k.KIO(-1,this.s_v_pseudo,4,t); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_v_combo_N},'ំ','្',{t:'a',a:this.s_subcons}])) { // Line 378 + else if(k.KFCM(4,t,[{t:'a',a:this.s_v_combo_N},'ំ','្',{t:'a',a:this.s_subcons}])) { // Line 375 m=1; k.KDC(4,t); k.KO(-1,t,"្"); @@ -3832,7 +3831,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_v_combo_N,1,t); k.KO(-1,t,"ំ"); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_v_combo_R},'ះ','្',{t:'a',a:this.s_subcons}])) { // Line 379 + else if(k.KFCM(4,t,[{t:'a',a:this.s_v_combo_R},'ះ','្',{t:'a',a:this.s_subcons}])) { // Line 376 m=1; k.KDC(4,t); k.KO(-1,t,"្"); @@ -3840,7 +3839,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_v_combo_R,1,t); k.KO(-1,t,"ះ"); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_c_shifter},{t:'a',a:this.s_v_any},'្',{t:'a',a:this.s_subcons}])) { // Line 383 + else if(k.KFCM(4,t,[{t:'a',a:this.s_c_shifter},{t:'a',a:this.s_v_any},'្',{t:'a',a:this.s_subcons}])) { // Line 380 m=1; k.KDC(4,t); k.KO(-1,t,"្"); @@ -3848,21 +3847,21 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_c_shifter,1,t); k.KIO(-1,this.s_v_any,2,t); } - else if(k.KFCM(4,t,['្','ដ','្','រ'])) { // Line 389 + else if(k.KFCM(4,t,['្','ដ','្','រ'])) { // Line 386 m=1; k.KDC(4,t); k.KO(-1,t,"្ត"); k.KO(-1,t,"្"); k.KO(-1,t,"រ"); } - else if(k.KFCM(4,t,['្','រ','្','ដ'])) { // Line 390 + else if(k.KFCM(4,t,['្','រ','្','ដ'])) { // Line 387 m=1; k.KDC(4,t); k.KO(-1,t,"្ត"); k.KO(-1,t,"្"); k.KO(-1,t,"រ"); } - else if(k.KFCM(4,t,['្','រ','្',{t:'a',a:this.s_subcons}])) { // Line 401 + else if(k.KFCM(4,t,['្','រ','្',{t:'a',a:this.s_subcons}])) { // Line 398 m=1; k.KDC(4,t); k.KO(-1,t,"្"); @@ -3870,7 +3869,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"្"); k.KO(-1,t,"រ"); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st},'ុ','ា','ំ'])) { // Line 469 + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st},'ុ','ា','ំ'])) { // Line 466 m=1; k.KDC(4,t); k.KIO(-1,this.s_shiftable_c_1st,1,t); @@ -3878,7 +3877,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd},'ុ','ា','ំ'])) { // Line 476 + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd},'ុ','ា','ំ'])) { // Line 473 m=1; k.KDC(4,t); k.KIO(-1,this.s_shiftable_c_2nd,1,t); @@ -3886,7 +3885,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd},'៊',{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo}])) { // Line 490 + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd},'៊',{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo}])) { // Line 487 m=1; k.KDC(4,t); k.KIO(-1,this.s_shiftable_c_2nd,1,t); @@ -3894,7 +3893,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_v_gen,3,t); k.KIO(-1,this.s_v_pseudo,4,t); } - else if(k.KFCM(4,t,['្',{t:'a',a:this.s_shiftable_c_2nd},'៊',{t:'a',a:this.s_v_above}])) { // Line 492 + else if(k.KFCM(4,t,['្',{t:'a',a:this.s_shiftable_c_2nd},'៊',{t:'a',a:this.s_v_above}])) { // Line 489 m=1; k.KDC(4,t); k.KO(-1,t,"្"); @@ -3902,43 +3901,43 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"៊"); k.KIO(-1,this.s_v_above,4,t); } - else if(k.KFCM(4,t,['ប','្','យ',{t:'a',a:this.s_c_shifter}])) { // Line 497 + else if(k.KFCM(4,t,['ប','្','យ',{t:'a',a:this.s_c_shifter}])) { // Line 494 m=1; k.KDC(4,t); k.KO(-1,t,"ប្យ"); k.KIO(-1,this.s_c_shifter,4,t); } - else if(k.KFCM(4,t,['ស','្','ប',{t:'a',a:this.s_c_shifter}])) { // Line 498 + else if(k.KFCM(4,t,['ស','្','ប',{t:'a',a:this.s_c_shifter}])) { // Line 495 m=1; k.KDC(4,t); k.KO(-1,t,"ស្ប"); k.KIO(-1,this.s_c_shifter,4,t); } - else if(k.KFCM(4,t,['ឆ','្','ប',{t:'a',a:this.s_c_shifter}])) { // Line 499 + else if(k.KFCM(4,t,['ឆ','្','ប',{t:'a',a:this.s_c_shifter}])) { // Line 496 m=1; k.KDC(4,t); k.KO(-1,t,"ឆ្ប"); k.KIO(-1,this.s_c_shifter,4,t); } - else if(k.KFCM(4,t,['ប','្','យ',{t:'a',a:this.s_c_shifter}])) { // Line 500 + else if(k.KFCM(4,t,['ប','្','យ',{t:'a',a:this.s_c_shifter}])) { // Line 497 m=1; k.KDC(4,t); k.KO(-1,t,"ប្យ"); k.KIO(-1,this.s_c_shifter,4,t); } - else if(k.KFCM(4,t,['ស','្','ប',{t:'a',a:this.s_c_shifter}])) { // Line 501 + else if(k.KFCM(4,t,['ស','្','ប',{t:'a',a:this.s_c_shifter}])) { // Line 498 m=1; k.KDC(4,t); k.KO(-1,t,"ស្ប"); k.KIO(-1,this.s_c_shifter,4,t); } - else if(k.KFCM(4,t,['ឆ','្','ប',{t:'a',a:this.s_c_shifter}])) { // Line 502 + else if(k.KFCM(4,t,['ឆ','្','ប',{t:'a',a:this.s_c_shifter}])) { // Line 499 m=1; k.KDC(4,t); k.KO(-1,t,"ឆ្ប"); k.KIO(-1,this.s_c_shifter,4,t); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st},'៉',{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo}])) { // Line 507 + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st},'៉',{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo}])) { // Line 504 m=1; k.KDC(4,t); k.KIO(-1,this.s_shiftable_c_1st,1,t); @@ -3946,7 +3945,7 @@ function Keyboard_khmer_angkor() k.KIO(-1,this.s_v_gen,3,t); k.KIO(-1,this.s_v_pseudo,4,t); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st},'ា','ុ','ំ'])) { // Line 528 + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st},'ា','ុ','ំ'])) { // Line 525 m=1; k.KDC(4,t); k.KIO(-1,this.s_shiftable_c_1st,1,t); @@ -3954,7 +3953,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st},'ុ','ំ','ា'])) { // Line 529 + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st},'ុ','ំ','ា'])) { // Line 526 m=1; k.KDC(4,t); k.KIO(-1,this.s_shiftable_c_1st,1,t); @@ -3962,7 +3961,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd},'ា','ុ','ំ'])) { // Line 554 + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd},'ា','ុ','ំ'])) { // Line 551 m=1; k.KDC(4,t); k.KIO(-1,this.s_shiftable_c_2nd,1,t); @@ -3970,7 +3969,7 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd},'ុ','ំ','ា'])) { // Line 555 + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd},'ុ','ំ','ា'])) { // Line 552 m=1; k.KDC(4,t); k.KIO(-1,this.s_shiftable_c_2nd,1,t); @@ -3978,268 +3977,268 @@ function Keyboard_khmer_angkor() k.KO(-1,t,"ា"); k.KO(-1,t,"ំ"); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st},'េ','ុ','ី'])) { // Line 565 + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st},'េ','ុ','ី'])) { // Line 562 m=1; k.KDC(4,t); k.KIO(-1,this.s_shiftable_c_1st,1,t); k.KO(-1,t,"៊ើ"); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st},'ុ','េ','ី'])) { // Line 566 + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st},'ុ','េ','ី'])) { // Line 563 m=1; k.KDC(4,t); k.KIO(-1,this.s_shiftable_c_1st,1,t); k.KO(-1,t,"៊ើ"); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st},'៉','េ','ី'])) { // Line 567 + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st},'៉','េ','ី'])) { // Line 564 m=1; k.KDC(4,t); k.KIO(-1,this.s_shiftable_c_1st,1,t); k.KO(-1,t,"៊ើ"); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd},'េ','ុ','ី'])) { // Line 599 + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd},'េ','ុ','ី'])) { // Line 596 m=1; k.KDC(4,t); k.KIO(-1,this.s_shiftable_c_2nd,1,t); k.KO(-1,t,"៉ើ"); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd},'ុ','េ','ី'])) { // Line 600 + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd},'ុ','េ','ី'])) { // Line 597 m=1; k.KDC(4,t); k.KIO(-1,this.s_shiftable_c_2nd,1,t); k.KO(-1,t,"៉ើ"); } - else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd},'៊','េ','ី'])) { // Line 601 + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd},'៊','េ','ី'])) { // Line 598 m=1; k.KDC(4,t); k.KIO(-1,this.s_shiftable_c_2nd,1,t); k.KO(-1,t,"៉ើ"); } - else if(k.KFCM(3,t,[{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo},{t:'a',a:this.s_c_shifter}])) { // Line 351 + else if(k.KFCM(3,t,[{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo},{t:'a',a:this.s_c_shifter}])) { // Line 348 m=1; k.KDC(3,t); k.KIO(-1,this.s_c_shifter,3,t); k.KIO(-1,this.s_v_gen,1,t); k.KIO(-1,this.s_v_pseudo,2,t); } - else if(k.KFCM(3,t,[{t:'a',a:this.s_c_shifter},{t:'a',a:this.s_v_any},{t:'a',a:this.s_c_shifter}])) { // Line 352 + else if(k.KFCM(3,t,[{t:'a',a:this.s_c_shifter},{t:'a',a:this.s_v_any},{t:'a',a:this.s_c_shifter}])) { // Line 349 m=1; k.KDC(3,t); k.KIO(-1,this.s_c_shifter,3,t); k.KIO(-1,this.s_v_any,2,t); } - else if(k.KFCM(3,t,[{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo},{t:'a',a:this.s_v_gen}])) { // Line 361 + else if(k.KFCM(3,t,[{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo},{t:'a',a:this.s_v_gen}])) { // Line 358 m=1; k.KDC(3,t); k.KIO(-1,this.s_v_gen,3,t); } - else if(k.KFCM(3,t,[{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo},{t:'a',a:this.s_v_pseudo}])) { // Line 362 + else if(k.KFCM(3,t,[{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo},{t:'a',a:this.s_v_pseudo}])) { // Line 359 m=1; k.KDC(3,t); k.KIO(-1,this.s_v_pseudo,3,t); } - else if(k.KFCM(3,t,[{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo}])) { // Line 363 + else if(k.KFCM(3,t,[{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo}])) { // Line 360 m=1; k.KDC(3,t); k.KIO(-1,this.s_v_gen,2,t); k.KIO(-1,this.s_v_pseudo,3,t); } - else if(k.KFCM(3,t,[{t:'a',a:this.s_v_pseudo},{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo}])) { // Line 364 + else if(k.KFCM(3,t,[{t:'a',a:this.s_v_pseudo},{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo}])) { // Line 361 m=1; k.KDC(3,t); k.KIO(-1,this.s_v_gen,2,t); k.KIO(-1,this.s_v_pseudo,3,t); } - else if(k.KFCM(3,t,['្',{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo}])) { // Line 373 + else if(k.KFCM(3,t,['្',{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_pseudo}])) { // Line 370 m=1; k.KDC(3,t); k.KIO(-1,this.s_v_gen,2,t); k.KIO(-1,this.s_v_pseudo,3,t); } - else if(k.KFCM(3,t,[{t:'a',a:this.s_v_any},'្',{t:'a',a:this.s_subcons}])) { // Line 377 + else if(k.KFCM(3,t,[{t:'a',a:this.s_v_any},'្',{t:'a',a:this.s_subcons}])) { // Line 374 m=1; k.KDC(3,t); k.KO(-1,t,"្"); k.KIO(-1,this.s_subcons,3,t); k.KIO(-1,this.s_v_any,1,t); } - else if(k.KFCM(3,t,[{t:'a',a:this.s_c_shifter},'្',{t:'a',a:this.s_subcons}])) { // Line 408 + else if(k.KFCM(3,t,[{t:'a',a:this.s_c_shifter},'្',{t:'a',a:this.s_subcons}])) { // Line 405 m=1; k.KDC(3,t); k.KO(-1,t,"្"); k.KIO(-1,this.s_subcons,3,t); k.KIO(-1,this.s_c_shifter,1,t); } - else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_1st},'ុ',{t:'a',a:this.s_v_above}])) { // Line 468 + else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_1st},'ុ',{t:'a',a:this.s_v_above}])) { // Line 465 m=1; k.KDC(3,t); k.KIO(-1,this.s_shiftable_c_1st,1,t); k.KO(-1,t,"៊"); k.KIO(-1,this.s_v_above,3,t); } - else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_1st},{t:'a',a:this.s_v_above},'ុ'])) { // Line 470 + else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_1st},{t:'a',a:this.s_v_above},'ុ'])) { // Line 467 m=1; k.KDC(3,t); k.KIO(-1,this.s_shiftable_c_1st,1,t); k.KO(-1,t,"៊"); k.KIO(-1,this.s_v_above,2,t); } - else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_2nd},'ុ',{t:'a',a:this.s_v_above}])) { // Line 475 + else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_2nd},'ុ',{t:'a',a:this.s_v_above}])) { // Line 472 m=1; k.KDC(3,t); k.KIO(-1,this.s_shiftable_c_2nd,1,t); k.KO(-1,t,"៉"); k.KIO(-1,this.s_v_above,3,t); } - else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_2nd},{t:'a',a:this.s_v_above},'ុ'])) { // Line 477 + else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_2nd},{t:'a',a:this.s_v_above},'ុ'])) { // Line 474 m=1; k.KDC(3,t); k.KIO(-1,this.s_shiftable_c_2nd,1,t); k.KO(-1,t,"៉"); k.KIO(-1,this.s_v_above,2,t); } - else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_2nd},'៊',{t:'a',a:this.s_v_above}])) { // Line 489 + else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_2nd},'៊',{t:'a',a:this.s_v_above}])) { // Line 486 m=1; k.KDC(3,t); k.KIO(-1,this.s_shiftable_c_2nd,1,t); k.KO(-1,t,"៉"); k.KIO(-1,this.s_v_above,3,t); } - else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_1st},'៉',{t:'a',a:this.s_v_above}])) { // Line 506 + else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_1st},'៉',{t:'a',a:this.s_v_above}])) { // Line 503 m=1; k.KDC(3,t); k.KIO(-1,this.s_shiftable_c_1st,1,t); k.KO(-1,t,"៊"); k.KIO(-1,this.s_v_above,3,t); } - else if(k.KFCM(3,t,['ណ','្','ត'])) { // Line 613 + else if(k.KFCM(3,t,['ណ','្','ត'])) { // Line 610 m=1; k.KDC(3,t); k.KO(-1,t,"ណ"); k.KO(-1,t,"្ដ"); } - else if(k.KFCM(3,t,['ន','្','ដ'])) { // Line 614 + else if(k.KFCM(3,t,['ន','្','ដ'])) { // Line 611 m=1; k.KDC(3,t); k.KO(-1,t,"ន"); k.KO(-1,t,"្ត"); } - else if(k.KFCM(3,t,['ទ','្','ប'])) { // Line 618 + else if(k.KFCM(3,t,['ទ','្','ប'])) { // Line 615 m=1; k.KDC(3,t); k.KO(-1,t,"ឡ"); } - else if(k.KFCM(3,t,['ប','្','ញ'])) { // Line 620 + else if(k.KFCM(3,t,['ប','្','ញ'])) { // Line 617 m=1; k.KDC(3,t); k.KO(-1,t,"ឫ"); } - else if(k.KFCM(3,t,['ព','្','ញ'])) { // Line 626 + else if(k.KFCM(3,t,['ព','្','ញ'])) { // Line 623 m=1; k.KDC(3,t); k.KO(-1,t,"ឭ"); } - else if(k.KFCM(3,t,['ព','្','ឋ'])) { // Line 629 + else if(k.KFCM(3,t,['ព','្','ឋ'])) { // Line 626 m=1; k.KDC(3,t); k.KO(-1,t,"ឰ"); } - else if(k.KFCM(3,t,['ដ','្','ធ'])) { // Line 637 + else if(k.KFCM(3,t,['ដ','្','ធ'])) { // Line 634 m=1; k.KDC(3,t); k.KO(-1,t,"ដ្ឋ"); } - else if(k.KFCM(3,t,['ទ','្','ឋ'])) { // Line 638 + else if(k.KFCM(3,t,['ទ','្','ឋ'])) { // Line 635 m=1; k.KDC(3,t); k.KO(-1,t,"ទ្ធ"); } - else if(k.KFCM(2,t,['េ','ា'])) { // Line 338 + else if(k.KFCM(2,t,['េ','ា'])) { // Line 335 m=1; k.KDC(2,t); k.KO(-1,t,"ោ"); } - else if(k.KFCM(2,t,['ា','េ'])) { // Line 339 + else if(k.KFCM(2,t,['ា','េ'])) { // Line 336 m=1; k.KDC(2,t); k.KO(-1,t,"ោ"); } - else if(k.KFCM(2,t,['េ','ី'])) { // Line 340 + else if(k.KFCM(2,t,['េ','ី'])) { // Line 337 m=1; k.KDC(2,t); k.KO(-1,t,"ើ"); } - else if(k.KFCM(2,t,['ី','េ'])) { // Line 341 + else if(k.KFCM(2,t,['ី','េ'])) { // Line 338 m=1; k.KDC(2,t); k.KO(-1,t,"ើ"); } - else if(k.KFCM(2,t,['ំ','ុ'])) { // Line 345 + else if(k.KFCM(2,t,['ំ','ុ'])) { // Line 342 m=1; k.KDC(2,t); k.KO(-1,t,"ុំ"); } - else if(k.KFCM(2,t,['ំ','ា'])) { // Line 346 + else if(k.KFCM(2,t,['ំ','ា'])) { // Line 343 m=1; k.KDC(2,t); k.KO(-1,t,"ាំ"); } - else if(k.KFCM(2,t,[{t:'a',a:this.s_v_any},{t:'a',a:this.s_c_shifter}])) { // Line 350 + else if(k.KFCM(2,t,[{t:'a',a:this.s_v_any},{t:'a',a:this.s_c_shifter}])) { // Line 347 m=1; k.KDC(2,t); k.KIO(-1,this.s_c_shifter,2,t); k.KIO(-1,this.s_v_any,1,t); } - else if(k.KFCM(2,t,[{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_gen}])) { // Line 357 + else if(k.KFCM(2,t,[{t:'a',a:this.s_v_gen},{t:'a',a:this.s_v_gen}])) { // Line 354 m=1; k.KDC(2,t); k.KIO(-1,this.s_v_gen,2,t); } - else if(k.KFCM(2,t,[{t:'a',a:this.s_v_pseudo},{t:'a',a:this.s_v_pseudo}])) { // Line 366 + else if(k.KFCM(2,t,[{t:'a',a:this.s_v_pseudo},{t:'a',a:this.s_v_pseudo}])) { // Line 363 m=1; k.KDC(2,t); k.KIO(-1,this.s_v_pseudo,2,t); } - else if(k.KFCM(2,t,['្','្'])) { // Line 371 + else if(k.KFCM(2,t,['្','្'])) { // Line 368 m=1; k.KDC(2,t); k.KO(-1,t,"្"); } - else if(k.KFCM(2,t,['្',{t:'a',a:this.s_v_any}])) { // Line 372 + else if(k.KFCM(2,t,['្',{t:'a',a:this.s_v_any}])) { // Line 369 m=1; k.KDC(2,t); k.KIO(-1,this.s_v_any,2,t); } - else if(k.KFCM(2,t,['ឫ','ុ'])) { // Line 621 + else if(k.KFCM(2,t,['ឫ','ុ'])) { // Line 618 m=1; k.KDC(2,t); k.KO(-1,t,"ឬ"); } - else if(k.KFCM(2,t,['ឭ','ា'])) { // Line 623 + else if(k.KFCM(2,t,['ឭ','ា'])) { // Line 620 m=1; k.KDC(2,t); k.KO(-1,t,"ញ"); } - else if(k.KFCM(2,t,['ឮ','ា'])) { // Line 624 + else if(k.KFCM(2,t,['ឮ','ា'])) { // Line 621 m=1; k.KDC(2,t); k.KO(-1,t,"ញ"); } - else if(k.KFCM(2,t,['ឭ','ុ'])) { // Line 627 + else if(k.KFCM(2,t,['ឭ','ុ'])) { // Line 624 m=1; k.KDC(2,t); k.KO(-1,t,"ឮ"); } - else if(k.KFCM(2,t,['ឧ','ិ'])) { // Line 631 + else if(k.KFCM(2,t,['ឧ','ិ'])) { // Line 628 m=1; k.KDC(2,t); k.KO(-1,t,"ឱ"); } - else if(k.KFCM(2,t,['ឧ','៌'])) { // Line 632 + else if(k.KFCM(2,t,['ឧ','៌'])) { // Line 629 m=1; k.KDC(2,t); k.KO(-1,t,"ឱ"); } - else if(k.KFCM(2,t,['ឧ','៍'])) { // Line 633 + else if(k.KFCM(2,t,['ឧ','៍'])) { // Line 630 m=1; k.KDC(2,t); k.KO(-1,t,"ឱ"); -- GitLab From 267fbdd6c0267055bf8efbc6465fa26cb1ecf6f5 Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Sun, 29 Apr 2018 17:26:21 -1000 Subject: [PATCH 019/356] search google if an unqualified url is entered --- .../WebBrowserViewController.swift | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift b/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift index 2e14f2799e..bd825e081f 100644 --- a/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift +++ b/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift @@ -179,8 +179,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 +197,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 -- GitLab From a2fa2ea0dd1712da9f01f386e1bcc334206ba280 Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Mon, 30 Apr 2018 13:41:00 +0700 Subject: [PATCH 020/356] Adds a warning to ambiguous AltGr emulation cases, defaulting to 'on.' --- web/source/kmwosk.ts | 57 ++++++++++++++---- .../resources/keyboards/test_chirality.js | 2 +- .../resources/keyboards/test_chirality.kmn | 2 - .../resources/keyboards/test_chirality.kmx | Bin 1908 -> 1864 bytes 4 files changed, 46 insertions(+), 15 deletions(-) diff --git a/web/source/kmwosk.ts b/web/source/kmwosk.ts index f43ebc0594..bc1fe34cf3 100644 --- a/web/source/kmwosk.ts +++ b/web/source/kmwosk.ts @@ -3094,26 +3094,53 @@ if(!window['keyman']['initialized']) { * @return {boolean} */ osk.emulatesAltGr = function(keyLabels) { - var activeKeyboard = keymanweb.keyboardManager.activeKeyboard; - if(activeKeyboard == null || activeKeyboard['KV'] == null) { + var layers; + + // If we're not chiral, we're not emulating. + if(!keymanweb.keyboardManager.isChiral()) { return false; } - var layers = keyLabels ? keyLabels : activeKeyboard['KV']['KLS']; + if(!keyLabels) { + var activeKeyboard = keymanweb.keyboardManager.activeKeyboard; + if(activeKeyboard == null || activeKeyboard['KV'] == null) { + return false; + } + + layers = activeKeyboard['KV']['KLS']; + } else { + layers = keyLabels; + } + + var emulationMask = osk.modifierCodes['LCTRL'] | osk.modifierCodes['LALT']; - var unshiftedEmulationLayer = layers[osk.getLayerId(osk.modifierCodes['LCTRL'] | osk.modifierCodes['LALT'])]; - var shiftedEmulationLayer = layers[osk.getLayerId(osk.modifierCodes['SHIFT'] | osk.modifierCodes['LCTRL'] | osk.modifierCodes['LALT'])]; + var unshiftedEmulationLayer = layers[osk.getLayerId(emulationMask)]; + var shiftedEmulationLayer = layers[osk.getLayerId(osk.modifierCodes['SHIFT'] | emulationMask)]; // buildDefaultLayout ensures that these are aliased to the original modifier set being emulated. // As a result, we can directly test for reference equality. - if(unshiftedEmulationLayer != layers[osk.getLayerId(osk.modifierCodes['RALT'])]) { + if(unshiftedEmulationLayer != null && + unshiftedEmulationLayer != layers[osk.getLayerId(osk.modifierCodes['RALT'])]) { return false; } - if(shiftedEmulationLayer != layers[osk.getLayerId(osk.modifierCodes['RALT'] | osk.modifierCodes('SHIFT'))]) { + if(shiftedEmulationLayer != null && + shiftedEmulationLayer != layers[osk.getLayerId(osk.modifierCodes['RALT'] | osk.modifierCodes['SHIFT'])]) { return false; } + // It's technically possible for the OSK to not specify anything while allowing chiral input. A last-ditch catch: + + var bitmask = keymanweb.keyboardManager.getKeyboardModifierBitmask(); + if((bitmask & emulationMask) != emulationMask) { + // At least one of the emulation modifiers is never used by the keyboard! We can confirm everything's safe. + return true; + } + + if(unshiftedEmulationLayer == null && shiftedEmulationLayer == null) { + // We've run out of things to go on; we can't detect if chiral AltGr emulation is intended or not. + console.warn("Could not detect if AltGr emulation is safe, but defaulting to active emulation!") + } return true; } @@ -3160,11 +3187,17 @@ if(!window['keyman']['initialized']) { validIdList = [ 'default' ].concat(validIdList); // Automatic AltGr emulation if the 'leftctrl-leftalt' layer is otherwise undefined. - if(osk.emulatesAltGr(keyLabels) && validIdList.indexOf('rightalt') != -1) { - validIdList.push('leftctrl-leftalt'); - validIdList.push('leftctrl-leftalt-shift'); - keyLabels['leftctrl-leftalt'] = keyLabels['rightalt']; - keyLabels['leftctrl-leftalt-shift'] = keyLabels['rightalt-shift']; + if(osk.emulatesAltGr(keyLabels)) { + // We insert only the layers that need to be emulated. + if((validIdList.indexOf('leftctrl-leftalt') == -1) && validIdList.indexOf('rightalt') != -1) { + validIdList.push('leftctrl-leftalt'); + keyLabels['leftctrl-leftalt'] = keyLabels['rightalt']; + } + + if((validIdList.indexOf('leftctrl-leftalt-shift') == -1) && validIdList.indexOf('rightalt-shift') != -1) { + validIdList.push('leftctrl-leftalt-shift'); + keyLabels['leftctrl-leftalt-shift'] = keyLabels['rightalt-shift']; + } } // For desktop devices, we must create all layers, even if invalid. diff --git a/web/unit_tests/resources/keyboards/test_chirality.js b/web/unit_tests/resources/keyboards/test_chirality.js index da50da1312..1011b551b3 100644 --- a/web/unit_tests/resources/keyboards/test_chirality.js +++ b/web/unit_tests/resources/keyboards/test_chirality.js @@ -1 +1 @@ -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_test_chirality());}function Keyboard_test_chirality(){this.KI="Keyboard_test_chirality";this.KN="KeymanWeb Chirality Tester";this.KMINVER="10.0";this.KV={F:' 1em "Arial"',K102:0};this.KDU=1;this.KLS={};this.KV.BK=(function(x){var e=Array.apply(null,Array(65)).map(String.prototype.valueOf,""),r=[],v,i,m=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt'];for(i=m.length-1;i>=0;i--)if((v=x[m[i]])||r.length)r=(v?v:e).slice().concat(r);return r})(this.KLS);this.KH='';this.KM=0;this.KBVER="1.0";this.KMBM=0x031F;this.KVER="10.0.1014.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,16658,65)) {r=m=1;k.KO(0,t,"CAPSLOCK_RC_CAP_a");}else if(k.KKM(e,16666,65)) {r=m=1;k.KO(0,t,"CAPSLOCK_RCA_CAP_a");}else if(k.KKM(e,16664,65)) {r=m=1;k.KO(0,t,"CAPSLOCK_RA_CAP_a");}else if(k.KKM(e,16657,65)) {r=m=1;k.KO(0,t,"CAPSLOCK_LC_CAP_a");}else if(k.KKM(e,16660,65)) {r=m=1;k.KO(0,t,"CAPSLOCK_LA_CAP_a");}else if(k.KKM(e,16642,65)) {r=m=1;k.KO(0,t,"CAPSLOCK_RC_a");}else if(k.KKM(e,16650,65)) {r=m=1;k.KO(0,t,"CAPSLOCK_RCA_a");}else if(k.KKM(e,16648,65)) {r=m=1;k.KO(0,t,"CAPSLOCK_RA_a");}else if(k.KKM(e,16644,65)) {r=m=1;k.KO(0,t,"CAPSLOCK_LA_a");}else if(k.KKM(e,16641,65)) {r=m=1;k.KO(0,t,"CAPSLOCK_LC_a");}else if(k.KKM(e,16645,65)) {r=m=1;k.KO(0,t,"CAPSLOCK_LCA_a");}else if(k.KKM(e,16644,65)) {r=m=1;k.KO(0,t,"CAPSLOCK_LA_a");}else if(k.KKM(e,16641,65)) {r=m=1;k.KO(0,t,"CAPSLOCK_LC_a");}else if(k.KKM(e,16914,65)) {r=m=1;k.KO(0,t,"RC_CAP_a");}else if(k.KKM(e,16922,65)) {r=m=1;k.KO(0,t,"RCA_CAP_a");}else if(k.KKM(e,16920,65)) {r=m=1;k.KO(0,t,"RA_CAP_a");}else if(k.KKM(e,16913,65)) {r=m=1;k.KO(0,t,"LC_CAP_a");}else if(k.KKM(e,16916,65)) {r=m=1;k.KO(0,t,"LA_CAP_a");}else if(k.KKM(e,16898,65)) {r=m=1;k.KO(0,t,"RC_a");}else if(k.KKM(e,16906,65)) {r=m=1;k.KO(0,t,"RCA_a");}else if(k.KKM(e,16904,65)) {r=m=1;k.KO(0,t,"RA_a");}else if(k.KKM(e,16900,65)) {r=m=1;k.KO(0,t,"LA_a");}else if(k.KKM(e,16897,65)) {r=m=1;k.KO(0,t,"LC_a");}else if(k.KKM(e,16901,65)) {r=m=1;k.KO(0,t,"LCA_a");}else if(k.KKM(e,16900,65)) {r=m=1;k.KO(0,t,"LA_a");}else if(k.KKM(e,16897,65)) {r=m=1;k.KO(0,t,"LC_a");}else if(k.KKM(e,16640,65)) {r=m=1;k.KO(0,t,"CAPSLOCK_DF_a");}else if(k.KKM(e,16912,65)) {r=m=1;k.KO(0,t,"DF_CAP_a");}else if(k.KKM(e,16656,65)) {r=m=1;k.KO(0,t,"CAPSLOCK_DF_CAP_a");}else if(k.KKM(e,16896,65)) {r=m=1;k.KO(0,t,"DF_a");}else if(k.KKM(e,16384,66)) {r=m=1;k.KO(0,t,"b");}return r;};} \ No newline at end of file +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_test_chirality());}function Keyboard_test_chirality(){this.KI="Keyboard_test_chirality";this.KN="KeymanWeb Chirality Tester";this.KMINVER="10.0";this.KV={F:' 1em "Arial"',K102:0};this.KDU=1;this.KV.KLS={};this.KV.BK=(function(x){var e=Array.apply(null,Array(65)).map(String.prototype.valueOf,""),r=[],v,i,m=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt'];for(i=m.length-1;i>=0;i--)if((v=x[m[i]])||r.length)r=(v?v:e).slice().concat(r);return r})(this.KV.KLS);this.KH='';this.KM=0;this.KBVER="1.0";this.KMBM=0x031F;this.KVER="10.0.1057.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,16658,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_RC_CAP_a");}else if(k.KKM(e,16666,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_RCA_CAP_a");}else if(k.KKM(e,16664,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_RA_CAP_a");}else if(k.KKM(e,16657,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_LC_CAP_a");}else if(k.KKM(e,16660,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_LA_CAP_a");}else if(k.KKM(e,16642,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_RC_a");}else if(k.KKM(e,16650,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_RCA_a");}else if(k.KKM(e,16648,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_RA_a");}else if(k.KKM(e,16644,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_LA_a");}else if(k.KKM(e,16641,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_LC_a");}else if(k.KKM(e,16645,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_LCA_a");}else if(k.KKM(e,16644,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_LA_a");}else if(k.KKM(e,16641,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_LC_a");}else if(k.KKM(e,16914,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"RC_CAP_a");}else if(k.KKM(e,16922,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"RCA_CAP_a");}else if(k.KKM(e,16920,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"RA_CAP_a");}else if(k.KKM(e,16913,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"LC_CAP_a");}else if(k.KKM(e,16916,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"LA_CAP_a");}else if(k.KKM(e,16898,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"RC_a");}else if(k.KKM(e,16906,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"RCA_a");}else if(k.KKM(e,16904,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"RA_a");}else if(k.KKM(e,16900,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"LA_a");}else if(k.KKM(e,16897,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"LC_a");}else if(k.KKM(e,16901,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"LCA_a");}else if(k.KKM(e,16900,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"LA_a");}else if(k.KKM(e,16897,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"LC_a");}else if(k.KKM(e,16640,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_DF_a");}else if(k.KKM(e,16912,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"DF_CAP_a");}else if(k.KKM(e,16656,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_DF_CAP_a");}else if(k.KKM(e,16896,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"DF_a");}else if(k.KKM(e,16384,66)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"b");}return r;};} \ No newline at end of file diff --git a/web/unit_tests/resources/keyboards/test_chirality.kmn b/web/unit_tests/resources/keyboards/test_chirality.kmn index eb870422e4..e0d4ecbe90 100644 --- a/web/unit_tests/resources/keyboards/test_chirality.kmn +++ b/web/unit_tests/resources/keyboards/test_chirality.kmn @@ -1,8 +1,6 @@ store(&TARGETS) 'any web desktop' store(©RIGHT) '© 2018 SIL International' store(&VISUALKEYBOARD) 'test_chirality.kvks' -store(&LANGUAGE) 'x0409' -store(&WINDOWSLANGUAGES) 'x0409' store(&NAME) 'KeymanWeb Chirality Tester' begin Unicode > use(main) diff --git a/web/unit_tests/resources/keyboards/test_chirality.kmx b/web/unit_tests/resources/keyboards/test_chirality.kmx index 8e276f650aa1a30fad62648053c6cbbd4b28b185..9eed98954574084b344c77010bf18dd26a6f76bd 100644 GIT binary patch literal 1864 zcmb`G!D>@M6oyYiqA?3eL#&|-&8oN(D_UKYnwnB93ACgIU5K$YEiF+iiKrA})$gQACQM-$<9o za>+SC%OBaqH&B&yb7$@09>#Q?s#eUy8Y7)mA zJS%dC>X(U8u4iddMU7f(e^qgvOuBcWBR(gyt{%UaP(}E;NGSUeefoBqLG4)J(}>$K zku`dY4ItL>n}%g!@9?{Z^}#;jzZ;f;9pF#J+xeof9Dc;GBy1Fa)35~W7Jk*R80;zj zrC|}+EBuyWao9HgvthdS3x3})UHc86KGLo)eUV`VOTyOi&kak!Uf^FF7K3fz-x?NyZQ{2Ki^I0@JBI1n_xKNn>DpcV zo?-g(zv2%JOA+@2f1DqaY1dMS6#jx?LfkMuPe=NeN8=~x1y)bRrUF7>OGgbm# z;V;k@9yQieTrW|jp7tzJYj2euUU&C%=^ou?eFfcT_2&LH`+stWy&+|tw^I&bVRs#N tvwjzUnpXCfYoEj3h|la}R39GI`CX06#P2)w+Q)Ri*RUv?W!`c)I(@e1>*)f6Y6JZN(ZBf zJ{9VB=&+1Fpwl7WMHf`loTgRhcUDw=C+;!GP*+9w=zf71$K6>PbWx?(Dp4b3$+NDJdzd+bw&%P}7S~UqEk{=6u!5^E zvP7SiN6NNd4*E1R#vEh1F@Si%OWI(z*dSsPzhzhk_5;6XSijrQBb{Zo_NEaz{B^_P zup)lmuoP?&ziwC(_8i|dECG9i|7=(c_65IfSPyImA3w6+i`$#PXAN_E&)}~ZHgJ{i z0bep~5LU*|8Qe3jf-$IIM}^Ff0Yz#D6p_3HyZqYFGmH4gcM+ z7;Fo_ZCDR%2fu5W+xrv$%P_Zh51-^C8bCa z^HX|>lhII8`BHLh!a@6c-> P)A?SbqHLC#;2-=4s_WKo -- GitLab From c4587e49ea73660bc4acd3ec6197e86663d919a7 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 30 Apr 2018 13:54:44 +0700 Subject: [PATCH 021/356] Fixes #746, fixes #766 -- BCP 47 picker is more complete and more stringent --- .../Keyman.Console.BuildStandardsData.pas | 10 ++ ...man.System.BuildLanguageSubtagRegistry.pas | 120 +++++++++++++++++ .../buildtools/build_standards_data/Makefile | 6 +- .../build_standards_data.dproj | 2 +- windows/src/developer/TIKE/Tike.dpr | 3 +- windows/src/developer/TIKE/Tike.dproj | 3 +- .../TIKE/child/UfrmPackageEditor.dfm | 34 ++--- .../TIKE/child/UfrmPackageEditor.pas | 60 +++++---- ...n.Developer.UI.UfrmSelectBCP47Language.dfm | 93 ++++++++----- ...n.Developer.UI.UfrmSelectBCP47Language.pas | 127 ++++++++++++++---- .../src/global/delphi/general/BCP47Tag.pas | 40 +++++- .../Keyman.System.LanguageCodeUtils.pas | 66 ++++++++- ...man.System.PackageInfoRefreshKeyboards.pas | 2 +- 13 files changed, 448 insertions(+), 118 deletions(-) diff --git a/windows/src/buildtools/build_standards_data/Keyman.Console.BuildStandardsData.pas b/windows/src/buildtools/build_standards_data/Keyman.Console.BuildStandardsData.pas index 83b6f68f3b..4fb15d0b59 100644 --- a/windows/src/buildtools/build_standards_data/Keyman.Console.BuildStandardsData.pas +++ b/windows/src/buildtools/build_standards_data/Keyman.Console.BuildStandardsData.pas @@ -26,6 +26,16 @@ begin TBuildISO6393Registry.Build(ParamStr(2), ParamStr(3)); end else if ParamStr(1) = 'subtag' then + begin + writeln('Building '+ParamStr(3)); + with TBuildLanguageSubtagRegistry.Create(ParamStr(2)) do + try + BuildSubtagRegistry(ParamStr(3)); + finally + Free; + end; + end + else if ParamStr(1) = 'suppress' then begin writeln('Building '+ParamStr(3)); with TBuildLanguageSubtagRegistry.Create(ParamStr(2)) do diff --git a/windows/src/buildtools/build_standards_data/Keyman.System.BuildLanguageSubtagRegistry.pas b/windows/src/buildtools/build_standards_data/Keyman.System.BuildLanguageSubtagRegistry.pas index 81f743c712..5b7fdf99cd 100644 --- a/windows/src/buildtools/build_standards_data/Keyman.System.BuildLanguageSubtagRegistry.pas +++ b/windows/src/buildtools/build_standards_data/Keyman.System.BuildLanguageSubtagRegistry.pas @@ -13,6 +13,7 @@ type constructor Create(ASubtagRegistryFile: string); destructor Destroy; override; procedure BuildSuppressScriptRegistry(const DestinationFile: string); + procedure BuildSubtagRegistry(const DestinationFile: string); end; implementation @@ -22,6 +23,124 @@ uses { TBuildLanguageSubtagRegistry } +procedure TBuildLanguageSubtagRegistry.BuildSubtagRegistry( + const DestinationFile: string); +var + FResult: TStringList; + FLanguages, FScripts, FRegions: TStringList; + + procedure ParseList; + var + i, n: Integer; + line: string; + code: string; + value: string; + FType: string; + FID: string; + FDescription: string; + begin + for i := 0 to FSubtagRegistry.Count-1 do + begin + line := Trim(FSubtagRegistry[i]); + if line = '%%' then + begin + if Pos('..', FID) = 0 then + begin + if FType = 'language' then + FLanguages.Add(FID + '=' + FDescription) + else if FType = 'script' then + FScripts.Add(FID + '=' + FDescription) + else if FType = 'region' then + FRegions.Add(FID + '=' + FDescription); + end; + FType := ''; + Continue; + end; + + n := Pos(':', line); + if n = 0 then + Continue; + + code := Copy(line, 1, n-1); + value := Trim(Copy(line, n+1, MaxInt)); + + if code = 'Type' then + FType := value + else if code = 'Subtag' then + FID := value + else if code = 'Description' then + FDescription := value; + end; + end; + + function Escape(s: string): string; + begin + Result := s.Replace('''', '''''', [rfReplaceAll]); + end; + + procedure AddDict(s: TStringList); + var + i: Integer; + begin + for i := 0 to s.Count - 1 do + FResult.Add(' dict.Add('''+Escape(s.Names[i])+''', '''+Escape(s.ValueFromIndex[i])+''');'); + end; +begin + FResult := TStringList.Create; + FLanguages := TStringList.Create; + FScripts := TStringList.Create; + FRegions := TStringList.Create; + try + ParseList; + FResult.Add('unit Keyman.System.Standards.BCP47SubtagRegistry;'); + FResult.Add(''); + FResult.Add('interface'); + FResult.Add(''); + FResult.Add('// File-Date: '+FormatDateTime('yyyy-mm-dd hh:nn:ss', Now)); + FResult.Add('// Extracted from http://www.iana.org/assignments/language-subtag-registry/language-subtag-registry'); + FResult.Add('// Generated by build_standards_data'); + FResult.Add(''); + FResult.Add('uses'); + FResult.Add(' System.Generics.Collections;'); + FResult.Add(''); + FResult.Add('type'); + FResult.Add(' TBCP47SubtagRegistry = class'); + FResult.Add(' public'); + FResult.Add(' class procedure FillLanguages(dict: TDictionary);'); + FResult.Add(' class procedure FillScripts(dict: TDictionary);'); + FResult.Add(' class procedure FillRegions(dict: TDictionary);'); + FResult.Add(' end;'); + FResult.Add(''); + FResult.Add('implementation'); + FResult.Add(''); + FResult.Add(''); + FResult.Add('{ TBCP47SubtagRegistry }'); + FResult.Add(''); + FResult.Add('class procedure TBCP47SubtagRegistry.FillLanguages(dict: TDictionary);'); + FResult.Add('begin'); + AddDict(FLanguages); + FResult.Add('end;'); + FResult.Add(''); + FResult.Add('class procedure TBCP47SubtagRegistry.FillScripts(dict: TDictionary);'); + FResult.Add('begin'); + AddDict(FScripts); + FResult.Add('end;'); + FResult.Add(''); + FResult.Add('class procedure TBCP47SubtagRegistry.FillRegions(dict: TDictionary);'); + FResult.Add('begin'); + AddDict(FRegions); + FResult.Add('end;'); + FResult.Add(''); + FResult.Add('end.'); + + FResult.SaveToFile(DestinationFile); + finally + FResult.Free; + FLanguages.Free; + FScripts.Free; + FRegions.Free; + end; +end; procedure TBuildLanguageSubtagRegistry.BuildSuppressScriptRegistry(const DestinationFile: string); var @@ -78,6 +197,7 @@ constructor TBuildLanguageSubtagRegistry.Create(ASubtagRegistryFile: string); begin FSubtagRegistry := TStringList.Create; FSubtagRegistry.LoadFromFile(ASubtagRegistryFile); + FSubtagRegistry.Add('%%'); // Force final entry to be processed end; destructor TBuildLanguageSubtagRegistry.Destroy; diff --git a/windows/src/buildtools/build_standards_data/Makefile b/windows/src/buildtools/build_standards_data/Makefile index fa20a7054c..7fc8505b67 100644 --- a/windows/src/buildtools/build_standards_data/Makefile +++ b/windows/src/buildtools/build_standards_data/Makefile @@ -13,7 +13,10 @@ ISO6393_DATA=$(STANDARDS_DATA_PATH)\iso639-3\iso639-3.tab ISO6393_PAS=$(STANDARDS_OUT_PATH)\Keyman.System.Standards.ISO6393ToBCP47Registry.pas SUBTAG_DATA=$(STANDARDS_DATA_PATH)\language-subtag-registry\language-subtag-registry -SUBTAG_PAS=$(STANDARDS_OUT_PATH)\Keyman.System.Standards.BCP47SuppressScriptRegistry.pas +SUBTAG_PAS=$(STANDARDS_OUT_PATH)\Keyman.System.Standards.BCP47SubtagRegistry.pas + +SUPPRESS_DATA=$(STANDARDS_DATA_PATH)\language-subtag-registry\language-subtag-registry +SUPPRESS_PAS=$(STANDARDS_OUT_PATH)\Keyman.System.Standards.BCP47SuppressScriptRegistry.pas LCID_DATA=$(STANDARDS_DATA_PATH)\windows-lcid-to-bcp-47\map_clean_win.txt LCID_PAS=$(STANDARDS_OUT_PATH)\Keyman.System.Standards.LCIDToBCP47Registry.pas @@ -21,6 +24,7 @@ LCID_PAS=$(STANDARDS_OUT_PATH)\Keyman.System.Standards.LCIDToBCP47Registry.pas build: $(DELPHI_MSBUILD) build_standards_data.dproj $(WIN32_TARGET_PATH)\build_standards_data.exe iso6393 $(ISO6393_DATA) $(ISO6393_PAS) + $(WIN32_TARGET_PATH)\build_standards_data.exe suppress $(SUPPRESS_DATA) $(SUPPRESS_PAS) $(WIN32_TARGET_PATH)\build_standards_data.exe subtag $(SUBTAG_DATA) $(SUBTAG_PAS) $(WIN32_TARGET_PATH)\build_standards_data.exe lcid $(LCID_DATA) $(LCID_PAS) diff --git a/windows/src/buildtools/build_standards_data/build_standards_data.dproj b/windows/src/buildtools/build_standards_data/build_standards_data.dproj index f87802831c..ad861c5d22 100644 --- a/windows/src/buildtools/build_standards_data/build_standards_data.dproj +++ b/windows/src/buildtools/build_standards_data/build_standards_data.dproj @@ -1,7 +1,7 @@  {1AD91C23-D720-4EB6-8A90-1C60FFB2FAAD} - 18.2 + 18.4 None build_standards_data.dpr True diff --git a/windows/src/developer/TIKE/Tike.dpr b/windows/src/developer/TIKE/Tike.dpr index 0136c859cd..f36b56d343 100644 --- a/windows/src/developer/TIKE/Tike.dpr +++ b/windows/src/developer/TIKE/Tike.dpr @@ -264,7 +264,8 @@ uses Keyman.System.LanguageCodeUtils in '..\..\global\delphi\general\Keyman.System.LanguageCodeUtils.pas', Keyman.System.RegExGroupHelperRSP19902 in '..\..\global\delphi\general\Keyman.System.RegExGroupHelperRSP19902.pas', Keyman.System.UpdateCheckResponse in '..\..\global\delphi\general\Keyman.System.UpdateCheckResponse.pas', - Keyman.Developer.System.HelpTopics in 'help\Keyman.Developer.System.HelpTopics.pas'; + Keyman.Developer.System.HelpTopics in 'help\Keyman.Developer.System.HelpTopics.pas', + Keyman.System.Standards.BCP47SubtagRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SubtagRegistry.pas'; {$R *.RES} {$R ICONS.RES} diff --git a/windows/src/developer/TIKE/Tike.dproj b/windows/src/developer/TIKE/Tike.dproj index fc3de23643..a4c5545830 100644 --- a/windows/src/developer/TIKE/Tike.dproj +++ b/windows/src/developer/TIKE/Tike.dproj @@ -7,7 +7,7 @@ 1 Application VCL - 18.3 + 18.4 Win32 @@ -504,6 +504,7 @@ + Cfg_2 diff --git a/windows/src/developer/TIKE/child/UfrmPackageEditor.dfm b/windows/src/developer/TIKE/child/UfrmPackageEditor.dfm index 6b73ded39b..fbe4fe8924 100644 --- a/windows/src/developer/TIKE/child/UfrmPackageEditor.dfm +++ b/windows/src/developer/TIKE/child/UfrmPackageEditor.dfm @@ -194,9 +194,6 @@ inherited frmPackageEditor: TfrmPackageEditor object pageFiles: TTabSheet Caption = 'Files' ImageIndex = 3 - ExplicitLeft = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object Panel1: TPanel Left = 0 Top = 0 @@ -353,9 +350,6 @@ inherited frmPackageEditor: TfrmPackageEditor object pageKeyboards: TTabSheet Caption = 'Keyboards' ImageIndex = 5 - ExplicitLeft = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object Panel5: TPanel Left = 0 Top = 0 @@ -515,10 +509,10 @@ inherited frmPackageEditor: TfrmPackageEditor DefaultRowHeight = 16 FixedCols = 0 RowCount = 9 - Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing, goEditing, goTabs] + Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing, goRowSelect] TabOrder = 7 OnClick = gridKeyboardLanguagesClick - OnSetEditText = gridKeyboardLanguagesSetEditText + OnDblClick = gridKeyboardLanguagesDblClick ColWidths = ( 78 64) @@ -534,7 +528,7 @@ inherited frmPackageEditor: TfrmPackageEditor OnClick = cmdKeyboardAddLanguageClick end object cmdKeyboardRemoveLanguage: TButton - Left = 339 + Left = 418 Top = 412 Width = 72 Height = 25 @@ -554,14 +548,21 @@ inherited frmPackageEditor: TfrmPackageEditor ReadOnly = True TabOrder = 4 end + object cmdKeyboardEditLanguage: TButton + Left = 339 + Top = 412 + Width = 73 + Height = 25 + Anchors = [akLeft, akBottom] + Caption = 'Ed&it...' + TabOrder = 10 + OnClick = cmdKeyboardEditLanguageClick + end end end object pageDetails: TTabSheet Caption = 'Details' ImageIndex = 2 - ExplicitLeft = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object Panel2: TPanel Left = 0 Top = 0 @@ -802,9 +803,6 @@ inherited frmPackageEditor: TfrmPackageEditor object pageShortcuts: TTabSheet Caption = 'Shortcuts' ImageIndex = 8 - ExplicitLeft = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object Panel3: TPanel Left = 0 Top = 0 @@ -968,16 +966,10 @@ inherited frmPackageEditor: TfrmPackageEditor object pageSource: TTabSheet Caption = 'Source' ImageIndex = 9 - ExplicitLeft = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 end object pageCompile: TTabSheet Caption = 'Compile' ImageIndex = 1 - ExplicitLeft = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object Panel4: TPanel Left = 0 Top = 0 diff --git a/windows/src/developer/TIKE/child/UfrmPackageEditor.pas b/windows/src/developer/TIKE/child/UfrmPackageEditor.pas index d0bd2b4398..7748f6921d 100644 --- a/windows/src/developer/TIKE/child/UfrmPackageEditor.pas +++ b/windows/src/developer/TIKE/child/UfrmPackageEditor.pas @@ -169,6 +169,7 @@ type chkFollowKeyboardVersion: TCheckBox; lblKeyboardRTL: TLabel; editKeyboardRTL: TEdit; + cmdKeyboardEditLanguage: TButton; procedure cmdCloseClick(Sender: TObject); procedure cmdAddFileClick(Sender: TObject); procedure cmdRemoveFileClick(Sender: TObject); @@ -211,11 +212,11 @@ type procedure cbKeyboardOSKFontClick(Sender: TObject); procedure cbKeyboardDisplayFontClick(Sender: TObject); procedure gridKeyboardLanguagesClick(Sender: TObject); - procedure gridKeyboardLanguagesSetEditText(Sender: TObject; ACol, - ARow: Integer; const Value: string); procedure cmdKeyboardRemoveLanguageClick(Sender: TObject); procedure cmdKeyboardAddLanguageClick(Sender: TObject); procedure chkFollowKeyboardVersionClick(Sender: TObject); + procedure gridKeyboardLanguagesDblClick(Sender: TObject); + procedure cmdKeyboardEditLanguageClick(Sender: TObject); private pack: TKPSFile; FSetup: Integer; @@ -245,7 +246,6 @@ type function SelectedKeyboard: TPackageKeyboard; procedure EnableKeyboardTabControls; function SelectedKeyboardLanguage: TPackageKeyboardLanguage; - function LookupLanguageName(bcp47id: string): string; procedure RefreshKeyboardLanguageList(k: TPackageKeyboard); procedure HandlePackageRefreshError(Sender: TObject; msg: string; State: TProjectLogState); @@ -1456,6 +1456,7 @@ begin e := e and (gridKeyboardLanguages.Row > 0); gridKeyboardLanguages.Enabled := e; cmdKeyboardRemoveLanguage.Enabled := e; + cmdKeyboardEditLanguage.Enabled := e; end; procedure TfrmPackageEditor.gridKeyboardLanguagesClick(Sender: TObject); @@ -1463,40 +1464,40 @@ begin EnableKeyboardTabControls; end; -function TfrmPackageEditor.LookupLanguageName(bcp47id: string): string; +procedure TfrmPackageEditor.gridKeyboardLanguagesDblClick(Sender: TObject); begin - // TODO: BCP47: - Result := bcp47id; + if SelectedKeyboardLanguage <> nil then + cmdKeyboardEditLanguage.Click; end; -procedure TfrmPackageEditor.gridKeyboardLanguagesSetEditText(Sender: TObject; - ACol, ARow: Integer; const Value: string); +procedure TfrmPackageEditor.cmdKeyboardAddLanguageClick(Sender: TObject); var + k: TPackageKeyboard; lang: TPackageKeyboardLanguage; + frm: TfrmSelectBCP47Language; begin - if FSetup > 0 then Exit; - - lang := SelectedKeyboardLanguage; - Assert(Assigned(lang)); + k := SelectedKeyboard; + Assert(Assigned(k)); - if ACol = 0 then - begin - lang.ID := Value; - if lang.Name='' then + frm := TfrmSelectBCP47Language.Create(Application.MainForm); + try + if frm.ShowModal = mrOk then begin - lang.Name := LookupLanguageName(lang.ID); - gridKeyboardLanguages.Cells[1, ARow] := lang.Name; + lang := TPackageKeyboardLanguage.Create(pack); + lang.ID := frm.LanguageID; + lang.Name := frm.LanguageName; + k.Languages.Add(lang); + RefreshKeyboardLanguageList(k); + gridKeyboardLanguages.Row := gridKeyboardLanguages.RowCount - 1; + gridKeyboardLanguagesClick(gridKeyboardLanguages); + Modified := True; end; - end - else if ACol = 1 then - begin - lang.Name := Value; + finally + frm.Free; end; - - Modified := True; end; -procedure TfrmPackageEditor.cmdKeyboardAddLanguageClick(Sender: TObject); +procedure TfrmPackageEditor.cmdKeyboardEditLanguageClick(Sender: TObject); var k: TPackageKeyboard; lang: TPackageKeyboardLanguage; @@ -1505,17 +1506,18 @@ begin k := SelectedKeyboard; Assert(Assigned(k)); + lang := SelectedKeyboardLanguage; + Assert(Assigned(lang)); + frm := TfrmSelectBCP47Language.Create(Application.MainForm); try + frm.LanguageID := lang.ID; + frm.LanguageName := lang.Name; if frm.ShowModal = mrOk then begin - lang := TPackageKeyboardLanguage.Create(pack); lang.ID := frm.LanguageID; lang.Name := frm.LanguageName; - k.Languages.Add(lang); RefreshKeyboardLanguageList(k); - gridKeyboardLanguages.Row := gridKeyboardLanguages.RowCount - 1; - gridKeyboardLanguagesClick(gridKeyboardLanguages); Modified := True; end; finally diff --git a/windows/src/developer/TIKE/dialogs/languages/Keyman.Developer.UI.UfrmSelectBCP47Language.dfm b/windows/src/developer/TIKE/dialogs/languages/Keyman.Developer.UI.UfrmSelectBCP47Language.dfm index ca571d76ff..183084e47f 100644 --- a/windows/src/developer/TIKE/dialogs/languages/Keyman.Developer.UI.UfrmSelectBCP47Language.dfm +++ b/windows/src/developer/TIKE/dialogs/languages/Keyman.Developer.UI.UfrmSelectBCP47Language.dfm @@ -1,13 +1,13 @@ inherited frmSelectBCP47Language: TfrmSelectBCP47Language - ActiveControl = editLanguageTag + ActiveControl = cbLanguageTag BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'Select BCP 47 Tag' - ClientHeight = 186 + ClientHeight = 216 ClientWidth = 436 Position = poScreenCenter OnDestroy = FormDestroy - ExplicitHeight = 215 + ExplicitHeight = 245 PixelsPerInch = 96 TextHeight = 13 object lblLanguageTag: TLabel @@ -16,7 +16,7 @@ inherited frmSelectBCP47Language: TfrmSelectBCP47Language Width = 70 Height = 13 Caption = '&Language tag:' - FocusControl = editLanguageTag + FocusControl = cbLanguageTag end object lblScriptTag: TLabel Left = 8 @@ -24,7 +24,7 @@ inherited frmSelectBCP47Language: TfrmSelectBCP47Language Width = 50 Height = 13 Caption = '&Script tag:' - FocusControl = editScriptTag + FocusControl = cbScriptTag end object lblRegionTag: TLabel Left = 8 @@ -32,7 +32,7 @@ inherited frmSelectBCP47Language: TfrmSelectBCP47Language Width = 56 Height = 13 Caption = '&Region tag:' - FocusControl = editRegionTag + FocusControl = cbRegionTag end object lblBCP47Code: TLabel Left = 8 @@ -50,86 +50,100 @@ inherited frmSelectBCP47Language: TfrmSelectBCP47Language AutoSize = False end object lblLanguageName: TLabel - Left = 224 + Left = 234 Top = 11 Width = 74 Height = 13 Caption = 'language-name' - FocusControl = editLanguageTag + FocusControl = cbLanguageTag end object lblScriptName: TLabel - Left = 224 + Left = 234 Top = 38 Width = 56 Height = 13 Caption = 'script-name' - FocusControl = editLanguageTag + FocusControl = cbLanguageTag end object lblRegionName: TLabel - Left = 224 + Left = 234 Top = 65 Width = 60 Height = 13 Caption = 'region-name' - FocusControl = editLanguageTag + FocusControl = cbLanguageTag + end + object Label1: TLabel + Left = 8 + Top = 153 + Width = 80 + Height = 13 + Caption = 'Language &name:' + FocusControl = editLanguageName end object cmdOK: TButton Left = 272 - Top = 151 + Top = 183 Width = 75 Height = 25 Caption = 'OK' Default = True ModalResult = 1 - TabOrder = 0 + TabOrder = 7 end object cmdCancel: TButton Left = 353 - Top = 151 + Top = 183 Width = 75 Height = 25 Cancel = True Caption = 'Cancel' ModalResult = 2 - TabOrder = 1 + TabOrder = 8 end - object editLanguageTag: TEdit - Left = 84 + object cbLanguageTag: TComboBox + Left = 94 Top = 8 Width = 121 Height = 21 - TabOrder = 2 - OnChange = editLanguageTagChange + MaxLength = 3 + Sorted = True + TabOrder = 0 + OnChange = cbLanguageTagChange end - object editScriptTag: TEdit - Left = 84 + object cbScriptTag: TComboBox + Left = 94 Top = 35 Width = 121 Height = 21 - TabOrder = 3 - OnChange = editScriptTagChange + MaxLength = 4 + Sorted = True + TabOrder = 1 + OnChange = cbScriptTagChange end - object editRegionTag: TEdit - Left = 84 + object cbRegionTag: TComboBox + Left = 94 Top = 62 Width = 121 Height = 21 - TabOrder = 4 - OnChange = editRegionTagChange + MaxLength = 3 + Sorted = True + TabOrder = 2 + OnChange = cbRegionTagChange end object editBCP47Code: TEdit - Left = 84 + Left = 94 Top = 89 Width = 229 Height = 21 TabStop = False ParentColor = True ReadOnly = True - TabOrder = 5 + TabOrder = 3 end object lblLinkToW3C: TLinkLabel Left = 8 - Top = 159 + Top = 191 Width = 194 Height = 17 Caption = @@ -138,4 +152,21 @@ inherited frmSelectBCP47Language: TfrmSelectBCP47Language TabOrder = 6 OnLinkClick = lblLinkToW3CLinkClick end + object editLanguageName: TEdit + Left = 94 + Top = 150 + Width = 186 + Height = 21 + TabOrder = 4 + OnChange = editLanguageNameChange + end + object cmdResetLanguageName: TButton + Left = 286 + Top = 149 + Width = 75 + Height = 23 + Caption = 'R&eset' + TabOrder = 5 + OnClick = cmdResetLanguageNameClick + end end diff --git a/windows/src/developer/TIKE/dialogs/languages/Keyman.Developer.UI.UfrmSelectBCP47Language.pas b/windows/src/developer/TIKE/dialogs/languages/Keyman.Developer.UI.UfrmSelectBCP47Language.pas index 5caba5f6b7..43778a92df 100644 --- a/windows/src/developer/TIKE/dialogs/languages/Keyman.Developer.UI.UfrmSelectBCP47Language.pas +++ b/windows/src/developer/TIKE/dialogs/languages/Keyman.Developer.UI.UfrmSelectBCP47Language.pas @@ -30,9 +30,9 @@ type lblLanguageTag: TLabel; lblScriptTag: TLabel; lblRegionTag: TLabel; - editLanguageTag: TEdit; - editScriptTag: TEdit; - editRegionTag: TEdit; + cbLanguageTag: TComboBox; + cbScriptTag: TComboBox; + cbRegionTag: TComboBox; lblBCP47Code: TLabel; editBCP47Code: TEdit; lblValidateCode: TLabel; @@ -40,41 +40,71 @@ type lblScriptName: TLabel; lblRegionName: TLabel; lblLinkToW3C: TLinkLabel; - procedure editLanguageTagChange(Sender: TObject); + Label1: TLabel; + editLanguageName: TEdit; + cmdResetLanguageName: TButton; + procedure cbLanguageTagChange(Sender: TObject); procedure FormCreate(Sender: TObject); - procedure editScriptTagChange(Sender: TObject); - procedure editRegionTagChange(Sender: TObject); + procedure cbScriptTagChange(Sender: TObject); + procedure cbRegionTagChange(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure lblLinkToW3CLinkClick(Sender: TObject; const Link: string; LinkType: TSysLinkType); + procedure cmdResetLanguageNameClick(Sender: TObject); + procedure editLanguageNameChange(Sender: TObject); private tag: TBCP47Tag; + FCustomLanguageName: Boolean; function GetLanguageID: string; function GetLanguageName: string; - procedure RefreshPreview; + procedure RefreshLanguageName; + procedure SetLanguageID(const Value: string); + procedure SetLanguageName(const Value: string); + function LookupLanguageName: string; protected function GetHelpTopic: string; override; public { Public declarations } - property LanguageID: string read GetLanguageID; - property LanguageName: string read GetLanguageName; + property LanguageID: string read GetLanguageID write SetLanguageID; + property LanguageName: string read GetLanguageName write SetLanguageName; end; implementation uses + System.Generics.Collections, + Keyman.Developer.System.HelpTopics, Keyman.System.KMXFileLanguages, + Keyman.System.LanguageCodeUtils, utilexecute; {$R *.dfm} { TfrmSelectBCP47Language } + procedure TfrmSelectBCP47Language.FormCreate(Sender: TObject); + procedure PopulateComboBoxFromDict(cb: TComboBox; dict: TDictionary); + var + i: Integer; + a: TArray>; + begin + cb.Items.BeginUpdate; + try + a := dict.ToArray; + for i := 0 to Length(a) - 1 do + cb.Items.Add(a[i].Key); + finally + cb.Items.EndUpdate; + end; + end; begin inherited; tag := TBCP47Tag.Create(''); + PopulateComboBoxFromDict(cbLanguageTag, TLanguageCodeUtils.BCP47Languages); + PopulateComboBoxFromDict(cbScriptTag, TLanguageCodeUtils.BCP47Scripts); + PopulateComboBoxFromDict(cbRegionTag, TLanguageCodeUtils.BCP47Regions); end; procedure TfrmSelectBCP47Language.FormDestroy(Sender: TObject); @@ -95,8 +125,7 @@ end; function TfrmSelectBCP47Language.GetLanguageName: string; begin - // TODO: BCP47: per lookup with BCP-47 feature - Result := tag.Tag; + Result := editLanguageName.Text; end; procedure TfrmSelectBCP47Language.lblLinkToW3CLinkClick(Sender: TObject; @@ -105,40 +134,86 @@ begin TUtilExecute.URL(Link); end; -procedure TfrmSelectBCP47Language.editLanguageTagChange(Sender: TObject); +function TfrmSelectBCP47Language.LookupLanguageName: string; +begin + Result := TLanguageCodeUtils.LanguageName(lblLanguageName.Caption, lblScriptName.Caption, lblRegionName.Caption); +end; + +procedure TfrmSelectBCP47Language.cmdResetLanguageNameClick(Sender: TObject); +begin + editLanguageName.Text := LookupLanguageName; + FCustomLanguageName := False; +end; + +procedure TfrmSelectBCP47Language.editLanguageNameChange(Sender: TObject); +begin + FCustomLanguageName := True; +end; + +procedure TfrmSelectBCP47Language.cbLanguageTagChange(Sender: TObject); begin inherited; - // TODO: BCP47: search on language names instead of just taking a tag - tag.Language := TKMXFileLanguages.TranslateISO6393ToBCP47(editLanguageTag.Text); - RefreshPreview; + tag.Language := TKMXFileLanguages.TranslateISO6393ToBCP47(cbLanguageTag.Text); + RefreshLanguageName; end; -procedure TfrmSelectBCP47Language.editRegionTagChange(Sender: TObject); +procedure TfrmSelectBCP47Language.cbRegionTagChange(Sender: TObject); begin inherited; - tag.Region := editRegionTag.Text; - RefreshPreview; + tag.Region := cbRegionTag.Text; + RefreshLanguageName; end; -procedure TfrmSelectBCP47Language.editScriptTagChange(Sender: TObject); +procedure TfrmSelectBCP47Language.cbScriptTagChange(Sender: TObject); begin inherited; - tag.Script := editScriptTag.Text; - RefreshPreview; + tag.Script := cbScriptTag.Text; + RefreshLanguageName; end; -procedure TfrmSelectBCP47Language.RefreshPreview; +procedure TfrmSelectBCP47Language.RefreshLanguageName; var msg: string; + + function GetDictEntry(subtag: string; dict: TDictionary): string; + begin + if subtag = '' then + Result := '' + else if not dict.TryGetValue(subtag, Result) then + Result := subtag; + end; + + begin editBCP47Code.Text := tag.Tag; - lblLanguageName.Caption := tag.Language; // TODO: BCP47: Lookup language name - lblScriptName.Caption := tag.Script; // TODO: BCP47: Lookup script name - lblRegionName.Caption := tag.Region; // TODO: BCP47: Lookup region name - cmdOK.Enabled := tag.IsValid(msg); + lblLanguageName.Caption := GetDictEntry(tag.Language, TLanguageCodeUtils.BCP47Languages); + lblScriptName.Caption := GetDictEntry(tag.Script, TLanguageCodeUtils.BCP47Scripts); + lblRegionName.Caption := GetDictEntry(tag.Region, TLanguageCodeUtils.BCP47Regions); + if not FCustomLanguageName then + begin + editLanguageName.Text := LookupLanguageName; + FCustomLanguageName := False; + end; + cmdOK.Enabled := tag.IsValid(True, msg); if not cmdOK.Enabled then lblValidateCode.Caption := msg else lblValidateCode.Caption := 'This is a valid BCP 47 tag'; end; +procedure TfrmSelectBCP47Language.SetLanguageID(const Value: string); +begin + tag.Tag := Value; + cbLanguageTag.Text := tag.Language; + cbRegionTag.Text := tag.Region; + cbScriptTag.Text := tag.Script; + RefreshLanguageName; + FCustomLanguageName := editLanguageName.Text <> LookupLanguageName; +end; + +procedure TfrmSelectBCP47Language.SetLanguageName(const Value: string); +begin + editLanguageName.Text := Value; + FCustomLanguageName := editLanguageName.Text <> LookupLanguageName; +end; + end. diff --git a/windows/src/global/delphi/general/BCP47Tag.pas b/windows/src/global/delphi/general/BCP47Tag.pas index b1bd2280df..336906530c 100644 --- a/windows/src/global/delphi/general/BCP47Tag.pas +++ b/windows/src/global/delphi/general/BCP47Tag.pas @@ -43,8 +43,8 @@ type procedure Clear; - function IsValid: Boolean; overload; - function IsValid(var msg: string): Boolean; overload; + function IsValid(Constrained: Boolean): Boolean; overload; + function IsValid(Constrained: Boolean; var msg: string): Boolean; overload; function IsCanonical: Boolean; overload; function IsCanonical(var msg: string): Boolean; overload; @@ -117,7 +117,7 @@ begin end; end; -function TBCP47Tag.IsValid(var msg: string): Boolean; +function TBCP47Tag.IsValid(Constrained: Boolean; var msg: string): Boolean; var NewTag: TBCP47Tag; begin @@ -152,13 +152,43 @@ begin begin msg := '''' + Tag + ''' is not a valid BCP 47 tag'; end; + + if Result and Constrained then + begin + NewTag := TBCP47Tag.Create(Tag); + try + // For our constrained use of tags, we allow only Language-Script-Region. + // We only allow 2 or 3 character IDs. + Result := + SameText(NewTag.Language, Language) and + (NewTag.ExtLang = '') and + SameText(NewTag.Script, Script) and + SameText(NewTag.Region, Region) and + (NewTag.Variant = '') and + (NewTag.Extension = '') and + (NewTag.PrivateUse = '') and + (NewTag.Grandfathered = '') and + (NewTag.LangTag_PrivateUse = ''); + + if not Result then + msg := '''' + Tag + ''' must contain only Language-Script-Region' + else + begin + Result := Length(NewTag.Language) <= 3; + if not Result then + msg := '''' + Tag + ''' language component must be no longer than 3 letters'; + end; + finally + NewTag.Free; + end; + end; end; -function TBCP47Tag.IsValid: Boolean; +function TBCP47Tag.IsValid(Constrained: Boolean): Boolean; var msg: string; begin - Result := IsValid(msg); + Result := IsValid(Constrained, msg); end; function TBCP47Tag.IsCanonical(var msg: string): Boolean; diff --git a/windows/src/global/delphi/general/Keyman.System.LanguageCodeUtils.pas b/windows/src/global/delphi/general/Keyman.System.LanguageCodeUtils.pas index ba0fb04062..8e6a5a3df2 100644 --- a/windows/src/global/delphi/general/Keyman.System.LanguageCodeUtils.pas +++ b/windows/src/global/delphi/general/Keyman.System.LanguageCodeUtils.pas @@ -12,9 +12,16 @@ type class var FISO6393ToBCP47: TDictionary; FLCIDToBCP47: TDictionary; + FBCP47Languages: TDictionary; + FBCP47Scripts: TDictionary; + FBCP47Regions: TDictionary; - class procedure BuildISO6393ToBCP47; + class procedure BuildISO6393ToBCP47; static; class procedure BuildLCIDToBCP47; static; + class procedure BuildSubtagRegistry; static; + class function GetBCP47Languages: TDictionary; static; + class function GetBCP47Regions: TDictionary; static; + class function GetBCP47Scripts: TDictionary; static; public class function TranslateISO6393ToBCP47(codes: TStringDynArray): TStringDynArray; overload; static; class function TranslateISO6393ToBCP47(code: string): string; overload; static; // single code @@ -25,12 +32,19 @@ type class function EthnologueCodeListToArray(codes: string): TStringDynArray; static; class function WindowsLanguageListToArray(codes: string): TIntegerDynArray; static; + + class function LanguageName(const LanguageName, ScriptName, RegionName: string): string; + + class property BCP47Languages: TDictionary read GetBCP47Languages; + class property BCP47Scripts: TDictionary read GetBCP47Scripts; + class property BCP47Regions: TDictionary read GetBCP47Regions; end; implementation uses System.SysUtils, + Keyman.System.Standards.BCP47SubtagRegistry, Keyman.System.Standards.ISO6393ToBCP47Registry, Keyman.System.Standards.LCIDToBCP47Registry, @@ -101,6 +115,21 @@ begin TLCIDToBCP47Map.Fill(FLCIDToBCP47); end; +class procedure TLanguageCodeUtils.BuildSubtagRegistry; +begin + if not Assigned(FBCP47Languages) then + begin + FBCP47Languages := TDictionary.Create; + TBCP47SubtagRegistry.FillLanguages(FBCP47Languages); + + FBCP47Scripts := TDictionary.Create; + TBCP47SubtagRegistry.FillScripts(FBCP47Scripts); + + FBCP47Regions := TDictionary.Create; + TBCP47SubtagRegistry.FillRegions(FBCP47Regions); + end; +end; + class function TLanguageCodeUtils.EthnologueCodeListToArray(codes: string): TStringDynArray; var code: string; @@ -116,6 +145,38 @@ begin end; end; +class function TLanguageCodeUtils.GetBCP47Languages: TDictionary; +begin + BuildSubtagRegistry; + Result := FBCP47Languages; +end; + +class function TLanguageCodeUtils.GetBCP47Scripts: TDictionary; +begin + BuildSubtagRegistry; + Result := FBCP47Scripts; +end; + +class function TLanguageCodeUtils.LanguageName(const LanguageName, ScriptName, RegionName: string): string; +begin + Result := LanguageName; + if ScriptName <> '' then + begin + Result := Result + ' ('+ScriptName; + if RegionName <> '' then + Result := Result + ', '+RegionName; + Result := Result + ')'; + end + else if RegionName <> '' then + Result := Result + ' ('+RegionName+')'; +end; + +class function TLanguageCodeUtils.GetBCP47Regions: TDictionary; +begin + BuildSubtagRegistry; + Result := FBCP47Regions; +end; + class function TLanguageCodeUtils.WindowsLanguageListToArray(codes: string): TIntegerDynArray; var code: string; @@ -140,5 +201,8 @@ initialization finalization FreeAndNil(TLanguageCodeUtils.FISO6393ToBCP47); FreeAndNil(TLanguageCodeUtils.FLCIDToBCP47); + FreeAndNil(TLanguageCodeUtils.FBCP47Languages); + FreeAndNil(TLanguageCodeUtils.FBCP47Regions); + FreeAndNil(TLanguageCodeUtils.FBCP47Scripts); end. diff --git a/windows/src/global/delphi/packages/Keyman.System.PackageInfoRefreshKeyboards.pas b/windows/src/global/delphi/packages/Keyman.System.PackageInfoRefreshKeyboards.pas index 28da588c55..47629be6c6 100644 --- a/windows/src/global/delphi/packages/Keyman.System.PackageInfoRefreshKeyboards.pas +++ b/windows/src/global/delphi/packages/Keyman.System.PackageInfoRefreshKeyboards.pas @@ -185,7 +185,7 @@ begin begin with TBCP47Tag.Create(lang.ID) do try - if not IsValid(msg) then + if not IsValid(True, msg) then begin DoError(Format(SError_LanguageTagIsNotValid, [kbd.ID, lang.ID, msg]), plsError); Result := False; -- GitLab From 800042af65da88c6ee97ab5ef8f3a1e2e297aec6 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 30 Apr 2018 14:24:11 +0700 Subject: [PATCH 022/356] Fixup other projects --- windows/src/buildtools/buildpkg/buildpkg.dpr | 3 ++- windows/src/buildtools/buildpkg/buildpkg.dproj | 3 ++- windows/src/desktop/kmshell/kmshell.dpr | 3 ++- windows/src/desktop/kmshell/kmshell.dproj | 11 ++++++----- .../developer/TIKE/compile/ValidateKeyboardInfo.pas | 4 ++-- windows/src/developer/kmcomp/kmcomp.dpr | 3 ++- windows/src/developer/kmcomp/kmcomp.dproj | 3 ++- windows/src/engine/keyman/keyman.dpr | 3 ++- windows/src/engine/keyman/keyman.dproj | 11 ++++++----- windows/src/engine/kmcomapi/kmcomapi.dpr | 3 ++- windows/src/engine/kmcomapi/kmcomapi.dproj | 3 ++- 11 files changed, 30 insertions(+), 20 deletions(-) diff --git a/windows/src/buildtools/buildpkg/buildpkg.dpr b/windows/src/buildtools/buildpkg/buildpkg.dpr index eac51d0ab5..78ec48da9f 100644 --- a/windows/src/buildtools/buildpkg/buildpkg.dpr +++ b/windows/src/buildtools/buildpkg/buildpkg.dpr @@ -68,7 +68,8 @@ uses Keyman.System.LanguageCodeUtils in '..\..\global\delphi\general\Keyman.System.LanguageCodeUtils.pas', Keyman.System.RegExGroupHelperRSP19902 in '..\..\global\delphi\general\Keyman.System.RegExGroupHelperRSP19902.pas', kmxfileconsts in '..\..\global\delphi\general\kmxfileconsts.pas', - BCP47Tag in '..\..\global\delphi\general\BCP47Tag.pas'; + BCP47Tag in '..\..\global\delphi\general\BCP47Tag.pas', + Keyman.System.Standards.BCP47SubtagRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SubtagRegistry.pas'; begin Run; diff --git a/windows/src/buildtools/buildpkg/buildpkg.dproj b/windows/src/buildtools/buildpkg/buildpkg.dproj index 496d1821b4..00187c96a4 100644 --- a/windows/src/buildtools/buildpkg/buildpkg.dproj +++ b/windows/src/buildtools/buildpkg/buildpkg.dproj @@ -7,7 +7,7 @@ 1 Console None - 18.3 + 18.4 Win32 @@ -156,6 +156,7 @@ + Cfg_2 Base diff --git a/windows/src/desktop/kmshell/kmshell.dpr b/windows/src/desktop/kmshell/kmshell.dpr index 0155e274fa..c9e69f55ce 100644 --- a/windows/src/desktop/kmshell/kmshell.dpr +++ b/windows/src/desktop/kmshell/kmshell.dpr @@ -152,7 +152,8 @@ uses Keyman.System.Standards.ISO6393ToBCP47Registry in '..\..\global\delphi\standards\Keyman.System.Standards.ISO6393ToBCP47Registry.pas', Keyman.System.Standards.LCIDToBCP47Registry in '..\..\global\delphi\standards\Keyman.System.Standards.LCIDToBCP47Registry.pas', kmxfileconsts in '..\..\global\delphi\general\kmxfileconsts.pas', - Keyman.System.UpdateCheckResponse in '..\..\global\delphi\general\Keyman.System.UpdateCheckResponse.pas'; + Keyman.System.UpdateCheckResponse in '..\..\global\delphi\general\Keyman.System.UpdateCheckResponse.pas', + Keyman.System.Standards.BCP47SubtagRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SubtagRegistry.pas'; {$R VERSION.RES} {$R manifest.res} diff --git a/windows/src/desktop/kmshell/kmshell.dproj b/windows/src/desktop/kmshell/kmshell.dproj index 0e71d89c1b..9ac34fa303 100644 --- a/windows/src/desktop/kmshell/kmshell.dproj +++ b/windows/src/desktop/kmshell/kmshell.dproj @@ -7,7 +7,7 @@ 1 Application VCL - 18.3 + 18.4 Win32 @@ -295,6 +295,7 @@ + Cfg_2 @@ -390,15 +391,15 @@ true - + - kmshell.exe + .\ true - + - .\ + kmshell.exe true diff --git a/windows/src/developer/TIKE/compile/ValidateKeyboardInfo.pas b/windows/src/developer/TIKE/compile/ValidateKeyboardInfo.pas index 547d64848e..650dbc325a 100644 --- a/windows/src/developer/TIKE/compile/ValidateKeyboardInfo.pas +++ b/windows/src/developer/TIKE/compile/ValidateKeyboardInfo.pas @@ -82,7 +82,7 @@ begin for i := 0 to alangs.Count - 1 do with TBCP47Tag.Create(alangs.Items[i].Value) do try - if not IsValid(msg) then + if not IsValid(False, msg) then Result := Failed(msg); if not IsCanonical(msg) then @@ -97,7 +97,7 @@ begin for i := 0 to olangs.Count - 1 do with TBCP47Tag.Create(olangs.Pairs[i].JsonString.Value) do try - if not IsValid(msg) then + if not IsValid(False, msg) then Result := Failed(msg); if not IsCanonical(msg) then diff --git a/windows/src/developer/kmcomp/kmcomp.dpr b/windows/src/developer/kmcomp/kmcomp.dpr index ae045863b9..1e3b7084ef 100644 --- a/windows/src/developer/kmcomp/kmcomp.dpr +++ b/windows/src/developer/kmcomp/kmcomp.dpr @@ -99,7 +99,8 @@ uses Keyman.System.KeyboardInfoFile in '..\..\global\delphi\keyboards\Keyman.System.KeyboardInfoFile.pas', BCP47Tag in '..\..\global\delphi\general\BCP47Tag.pas', Keyman.System.LanguageCodeUtils in '..\..\global\delphi\general\Keyman.System.LanguageCodeUtils.pas', - Keyman.System.RegExGroupHelperRSP19902 in '..\..\global\delphi\general\Keyman.System.RegExGroupHelperRSP19902.pas'; + Keyman.System.RegExGroupHelperRSP19902 in '..\..\global\delphi\general\Keyman.System.RegExGroupHelperRSP19902.pas', + Keyman.System.Standards.BCP47SubtagRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SubtagRegistry.pas'; {$R icons.RES} {$R version.res} diff --git a/windows/src/developer/kmcomp/kmcomp.dproj b/windows/src/developer/kmcomp/kmcomp.dproj index 45d74c8784..2ef9918983 100644 --- a/windows/src/developer/kmcomp/kmcomp.dproj +++ b/windows/src/developer/kmcomp/kmcomp.dproj @@ -7,7 +7,7 @@ 1 Console None - 18.3 + 18.4 Win32 @@ -202,6 +202,7 @@ + Cfg_2 Base diff --git a/windows/src/engine/keyman/keyman.dpr b/windows/src/engine/keyman/keyman.dpr index e2bb3062bd..6b31ecc9e5 100644 --- a/windows/src/engine/keyman/keyman.dpr +++ b/windows/src/engine/keyman/keyman.dpr @@ -135,7 +135,8 @@ uses Keyman.System.LanguageCodeUtils in '..\..\global\delphi\general\Keyman.System.LanguageCodeUtils.pas', Keyman.System.Standards.ISO6393ToBCP47Registry in '..\..\global\delphi\standards\Keyman.System.Standards.ISO6393ToBCP47Registry.pas', Keyman.System.Standards.LCIDToBCP47Registry in '..\..\global\delphi\standards\Keyman.System.Standards.LCIDToBCP47Registry.pas', - kmxfileconsts in '..\..\global\delphi\general\kmxfileconsts.pas'; + kmxfileconsts in '..\..\global\delphi\general\kmxfileconsts.pas', + Keyman.System.Standards.BCP47SubtagRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SubtagRegistry.pas'; {$R ICONS.RES} {$R VERSION.RES} diff --git a/windows/src/engine/keyman/keyman.dproj b/windows/src/engine/keyman/keyman.dproj index 5d9e00d927..65074d29cf 100644 --- a/windows/src/engine/keyman/keyman.dproj +++ b/windows/src/engine/keyman/keyman.dproj @@ -7,7 +7,7 @@ 1 Console VCL - 18.3 + 18.4 Win32 @@ -260,6 +260,7 @@ + Cfg_2 @@ -322,9 +323,9 @@ False - + - keyman.exe + .\ true @@ -334,9 +335,9 @@ true - + - .\ + keyman.exe true diff --git a/windows/src/engine/kmcomapi/kmcomapi.dpr b/windows/src/engine/kmcomapi/kmcomapi.dpr index debc6bcaa6..55114c1558 100644 --- a/windows/src/engine/kmcomapi/kmcomapi.dpr +++ b/windows/src/engine/kmcomapi/kmcomapi.dpr @@ -151,7 +151,8 @@ uses Keyman.System.Standards.LCIDToBCP47Registry in '..\..\global\delphi\standards\Keyman.System.Standards.LCIDToBCP47Registry.pas', keymankeyboardlanguage in 'com\keyboardlanguages\keymankeyboardlanguage.pas', keymankeyboardlanguagesfile in 'com\keyboardlanguages\keymankeyboardlanguagesfile.pas', - keymankeyboardlanguagefile in 'com\keyboardlanguages\keymankeyboardlanguagefile.pas'; + keymankeyboardlanguagefile in 'com\keyboardlanguages\keymankeyboardlanguagefile.pas', + Keyman.System.Standards.BCP47SubtagRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SubtagRegistry.pas'; {$R *.TLB} diff --git a/windows/src/engine/kmcomapi/kmcomapi.dproj b/windows/src/engine/kmcomapi/kmcomapi.dproj index 8388b5a475..ee1e5e7e3c 100644 --- a/windows/src/engine/kmcomapi/kmcomapi.dproj +++ b/windows/src/engine/kmcomapi/kmcomapi.dproj @@ -7,7 +7,7 @@ 3 Library None - 18.3 + 18.4 Win32 @@ -291,6 +291,7 @@ + Cfg_2 -- GitLab From 5c64093a31ca16925173b142567df601ae112ed5 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 30 Apr 2018 14:35:40 +0700 Subject: [PATCH 023/356] Fix test project includes --- .../KeyboardPackageVersionsTestSuite.dpr | 3 ++- .../KeyboardPackageVersionsTestSuite.dproj | 3 ++- .../kmx-file-languages/KMXFileLanguagesTestSuite.dpr | 3 ++- .../kmx-file-languages/KMXFileLanguagesTestSuite.dproj | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/windows/src/unit-tests/keyboard-package-versions/KeyboardPackageVersionsTestSuite.dpr b/windows/src/unit-tests/keyboard-package-versions/KeyboardPackageVersionsTestSuite.dpr index 5ff3708fed..2bd552e652 100644 --- a/windows/src/unit-tests/keyboard-package-versions/KeyboardPackageVersionsTestSuite.dpr +++ b/windows/src/unit-tests/keyboard-package-versions/KeyboardPackageVersionsTestSuite.dpr @@ -88,7 +88,8 @@ uses Keyman.System.LanguageCodeUtils in '..\..\global\delphi\general\Keyman.System.LanguageCodeUtils.pas', Keyman.System.RegExGroupHelperRSP19902 in '..\..\global\delphi\general\Keyman.System.RegExGroupHelperRSP19902.pas', DUnitX.Loggers.TeamCity in '..\..\global\delphi\general\DUnitX.Loggers.TeamCity.pas', - BCP47Tag in '..\..\global\delphi\general\BCP47Tag.pas'; + BCP47Tag in '..\..\global\delphi\general\BCP47Tag.pas', + Keyman.System.Standards.BCP47SubtagRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SubtagRegistry.pas'; var runner : ITestRunner; diff --git a/windows/src/unit-tests/keyboard-package-versions/KeyboardPackageVersionsTestSuite.dproj b/windows/src/unit-tests/keyboard-package-versions/KeyboardPackageVersionsTestSuite.dproj index b7a5af341d..46cc4da013 100644 --- a/windows/src/unit-tests/keyboard-package-versions/KeyboardPackageVersionsTestSuite.dproj +++ b/windows/src/unit-tests/keyboard-package-versions/KeyboardPackageVersionsTestSuite.dproj @@ -1,7 +1,7 @@  {7A8E88E4-B407-442B-9A53-DE6F43F1C0F1} - 18.3 + 18.4 VCL KeyboardPackageVersionsTestSuite.dpr True @@ -176,6 +176,7 @@ + Cfg_2 Base diff --git a/windows/src/unit-tests/kmx-file-languages/KMXFileLanguagesTestSuite.dpr b/windows/src/unit-tests/kmx-file-languages/KMXFileLanguagesTestSuite.dpr index 5390c87a4e..d84d25faf2 100644 --- a/windows/src/unit-tests/kmx-file-languages/KMXFileLanguagesTestSuite.dpr +++ b/windows/src/unit-tests/kmx-file-languages/KMXFileLanguagesTestSuite.dpr @@ -28,7 +28,8 @@ uses Keyman.System.Standards.LCIDToBCP47Registry in '..\..\global\delphi\standards\Keyman.System.Standards.LCIDToBCP47Registry.pas', Keyman.System.LanguageCodeUtils in '..\..\global\delphi\general\Keyman.System.LanguageCodeUtils.pas', DUnitX.Loggers.TeamCity in '..\..\global\delphi\general\DUnitX.Loggers.TeamCity.pas', - kmxfileconsts in '..\..\global\delphi\general\kmxfileconsts.pas'; + kmxfileconsts in '..\..\global\delphi\general\kmxfileconsts.pas', + Keyman.System.Standards.BCP47SubtagRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SubtagRegistry.pas'; var runner : ITestRunner; diff --git a/windows/src/unit-tests/kmx-file-languages/KMXFileLanguagesTestSuite.dproj b/windows/src/unit-tests/kmx-file-languages/KMXFileLanguagesTestSuite.dproj index 156e2f35d9..e8b9ee25e6 100644 --- a/windows/src/unit-tests/kmx-file-languages/KMXFileLanguagesTestSuite.dproj +++ b/windows/src/unit-tests/kmx-file-languages/KMXFileLanguagesTestSuite.dproj @@ -1,7 +1,7 @@  {A9388625-2992-4E7C-9AE8-4B2A25BC30E3} - 18.3 + 18.4 None KMXFileLanguagesTestSuite.dpr True @@ -107,6 +107,7 @@ + Cfg_2 Base -- GitLab From 694a4ae7bf3e8e2e8823e25566c928f718d3428b Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 30 Apr 2018 14:44:22 +0700 Subject: [PATCH 024/356] history --- windows/src/developer/history.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/windows/src/developer/history.md b/windows/src/developer/history.md index b63b3ae872..8356345132 100644 --- a/windows/src/developer/history.md +++ b/windows/src/developer/history.md @@ -1,5 +1,8 @@ # Keyman Developer Version History +## 2018-04-30 10.0.1067.0 beta +* BCP 47 picker in package editor now does name lookups and constrains codes as required by target operating systems (#746, #766) + ## 2018-04-12 10.0.1057.0 beta * No changes in Keyman Developer -- GitLab From 1d586cda7227caa3a262c100e219b17405de381a Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 30 Apr 2018 15:51:48 +0700 Subject: [PATCH 025/356] Fixes sillsdev/keyman-keyman-issues#5563 - crash after save or source view change in OSK Editor --- .../developer/TIKE/main/UframeOnScreenKeyboardEditor.pas | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/windows/src/developer/TIKE/main/UframeOnScreenKeyboardEditor.pas b/windows/src/developer/TIKE/main/UframeOnScreenKeyboardEditor.pas index 935405b7a2..7f47555785 100644 --- a/windows/src/developer/TIKE/main/UframeOnScreenKeyboardEditor.pas +++ b/windows/src/developer/TIKE/main/UframeOnScreenKeyboardEditor.pas @@ -346,6 +346,8 @@ begin FVK.LoadFromStream(stream); VK_UpdateData; VK_UpdateKeyFont; + FVKCurrentKey := nil; + VK_SelectVKey; finally FVKLoading := False; end; @@ -1391,9 +1393,10 @@ end; procedure TframeOnScreenKeyboardEditor.VK_FocusKey; begin - if rbKeyText.Checked - then editVKKeyText.SetFocus - else cmdBrowseKeyBitmap.SetFocus; + if editVKKeyText.CanFocus then + if rbKeyText.Checked + then editVKKeyText.SetFocus + else cmdBrowseKeyBitmap.SetFocus; end; { ---------------------------------------------------------------------------- } -- GitLab From fe06753df3a92a8e1da4ee68f1d8074c7a5d3765 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Mon, 30 Apr 2018 15:43:01 -0400 Subject: [PATCH 026/356] [Mac] 709:Added code to detect link that should open in browser This allows "Go to keyman.com" button to work correctly. --- .../KMDownloadKBWindowController.m | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.m index 7373535fd4..ef5ae9d4ed 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" @@ -24,10 +24,28 @@ [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); [self.webView.mainFrame loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]]; + +// REVIEW: Compare this implementation to the one in KMKeyboardHelpWindowController. Should we +// use a consistent prefix? +- (void) webView:(WebView*) sender decidePolicyForNavigationAction:(NSDictionary*) actionInformation request:(NSURLRequest*) request frame:(WebFrame*) frame decisionListener:(id ) listener { + NSString* url = [[request URL] description]; + NSLog(@"decidePolicyForNavigationAction, navigating to %@", url); + if ([request.URL.absoluteString startsWith:@"keyman:link?url="]) + { + [listener ignore]; + url = [request.URL.absoluteString substringFromIndex:[@"keyman:link?url=" length]]; + [[NSWorkspace sharedWorkspace] openURL: [[NSURL alloc] initWithString:url]]; + } + else + { + [listener use]; + } } @end -- GitLab From dce4f02a928bbf019dbe79171740afbb57e98aa3 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Mon, 30 Apr 2018 17:03:03 -0400 Subject: [PATCH 027/356] Fixed mess caused by previous check-in --- .../KMDownloadKeyboard/KMDownloadKBWindowController.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.m index ef5ae9d4ed..24303b5d48 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.m @@ -30,10 +30,11 @@ NSString *url = [NSString stringWithFormat:@"https://keyman.com/go/macos/10.0/download-keyboards/?version=%@", version]; NSLog(@"KMDownloadKBWindowController opening url = %@, version = '%@'", url, version); [self.webView.mainFrame loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]]; +} // REVIEW: Compare this implementation to the one in KMKeyboardHelpWindowController. Should we // use a consistent prefix? -- (void) webView:(WebView*) sender decidePolicyForNavigationAction:(NSDictionary*) actionInformation request:(NSURLRequest*) request frame:(WebFrame*) frame decisionListener:(id ) listener { +- (void) decidePolicyForNavigationAction:(NSDictionary*) actionInformation request:(NSURLRequest*) request frame:(WebFrame*) frame decisionListener:(id ) listener { NSString* url = [[request URL] description]; NSLog(@"decidePolicyForNavigationAction, navigating to %@", url); if ([request.URL.absoluteString startsWith:@"keyman:link?url="]) -- GitLab From 02111855739b6744b35b6ea4727b16c67bec6bff Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Mon, 30 Apr 2018 19:11:52 -0600 Subject: [PATCH 028/356] search google for input if an invalid URL is specified --- .../WebBrowserViewController.swift | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift b/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift index 2e14f2799e..bd825e081f 100644 --- a/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift +++ b/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift @@ -179,8 +179,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 +197,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 -- GitLab From 50f344616fb278e685827a3d53741e116fb3ac7b Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Thu, 26 Apr 2018 18:24:17 -1000 Subject: [PATCH 029/356] fixes iPhoneX resolution issues --- .../LaunchImage.launchimage/Contents.json | 42 +++++++++++++----- .../launch_iphoneX_landscape@3x.png | Bin 0 -> 86109 bytes .../launch_iphonex_portrait@3x.png | Bin 0 -> 98026 bytes .../Keyman/Keyman Navbar/keyman_logo@3x.png | Bin 0 -> 31343 bytes 4 files changed, 30 insertions(+), 12 deletions(-) create mode 100644 ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/launch_iphoneX_landscape@3x.png create mode 100644 ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/launch_iphonex_portrait@3x.png create mode 100644 ios/keyman/Keyman/Keyman/Keyman Navbar/keyman_logo@3x.png 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 7b9945524d..8d740e45e3 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 GIT binary patch literal 86109 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

so=wHIEqinY{D~<7_($};Ot;x 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 literal 0 HcmV?d00001 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 GIT binary patch literal 98026 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 Qx9I${$4|9qF8}`j02^=^&Hw-a literal 0 HcmV?d00001 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 GIT binary patch literal 31343 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 Date: Thu, 26 Apr 2018 18:24:53 -1000 Subject: [PATCH 030/356] refactoring navbar background image --- .../Keyman/Keyman/MainViewController.swift | 57 ++++++------------- 1 file changed, 17 insertions(+), 40 deletions(-) diff --git a/ios/keyman/Keyman/Keyman/MainViewController.swift b/ios/keyman/Keyman/Keyman/MainViewController.swift index 883b676522..12c882d018 100644 --- a/ios/keyman/Keyman/Keyman/MainViewController.swift +++ b/ios/keyman/Keyman/Keyman/MainViewController.swift @@ -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,10 @@ 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 + //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 @@ -170,46 +171,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 nb = navigationController?.navigationBar { + navbarBackground = KMNavigationBarBackgroundView() + navbarBackground.addToNavbar(nb) + 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,6 +345,11 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg }, completion: nil) } + if let navbarBackground = navbarBackground { + navbarBackground.setOrientation(toInterfaceOrientation) + } + + /* // TODO: Refactor if UIDevice.current.userInterfaceIdiom == .phone { let screenRect = UIScreen.main.bounds @@ -398,11 +373,13 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg navigationController?.navigationBar.setBackgroundImage(#imageLiteral(resourceName: "navbar-Landscape.png"), for: UIBarMetrics.default) } } + */ popover?.dismiss(animated: false) _ = dismissDropDownMenu() } override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) { + let f = navigationController?.navigationBar.frame if infoView?.view?.isHidden ?? true { setNavBarButtons() } -- GitLab From 49c8a416c6ab038c4f7ffa4fd7f3ee0c327a40fa Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Thu, 26 Apr 2018 18:26:24 -1000 Subject: [PATCH 031/356] implementing new directory structure for file organization, utility classes and new KM views for navbar backgrounds --- .../Extensions/UIDevice+Extensions.swift | 18 +++++ .../Extensions/UIView+Extensions.swift | 77 +++++++++++++++++++ .../View/KMNavigationBarBackgroundView.swift | 75 ++++++++++++++++++ .../Classes/View/KMUnderscoreView.swift | 49 ++++++++++++ 4 files changed, 219 insertions(+) create mode 100644 ios/keyman/Keyman/Keyman/Classes/Extensions/UIDevice+Extensions.swift create mode 100644 ios/keyman/Keyman/Keyman/Classes/Extensions/UIView+Extensions.swift create mode 100644 ios/keyman/Keyman/Keyman/Classes/View/KMNavigationBarBackgroundView.swift create mode 100644 ios/keyman/Keyman/Keyman/Classes/View/KMUnderscoreView.swift 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 0000000000..38e3aff4c0 --- /dev/null +++ b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIDevice+Extensions.swift @@ -0,0 +1,18 @@ +// +// 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 screenRect = UIScreen.main.bounds + let size = CGFloat.maximum(screenRect.width, screenRect.height) + return UIDevice.current.userInterfaceIdiom == .phone && size == 812 + } +} 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 0000000000..2c8cb9d710 --- /dev/null +++ b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIView+Extensions.swift @@ -0,0 +1,77 @@ +// +// UIView+Constraints.swfit.swift +// 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) + + //constraint.isActive = true + 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) + + //constraint.isActive = true + 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"] ?? -20)).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["bottom.constant"] ?? 0)).isActive = true + + NSLayoutConstraint(item: self, + attribute: .trailing, + relatedBy: .equal, + toItem: parent, + attribute: .trailing, + multiplier: 1, + constant: (options["bottom.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 0000000000..55662237fa --- /dev/null +++ b/ios/keyman/Keyman/Keyman/Classes/View/KMNavigationBarBackgroundView.swift @@ -0,0 +1,75 @@ +// +// 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 { + + var imageLeadingConstraint: NSLayoutConstraint? + + 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 + + setupLogo() + setupUnderscore() + } + + 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: 3, 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: -8).isActive = true + imageView.constrainEqually(to: 100, attribute: .width).isActive = true + + imageLeadingConstraint = imageView.constrainEqually(to: self, attribute: .leading, constant: 10) + imageLeadingConstraint?.isActive = true + } + + func addToNavbar(_ navbar: UINavigationBar!) { + navbar.addSubview(self) + self.constrainCorners(to: navbar, options: ["top.constant": 0]) + } + + func setOrientation(_ orientation: UIInterfaceOrientation) { + var constant: CGFloat = 10 + if let constraint = imageLeadingConstraint { + if orientation.isLandscape && UIDevice.isIphoneX { + constant = 25 + } + 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 0000000000..917a3ae724 --- /dev/null +++ b/ios/keyman/Keyman/Keyman/Classes/View/KMUnderscoreView.swift @@ -0,0 +1,49 @@ +// +// KMUnderscoreView.swift +// Keyman +// +// Created by Jacob Bullock on 4/26/18. +// Copyright © 2018 SIL International. All rights reserved. +// + +import Foundation +import UIKit + +class KMUnderscoreView: 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() { + } + + override func draw(_ rect: CGRect) { + let color: UIColor = .yellow + + + let widths: [CGFloat] = [0.6, 0.25, 0.15] + let colors: [UIColor] = [ UIColor(red: 244/255, green: 113/255, blue: 32/255, alpha: 1.0), + UIColor(red: 186/255, green: 32/255, blue: 52/255, alpha: 1.0), + UIColor(red: 105/255, green: 183/255, blue: 211/255, alpha: 1.0)] + + 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 c = colors[i] + c.set() + bpath.fill() + + x += w + } + + } +} -- GitLab From dd1fca1108b46b391994a6be888bfd3399f80e34 Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Thu, 26 Apr 2018 18:26:33 -1000 Subject: [PATCH 032/356] file references --- .../Keyman/Keyman.xcodeproj/project.pbxproj | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj b/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj index 38d6352cd7..9612802a09 100644 --- a/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj +++ b/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj @@ -7,6 +7,11 @@ 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 */; }; 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,6 +204,11 @@ /* 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 = ""; }; 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 = ""; }; @@ -389,6 +399,41 @@ /* 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 */, + ); + path = Extensions; + sourceTree = ""; + }; + 162E2C9820926C8600F40769 /* View */ = { + isa = PBXGroup; + children = ( + 162E2C9A20926C9B00F40769 /* KMNavigationBarBackgroundView.swift */, + 162E2C9C2092BFE400F40769 /* KMUnderscoreView.swift */, + ); + path = View; + sourceTree = ""; + }; 9845A79A1A43983300544E2E /* KMWebBrowser */ = { isa = PBXGroup; children = ( @@ -594,6 +639,7 @@ 98ABADB9176935E400B62590 /* Keyman */ = { isa = PBXGroup; children = ( + 162E2C9420926C8600F40769 /* Classes */, 9845A7BE1A439A9200544E2E /* GetStartedViewController */, 98C893F119F0811A000B9AC8 /* Images.xcassets */, 9845A7C21A439A9200544E2E /* InfoViewController */, @@ -677,6 +723,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 +936,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 */, @@ -1029,11 +1077,15 @@ 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 */, C0FF769E1F5D4ECB00BD23C3 /* ActivityItemProvider.swift in Sources */, ); -- GitLab From bdb5f304390cc88cb095035ac20b87468ade45f7 Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Thu, 26 Apr 2018 18:28:11 -1000 Subject: [PATCH 033/356] removing old code for navbar background in rotation --- .../Keyman/Keyman/MainViewController.swift | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/ios/keyman/Keyman/Keyman/MainViewController.swift b/ios/keyman/Keyman/Keyman/MainViewController.swift index 12c882d018..082e4e751c 100644 --- a/ios/keyman/Keyman/Keyman/MainViewController.swift +++ b/ios/keyman/Keyman/Keyman/MainViewController.swift @@ -349,31 +349,6 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg navbarBackground.setOrientation(toInterfaceOrientation) } - /* - // 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) - } - } - */ popover?.dismiss(animated: false) _ = dismissDropDownMenu() } -- GitLab From 2506a1e5de682163f86a7230391ed9976bb9c44c Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Thu, 26 Apr 2018 21:37:16 -1000 Subject: [PATCH 034/356] fixing comments for file name --- .../Keyman/Keyman/Classes/Extensions/UIView+Extensions.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/keyman/Keyman/Keyman/Classes/Extensions/UIView+Extensions.swift b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIView+Extensions.swift index 2c8cb9d710..9fda952a14 100644 --- a/ios/keyman/Keyman/Keyman/Classes/Extensions/UIView+Extensions.swift +++ b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIView+Extensions.swift @@ -1,5 +1,5 @@ // -// UIView+Constraints.swfit.swift +// UIView+Extensions.swfit // Keyman // // Created by Jacob Bullock on 4/26/18. -- GitLab From 855504043fef63a619bdbc69cf3b6511aec14166 Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Thu, 26 Apr 2018 22:01:21 -1000 Subject: [PATCH 035/356] add method to hide logo --- .../Classes/View/KMNavigationBarBackgroundView.swift | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ios/keyman/Keyman/Keyman/Classes/View/KMNavigationBarBackgroundView.swift b/ios/keyman/Keyman/Keyman/Classes/View/KMNavigationBarBackgroundView.swift index 55662237fa..57e3b6c6f1 100644 --- a/ios/keyman/Keyman/Keyman/Classes/View/KMNavigationBarBackgroundView.swift +++ b/ios/keyman/Keyman/Keyman/Classes/View/KMNavigationBarBackgroundView.swift @@ -12,6 +12,7 @@ import UIKit class KMNavigationBarBackgroundView: UIView { var imageLeadingConstraint: NSLayoutConstraint? + var logoImageView: UIImageView? required public init?(coder: NSCoder) { super.init(coder: coder) @@ -25,10 +26,16 @@ class KMNavigationBarBackgroundView: UIView { 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()) @@ -55,6 +62,8 @@ class KMNavigationBarBackgroundView: UIView { imageLeadingConstraint = imageView.constrainEqually(to: self, attribute: .leading, constant: 10) imageLeadingConstraint?.isActive = true + + logoImageView = imageView } func addToNavbar(_ navbar: UINavigationBar!) { -- GitLab From 3ce8bcced864a60a853b6392489e1a829154ecae Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Thu, 26 Apr 2018 22:02:31 -1000 Subject: [PATCH 036/356] remove unnecessary debug code, use better variable names in let conditional --- ios/keyman/Keyman/Keyman/MainViewController.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ios/keyman/Keyman/Keyman/MainViewController.swift b/ios/keyman/Keyman/Keyman/MainViewController.swift index 082e4e751c..aa77b5b55c 100644 --- a/ios/keyman/Keyman/Keyman/MainViewController.swift +++ b/ios/keyman/Keyman/Keyman/MainViewController.swift @@ -170,10 +170,9 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg } // Setup NavigationBar - // TODO: refactor - if let nb = navigationController?.navigationBar { + if let navbar = navigationController?.navigationBar { navbarBackground = KMNavigationBarBackgroundView() - navbarBackground.addToNavbar(nb) + navbarBackground.addToNavbar(navbar) navbarBackground.setOrientation(UIApplication.shared.statusBarOrientation) } -- GitLab From e4c316a195c1680e98224348acc98397f62dc2d3 Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Thu, 26 Apr 2018 22:02:42 -1000 Subject: [PATCH 037/356] remove unnecessary debug code, use better variable names in let conditional --- ios/keyman/Keyman/Keyman/MainViewController.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/ios/keyman/Keyman/Keyman/MainViewController.swift b/ios/keyman/Keyman/Keyman/MainViewController.swift index aa77b5b55c..cd8f33a1be 100644 --- a/ios/keyman/Keyman/Keyman/MainViewController.swift +++ b/ios/keyman/Keyman/Keyman/MainViewController.swift @@ -353,7 +353,6 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg } override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) { - let f = navigationController?.navigationBar.frame if infoView?.view?.isHidden ?? true { setNavBarButtons() } -- GitLab From 05b2ea13fab5bf828cb89809242b8de90660ac7a Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Thu, 26 Apr 2018 22:03:05 -1000 Subject: [PATCH 038/356] implement new navbar bg in browser viewcontroller --- .../WebBrowserViewController.swift | 68 ++----------------- 1 file changed, 7 insertions(+), 61 deletions(-) diff --git a/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift b/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift index 2e14f2799e..846d0ccb3f 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) } } -- GitLab From babcbe8024c0b271d7c8be05f23265837298c894 Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Sun, 29 Apr 2018 23:47:12 -1000 Subject: [PATCH 039/356] removing commented code --- .../Keyman/Classes/Extensions/UIColor+Extensions.swift | 9 +++++++++ ios/keyman/Keyman/Keyman/Classes/View/KMView.swift | 9 +++++++++ ios/keyman/Keyman/Keyman/MainViewController.swift | 4 ---- 3 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 ios/keyman/Keyman/Keyman/Classes/Extensions/UIColor+Extensions.swift create mode 100644 ios/keyman/Keyman/Keyman/Classes/View/KMView.swift 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 0000000000..65475ba0cc --- /dev/null +++ b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIColor+Extensions.swift @@ -0,0 +1,9 @@ +// +// UIColor+Extensions.swift +// Keyman +// +// Created by Jacob Bullock on 4/29/18. +// Copyright © 2018 SIL International. All rights reserved. +// + +import Foundation 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 0000000000..e93908eee4 --- /dev/null +++ b/ios/keyman/Keyman/Keyman/Classes/View/KMView.swift @@ -0,0 +1,9 @@ +// +// KMView.swift +// Keyman +// +// Created by Jacob Bullock on 4/29/18. +// Copyright © 2018 SIL International. All rights reserved. +// + +import Foundation diff --git a/ios/keyman/Keyman/Keyman/MainViewController.swift b/ios/keyman/Keyman/Keyman/MainViewController.swift index cd8f33a1be..9fc15de3c6 100644 --- a/ios/keyman/Keyman/Keyman/MainViewController.swift +++ b/ios/keyman/Keyman/Keyman/MainViewController.swift @@ -136,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 -- GitLab From a5209c57bc998bd14600cc3a34995cab9ce654ff Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Sun, 29 Apr 2018 23:48:00 -1000 Subject: [PATCH 040/356] implement new view for boilerplate custom views --- .../Keyman/Keyman/Classes/View/KMView.swift | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ios/keyman/Keyman/Keyman/Classes/View/KMView.swift b/ios/keyman/Keyman/Keyman/Classes/View/KMView.swift index e93908eee4..3f8a1efb1e 100644 --- a/ios/keyman/Keyman/Keyman/Classes/View/KMView.swift +++ b/ios/keyman/Keyman/Keyman/Classes/View/KMView.swift @@ -7,3 +7,19 @@ // 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() { + } +} -- GitLab From 76e94fae4a1829a6a94ccb3c43ae666207cd88c8 Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Sun, 29 Apr 2018 23:49:21 -1000 Subject: [PATCH 041/356] implement new super view, used UIColor constants --- .../Classes/View/KMUnderscoreView.swift | 33 +++++-------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/ios/keyman/Keyman/Keyman/Classes/View/KMUnderscoreView.swift b/ios/keyman/Keyman/Keyman/Classes/View/KMUnderscoreView.swift index 917a3ae724..96e6a2f1ab 100644 --- a/ios/keyman/Keyman/Keyman/Classes/View/KMUnderscoreView.swift +++ b/ios/keyman/Keyman/Keyman/Classes/View/KMUnderscoreView.swift @@ -9,37 +9,22 @@ import Foundation import UIKit -class KMUnderscoreView: 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() { - } - +class KMUnderscoreView: KMView { override func draw(_ rect: CGRect) { - let color: UIColor = .yellow - - + //percentage based widths for the color bar portion of the logo let widths: [CGFloat] = [0.6, 0.25, 0.15] - let colors: [UIColor] = [ UIColor(red: 244/255, green: 113/255, blue: 32/255, alpha: 1.0), - UIColor(red: 186/255, green: 32/255, blue: 52/255, alpha: 1.0), - UIColor(red: 105/255, green: 183/255, blue: 211/255, alpha: 1.0)] + 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 drect = CGRect(x: x, y: 0, width: w, height: rect.height) let bpath: UIBezierPath = UIBezierPath(rect: drect) - - let c = colors[i] - c.set() + + let color = colors[i] + color.set() bpath.fill() x += w -- GitLab From bb7de64a295392216c83f4af6ef0fd7c3de5f54a Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Sun, 29 Apr 2018 23:49:45 -1000 Subject: [PATCH 042/356] adding static color references for keyman colors --- .../Classes/Extensions/UIColor+Extensions.swift | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ios/keyman/Keyman/Keyman/Classes/Extensions/UIColor+Extensions.swift b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIColor+Extensions.swift index 65475ba0cc..8664f3be77 100644 --- a/ios/keyman/Keyman/Keyman/Classes/Extensions/UIColor+Extensions.swift +++ b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIColor+Extensions.swift @@ -7,3 +7,18 @@ // 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) + } +} -- GitLab From d2880890bbcd1b2beab88a599a55453d40a262a1 Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Sun, 29 Apr 2018 23:50:18 -1000 Subject: [PATCH 043/356] fix option references, clean up spacing --- .../Keyman/Keyman/Classes/Extensions/UIDevice+Extensions.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ios/keyman/Keyman/Keyman/Classes/Extensions/UIDevice+Extensions.swift b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIDevice+Extensions.swift index 38e3aff4c0..822a929918 100644 --- a/ios/keyman/Keyman/Keyman/Classes/Extensions/UIDevice+Extensions.swift +++ b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIDevice+Extensions.swift @@ -11,8 +11,9 @@ 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 == 812 + return UIDevice.current.userInterfaceIdiom == .phone && size == iphonexScreenHeight } } -- GitLab From b6f046b8c0af4b2f922dd4a3471cb50d8432c8ac Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Sun, 29 Apr 2018 23:51:04 -1000 Subject: [PATCH 044/356] get rid of magic values and specify constants for better readability --- .../View/KMNavigationBarBackgroundView.swift | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/ios/keyman/Keyman/Keyman/Classes/View/KMNavigationBarBackgroundView.swift b/ios/keyman/Keyman/Keyman/Classes/View/KMNavigationBarBackgroundView.swift index 57e3b6c6f1..76a58ad7de 100644 --- a/ios/keyman/Keyman/Keyman/Classes/View/KMNavigationBarBackgroundView.swift +++ b/ios/keyman/Keyman/Keyman/Classes/View/KMNavigationBarBackgroundView.swift @@ -11,6 +11,12 @@ 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? @@ -30,7 +36,7 @@ class KMNavigationBarBackgroundView: UIView { setupLogo() setupUnderscore() } - + func hideLogo() { if let logoImageView = logoImageView { logoImageView.alpha = 0 @@ -45,7 +51,7 @@ class KMNavigationBarBackgroundView: UIView { 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: 3, attribute: .height).isActive = true + v.constrainEqually(to: CGFloat(underscoreHeight), attribute: .height).isActive = true } func setupLogo() { @@ -57,10 +63,12 @@ class KMNavigationBarBackgroundView: UIView { imageView.constrainEqually(to: self, attribute: .centerY).isActive = true imageView.constrainEqually(to: self, attribute: .centerY).isActive = true - imageView.constrainEqually(to: self, attribute: .height, constant: -8).isActive = true - imageView.constrainEqually(to: 100, attribute: .width).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: 10) + imageLeadingConstraint = imageView.constrainEqually(to: self, + attribute: .leading, + constant: CGFloat(defaultImageLeading)) imageLeadingConstraint?.isActive = true logoImageView = imageView @@ -72,10 +80,10 @@ class KMNavigationBarBackgroundView: UIView { } func setOrientation(_ orientation: UIInterfaceOrientation) { - var constant: CGFloat = 10 + var constant: CGFloat = CGFloat(defaultImageLeading) if let constraint = imageLeadingConstraint { if orientation.isLandscape && UIDevice.isIphoneX { - constant = 25 + constant = CGFloat(iphonexImageLeading) } constraint.constant = constant self.setNeedsLayout() -- GitLab From 38a23b4971753bbd07bea101f6f1ba58e6fcfa81 Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Sun, 29 Apr 2018 23:52:09 -1000 Subject: [PATCH 045/356] fix option references, clean up spacing --- .../Keyman/Classes/Extensions/UIView+Extensions.swift | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/ios/keyman/Keyman/Keyman/Classes/Extensions/UIView+Extensions.swift b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIView+Extensions.swift index 9fda952a14..697acb77dc 100644 --- a/ios/keyman/Keyman/Keyman/Classes/Extensions/UIView+Extensions.swift +++ b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIView+Extensions.swift @@ -14,6 +14,7 @@ extension UIView { func constrainEqually(to parent: UIView, attribute: NSLayoutAttribute, constant: CGFloat = 0) -> NSLayoutConstraint { + let constraint = NSLayoutConstraint(item: self, attribute: attribute, relatedBy: .equal, @@ -21,8 +22,6 @@ extension UIView { attribute: attribute, multiplier: 1, constant: constant) - - //constraint.isActive = true return constraint } @@ -35,8 +34,6 @@ extension UIView { attribute: .notAnAttribute, multiplier: 1.0, constant: constant) - - //constraint.isActive = true return constraint } @@ -48,7 +45,7 @@ extension UIView { toItem: parent, attribute: .top, multiplier: 1, - constant: (options["top.constant"] ?? -20)).isActive = true + constant: (options["top.constant"] ?? 0)).isActive = true NSLayoutConstraint(item: self, attribute: .bottom, @@ -64,7 +61,7 @@ extension UIView { toItem: parent, attribute: .leading, multiplier: 1, - constant: (options["bottom.constant"] ?? 0)).isActive = true + constant: (options["leading.constant"] ?? 0)).isActive = true NSLayoutConstraint(item: self, attribute: .trailing, @@ -72,6 +69,6 @@ extension UIView { toItem: parent, attribute: .trailing, multiplier: 1, - constant: (options["bottom.constant"] ?? 0)).isActive = true + constant: (options["trailing.constant"] ?? 0)).isActive = true } } -- GitLab From 9cc8ec7abffbefe4bbf787281a7eaea9d1409b01 Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Sun, 29 Apr 2018 23:52:17 -1000 Subject: [PATCH 046/356] file references --- ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj b/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj index 9612802a09..79ef96593b 100644 --- a/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj +++ b/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj @@ -12,6 +12,8 @@ 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, ); }; }; @@ -210,6 +212,8 @@ 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; }; @@ -421,6 +425,7 @@ children = ( 162E2C9720926C8600F40769 /* UIView+Extensions.swift */, 162E2C9E2092D36800F40769 /* UIDevice+Extensions.swift */, + 165EB3992097165B00040A69 /* UIColor+Extensions.swift */, ); path = Extensions; sourceTree = ""; @@ -430,6 +435,7 @@ children = ( 162E2C9A20926C9B00F40769 /* KMNavigationBarBackgroundView.swift */, 162E2C9C2092BFE400F40769 /* KMUnderscoreView.swift */, + 165EB39B2097181D00040A69 /* KMView.swift */, ); path = View; sourceTree = ""; @@ -1072,6 +1078,7 @@ 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 */, @@ -1087,6 +1094,7 @@ 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; -- GitLab From 27b6460bcfcb7d5c0b482107da7aed1a3a422748 Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Sun, 29 Apr 2018 23:54:04 -1000 Subject: [PATCH 047/356] removing magic values with static references --- .../Keyman/Keyman/Classes/Extensions/UIDevice+Extensions.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/keyman/Keyman/Keyman/Classes/Extensions/UIDevice+Extensions.swift b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIDevice+Extensions.swift index 822a929918..c7f6c850e5 100644 --- a/ios/keyman/Keyman/Keyman/Classes/Extensions/UIDevice+Extensions.swift +++ b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIDevice+Extensions.swift @@ -14,6 +14,6 @@ extension UIDevice { let iphonexScreenHeight: Int = 812 let screenRect = UIScreen.main.bounds let size = CGFloat.maximum(screenRect.width, screenRect.height) - return UIDevice.current.userInterfaceIdiom == .phone && size == iphonexScreenHeight + return UIDevice.current.userInterfaceIdiom == .phone && size == CGFloat(iphonexScreenHeight) } } -- GitLab From 9ed15f5587b9e5c7e1e60adb4f2b44e2a42fe9e8 Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Sun, 29 Apr 2018 23:57:07 -1000 Subject: [PATCH 048/356] lint violations --- ios/keyman/Keyman/Keyman/AppDelegate.swift | 2 +- .../Keyman/Classes/View/KMNavigationBarBackgroundView.swift | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ios/keyman/Keyman/Keyman/AppDelegate.swift b/ios/keyman/Keyman/Keyman/AppDelegate.swift index dd330bf0e2..0889392b39 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/View/KMNavigationBarBackgroundView.swift b/ios/keyman/Keyman/Keyman/Classes/View/KMNavigationBarBackgroundView.swift index 76a58ad7de..09eb4aeb6b 100644 --- a/ios/keyman/Keyman/Keyman/Classes/View/KMNavigationBarBackgroundView.swift +++ b/ios/keyman/Keyman/Keyman/Classes/View/KMNavigationBarBackgroundView.swift @@ -15,7 +15,7 @@ class KMNavigationBarBackgroundView: UIView { let iphonexImageLeading: Int = 25 let underscoreHeight: Int = 3 let logoImageWidth: Int = 100 - let logoImageHeightDiff:Int = -8 + let logoImageHeightDiff: Int = -8 var imageLeadingConstraint: NSLayoutConstraint? var logoImageView: UIImageView? @@ -63,7 +63,9 @@ class KMNavigationBarBackgroundView: UIView { 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: self, + attribute: .height, + constant: CGFloat(logoImageHeightDiff)).isActive = true imageView.constrainEqually(to: CGFloat(logoImageWidth), attribute: .width).isActive = true imageLeadingConstraint = imageView.constrainEqually(to: self, -- GitLab From aac791f8df032e753603abda145a5bc024c5d97c Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Mon, 30 Apr 2018 20:15:51 -0600 Subject: [PATCH 049/356] updating history --- ios/history.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ios/history.md b/ios/history.md index ac80c9d424..2717a39d9c 100644 --- a/ios/history.md +++ b/ios/history.md @@ -1,5 +1,8 @@ # Keyman for iPhone and iPad Version History +## 2018-04-25 10.0.141 beta +* Refactor navigation bar branding. (#802) + ## 2018-04-25 10.0.140 beta * Fixed lack of output for certain punctuation longpress keys. (#702) -- GitLab From f5c2e888241d4aeb4d2ca08df1675c47c4fb0b39 Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Mon, 30 Apr 2018 20:18:36 -0600 Subject: [PATCH 050/356] updating historyu --- ios/history.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ios/history.md b/ios/history.md index ac80c9d424..bff1be0d43 100644 --- a/ios/history.md +++ b/ios/history.md @@ -1,5 +1,8 @@ # Keyman for iPhone and iPad Version History +## 2018-04-25 10.0.141 beta +* Search google when an invalid URL is entered in the address bar. (#801) + ## 2018-04-25 10.0.140 beta * Fixed lack of output for certain punctuation longpress keys. (#702) -- GitLab From ffa7968aa9808294405f997e50b16096c7b3fa9e Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Tue, 1 May 2018 05:31:24 -0600 Subject: [PATCH 051/356] fix mixed case alphabetical list --- .../Classes/LanguagePicker/LanguageViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageViewController.swift index da968e993d..ab88986356 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageViewController.swift @@ -115,7 +115,7 @@ class LanguageViewController: UITableViewController, UIAlertViewDelegate { sectionIndexTitles = [] indices = [] for (index, language) in languages.enumerated() { - let firstLetter = String(language.name.prefix(1)) + let firstLetter = String(language.name.prefix(1)).uppercased() if !sectionIndexTitles.contains(firstLetter) { sectionIndexTitles.append(firstLetter) indices.append(index) -- GitLab From 3a2f7a14b46996ca2a736555f060559f757314c4 Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Tue, 1 May 2018 05:31:34 -0600 Subject: [PATCH 052/356] updating history --- ios/history.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ios/history.md b/ios/history.md index ac80c9d424..cdc62b437e 100644 --- a/ios/history.md +++ b/ios/history.md @@ -1,5 +1,8 @@ # Keyman for iPhone and iPad Version History +## 2018-04-25 10.0.141 beta +* Fix alphabetical list to be case insensitive on new keyboard list + ## 2018-04-25 10.0.140 beta * Fixed lack of output for certain punctuation longpress keys. (#702) -- GitLab From 4682b887f01764884fd22edc2d4fabfff9738655 Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Tue, 1 May 2018 06:30:26 -0600 Subject: [PATCH 053/356] add fallback strategy when json date includes milliseconds --- .../KMEI/KeymanEngine/Classes/Manager.swift | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift index 41a6c068ed..05e56fad74 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift @@ -582,15 +582,24 @@ 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 = .ios8601WithMilliseconds + do { + let keyboard = try decoder.decode(KeyboardAPICall.self, from: data) + downloadKeyboard(keyboard) + } catch { + downloadFailed(forKeyboards: [], error: error) + } } } -- GitLab From 4360fdbed21c02a10f02be5d2111cb28e9a82441 Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Tue, 1 May 2018 06:31:17 -0600 Subject: [PATCH 054/356] convenience method for getting date strategy that supports milliseconds --- ...SONDecoder.DateDecodingStrategy+ISO8601Fallback.swift | 9 +++++++++ 1 file changed, 9 insertions(+) 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 961b2a5305..5d4274bf07 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Extension/JSONDecoder.DateDecodingStrategy+ISO8601Fallback.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Extension/JSONDecoder.DateDecodingStrategy+ISO8601Fallback.swift @@ -18,4 +18,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 ) + } } -- GitLab From fa77f04b264b24c34aeeecb450bd30e0262da1be Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Tue, 1 May 2018 07:03:01 -0600 Subject: [PATCH 055/356] adding custom errors for throwing --- .../KMEI/KeymanEngine.xcodeproj/project.pbxproj | 12 ++++++++++++ .../KeymanEngine/Classes/Errors/KeyboardError.swift | 13 +++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 ios/engine/KMEI/KeymanEngine/Classes/Errors/KeyboardError.swift diff --git a/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj b/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj index 26138a7d5b..82b72fd0d5 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/Errors/KeyboardError.swift b/ios/engine/KMEI/KeymanEngine/Classes/Errors/KeyboardError.swift new file mode 100644 index 0000000000..bf705e360c --- /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 +} -- GitLab From 30d7ffabc7ba5f21f00925e40040c825c19effbc Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Tue, 1 May 2018 07:04:09 -0600 Subject: [PATCH 056/356] fixed unused call warnings by using '_ =' or changing method signature to throw instead of return a bool --- .../Classes/KeyboardMenuView.swift | 2 +- .../KeyboardInfoViewController.swift | 2 +- .../KeyboardPickerViewController.swift | 4 +-- .../KMEI/KeymanEngine/Classes/Manager.swift | 26 ++++++++++--------- .../KMEI/KeymanEngine/Classes/TextField.swift | 2 +- .../KMEI/KeymanEngine/Classes/TextView.swift | 2 +- ios/keyman/Keyman/Keyman/AppDelegate.swift | 2 +- .../Keyman/Keyman/MainViewController.swift | 4 +-- 8 files changed, 23 insertions(+), 21 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/KeyboardMenuView.swift b/ios/engine/KMEI/KeymanEngine/Classes/KeyboardMenuView.swift index 8e51c0f74a..e12ad40f3a 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/KeyboardMenuView.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/KeyboardMenuView.swift @@ -325,7 +325,7 @@ class KeyboardMenuView: UIView, UITableViewDelegate, UITableViewDataSource, UIGe guard let kb = tableList[index] as? InstallableKeyboard else { return } - if Manager.shared.setKeyboard(kb) { + if let _ = try? Manager.shared.setKeyboard(kb) { tableView?.reloadData() } } diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardInfoViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardInfoViewController.swift index ac1e4df0b8..61a518b5f9 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardInfoViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardInfoViewController.swift @@ -70,7 +70,7 @@ class KeyboardInfoViewController: UITableViewController, UIAlertViewDelegate { if indexPath.row == 1 { let url = URL(string: "http://help.keyman.com/keyboard/\(keyboardID)/\(keyboardVersion)/")! if let openURL = Manager.shared.openURL { - openURL(url) + _ = openURL(url) } else { log.error("openURL not set in Manager. Failed to open \(url)") } diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardPickerViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardPickerViewController.swift index 8e0967c5d3..5bfd2b4d28 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardPickerViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardPickerViewController.swift @@ -232,7 +232,7 @@ class KeyboardPickerViewController: UITableViewController, UIAlertViewDelegate { // Add keyboard. for keyboard in keyboards { Manager.shared.addKeyboard(keyboard) - Manager.shared.setKeyboard(keyboard) + try? Manager.shared.setKeyboard(keyboard) } navigationController?.popToRootViewController(animated: true) @@ -263,7 +263,7 @@ class KeyboardPickerViewController: UITableViewController, UIAlertViewDelegate { private func switchKeyboard(_ index: Int) { // Switch keyboard and register to user defaults. - if Manager.shared.setKeyboard(userKeyboards[index]) { + if let _ = try? Manager.shared.setKeyboard(userKeyboards[index]) { tableView.reloadData() } diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift index 41a6c068ed..8cf11fc9af 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift @@ -191,20 +191,23 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat /// - SeeAlso: /// - addKeyboard() /// - Returns: Whether the keyboard was set successfully + //TODO: this method appears unused, should we remove it? public func setKeyboard(withFullID fullID: FullKeyboardID) -> Bool { - if let keyboard = Storage.active.userDefaults.userKeyboard(withFullID: fullID) { - return setKeyboard(keyboard) + if let keyboard = Storage.active.userDefaults.userKeyboard(withFullID: fullID), + let _ = try? setKeyboard(keyboard) { + return true } return false } + /// Set the current keyboard. /// - /// - Returns: Whether the keyboard was set successfully - public func setKeyboard(_ kb: InstallableKeyboard) -> Bool { + /// - Throws: error if the keyboard was unchanged + public func setKeyboard(_ kb: InstallableKeyboard) throws { if kb.fullID == currentKeyboardID { log.info("Keyboard unchanged: \(kb.fullID)") - return false + throw KeyboardError.unchanged } log.info("Setting language: \(kb.fullID)") @@ -234,7 +237,6 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat NotificationCenter.default.post(name: Notifications.keyboardChanged, object: self, value: kb) - return true } /// Adds a new keyboard to the list in the keyboard picker if it doesn't already exist. @@ -297,7 +299,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat // Set a new keyboard if deleting the current one if kb.fullID == currentKeyboardID { - setKeyboard(userKeyboards[0]) + try? setKeyboard(userKeyboards[0]) } if !userKeyboards.contains(where: { $0.id == kb.id }) { @@ -332,7 +334,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat return nil } let newIndex = (index + 1) % userKeyboards.count - setKeyboard(userKeyboards[newIndex]) + try? setKeyboard(userKeyboards[newIndex]) return newIndex } @@ -995,11 +997,11 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat currentKeyboardID = nil if let keyboard = keyboard { - setKeyboard(keyboard) + try? setKeyboard(keyboard) } else if let keyboard = Storage.active.userDefaults.userKeyboards?[safe: 0] { - setKeyboard(keyboard) + try? setKeyboard(keyboard) } else { - setKeyboard(Defaults.keyboard) + try? setKeyboard(Defaults.keyboard) } } @@ -1145,7 +1147,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat } else if let userKbs = Storage.active.userDefaults.userKeyboards, !userKbs.isEmpty { newKb = userKbs[0] } - setKeyboard(newKb) + try? setKeyboard(newKb) } NotificationCenter.default.post(name: Notifications.keyboardLoaded, object: self, value: newKb) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/TextField.swift b/ios/engine/KMEI/KeymanEngine/Classes/TextField.swift index 0e656d55f4..80e44f4f25 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 df52e8a896..ba2133a3f9 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/keyman/Keyman/Keyman/AppDelegate.swift b/ios/keyman/Keyman/Keyman/AppDelegate.swift index dd330bf0e2..0889392b39 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/MainViewController.swift b/ios/keyman/Keyman/Keyman/MainViewController.swift index 883b676522..2605c3b5eb 100644 --- a/ios/keyman/Keyman/Keyman/MainViewController.swift +++ b/ios/keyman/Keyman/Keyman/MainViewController.swift @@ -495,7 +495,7 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg for keyboard in keyboards { Manager.shared.addKeyboard(keyboard) - Manager.shared.setKeyboard(keyboard) + try? Manager.shared.setKeyboard(keyboard) } launchUrl = nil @@ -879,7 +879,7 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg cancelButtonTitle: "Cancel", otherButtonTitles: "Install", tag: 0) } else { Manager.shared.addKeyboard(keyboard) - Manager.shared.setKeyboard(keyboard) + try? Manager.shared.setKeyboard(keyboard) } } else { launchUrl = nil -- GitLab From d86cca4724457f07dcd6e3518e90614676db6775 Mon Sep 17 00:00:00 2001 From: Jacob Bullock Date: Tue, 1 May 2018 07:27:15 -0600 Subject: [PATCH 057/356] cleaning up statements and removing force unwrap --- ios/engine/KMEI/KeymanEngine/Classes/Manager.swift | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift index 8cf11fc9af..9c69edea65 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift @@ -412,16 +412,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 { -- GitLab From f388d19fed59f2893653868f4aee533ea6876724 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Tue, 1 May 2018 15:13:10 -0400 Subject: [PATCH 058/356] Fixed the previous fix so it actually works. --- .../KMDownloadKeyboard/KMDownloadKBWindowController.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.m index 24303b5d48..a0fc548950 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.m @@ -28,15 +28,15 @@ [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]]]; } -// REVIEW: Compare this implementation to the one in KMKeyboardHelpWindowController. Should we -// use a consistent prefix? -- (void) decidePolicyForNavigationAction:(NSDictionary*) actionInformation request:(NSURLRequest*) request frame:(WebFrame*) frame decisionListener:(id ) listener { +- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener { NSString* url = [[request URL] description]; - NSLog(@"decidePolicyForNavigationAction, navigating to %@", url); + if (self.AppDelegate.debugMode) + NSLog(@"decidePolicyForNavigationAction, navigating to %@", url); if ([request.URL.absoluteString startsWith:@"keyman:link?url="]) { [listener ignore]; -- GitLab From 4cb297a5e60b094418996eac67c334f4a4609779 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Tue, 1 May 2018 16:58:07 -0400 Subject: [PATCH 059/356] Got all the typing working in config windows and most link navigation Still need to investigate why some links to help.keyman.com/... don't work in download window. Also, this check-in contains some commmented-out code to try to get mouse pointer to change over hyperlinks. Need to get it working or revert (possibly need to report as a separate issue). Also, it would be nice for there to be some user feedback when loading pages, which can be quite slow at times. --- .../KMConfiguration/preferences.xib | 121 +++++++++--------- .../KMDownloadKBWindowController.m | 40 +++++- .../KMDownloadKBWindowController.xib | 13 +- .../KMInfoWindow/KMInfoWindowController.xib | 19 +-- .../Keyman4MacIM/KMInputMethodAppDelegate.h | 1 + .../Keyman4MacIM/KMInputMethodAppDelegate.m | 12 +- .../KMKeyboardHelpWindowController.xib | 18 ++- 7 files changed, 136 insertions(+), 88 deletions(-) diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/preferences.xib b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/preferences.xib index 1aad31feb3..7a90583a15 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/preferences.xib +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/preferences.xib @@ -1,8 +1,10 @@ - - + + - - + + + + @@ -15,8 +17,8 @@ - - + + @@ -49,11 +51,11 @@ - + - + @@ -156,7 +158,7 @@ Presentation: +
@@ -52,7 +53,7 @@ - + @@ -79,7 +80,7 @@ - + @@ -96,7 +97,7 @@

-
+

-- GitLab From 51a3d6c09e6a3a200cbcfa8e0e861ed281b62d6d Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 3 May 2018 11:58:13 +0700 Subject: [PATCH 063/356] Ensure only one key is selected so modifying or deleting it doesn't break JSON --- .../src/developer/TIKE/xml/layoutbuilder/builder.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/windows/src/developer/TIKE/xml/layoutbuilder/builder.js b/windows/src/developer/TIKE/xml/layoutbuilder/builder.js index c7199d027a..a6b672d239 100644 --- a/windows/src/developer/TIKE/xml/layoutbuilder/builder.js +++ b/windows/src/developer/TIKE/xml/layoutbuilder/builder.js @@ -663,8 +663,8 @@ $(function () { builder.selectPlatform(); $('#selLayer').val(s.layer); builder.selectLayer(); - builder.selectKey($('#kbd .key').filter(function (index) { return $(this).data('id') === s.key; })); - if (s.subkey) builder.selectSubKey($('#sk .key').filter(function (index) { return $(this).data('id') === s.subkey; })); + builder.selectKey($('#kbd .key').filter(function (index) { return $(this).data('id') === s.id; }).first()); + if (s.subkey) builder.selectSubKey($('#sk .key').filter(function (index) { return $(this).data('id') === s.subkey; }).first()); } this.saveUndo = function (saveToRedo) { @@ -738,7 +738,7 @@ $(function () { return row; }; - + this.addKey = function (position, isSubKey, sp) { var key = document.createElement('div'); var ktext = document.createElement('div'); @@ -749,7 +749,7 @@ $(function () { $(key).append(ktext); $(key).addClass('key'); $(key).data('id', 'T_new_' + this.uniqId); - this.uniqId++; + builder.uniqId++; builder.updateKeyId(key); if (isSubKey) { @@ -1170,7 +1170,7 @@ $(function () { var keyId = builder.selectedKey().data('id'); //$('#kbd .key') builder.prepareLayer(); if (keyId !== null) - builder.selectKey($('#kbd .key').filter(function (index) { return $(this).data('id') === keyId; })); + builder.selectKey($('#kbd .key').filter(function (index) { return $(this).data('id') === keyId; }).first()); } // -- GitLab From 5b4307e8cd8db751a2d47775b9b9d9f0a0ba8967 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 3 May 2018 12:13:39 +0700 Subject: [PATCH 064/356] [developer] When importing a KVK into touch layout, treats sp, width and pad as strings to mitigate #743 --- .../src/developer/TIKE/oskbuilder/TouchLayout.pas | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/windows/src/developer/TIKE/oskbuilder/TouchLayout.pas b/windows/src/developer/TIKE/oskbuilder/TouchLayout.pas index 4bb1c9459c..925ace41d7 100644 --- a/windows/src/developer/TIKE/oskbuilder/TouchLayout.pas +++ b/windows/src/developer/TIKE/oskbuilder/TouchLayout.pas @@ -692,12 +692,12 @@ begin AddJSONValue(JSON, 'nextlayer', FNextLayer); AddJSONValue(JSON, 'fontsize', FFontSize); AddJSONValue(JSON, 'layer', FLayer); - AddJSONValue(JSON, 'width', FWidth); + if FWidth <> 0 then AddJSONValue(JSON, 'width', IntToStr(FWidth)); AddJSONValue(JSON, 'dk', FDk); AddJSONValue(JSON, 'font', FFont); AddJSONValue(JSON, 'id', FId); - AddJSONValue(JSON, 'pad', FPad); - AddJSONValue(JSON, 'sp', FSp); + if FPad <> 0 then AddJSONValue(JSON, 'pad', IntToStr(FPad)); + if FSp <> 0 then AddJSONValue(JSON, 'sp', IntToStr(FSp)); AddJSONValue(JSON, 'text', FText); end; @@ -841,12 +841,12 @@ begin AddJSONValue(JSON, 'nextlayer', FNextLayer); AddJSONValue(JSON, 'fontsize', FFontSize); AddJSONValue(JSON, 'layer', FLayer); - AddJSONValue(JSON, 'width', FWidth); + if FWidth <> 0 then AddJSONValue(JSON, 'width', IntToStr(FWidth)); AddJSONValue(JSON, 'dk', FDk); AddJSONValue(JSON, 'font', FFont); AddJSONValue(JSON, 'id', FId); - AddJSONValue(JSON, 'pad', FPad); - AddJSONValue(JSON, 'sp', FSp); + if FPad <> 0 then AddJSONValue(JSON, 'pad', IntToStr(FPad)); + if FSp <> 0 then AddJSONValue(JSON, 'sp', IntToStr(FSp)); AddJSONValue(JSON, 'text', FText); if FSk.Count > 0 then -- GitLab From f0ef356b8f7f136c6943e26eae5ed63fffed1d5a Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 3 May 2018 15:11:07 +0700 Subject: [PATCH 065/356] Trap errors if Keyman Desktop is not installed when trying to install a keyboard --- .../TIKE/main/KeymanDeveloperUtils.pas | 25 ++++++++++++++++--- .../src/global/delphi/general/KeymanPaths.pas | 12 ++++++--- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/windows/src/developer/TIKE/main/KeymanDeveloperUtils.pas b/windows/src/developer/TIKE/main/KeymanDeveloperUtils.pas index 5cc891f958..6a3eaacc43 100644 --- a/windows/src/developer/TIKE/main/KeymanDeveloperUtils.pas +++ b/windows/src/developer/TIKE/main/KeymanDeveloperUtils.pas @@ -340,7 +340,12 @@ end; function IsKeymanDesktopInstalled: Boolean; begin - Result := FileExists(TKeymanPaths.KeymanDesktopInstallPath(TKeymanPaths.S_KMShell)); + try + Result := FileExists(TKeymanPaths.KeymanDesktopInstallPath(TKeymanPaths.S_KMShell)); + except + on E:EKeymanPath do + Result := False; + end; end; procedure InstallPackage(const nm: string; FCanInstallUnreg: Boolean); @@ -356,7 +361,16 @@ begin Exit; end; - kmshell := TKeymanPaths.KeymanDesktopInstallPath(TKeymanPaths.S_KMShell); + try + kmshell := TKeymanPaths.KeymanDesktopInstallPath(TKeymanPaths.S_KMShell); + except + on E:EKeymanPath do + begin + ShowMessage('Keyman Desktop is not installed. You must install Keyman Desktop to install this keyboard.'); + Exit; + end; + end; + if TUtilExecute.WaitForProcess('"'+kmshell+'" -i "'+nm+'"', ExtractFilePath(nm)) = False then // I3475 ShowMessage('Failed to install package: '+errmsg); @@ -615,7 +629,12 @@ end; function GetKMShellPath(var ps: string): Boolean; // I3655 begin - ps := TKeymanPaths.KeymanDesktopInstallPath(TKeymanPaths.S_KMShell); + try + ps := TKeymanPaths.KeymanDesktopInstallPath(TKeymanPaths.S_KMShell); + except + on E:EKeymanPath do + Exit(False); + end; Result := FileExists(ps); end; diff --git a/windows/src/global/delphi/general/KeymanPaths.pas b/windows/src/global/delphi/general/KeymanPaths.pas index 5ec2df5cba..5e92b59533 100644 --- a/windows/src/global/delphi/general/KeymanPaths.pas +++ b/windows/src/global/delphi/general/KeymanPaths.pas @@ -2,7 +2,12 @@ unit KeymanPaths; interface +uses + System.SysUtils; + type + EKeymanPath = class(Exception); + TKeymanPaths = class public const S_KMShell = 'kmshell.exe'; @@ -28,7 +33,6 @@ uses Winapi.Windows, Winapi.ActiveX, Winapi.ShlObj, - System.SysUtils, System.Win.Registry, DebugPaths, @@ -90,7 +94,7 @@ begin Result := GetDebugPath('KeymanDesktop', Result); if Result = '' then - raise Exception.Create('Unable to find the Keyman Desktop directory. You should reinstall the product.'); + raise EKeymanPath.Create('Unable to find the Keyman Desktop directory. You should reinstall the product.'); Result := IncludeTrailingPathDelimiter(Result) + filename; end; @@ -114,7 +118,7 @@ begin Result := GetDebugPath('KeymanEngine', Result); if Result = '' then - raise Exception.Create('Unable to find the Keyman Engine directory. You should reinstall the product.'); + raise EKeymanPath.Create('Unable to find the Keyman Engine directory. You should reinstall the product.'); Result := IncludeTrailingPathDelimiter(Result) + filename; end; @@ -147,7 +151,7 @@ begin Result := GetDebugPath('Keyboards', Result, True); if Result = '' then - raise Exception.Create('Unable to find the Keyboards directory. You should reinstall the product.'); + raise EKeymanPath.Create('Unable to find the Keyboards directory. You should reinstall the product.'); Result := Result + Filename; end; -- GitLab From 29b51dee7c357ba9e780fe9a2f8b1aa0f7b5e6c6 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 3 May 2018 15:36:07 +0700 Subject: [PATCH 066/356] Avoid crash if online update already running --- .../src/developer/TIKE/actions/dmActionsMain.pas | 6 ++++++ windows/src/developer/history.md | 6 ++++++ .../src/global/delphi/online/OnlineUpdateCheck.pas | 13 +++++++++++++ 3 files changed, 25 insertions(+) diff --git a/windows/src/developer/TIKE/actions/dmActionsMain.pas b/windows/src/developer/TIKE/actions/dmActionsMain.pas index fa9fc006e9..63dbf5afd4 100644 --- a/windows/src/developer/TIKE/actions/dmActionsMain.pas +++ b/windows/src/developer/TIKE/actions/dmActionsMain.pas @@ -423,6 +423,12 @@ end; procedure TmodActionsMain.actHelpCheckForUpdatesExecute(Sender: TObject); begin + if TOnlineUpdateCheck.Running then + begin + ShowMessage('An online update check is already running.'); + Exit; + end; + with TOnlineUpdateCheck.Create(SRegKey_KeymanDeveloper_CU, OnlineProductID_KeymanDeveloper_100, True, False, False, GetProxySettings.Server, GetProxySettings.Port, GetProxySettings.Username, GetProxySettings.Password) do // I3377 try if Run = oucShutDown then diff --git a/windows/src/developer/history.md b/windows/src/developer/history.md index 8356345132..718cecf070 100644 --- a/windows/src/developer/history.md +++ b/windows/src/developer/history.md @@ -1,5 +1,11 @@ # Keyman Developer Version History + +## 2018-05-03 10.0.1072.0 beta +* Special keys imported from a visual keyboard into a touch layout now display correctly (#812) +* Touch layout editor no longer leaves broken JSON when deleting or modifying some keys (#811) +* Checking for online update when it is already running in background can crash Developer (#813) + ## 2018-04-30 10.0.1067.0 beta * BCP 47 picker in package editor now does name lookups and constrains codes as required by target operating systems (#746, #766) diff --git a/windows/src/global/delphi/online/OnlineUpdateCheck.pas b/windows/src/global/delphi/online/OnlineUpdateCheck.pas index 1b6a613c60..bd51117c27 100644 --- a/windows/src/global/delphi/online/OnlineUpdateCheck.pas +++ b/windows/src/global/delphi/online/OnlineUpdateCheck.pas @@ -70,6 +70,8 @@ type function DoRun: TOnlineUpdateCheckResult; procedure SyncShowUpdateForm; procedure SyncShutDown; + private + class var FRunning: Boolean; public protected @@ -79,6 +81,7 @@ type constructor Create(ARootKey: string; AOnlineProductID: Integer; AForce, ASilent, AThread: Boolean; AProxyServer: string; AProxyPort: Integer; AProxyUsername, AProxyPassword: string); destructor Destroy; override; function Run: TOnlineUpdateCheckResult; + class function Running: Boolean; property CurrentVersion: string read FCurrentVersion write FCurrentVersion; property ShowErrors: Boolean read FShowErrors write FShowErrors; end; @@ -108,6 +111,9 @@ uses constructor TOnlineUpdateCheck.Create(ARootKey: string; AOnlineProductID: Integer; AForce, ASilent, AThread: Boolean; AProxyServer: string; AProxyPort: Integer; AProxyUsername, AProxyPassword: string); begin + Assert(not FRunning); + FRunning := True; + FShowErrors := True; FCurrentVersion := GetVersionString; FParams.Result := oucUnknown; @@ -138,6 +144,8 @@ begin KL.Log('TOnlineUpdateCheck.Destroy: FErrorMessage = '+FErrorMessage); KL.Log('TOnlineUpdateCheck.Destroy: FParams.Result = '+IntToStr(Ord(FParams.Result))); + FRunning := False; + inherited Destroy; end; @@ -155,6 +163,11 @@ begin end; end; +class function TOnlineUpdateCheck.Running: Boolean; +begin + Result := FRunning; +end; + procedure TOnlineUpdateCheck.DoDownloadUpdate(AOwner: TfrmDownloadProgress; var Result: Boolean); begin Result := False; -- GitLab From 1c0b79379f3db97460c32a5261a316e1873f64b9 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 3 May 2018 15:52:11 +0700 Subject: [PATCH 067/356] Don't create a blank project on 'opening' a project, either on startup or via menu, fixes #151 --- windows/src/developer/TIKE/actions/dmActionsMain.pas | 6 ++++++ windows/src/developer/TIKE/main/UfrmMain.pas | 2 ++ 2 files changed, 8 insertions(+) diff --git a/windows/src/developer/TIKE/actions/dmActionsMain.pas b/windows/src/developer/TIKE/actions/dmActionsMain.pas index fa9fc006e9..ca51bb5a53 100644 --- a/windows/src/developer/TIKE/actions/dmActionsMain.pas +++ b/windows/src/developer/TIKE/actions/dmActionsMain.pas @@ -487,6 +487,12 @@ end; procedure TmodActionsMain.OpenProject(FileName: WideString); begin + if (FileName <> '') and not FileExists(FileName) then + begin + ShowMessage('The project '+FileName+' does not exist.'); + Exit; + end; + FGlobalProject.Save; FreeAndNil(FGlobalProject); FGlobalProject := TProjectUI.Create(FileName); // I4687 diff --git a/windows/src/developer/TIKE/main/UfrmMain.pas b/windows/src/developer/TIKE/main/UfrmMain.pas index b8693479fc..ee024815b2 100644 --- a/windows/src/developer/TIKE/main/UfrmMain.pas +++ b/windows/src/developer/TIKE/main/UfrmMain.pas @@ -502,6 +502,8 @@ begin RemoveOldestTikeEditFonts(False); RemoveOldestTikeTestFonts(False); + if (FActiveProject <> '') and not FileExists(FActiveProject) then + FActiveProject := ''; TProjectUI.Create(FActiveProject, True); // I4687 -- GitLab From 1dc54d46348a02c7cd7dc4992330632ef3ec9fe2 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 4 May 2018 07:55:23 +0700 Subject: [PATCH 068/356] Update history --- windows/src/developer/history.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/windows/src/developer/history.md b/windows/src/developer/history.md index 718cecf070..ee45191590 100644 --- a/windows/src/developer/history.md +++ b/windows/src/developer/history.md @@ -1,10 +1,12 @@ # Keyman Developer Version History - -## 2018-05-03 10.0.1072.0 beta -* Special keys imported from a visual keyboard into a touch layout now display correctly (#812) +## 2018-05-03 10.0.1074.0 beta +* Restrict modifier options to a small set by default in touch layout editor (#810) * Touch layout editor no longer leaves broken JSON when deleting or modifying some keys (#811) +* Special keys imported from a visual keyboard into a touch layout now display correctly (#812) * Checking for online update when it is already running in background can crash Developer (#813) +* Avoid crash if online update already running (#814) +* Don't create a blank project on 'opening' a project, either on startup or via menu (#815) ## 2018-04-30 10.0.1067.0 beta * BCP 47 picker in package editor now does name lookups and constrains codes as required by target operating systems (#746, #766) -- GitLab From a375e69b5edc8c488d5903e1302443d3a646b3f2 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 4 May 2018 09:12:34 +0700 Subject: [PATCH 069/356] Ensure that visual keyboard is correctly associated with kmx at compile time --- windows/src/developer/TIKE/project/kmnProjectFile.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/windows/src/developer/TIKE/project/kmnProjectFile.pas b/windows/src/developer/TIKE/project/kmnProjectFile.pas index 4831969ff5..edaaa8cbf5 100644 --- a/windows/src/developer/TIKE/project/kmnProjectFile.pas +++ b/windows/src/developer/TIKE/project/kmnProjectFile.pas @@ -179,6 +179,7 @@ begin end; if not SameFileName(AKVKSourceFile, AKVKTargetFile) then try + Header.AssociatedKeyboard := ChangeFileExt(ExtractFileName(Self.FileName), ''); SaveToFile(AKVKTargetFile, kvksfBinary); except on E:Exception do -- GitLab From 247f7d2cbb5ce5cc9150ef1a48c7e50386fff25c Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 4 May 2018 15:55:56 +0700 Subject: [PATCH 070/356] Fixes #365. Scroll editor into view after undo --- windows/src/global/delphi/comp/KMDActions.pas | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/windows/src/global/delphi/comp/KMDActions.pas b/windows/src/global/delphi/comp/KMDActions.pas index f028823f7b..099aa7249a 100644 --- a/windows/src/global/delphi/comp/KMDActions.pas +++ b/windows/src/global/delphi/comp/KMDActions.pas @@ -351,7 +351,11 @@ end; procedure TKMDEditUndo.ExecuteTarget(Target: TObject); begin if Target is TCustomEdit then GetCustomEdit(Target).Undo - else if Target is TKeymanDeveloperMemo then GetPlusMemo(Target).Undo + else if Target is TKeymanDeveloperMemo then + begin + GetPlusMemo(Target).Undo; + GetPlusMemo(Target).ScrollInView; + end else GetInterface(Target).Undo; end; -- GitLab From 74c3fe003c01233135705dca055f037d209773a6 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 4 May 2018 15:57:51 +0700 Subject: [PATCH 071/356] Add #821 --- windows/src/developer/history.md | 1 + 1 file changed, 1 insertion(+) diff --git a/windows/src/developer/history.md b/windows/src/developer/history.md index ee45191590..76e7192aff 100644 --- a/windows/src/developer/history.md +++ b/windows/src/developer/history.md @@ -7,6 +7,7 @@ * Checking for online update when it is already running in background can crash Developer (#813) * Avoid crash if online update already running (#814) * Don't create a blank project on 'opening' a project, either on startup or via menu (#815) +* Scroll text editor cursor into view after undo (#821) ## 2018-04-30 10.0.1067.0 beta * BCP 47 picker in package editor now does name lookups and constrains codes as required by target operating systems (#746, #766) -- GitLab From c5e4f7d8e418b6b363a533f2c25f2772dd51ff42 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 4 May 2018 15:58:32 +0700 Subject: [PATCH 072/356] Version --- windows/src/developer/history.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/src/developer/history.md b/windows/src/developer/history.md index 76e7192aff..9e44db9185 100644 --- a/windows/src/developer/history.md +++ b/windows/src/developer/history.md @@ -1,6 +1,6 @@ # Keyman Developer Version History -## 2018-05-03 10.0.1074.0 beta +## 2018-05-03 10.0.1075.0 beta * Restrict modifier options to a small set by default in touch layout editor (#810) * Touch layout editor no longer leaves broken JSON when deleting or modifying some keys (#811) * Special keys imported from a visual keyboard into a touch layout now display correctly (#812) -- GitLab From 6441c77723e5c9837d25d5032a646405c95aec64 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 4 May 2018 16:06:13 +0700 Subject: [PATCH 073/356] Fixes #756. Correctly show messages window after compile. --- windows/src/developer/TIKE/child/UfrmKeymanWizard.pas | 2 +- windows/src/developer/TIKE/child/UfrmPackageEditor.pas | 2 +- windows/src/developer/TIKE/project/kmnProjectFileUI.pas | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/windows/src/developer/TIKE/child/UfrmKeymanWizard.pas b/windows/src/developer/TIKE/child/UfrmKeymanWizard.pas index df9c0c4230..4fb2fa1607 100644 --- a/windows/src/developer/TIKE/child/UfrmKeymanWizard.pas +++ b/windows/src/developer/TIKE/child/UfrmKeymanWizard.pas @@ -2923,7 +2923,7 @@ begin frmMessages.Clear; if CompileKeyboardFile(PChar(KMNFileName.Name), PChar(KMXFileName2), False, False, False, CompilerMessage) <= 0 then // I4181 // I4865 // I4866 begin - frmMessages.Show; + frmMessages.DoShowForm; ShowMessage('There were errors compiling the keyboard to convert to the On Screen Keyboard.'); FreeAndNil(KMXFileName); // I4181 end; diff --git a/windows/src/developer/TIKE/child/UfrmPackageEditor.pas b/windows/src/developer/TIKE/child/UfrmPackageEditor.pas index 7748f6921d..c381ba7104 100644 --- a/windows/src/developer/TIKE/child/UfrmPackageEditor.pas +++ b/windows/src/developer/TIKE/child/UfrmPackageEditor.pas @@ -1276,7 +1276,7 @@ begin try OnError := Self.HandlePackageRefreshError; if not Execute then - frmMessages.Show; + frmMessages.DoShowForm; finally Free; end; diff --git a/windows/src/developer/TIKE/project/kmnProjectFileUI.pas b/windows/src/developer/TIKE/project/kmnProjectFileUI.pas index 5d562f4351..2acbbef4c9 100644 --- a/windows/src/developer/TIKE/project/kmnProjectFileUI.pas +++ b/windows/src/developer/TIKE/project/kmnProjectFileUI.pas @@ -150,7 +150,7 @@ begin end; if not FSilent then - frmMessages.Show; + frmMessages.DoShowForm; Result := ProjectFile.CompileKeyboard; end; -- GitLab From 4e0e0655f077fe842d5a6e14194552b3d7a91980 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 4 May 2018 16:11:36 +0700 Subject: [PATCH 074/356] history --- windows/src/developer/history.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/windows/src/developer/history.md b/windows/src/developer/history.md index 9e44db9185..d37ac97d18 100644 --- a/windows/src/developer/history.md +++ b/windows/src/developer/history.md @@ -1,6 +1,6 @@ # Keyman Developer Version History -## 2018-05-03 10.0.1075.0 beta +## 2018-05-03 10.0.1076.0 beta * Restrict modifier options to a small set by default in touch layout editor (#810) * Touch layout editor no longer leaves broken JSON when deleting or modifying some keys (#811) * Special keys imported from a visual keyboard into a touch layout now display correctly (#812) @@ -8,6 +8,7 @@ * Avoid crash if online update already running (#814) * Don't create a blank project on 'opening' a project, either on startup or via menu (#815) * Scroll text editor cursor into view after undo (#821) +* Correctly show the messages window after a compile (#822) ## 2018-04-30 10.0.1067.0 beta * BCP 47 picker in package editor now does name lookups and constrains codes as required by target operating systems (#746, #766) -- GitLab From 3fb90728a82685bb3d61e8bc33c1d587661afb94 Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Mon, 7 May 2018 10:02:31 +0700 Subject: [PATCH 075/356] Fixes #162, treating virtual keys case-insensitively. --- web/source/kmwosk.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/web/source/kmwosk.ts b/web/source/kmwosk.ts index bc1fe34cf3..6b414afc2f 100644 --- a/web/source/kmwosk.ts +++ b/web/source/kmwosk.ts @@ -795,24 +795,24 @@ if(!window['keyman']['initialized']) { * @param {string} keyName custom virtual key code to lookup in the dictionary * @return {number} key code > 255 on success, or 0 if not found */ - osk.getVKDictionaryCode = function(keyName) - { + osk.getVKDictionaryCode = function(keyName) { var activeKeyboard = keymanweb.keyboardManager.activeKeyboard; - if(!activeKeyboard['VKDictionary']) - { + if(!activeKeyboard['VKDictionary']) { var a=[]; - if(typeof activeKeyboard['KVKD'] == 'string') - { + if(typeof activeKeyboard['KVKD'] == 'string') { // Build the VK dictionary - // TODO: Move the dictionary build into the compiler -- so compiler generates code such as following. Makes the VKDictionary member unnecessary + // TODO: Move the dictionary build into the compiler -- so compiler generates code such as following. + // Makes the VKDictionary member unnecessary. // this.KVKD={"K_ABC":256,"K_DEF":257,...}; var s=activeKeyboard['KVKD'].split(' '); - for(var i=0; i Date: Mon, 7 May 2018 10:05:55 +0700 Subject: [PATCH 076/356] Web history.md tweak. --- web/history.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/history.md b/web/history.md index 43f0e10d42..71cda75ad8 100644 --- a/web/history.md +++ b/web/history.md @@ -1,5 +1,8 @@ # KeymanWeb Version History +## 2018-05-07 10.0.89 beta +* Fixes an issue with case sensitivite virtual keys used by some Keyman keyboards. (#162) + ## 2018-04-25 10.0.86 beta * Fixes display of popup keys representing modifiers and other special characters. (#698) -- GitLab From 6f9a0406b0ef9fdd867250b17086ce59a25e17ea Mon Sep 17 00:00:00 2001 From: Joshua Horton Date: Mon, 7 May 2018 13:34:01 +0700 Subject: [PATCH 077/356] Fixed history.md typo. --- web/history.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/history.md b/web/history.md index 71cda75ad8..5e2d843a76 100644 --- a/web/history.md +++ b/web/history.md @@ -1,7 +1,7 @@ # KeymanWeb Version History ## 2018-05-07 10.0.89 beta -* Fixes an issue with case sensitivite virtual keys used by some Keyman keyboards. (#162) +* Fixes an issue with case sensitive virtual keys used by some Keyman keyboards. (#162) ## 2018-04-25 10.0.86 beta * Fixes display of popup keys representing modifiers and other special characters. (#698) -- GitLab From e40a4eaacb69511bc55f67b502b92db30c04ce90 Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Mon, 7 May 2018 14:12:11 +0700 Subject: [PATCH 078/356] Adds support for 'beep' in stores to KMW. Nothing for Developer yet. --- web/source/kmwcallback.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/web/source/kmwcallback.ts b/web/source/kmwcallback.ts index 1466efe325..84057bab42 100644 --- a/web/source/kmwcallback.ts +++ b/web/source/kmwcallback.ts @@ -83,7 +83,13 @@ namespace com.keyman { ['t']: 'n'; } - type ContextNonCharEntry = RuleDeadkey | ContextAny | RuleIndex | ContextEx | ContextNul; + class ContextBeep { + /** Discriminant field - 'b' for `beep` + */ + ['t']: 'b'; + } + + type ContextNonCharEntry = RuleDeadkey | ContextAny | RuleIndex | ContextEx | ContextNul | ContextBeep ; type ContextEntry = RuleChar | ContextNonCharEntry; /** @@ -507,6 +513,9 @@ namespace com.keyman { mismatch = true; } break; + case 'b': + this.beep(Ptarg); + break; default: assertNever(r); } -- GitLab From 594eba58140fa33ba5e5b0987526f186407aa663 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 7 May 2018 14:36:21 +0700 Subject: [PATCH 079/356] Fixes #731, fixes #816 - add language dialog adds script and/or region as required and also shows friendly language name when bcp 47 tag entered --- resources/standards-data/alltags/alltags.txt | 6106 +++++++++++++++++ resources/standards-data/alltags/readme.md | 13 + .../Keyman.Console.BuildStandardsData.pas | 8 +- .../Keyman.System.BuildISO6393Registry.pas | 4 +- ...Keyman.System.BuildLCIDToBCP47Registry.pas | 4 +- ...man.System.BuildLanguageSubtagRegistry.pas | 6 +- .../Keyman.System.BuildLibPalasoAllTags.pas | 90 + .../buildtools/build_standards_data/Makefile | 4 + .../build_standards_data.dpr | 3 +- .../build_standards_data.dproj | 2 +- .../install/UfrmInstallKeyboardLanguage.pas | 70 +- windows/src/desktop/kmshell/kmshell.dpr | 5 +- windows/src/desktop/kmshell/kmshell.dproj | 11 +- windows/src/desktop/kmshell/kmshell.res | Bin 7040 -> 7040 bytes ...yman.System.CanonicalLanguageCodeUtils.pas | 99 + .../Keyman.System.LanguageCodeUtils.pas | 72 +- 16 files changed, 6453 insertions(+), 44 deletions(-) create mode 100644 resources/standards-data/alltags/alltags.txt create mode 100644 resources/standards-data/alltags/readme.md create mode 100644 windows/src/buildtools/build_standards_data/Keyman.System.BuildLibPalasoAllTags.pas create mode 100644 windows/src/global/delphi/general/Keyman.System.CanonicalLanguageCodeUtils.pas diff --git a/resources/standards-data/alltags/alltags.txt b/resources/standards-data/alltags/alltags.txt new file mode 100644 index 0000000000..f4b06cd705 --- /dev/null +++ b/resources/standards-data/alltags/alltags.txt @@ -0,0 +1,6106 @@ +*aa = *aa-ET = aa-Latn = aa-Latn-ET +*aa-DJ = aa-Latn-DJ +*aa-ER = aa-Latn-ER +aa-Ethi = aa-Ethi-ET +aac = aac-PG = aac-Latn = aac-Latn-PG +aad = aad-PG = aad-Latn = aad-Latn-PG +aae = aae-IT = aae-Latn = aae-Latn-IT +aae-Grek = aae-Grek-IT +aag = aag-PG = aag-Latn = aag-Latn-PG +aah = aah-PG = aah-Latn = aah-Latn-PG +aai = aai-PG = *aai-Latn = aai-Latn-PG +aak = aak-PG = *aak-Latn = aak-Latn-PG +aal = aal-CM = aal-Latn = aal-Latn-CM +aan = aan-BR = aan-Latn = aan-Latn-BR +aap = aap-BR = aap-Latn = aap-Latn-BR +aas = aas-TZ = aas-Latn = aas-Latn-TZ +aat = aat-GR = aat-Grek = aat-Grek-GR +aau = aau-PG = *aau-Latn = aau-Latn-PG +aaw = aaw-PG = aaw-Latn = aaw-Latn-PG +aaz = aaz-ID = aaz-Latn = aaz-Latn-ID +ab = ab-GE = ab-Cyrl = ab-Cyrl-GE +ab-Geor = ab-Geor-GE +aba = aba-CI = aba-Latn = aba-Latn-CI +abc = abc-PH = abc-Latn = abc-Latn-PH +abe = abe-CA = abe-Latn = abe-Latn-CA +abg = abg-PG = abg-Latn = abg-Latn-PG +abh = abh-TJ = abh-Arab = abh-Arab-TJ +abi = abi-CI = *abi-Latn = abi-Latn-CI +abl-Rjng = abl-Rjng-ID +abn = abn-NG = abn-Latn = abn-Latn-NG +abp = abp-PH = abp-Latn = abp-Latn-PH +abq = abq-RU = abq-Cyrl = abq-Cyrl-RU +*abq-Latn = abq-Latn-TR +abr = abr-GH = abr-Latn = abr-Latn-GH +abs = abs-ID = abs-Latn = abs-Latn-ID +abt = abt-PG = *abt-Latn = abt-Latn-PG +abu = abu-CI = abu-Latn = abu-Latn-CI +abv = abv-BH = abv-Arab = abv-Arab-BH +abw = abw-PG = abw-Latn = abw-Latn-PG +abx = abx-PH = abx-Latn = abx-Latn-PH +aby = aby-PG = *aby-Latn = aby-Latn-PG +aca = aca-CO = aca-Latn = aca-Latn-CO +acd = acd-GH = *acd-Latn = acd-Latn-GH +ace = ace-ID = ace-Latn = ace-Latn-ID +acf = acf-LC = acf-Latn = acf-Latn-LC +ach = ach-UG = ach-Latn = ach-Latn-UG +acm = acm-IQ = acm-Arab = acm-Arab-IQ +acn = acn-CN = acn-Latn = acn-Latn-CN +acq = acq-YE = acq-Arab = acq-Arab-YE +acr = acr-GT = acr-Latn = acr-Latn-GT +acs = acs-BR = acs-Latn = acs-Latn-BR +act = act-NL = act-Latn = act-Latn-NL +acu = acu-EC = acu-Latn = acu-Latn-EC +acv = acv-US = acv-Latn = acv-Latn-US +acw = acw-SA = acw-Arab = acw-Arab-SA +acx = acx-OM = acx-Arab = acx-Arab-OM +acy-Arab = acy-Arab-CY +acy-Grek = acy-Grek-CY +acy-Latn = acy-Latn-CY +acz = acz-SD = acz-Latn = acz-Latn-SD +ada = ada-GH = *ada-Latn = ada-Latn-GH +adb = adb-TL = adb-Latn = adb-Latn-TL +add = add-CM = add-Latn = add-Latn-CM +ade = ade-TG = *ade-Latn = ade-Latn-TG +adg = adg-AU = adg-Latn = adg-Latn-AU +adh = adh-UG = adh-Latn = adh-Latn-UG +adi-Latn = adi-Latn-IN +adi-Tibt = adi-Tibt-CN +adj = adj-CI = *adj-Latn = adj-Latn-CI +adl-Latn = adl-Latn-IN +ado = ado-PG = ado-Latn = ado-Latn-PG +adq = adq-GH = adq-Latn = adq-Latn-GH +ads = ads-GH = ads-Latn = ads-Latn-GH +adt = adt-AU = adt-Latn = adt-Latn-AU +adw = adw-BR = adw-Latn = adw-Latn-BR +adx-Tibt = adx-Tibt-CN +ady = ady-RU = ady-Cyrl = ady-Cyrl-RU +ady-Arab = ady-Arab-RU +ady-Latn = ady-Latn-TR +adz = adz-PG = *adz-Latn = adz-Latn-PG +ae = ae-IR = ae-Avst = ae-Avst-IR +ae-Arab = ae-Arab-IR +ae-Gujr = ae-Gujr-IR +aea = aea-AU = aea-Latn = aea-Latn-AU +aeb = aeb-TN = *aeb-Arab = aeb-Arab-TN +*aeb-Latn = aeb-Latn-TN +aec-Arab = aec-Arab-EG +aek = aek-NC = aek-Latn = aek-Latn-NC +aer = aer-AU = aer-Latn = aer-Latn-AU +aeu = aeu-CN = aeu-Latn = aeu-Latn-CN +aew = aew-PG = aew-Latn = aew-Latn-PG +aey = aey-PG = *aey-Latn = aey-Latn-PG +aez = aez-PG = aez-Latn = aez-Latn-PG +*af = *af-ZA = af-Latn = af-Latn-ZA +af-Brai = af-Brai-ZA +*af-NA = af-Latn-NA +afb-Arab = afb-Arab-KW +afd = afd-PG = afd-Latn = afd-Latn-PG +afe-Latn = afe-Latn-NG +afh = afh-GH = afh-Latn = afh-Latn-GH +afi = afi-PG = afi-Latn = afi-Latn-PG +afk = afk-PG = afk-Latn = afk-Latn-PG +afo-Latn = afo-Latn-NG +afp = afp-PG = afp-Latn = afp-Latn-PG +afs = afs-MX = afs-Latn = afs-Latn-MX +afu = afu-GH = afu-Latn = afu-Latn-GH +afz-Latn = afz-Latn-ID +aga = aga-PE = aga-Latn = aga-Latn-PE +agc = agc-NG = *agc-Latn = agc-Latn-NG +agd = agd-PG = *agd-Latn = agd-Latn-PG +age = age-PG = age-Latn = age-Latn-PG +agg = agg-PG = *agg-Latn = agg-Latn-PG +agj = agj-ET = agj-Ethi = agj-Ethi-ET +agl = agl-PG = agl-Latn = agl-Latn-PG +agm = agm-PG = *agm-Latn = agm-Latn-PG +agn-Latn = agn-Latn-PH +ago = ago-PG = *ago-Latn = ago-Latn-PG +*agq = *agq-CM = agq-Latn = agq-Latn-CM +agr = agr-PE = agr-Latn = agr-Latn-PE +ags = ags-CM = ags-Latn = ags-Latn-CM +agt-Latn = agt-Latn-PH +agu = agu-GT = agu-Latn = agu-Latn-GT +agw = agw-SB = agw-Latn = agw-Latn-SB +agx-Cyrl = agx-Cyrl-RU +agy-Latn = agy-Latn-PH +aha = aha-GH = *aha-Latn = aha-Latn-GH +ahb = ahb-VU = ahb-Latn = ahb-Latn-VU +ahg-Ethi = ahg-Ethi-ET +ahk = ahk-MM = ahk-Latn = ahk-Latn-MM +ahk-Mymr = ahk-Mymr-MM +ahk-TH = ahk-Latn-TH +ahk-Thai = ahk-Thai-TH +ahl = ahl-TG = *ahl-Latn = ahl-Latn-TG +aho = aho-IN = aho-Ahom = aho-Ahom-IN +ahs-Latn = ahs-Latn-NG +aht = aht-US = aht-Latn = aht-Latn-US +aia = aia-SB = aia-Latn = aia-Latn-SB +aic = aic-PG = aic-Latn = aic-Latn-PG +aid = aid-AU = aid-Latn = aid-Latn-AU +aie = aie-PG = aie-Latn = aie-Latn-PG +aif = aif-PG = aif-Latn = aif-Latn-PG +aig-Latn = aig-Latn-AG +aii-Syrc = aii-Syrc-IQ +aij-Hebr = aij-Hebr-IL +ail = ail-PG = ail-Latn = ail-Latn-PG +aim-Latn = aim-Latn-IN +ain-Kana = ain-Kana-JP +ain-Latn = ain-Latn-JP +aio-Mymr = aio-Mymr-IN +ait = ait-BR = ait-Latn = ait-Latn-BR +aiw-Ethi = aiw-Ethi-ET +aiw-Latn = aiw-Latn-ET +aix = aix-PG = aix-Latn = aix-Latn-PG +aiy = aiy-CF = aiy-Latn = aiy-Latn-CF +aja = aja-SS = aja-Latn = aja-Latn-SS +ajg = ajg-BJ = *ajg-Latn = ajg-Latn-BJ +aji = aji-NC = aji-Latn = aji-Latn-NC +ajn = ajn-AU = ajn-Latn = ajn-Latn-AU +ajp-Arab = ajp-Arab-JO +ajt-Arab = ajt-Arab-TN +ajt-Hebr = ajt-Hebr-IL +ajz-Latn = ajz-Latn-IN +*ak = fat = *ak-GH = fat-GH = ak-Latn = fat-Latn = ak-Latn-GH = fat-Latn-GH +akb-Batk = akb-Batk-ID +akb-Latn = akb-Latn-ID +akc-Latn = akc-Latn-ID +ake = ake-GY = ake-Latn = ake-Latn-GY +akh = akh-PG = akh-Latn = akh-Latn-PG +aki = aki-PG = aki-Latn = aki-Latn-PG +akk = akk-IQ = akk-Xsux = akk-Xsux-IQ +akl-Latn = akl-Latn-PH +ako = ako-SR = ako-Latn = ako-Latn-SR +akp = akp-GH = akp-Latn = akp-Latn-GH +akq = akq-PG = akq-Latn = akq-Latn-PG +akr = akr-VU = akr-Latn = akr-Latn-VU +akt = akt-PG = akt-Latn = akt-Latn-PG +akw = akw-CG = akw-Latn = akw-Latn-CG +akz = akz-US = akz-Latn = akz-Latn-US +ala = ala-NG = *ala-Latn = ala-Latn-NG +alc = alc-CL = alc-Latn = alc-Latn-CL +ald-Latn = ald-Latn-CI +ale-Cyrs = ale-Cyrs-US +ale-Latn = ale-Latn-US +alh = alh-AU = alh-Latn = alh-Latn-AU +ali = ali-PG = *ali-Latn = ali-Latn-PG +alj-Latn = alj-Latn-PH +all-Mlym = all-Mlym-IN +alm = alm-VU = alm-Latn = alm-Latn-VU +aln = aln-XK = aln-Latn = aln-Latn-XK +aln-Brai = aln-Brai-AL +alo-Latn = alo-Latn-ID +alp-Latn = alp-Latn-ID +alq = alq-CA = alq-Latn = alq-Latn-CA +als-Elba = als-Elba-AL +alt = alt-RU = alt-Cyrl = alt-Cyrl-RU +alt-Mong = alt-Mong-RU +alu = alu-SB = alu-Latn = alu-Latn-SB +alw-Ethi = alw-Ethi-ET +alx = alx-PG = alx-Latn = alx-Latn-PG +aly = aly-AU = aly-Latn = aly-Latn-AU +alz = alz-CD = alz-Latn = alz-Latn-CD +*am = *am-ET = am-Ethi = am-Ethi-ET +am-Brai = am-Brai-ET +ama = ama-BR = ama-Latn = ama-Latn-BR +amc = amc-PE = amc-Latn = amc-Latn-PE +ame = ame-PE = ame-Latn = ame-Latn-PE +amf-Ethi = amf-Ethi-ET +amf-Latn = amf-Latn-ET +amg = amg-AU = amg-Latn = amg-Latn-AU +ami = ami-TW = ami-Latn = ami-Latn-TW +amk-Latn = amk-Latn-ID +amm = amm-PG = *amm-Latn = amm-Latn-PG +amn = amn-PG = *amn-Latn = amn-Latn-PG +amo = amo-NG = amo-Latn = amo-Latn-NG +amp = amp-PG = *amp-Latn = amp-Latn-PG +amr = amr-PE = amr-Latn = amr-Latn-PE +amt = amt-PG = amt-Latn = amt-Latn-PG +amu = amu-MX = amu-Latn = amu-Latn-MX +amx = amx-AU = amx-Latn = amx-Latn-AU +amy = amy-AU = amy-Latn = amy-Latn-AU +amz = amz-AU = amz-Latn = amz-Latn-AU +an = an-ES = an-Latn = an-Latn-ES +ana = ana-CO = ana-Latn = ana-Latn-CO +anb = anb-PE = anb-Latn = anb-Latn-PE +anc = anc-NG = *anc-Latn = anc-Latn-NG +ane = ane-NC = ane-Latn = ane-Latn-NC +anf = anf-GH = anf-Latn = anf-Latn-GH +ang = ang-GB = ang-Latn = ang-Latn-GB +anh = anh-PG = anh-Latn = anh-Latn-PG +ani-Cyrl = ani-Cyrl-RU +anj = anj-PG = anj-Latn = anj-Latn-PG +ank = ank-NG = *ank-Latn = ank-Latn-NG +anl = anl-MM = anl-Latn = anl-Latn-MM +anm-Latn = anm-Latn-IN +ann = ann-NG = *ann-Latn = ann-Latn-NG +ano = ano-CO = ano-Latn = ano-Latn-CO +anp-Deva = anp-Deva-IN +anr-Deva = anr-Deva-IN +ans = ans-CO = ans-Latn = ans-Latn-CO +ant = ant-AU = ant-Latn = ant-Latn-AU +anu-Ethi = anu-Ethi-ET +anu-Latn = anu-Latn-SS +anv = anv-CM = anv-Latn = anv-Latn-CM +anw-Latn = anw-Latn-NG +anx = anx-PG = anx-Latn = anx-Latn-PG +any = any-CI = *any-Latn = any-Latn-CI +anz = anz-PG = anz-Latn = anz-Latn-PG +aob = aob-PG = aob-Latn = aob-Latn-PG +aoc = aoc-VE = aoc-Latn = aoc-Latn-VE +aod = aod-PG = aod-Latn = aod-Latn-PG +aoe = aoe-PG = aoe-Latn = aoe-Latn-PG +aof = aof-PG = aof-Latn = aof-Latn-PG +aog = aog-PG = aog-Latn = aog-Latn-PG +aoh = aoh-CO = aoh-Latn = aoh-Latn-CO +aoi = aoi-AU = aoi-Latn = aoi-Latn-AU +aoj = aoj-PG = *aoj-Latn = aoj-Latn-PG +aok = aok-NC = aok-Latn = aok-Latn-NC +aom = aom-PG = *aom-Latn = aom-Latn-PG +aon = aon-PG = aon-Latn = aon-Latn-PG +aox = aox-GY = aox-Latn = aox-Latn-GY +aoz = aoz-ID = aoz-Latn = aoz-Latn-ID +apb = apb-SB = apb-Latn = apb-Latn-SB +apc = apc-SY = *apc-Arab = apc-Arab-SY +apd = apd-TG = apd-Arab = apd-Arab-TG +*apd-Latn = apd-Latn-SD +ape = ape-PG = *ape-Latn = ape-Latn-PG +apf-Latn = apf-Latn-PH +aph-Deva = aph-Deva-NP +api = api-BR = api-Latn = api-Latn-BR +apj = apj-US = apj-Latn = apj-Latn-US +apk = apk-US = apk-Latn = apk-Latn-US +apl = apl-US = apl-Latn = apl-Latn-US +apm = apm-US = apm-Latn = apm-Latn-US +apn = apn-BR = apn-Latn = apn-Latn-BR +apo = apo-PG = apo-Latn = apo-Latn-PG +app = app-VU = app-Latn = app-Latn-VU +apr = apr-PG = *apr-Latn = apr-Latn-PG +aps = aps-PG = *aps-Latn = aps-Latn-PG +apt-Latn = apt-Latn-IN +apu = apu-BR = apu-Latn = apu-Latn-BR +apv = apv-BR = apv-Latn = apv-Latn-BR +apw = apw-US = apw-Latn = apw-Latn-US +apy = apy-BR = apy-Latn = apy-Latn-BR +apz = apz-PG = *apz-Latn = apz-Latn-PG +aqr = aqr-NC = aqr-Latn = aqr-Latn-NC +aqt = aqt-PY = aqt-Latn = aqt-Latn-PY +aqz = aqz-BR = aqz-Latn = aqz-Latn-BR +*ar = arb = *ar-EG = arb-SA = ar-Arab = arb-Arab = ar-Arab-EG = arb-Arab-SA +ar-Brai = arb-Brai = ar-Brai-SA = arb-Brai-SA +*ar-SA = ar-Arab-SA +ar-Syrc = ar-Syrc-SA +arc = arc-IR = arc-Armi = arc-Armi-IR +arc-Nbat = arc-Nbat-JO +arc-Palm = arc-Palm-SY +ard = ard-AU = ard-Latn = ard-Latn-AU +are = are-AU = are-Latn = are-Latn-AU +arh = arh-CO = *arh-Latn = arh-Latn-CO +ari = ari-US = ari-Latn = ari-Latn-US +arj = arj-BR = arj-Latn = arj-Latn-BR +ark = ark-BR = ark-Latn = ark-Latn-BR +arl = arl-PE = arl-Latn = arl-Latn-PE +arn = arn-CL = arn-Latn = arn-Latn-CL +aro = aro-BO = aro-Latn = aro-Latn-BO +arp = arp-US = arp-Latn = arp-Latn-US +arq = arq-DZ = arq-Arab = arq-Arab-DZ +arr = arr-BR = arr-Latn = arr-Latn-BR +ars-Arab = ars-Arab-SA +aru = aru-BR = aru-Latn = aru-Latn-BR +arw = arw-SR = arw-Latn = arw-Latn-SR +arx = arx-BR = arx-Latn = arx-Latn-BR +ary = ary-MA = ary-Arab = ary-Arab-MA +arz = arz-EG = *arz-Arab = arz-Arab-EG +arz-Brai = arz-Brai-EG +*as = *as-IN = as-Beng = as-Beng-IN +*asa = *asa-TZ = asa-Latn = asa-Latn-TZ +asb = asb-CA = asb-Latn = asb-Latn-CA +asd = asd-PG = asd-Latn = asd-Latn-PG +ase = ase-US = ase-Sgnw = ase-Sgnw-US +asg = asg-NG = *asg-Latn = asg-Latn-NG +ash = ash-PE = ash-Latn = ash-Latn-PE +asj = asj-CM = asj-Latn = asj-Latn-CM +asn = asn-BR = asn-Latn = asn-Latn-BR +aso = aso-PG = *aso-Latn = aso-Latn-PG +asr-Deva = asr-Deva-IN +ass = ass-CM = ass-Latn = ass-Latn-CM +*ast = *ast-ES = ast-Latn = ast-Latn-ES +asu = asu-BR = asu-Latn = asu-Latn-BR +asx = asx-PG = asx-Latn = asx-Latn-PG +asy-Latn = asy-Latn-ID +ata = ata-PG = *ata-Latn = ata-Latn-PG +atb = atb-CN = atb-Latn = atb-Latn-CN +atb-Lisu = atb-Lisu-CN +atc = atc-PE = atc-Latn = atc-Latn-PE +atd-Latn = atd-Latn-PH +ate = ate-PG = ate-Latn = ate-Latn-PG +atg = atg-NG = *atg-Latn = atg-Latn-NG +ati-Latn = ati-Latn-CI +atj = atj-CA = atj-Latn = atj-Latn-CA +atn-Arab = atn-Arab-IR +atq-Latn = atq-Latn-ID +atr = atr-BR = atr-Latn = atr-Latn-BR +ats = ats-US = ats-Latn = ats-Latn-US +att-Latn = att-Latn-PH +atu = atu-SS = atu-Latn = atu-Latn-SS +atv-Cyrl = atv-Cyrl-RU +atw = atw-US = atw-Latn = atw-Latn-US +atx = atx-BR = atx-Latn = atx-Latn-BR +aty = aty-VU = aty-Latn = aty-Latn-VU +aua = aua-SB = aua-Latn = aua-Latn-SB +auc = auc-EC = auc-Latn = auc-Latn-EC +aud = aud-SB = aud-Latn = aud-Latn-SB +auh = auh-ZM = auh-Latn = auh-Latn-ZM +aui = aui-PG = aui-Latn = aui-Latn-PG +auk = auk-PG = auk-Latn = auk-Latn-PG +aul = aul-VU = aul-Latn = aul-Latn-VU +aun = aun-PG = aun-Latn = aun-Latn-PG +aup = aup-PG = aup-Latn = aup-Latn-PG +aur = aur-PG = aur-Latn = aur-Latn-PG +auu-Latn = auu-Latn-ID +aux = aux-BR = aux-Latn = aux-Latn-BR +auy = auy-PG = *auy-Latn = auy-Latn-PG +av = av-RU = av-Cyrl = av-Cyrl-RU +avb = avb-PG = avb-Latn = avb-Latn-PG +avi-Latn = avi-Latn-CI +avk-Latn = avk-Latn-?? +avl = avl-EG = *avl-Arab = avl-Arab-EG +avm = avm-AU = avm-Latn = avm-Latn-AU +avn = avn-GH = *avn-Latn = avn-Latn-GH +avo = avo-BR = avo-Latn = avo-Latn-BR +avs = avs-PE = avs-Latn = avs-Latn-PE +avt = avt-PG = *avt-Latn = avt-Latn-PG +avu = avu-SS = *avu-Latn = avu-Latn-SS +avv = avv-BR = avv-Latn = avv-Latn-BR +awa = awa-IN = awa-Deva = awa-Deva-IN +awb = awb-PG = *awb-Latn = awb-Latn-PG +awe = awe-BR = awe-Latn = awe-Latn-BR +awg = awg-AU = awg-Latn = awg-Latn-AU +awi = awi-PG = awi-Latn = awi-Latn-PG +awk = awk-AU = awk-Latn = awk-Latn-AU +awm = awm-PG = awm-Latn = awm-Latn-PG +awn-Ethi = awn-Ethi-ET +awo = awo-NG = *awo-Latn = awo-Latn-NG +awt = awt-BR = awt-Latn = awt-Latn-BR +awu-Latn = awu-Latn-ID +aww = aww-PG = aww-Latn = aww-Latn-PG +awx = awx-PG = *awx-Latn = awx-Latn-PG +axb = axb-AR = axb-Latn = axb-Latn-AR +axe = axe-AU = axe-Latn = axe-Latn-AU +axg = axg-BR = axg-Latn = axg-Latn-BR +axk = axk-CF = axk-Latn = axk-Latn-CF +axl = axl-AU = axl-Latn = axl-Latn-AU +axx = axx-NC = axx-Latn = axx-Latn-NC +ay = ayr = ay-BO = ayr-BO = ay-Latn = ayr-Latn = ay-Latn-BO = ayr-Latn-BO +aya = aya-PG = aya-Latn = aya-Latn-PG +ayb = ayb-BJ = *ayb-Latn = ayb-Latn-BJ +ayc = ayc-PE = ayc-Latn = ayc-Latn-PE +ayd = ayd-AU = ayd-Latn = ayd-Latn-AU +ayg = ayg-TG = ayg-Latn = ayg-Latn-TG +ayl-Arab = ayl-Arab-LY +ayn-Arab = ayn-Arab-YE +ayo = ayo-PY = ayo-Latn = ayo-Latn-PY +ayp-Arab = ayp-Arab-IQ +ayq = ayq-PG = ayq-Latn = ayq-Latn-PG +ayz-Latn = ayz-Latn-ID +*az = azj = az-AZ = azj-AZ = *az-Latn = azj-Latn = *az-Latn-AZ = azj-Latn-AZ +az-Brai = azj-Brai = az-Brai-IR = azj-Brai-AZ +*az-Cyrl-AZ +az-IQ = az-Arab-IQ +az-IR = az-Arab = azj-Arab = az-Arab-IR = azj-Arab-AZ +az-RU = *az-Cyrl = azj-Cyrl = az-Cyrl-RU = azj-Cyrl-AM +*azb-Arab = azb-Arab-IR +azd = azd-MX = azd-Latn = azd-Latn-MX +azg = azg-MX = azg-Latn = azg-Latn-MX +azm = azm-MX = azm-Latn = azm-Latn-MX +azn = azn-MX = azn-Latn = azn-Latn-MX +azo = azo-CM = azo-Latn = azo-Latn-CM +azz = azz-MX = azz-Latn = azz-Latn-MX +ba = ba-RU = ba-Cyrl = ba-Cyrl-RU +baa = baa-SB = baa-Latn = baa-Latn-SB +bae = bae-VE = bae-Latn = bae-Latn-VE +bag = bag-CM = bag-Latn = bag-Latn-CM +bah = bah-BS = bah-Latn = bah-Latn-BS +bal = bcc = bal-PK = bcc-PK = bal-Arab = *bcc-Arab = bal-Arab-PK = bcc-Arab-PK +bal-Latn = *bcc-Latn = bal-Latn-PK = bcc-Latn-PK +ban = ban-ID = ban-Latn = ban-Latn-ID +ban-Bali = ban-Bali-ID +ban-Java = ban-Java-ID +bao = bao-CO = bao-Latn = bao-Latn-CO +bap = bap-NP = bap-Deva = bap-Deva-NP +bar = bar-AT = bar-Latn = bar-Latn-AT +*bas = *bas-CM = bas-Latn = bas-Latn-CM +bav = bav-CM = *bav-Latn = bav-Latn-CM +baw = baw-CM = baw-Latn = baw-Latn-CM +bax = bax-CM = bax-Bamu = bax-Bamu-CM +bax-Latn = bax-Latn-CM +bba = bba-BJ = *bba-Latn = bba-Latn-BJ +bbb = bbb-PG = *bbb-Latn = bbb-Latn-PG +bbc = bbc-ID = bbc-Latn = bbc-Latn-ID +bbc-Batk = bbc-Batk-ID +bbd = bbd-PG = *bbd-Latn = bbd-Latn-PG +bbf = bbf-PG = bbf-Latn = bbf-Latn-PG +bbg = bbg-GA = bbg-Latn = bbg-Latn-GA +bbj = bbj-CM = bbj-Latn = bbj-Latn-CM +bbk = bbk-CM = bbk-Latn = bbk-Latn-CM +bbn = bbn-PG = bbn-Latn = bbn-Latn-PG +bbo-Latn = bbo-Latn-BF +bbp = bbp-Latn +bbq = bbq-CM = bbq-Latn = bbq-Latn-CM +bbr = bbr-PG = *bbr-Latn = bbr-Latn-PG +bbu-Latn = bbu-Latn-NG +bbv = bbv-PG = bbv-Latn = bbv-Latn-PG +bbw = bbw-CM = bbw-Latn = bbw-Latn-CM +bca-Hani = bca-Hani-CN +bca-Latn = bca-Latn-CN +bcb-Latn = bcb-Latn-SN +bcf = bcf-PG = *bcf-Latn = bcf-Latn-PG +bch = bch-PG = *bch-Latn = bch-Latn-PG +bci = bci-CI = *bci-Latn = bci-Latn-CI +bcj = bcj-AU = bcj-Latn = bcj-Latn-AU +bck = bck-AU = bck-Latn = bck-Latn-AU +bcm = bcm-PG = bcm-Latn = bcm-Latn-PG +bcn = bcn-NG = *bcn-Latn = bcn-Latn-NG +bco = bco-PG = *bco-Latn = bco-Latn-PG +bcp = bcp-CD = bcp-Latn = bcp-Latn-CD +bcq = bcq-ET = *bcq-Ethi = bcq-Ethi-ET +*bcq-Latn = bcq-Latn-ET +bcr = bcr-CA = bcr-Latn = bcr-Latn-CA +bcu = bcu-PG = *bcu-Latn = bcu-Latn-PG +bcw = bcw-CM = bcw-Latn = bcw-Latn-CM +*bcy-Latn = bcy-Latn-NG +bcz-Latn = bcz-Latn-SN +bda-Latn = bda-Latn-SN +bdc = bdc-CO = bdc-Latn = bdc-Latn-CO +bdd = bdd-PG = *bdd-Latn = bdd-Latn-PG +bde-Latn = bde-Latn-NG +bdf = bdf-PG = bdf-Latn = bdf-Latn-PG +bdg-Latn = bdg-Latn-MY +bdh = bdh-SS = bdh-Latn = bdh-Latn-SS +bdi = bdi-SD = bdi-Latn = bdi-Latn-SD +bdm = bdm-TD = bdm-Latn = bdm-Latn-TD +bdq = bdq-VN = bdq-Latn = bdq-Latn-VN +bdr-Latn = bdr-Latn-MY +bds = bds-TZ = bds-Latn = bds-Latn-TZ +bdt = bdt-CF = bdt-Latn = bdt-Latn-CF +bdu = bdu-CM = bdu-Latn = bdu-Latn-CM +bdv-Orya = bdv-Orya-IN +bdy = bdy-AU = bdy-Latn = bdy-Latn-AU +*be = *be-BY = be-Cyrl = be-Cyrl-BY +be-Brai = be-Brai-BY +be-Latn = be-Latn-BY +bea = bea-CA = bea-Latn = bea-Latn-CA +bea-Cans = bea-Cans-CA +beb = beb-CM = beb-Latn = beb-Latn-CM +bec = bec-CM = bec-Latn = bec-Latn-CM +bee-Deva = bee-Deva-IN +bef = bef-PG = *bef-Latn = bef-Latn-PG +beh = beh-BJ = *beh-Latn = beh-Latn-BJ +bei-Latn = bei-Latn-ID +bej = bej-SD = bej-Arab = bej-Arab-SD +*bej-Latn = bej-Latn-ER +bek = bek-PG = bek-Latn = bek-Latn-PG +*bem = *bem-ZM = bem-Latn = bem-Latn-ZM +bem-Brai = bem-Brai-ZM +beo = beo-PG = beo-Latn = beo-Latn-PG +bep-Latn = bep-Latn-ID +beq = beq-CG = beq-Latn = beq-Latn-CG +bet = bet-CI = *bet-Latn = bet-Latn-CI +beu = beu-ID = beu-Latn = beu-Latn-ID +bev-Latn = bev-Latn-CI +bew = bew-ID = bew-Latn = bew-Latn-ID +bex = bex-SS = *bex-Latn = bex-Latn-SS +bey = bey-PG = bey-Latn = bey-Latn-PG +*bez = *bez-TZ = bez-Latn = bez-Latn-TZ +bfa = bfa-SS = bfa-Latn = bfa-Latn-SS +bfb-Deva = bfb-Deva-IN +bfc = bfc-CN = bfc-Latn = bfc-Latn-CN +bfd = bfd-CM = *bfd-Latn = bfd-Latn-CM +bff = bff-CF = bff-Latn = bff-Latn-CF +bfh = bfh-PG = bfh-Latn = bfh-Latn-PG +bfi-x-stokoe = bfi-GB-x-stokoe = bfi-Qaaa-x-stokoe = bfi-Qaaa-GB-x-stokoe +bfj = bfj-CM = bfj-Latn = bfj-Latn-CM +bfm = bfm-CM = bfm-Latn = bfm-Latn-CM +bfn = bfn-TL = bfn-Latn = bfn-Latn-TL +bfo-Latn = bfo-Latn-BF +bfq = bfq-IN = bfq-Taml = bfq-Taml-IN +bfq-Knda = bfq-Knda-IN +bfq-Latn = bfq-Latn-IN +bfq-Qabq = bfq-Qabq-IN +bfs-Hani = bfs-Hani-CN +bfs-Latn = bfs-Latn-CN +bft = bft-PK = *bft-Arab = bft-Arab-PK +bft-Tibt = bft-Tibt-PK +bft-x-baltia-pk +bfu-Takr = bfu-Takr-IN +bfu-Tibt = bfu-Tibt-IN +bfw-Orya = bfw-Orya-IN +bfy = bfy-IN = bfy-Deva = bfy-Deva-IN +bfz-Deva = bfz-Deva-IN +*bg = *bg-BG = bg-Cyrl = bg-Cyrl-BG +bg-Brai = bg-Brai-BG +bgc = bgc-IN = bgc-Deva = bgc-Deva-IN +bgd-Deva = bgd-Deva-IN +bgg-Latn = bgg-Latn-IN +bgj = bgj-CM = bgj-Latn = bgj-Latn-CM +bgn = bgn-PK = bgn-Arab = bgn-Arab-PK +bgn-Cyrl = bgn-Cyrl-TM +bgp = bgp-PK = bgp-Arab = bgp-Arab-PK +bgq-Deva = bgq-Deva-IN +bgr-Latn = bgr-Latn-IN +bgs-Latn = bgs-Latn-PH +bgt = bgt-SB = bgt-Latn = bgt-Latn-SB +bgw-Deva = bgw-Deva-IN +bgx = bgx-TR = bgx-Grek = bgx-Grek-TR +bgx-Latn = bgx-Latn-TR +bgz-Latn = bgz-Latn-ID +bh = bho = bh-IN = bho-IN = bh-Kthi = bho-Deva = bh-Kthi-IN = bho-Deva-IN +bha-Deva = bha-Deva-IN +bhb = bhb-IN = bhb-Deva = bhb-Deva-IN +bhb-Gujr = bhb-Gujr-IN +bhd-Arab = bhd-Arab-IN +bhd-Deva = bhd-Deva-IN +bhf = bhf-PG = bhf-Latn = bhf-Latn-PG +bhg = bhg-PG = *bhg-Latn = bhg-Latn-PG +bhh = bhh-IL = bhh-Cyrl = bhh-Cyrl-IL +bhh-Hebr = bhh-Hebr-IL +bhh-Latn = bhh-Latn-IL +bhi = bhi-IN = bhi-Deva = bhi-Deva-IN +bhj-Deva = bhj-Deva-NP +bhk = bhk-PH = bhk-Latn = bhk-Latn-PH +bhl = bhl-PG = *bhl-Latn = bhl-Latn-PG +bho-Kthi = bho-Kthi-IN +bhp = bhp-ID = bhp-Latn = bhp-Latn-ID +bhr = bhr-MG = bhr-Latn = bhr-Latn-MG +bhs = bhs-CM = bhs-Latn = bhs-Latn-CM +bhu-Deva = bhu-Deva-IN +bhw-Latn = bhw-Latn-ID +bhy = bhy-CD = *bhy-Latn = bhy-Latn-CD +bhz-Latn = bhz-Latn-ID +bi = bi-VU = bi-Latn = bi-Latn-VU +bia = bia-AU = bia-Latn = bia-Latn-AU +bib = bib-BF = *bib-Latn = bib-Latn-BF +bic = bic-PG = bic-Latn = bic-Latn-PG +bid = bid-TD = bid-Latn = bid-Latn-TD +bie = bie-PG = bie-Latn = bie-Latn-PG +big = big-PG = *big-Latn = big-Latn-PG +bik = bcl = bik-PH = bcl-PH = bik-Latn = bcl-Latn = bik-Latn-PH = bcl-Latn-PH +bik-Brai = bcl-Brai = bik-Brai-PH = bcl-Brai-PH +bim = bim-GH = *bim-Latn = bim-Latn-GH +bin = bin-NG = *bin-Latn = bin-Latn-NG +bio = bio-PG = *bio-Latn = bio-Latn-PG +biq = biq-PG = biq-Latn = biq-Latn-PG +bir = bir-PG = bir-Latn = bir-Latn-PG +bit = bit-PG = bit-Latn = bit-Latn-PG +biu-Latn = biu-Latn-IN +biv = biv-GH = biv-Latn = biv-Latn-GH +biw = biw-CM = biw-Latn = biw-Latn-CM +biy-Deva = biy-Deva-IN +bja = bja-CD = bja-Latn = bja-Latn-CD +bjb = bjb-AU = bjb-Latn = bjb-Latn-AU +bjc = bjc-PG = bjc-Latn = bjc-Latn-PG +bjg-Latn = bjg-Latn-GW +bjh = bjh-PG = *bjh-Latn = bjh-Latn-PG +bji = bji-ET = *bji-Ethi = bji-Ethi-ET +bjj = bjj-IN = bjj-Deva = bjj-Deva-IN +bjk = bjk-PG = bjk-Latn = bjk-Latn-PG +bjl = bjl-PG = bjl-Latn = bjl-Latn-PG +bjn = bjn-ID = bjn-Latn = bjn-Latn-ID +bjn-Arab = bjn-Arab-ID +bjo = bjo-CF = bjo-Latn = bjo-Latn-CF +bjp = bjp-PG = bjp-Latn = bjp-Latn-PG +bjr = bjr-PG = *bjr-Latn = bjr-Latn-PG +bjt = bjt-SN = bjt-Latn = bjt-Latn-SN +*bjt-Arab = bjt-Arab-SN +bjv = bjv-TD = bjv-Latn = bjv-Latn-TD +bjw-Latn = bjw-Latn-CI +bjy = bjy-AU = bjy-Latn = bjy-Latn-AU +bjz = bjz-PG = *bjz-Latn = bjz-Latn-PG +bkc = bkc-CM = *bkc-Latn = bkc-Latn-CM +bkd-Latn = bkd-Latn-PH +bkh = bkh-CM = bkh-Latn = bkh-Latn-CM +bki = bki-VU = bki-Latn = bki-Latn-VU +bkk-x-baltia-in +bkl-Latn = bkl-Latn-ID +bkm = bkm-CM = *bkm-Latn = bkm-Latn-CM +bkq = bkq-BR = *bkq-Latn = bkq-Latn-BR +bkt = bkt-CD = bkt-Latn = bkt-Latn-CD +bku = bku-PH = bku-Latn = bku-Latn-PH +bku-Buhd = bku-Buhd-PH +bkv = bkv-NG = *bkv-Latn = bkv-Latn-NG +bkw = bkw-CG = bkw-Latn = bkw-Latn-CG +bkx = bkx-TL = bkx-Latn = bkx-Latn-TL +bky = bky-NG = bky-Latn = bky-Latn-NG +bla = bla-CA = bla-Latn = bla-Latn-CA +bla-Cans = bla-Cans-CA +blb = blb-SB = blb-Latn = blb-Latn-SB +blc = blc-CA = blc-Latn = blc-Latn-CA +ble-Latn = ble-Latn-GW +blf-Latn = blf-Latn-ID +blh = blh-LR = blh-Latn = blh-Latn-LR +bli = bli-CD = bli-Latn = bli-Latn-CD +blk = blk-MM = blk-Mymr = blk-Mymr-MM +blm = blm-SS = blm-Latn = blm-Latn-SS +*blo-Latn = blo-Latn-BJ +blp = blp-SB = blp-Latn = blp-Latn-SB +blq = blq-PG = blq-Latn = blq-Latn-PG +blr-Latn = blr-Latn-CN +blr-Latn-x-pangpung = blr-Latn-MM-x-pangpung +blr-Tale = blr-Tale-CN +blr-Thai = blr-Thai-TH +blt = blt-VN = *blt-Tavt = blt-Tavt-VN +blt-Laoo = blt-Laoo-LA +*blt-Latn = blt-Latn-VN +blv = blv-AO = blv-Latn = blv-Latn-AO +blw-Latn = blw-Latn-PH +blx-Latn = blx-Latn-PH +blz-Latn = blz-Latn-ID +*bm = *bm-ML = *bm-Latn = *bm-Latn-ML +bm-Nkoo = bm-Nkoo-ML +bmb = bmb-CD = bmb-Latn = bmb-Latn-CD +bmc = bmc-PG = bmc-Latn = bmc-Latn-PG +bmh = bmh-PG = *bmh-Latn = bmh-Latn-PG +bmi = bmi-TD = bmi-Latn = bmi-Latn-TD +bmj-Deva = bmj-Deva-NP +bmk = bmk-PG = *bmk-Latn = bmk-Latn-PG +bmm = bmm-MG = bmm-Latn = bmm-Latn-MG +bmo = bmo-CM = bmo-Latn = bmo-Latn-CM +bmp = bmp-PG = bmp-Latn = bmp-Latn-PG +bmq = bmq-ML = *bmq-Latn = bmq-Latn-ML +bmr = bmr-CO = bmr-Latn = bmr-Latn-CO +bms-Latn = bms-Latn-NE +bmu = bmu-PG = *bmu-Latn = bmu-Latn-PG +bmv = bmv-CM = bmv-Latn = bmv-Latn-CM +bmw = bmw-CG = bmw-Latn = bmw-Latn-CG +bmx = bmx-PG = bmx-Latn = bmx-Latn-PG +bmz = bmz-PG = bmz-Latn = bmz-Latn-PG +*bn = *bn-BD = bn-Beng = bn-Beng-BD +bn-Brai = bn-Brai-BD +*bn-IN = bn-Beng-IN +bn-Newa = bn-Newa-NP +bnb-Latn = bnb-Latn-MY +bnc-Latn = lbk-Latn = bnc-Latn-PH = lbk-Latn-PH +bng = bng-GQ = *bng-Latn = bng-Latn-GQ +bni = bni-CD = bni-Latn = bni-Latn-CD +bnj-Latn = bnj-Latn-PH +bnk = bnk-VU = bnk-Latn = bnk-Latn-VU +bnm = bnm-GQ = *bnm-Latn = bnm-Latn-GQ +bnn-Latn = bnn-Latn-TW +bno-Latn = bno-Latn-PH +bnp = bnp-PG = *bnp-Latn = bnp-Latn-PG +bnr = bnr-VU = bnr-Latn = bnr-Latn-VU +bns-Deva = bns-Deva-IN +bnw = bnw-PG = bnw-Latn = bnw-Latn-PG +*bo = *bo-CN = bo-Tibt = bo-Tibt-CN +*bo-IN = bo-Tibt-IN +bo-Marc = bo-Marc-CN +bo-Phag = bo-Phag-CN +boa = boa-PE = boa-Latn = boa-Latn-PE +bob = bob-KE = bob-Latn = bob-Latn-KE +boh = boh-CD = boh-Latn = boh-Latn-CD +boj = boj-PG = *boj-Latn = boj-Latn-PG +bom = bom-NG = *bom-Latn = bom-Latn-NG +bon = bon-PG = *bon-Latn = bon-Latn-PG +bop = bop-PG = bop-Latn = bop-Latn-PG +boq = boq-PG = boq-Latn = boq-Latn-PG +bor = bor-BR = bor-Latn = bor-Latn-BR +bot = bot-SS = bot-Latn = bot-Latn-SS +bou = bou-TZ = bou-Latn = bou-Latn-TZ +bov = bov-GH = bov-Latn = bov-Latn-GH +bow = bow-PG = bow-Latn = bow-Latn-PG +box-Latn = box-Latn-BF +*boz-Arab = boz-Arab-ML +*boz-Latn = boz-Latn-ML +bpa = bpa-VU = bpa-Latn = bpa-Latn-VU +bpb = bpb-CO = bpb-Latn = bpb-Latn-CO +bpi = bpi-PG = bpi-Latn = bpi-Latn-PG +bpj = bpj-CD = bpj-Latn = bpj-Latn-CD +bpk = bpk-NC = bpk-Latn = bpk-Latn-NC +bpl = bpl-AU = bpl-Latn = bpl-Latn-AU +bpm = bpm-PG = bpm-Latn = bpm-Latn-PG +bpp-Latn = bpp-Latn-ID +bpr-Latn = bpr-Latn-PH +bps-Latn = bps-Latn-PH +bpt = bpt-AU = bpt-Latn = bpt-Latn-AU +bpu = bpu-PG = bpu-Latn = bpu-Latn-PG +bpw = bpw-PG = bpw-Latn = bpw-Latn-PG +bpy = bpy-IN = bpy-Beng = bpy-Beng-IN +bqc = bqc-BJ = *bqc-Latn = bqc-Latn-BJ +bqg-Latn = bqg-Latn-TG +bqi = bqi-IR = *bqi-Arab = bqi-Arab-IR +bqj-Latn = bqj-Latn-SN +bql = bql-PG = bql-Latn = bql-Latn-PG +bqp = bqp-NG = *bqp-Latn = bqp-Latn-NG +bqs = bqs-PG = bqs-Latn = bqs-Latn-PG +bqt = bqt-CM = bqt-Latn = bqt-Latn-CM +bqv = bqv-CI = bqv-Latn = bqv-Latn-CI +bqz = bqz-CM = bqz-Latn = bqz-Latn-CM +*br = *br-FR = br-Latn = br-Latn-FR +bra = bra-IN = bra-Deva = bra-Deva-IN +brb = brb-KH = brb-Khmr = brb-Khmr-KH +brb-Laoo = brb-Laoo-LA +brb-Latn = brb-Latn-VN +brc = brc-GY = brc-Latn = brc-Latn-GY +brd-Deva = brd-Deva-NP +brf = brf-CD = brf-Latn = brf-Latn-CD +brg = brg-BO = brg-Latn = brg-Latn-BO +brh = brh-PK = brh-Arab = brh-Arab-PK +bri = bri-CM = bri-Latn = bri-Latn-CM +brj = brj-VU = brj-Latn = brj-Latn-VU +brl = brl-BW = brl-Latn = brl-Latn-BW +brn = brn-CR = brn-Latn = brn-Latn-CR +brq = brq-PG = brq-Latn = brq-Latn-PG +brr = brr-SB = brr-Latn = brr-Latn-SB +bru = bru-VN = bru-Latn = bru-Latn-VN +bru-Laoo = bru-Laoo-LA +bru-Thai = bru-Thai-LA +brv-Laoo = brv-Laoo-LA +brv-Thai-x-brusakonnakhorn = brv-Thai-TH-x-brusakonnakhorn +brv-Thai-x-dongluang = brv-Thai-TH-x-dongluang +brv-Thai-x-khongchiem = brv-Thai-TH-x-khongchiem +*brx = *brx-IN = brx-Deva = brx-Deva-IN +brx-Beng = brx-Beng-IN +brx-Latn = brx-Latn-IN +bry = bry-PG = bry-Latn = bry-Latn-PG +brz = brz-PG = brz-Latn = brz-Latn-PG +*bs = bs-BA = *bs-Latn = *bs-Latn-BA +*bs-Cyrl = *bs-Cyrl-BA +bsa-Latn = bsa-Latn-ID +bsb-Latn = bsb-Latn-BN +bsc-Latn = bsc-Latn-SN +bse = bse-CM = bse-Latn = bse-Latn-CM +bsh-Arab = bsh-Arab-AF +bsj = bsj-NG = *bsj-Latn = bsj-Latn-NG +bsk = bsk-PK = bsk-Arab = bsk-Arab-PK +bsk-Latn = bsk-Latn-PK +bsn = bsn-CO = bsn-Latn = bsn-Latn-CO +bsp-Latn = bsp-Latn-GN +bsq = bsq-LR = bsq-Bass = bsq-Bass-LR +*bsq-Latn = bsq-Latn-LR +bss = bss-CM = *bss-Latn = bss-Latn-CM +bst = bst-ET = *bst-Ethi = bst-Ethi-ET +bsy-Latn = bsy-Latn-MY +btd-Batk = btd-Batk-ID +bth-Latn = bth-Latn-MY +btm-Batk = btm-Batk-ID +bto = bto-PH = bto-Latn = bto-Latn-PH +btp = btp-PG = btp-Latn = btp-Latn-PG +btr = btr-VU = btr-Latn = btr-Latn-VU +bts-Batk = bts-Batk-ID +bts-Latn = bts-Latn-ID +btt = btt-NG = *btt-Latn = btt-Latn-NG +btv = btv-PK = btv-Deva = btv-Deva-PK +btx-Batk = btx-Batk-ID +btx-Latn = btx-Latn-ID +bua = bxr = bua-RU = bxr-RU = bua-Cyrl = bxr-Cyrl = bua-Cyrl-RU = bxr-Cyrl-RU +buc = buc-YT = buc-Latn = buc-Latn-YT +bud = bud-TG = *bud-Latn = bud-Latn-TG +bud-Brai = bud-Brai-TG +bue = bue-CA = bue-Latn = bue-Latn-CA +buf = buf-CD = buf-Latn = buf-Latn-CD +bug = bug-ID = bug-Latn = bug-Latn-ID +bug-Bugi = bug-Bugi-ID +buh-Latn = buh-Latn-CN +bui = bui-CG = bui-Latn = bui-Latn-CG +buk = buk-PG = *buk-Latn = buk-Latn-PG +bum = bum-CM = *bum-Latn = bum-Latn-CM +buo = buo-PG = *buo-Latn = buo-Latn-PG +buq = buq-PG = buq-Latn = buq-Latn-PG +bus = bus-NG = *bus-Latn = bus-Latn-NG +but = but-PG = but-Latn = but-Latn-PG +buu = buu-CD = *buu-Latn = buu-Latn-CD +buv = buv-PG = buv-Latn = buv-Latn-PG +buw = buw-GA = buw-Latn = buw-Latn-GA +bux-Latn = bux-Latn-NG +buy = buy-SL = buy-Latn = buy-Latn-SL +bva = bva-TD = bva-Latn = bva-Latn-TD +bvb = bvb-GQ = *bvb-Latn = bvb-Latn-GQ +bvc = bvc-SB = bvc-Latn = bvc-Latn-SB +bvd = bvd-SB = bvd-Latn = bvd-Latn-SB +bvi = bvi-SS = bvi-Latn = bvi-Latn-SS +bvm = bvm-CM = bvm-Latn = bvm-Latn-CM +bvn = bvn-PG = bvn-Latn = bvn-Latn-PG +bvr = bvr-AU = bvr-Latn = bvr-Latn-AU +bvx = bvx-CG = bvx-Latn = bvx-Latn-CG +bvz-Latn = bvz-Latn-ID +bwa = bwa-NC = bwa-Latn = bwa-Latn-NC +bwb = bwb-FJ = bwb-Latn = bwb-Latn-FJ +bwc = bwc-ZM = bwc-Latn = bwc-Latn-ZM +bwd = bwd-PG = *bwd-Latn = bwd-Latn-PG +bwe = bwe-MM = bwe-Mymr = bwe-Mymr-MM +bwf = bwf-PG = bwf-Latn = bwf-Latn-PG +bwg-Latn = bwg-Latn-MZ +bwi = bwi-VE = bwi-Latn = bwi-Latn-VE +bwj-Latn = bwj-Latn-BF +bwk = bwk-PG = bwk-Latn = bwk-Latn-PG +bwm = bwm-PG = bwm-Latn = bwm-Latn-PG +bwo-Ethi = bwo-Ethi-ET +bwo-Latn = bwo-Latn-ET +bwq-Latn = bwq-Latn-BF +bwr = bwr-NG = *bwr-Latn = bwr-Latn-NG +bwu = bwu-GH = bwu-Latn = bwu-Latn-GH +bww = bww-CD = bww-Latn = bww-Latn-CD +bwx-Latn = bwx-Latn-CN +bxa = bxa-SB = bxa-Latn = bxa-Latn-SB +bxb = bxb-SS = bxb-Latn = bxb-Latn-SS +bxc = bxc-GQ = bxc-Latn = bxc-Latn-GQ +bxf = bxf-PG = bxf-Latn = bxf-Latn-PG +bxg = bxg-CD = bxg-Latn = bxg-Latn-CD +bxh = bxh-PG = *bxh-Latn = bxh-Latn-PG +bxi = bxi-AU = bxi-Latn = bxi-Latn-AU +bxj = bxj-AU = bxj-Latn = bxj-Latn-AU +bxm-Cyrl = bxm-Cyrl-MN +bxm-Latn = bxm-Latn-MN +bxm-Mong = bxm-Mong-MN +bxn = bxn-AU = bxn-Latn = bxn-Latn-AU +bxz = bxz-PG = bxz-Latn = bxz-Latn-PG +bya-Latn = bya-Latn-PH +byc-Latn = byc-Latn-NG +byd-Latn = byd-Latn-ID +bye = bye-PG = *bye-Latn = bye-Latn-PG +byh-Deva = byh-Deva-NP +bym = bym-AU = bym-Latn = bym-Latn-AU +*byn = byn-ER = byn-Ethi = byn-Ethi-ER +*byn-Latn = byn-Latn-ER +byr = byr-PG = *byr-Latn = byr-Latn-PG +bys = bys-NG = *bys-Latn = bys-Latn-NG +byv = byv-CM = byv-Latn = byv-Latn-CM +byw-Deva = byw-Deva-NP +byx = byx-PG = *byx-Latn = byx-Latn-PG +byz = byz-PG = byz-Latn = byz-Latn-PG +bza = bza-LR = *bza-Latn = bza-Latn-LR +bzd = bzd-CR = bzd-Latn = bzd-Latn-CR +bze = bze-ML = *bze-Latn = bze-Latn-ML +*bze-Arab = bze-Arab-ML +bzf = bzf-PG = *bzf-Latn = bzf-Latn-PG +bzh = bzh-PG = *bzh-Latn = bzh-Latn-PG +bzi = bzi-TH = bzi-Thai = bzi-Thai-TH +bzj = bzj-BZ = bzj-Latn = bzj-Latn-BZ +bzk = bzk-NI = bzk-Latn = bzk-Latn-NI +bzm = bzm-CD = bzm-Latn = bzm-Latn-CD +bzr = bzr-AU = bzr-Latn = bzr-Latn-AU +bzv = bzv-CM = bzv-Latn = bzv-Latn-CM +bzw = bzw-NG = *bzw-Latn = bzw-Latn-NG +*ca = *ca-ES = ca-Latn = ca-Latn-ES +*ca-AD = ca-Latn-AD +*ca-FR = ca-Latn-FR +*ca-IT = ca-Latn-IT +caa = caa-GT = caa-Latn = caa-Latn-GT +cab = cab-HN = cab-Latn = cab-Latn-HN +cac = cac-GT = cac-Latn = cac-Latn-GT +cad = cad-US = cad-Latn = cad-Latn-US +cae-Latn = cae-Latn-SN +caf = caf-CA = caf-Latn = caf-Latn-CA +caf-Cans = caf-Cans-CA +cag = cag-PY = cag-Latn = cag-Latn-PY +cah = cah-PE = cah-Latn = cah-Latn-PE +caj = caj-AR = caj-Latn = caj-Latn-AR +cak = cak-GT = cak-Latn = cak-Latn-GT +cal = cal-MP = cal-Latn = cal-Latn-MP +cam = cam-NC = cam-Latn = cam-Latn-NC +can = can-PG = can-Latn = can-Latn-PG +cao = cao-BO = cao-Latn = cao-Latn-BO +cap = cap-BO = cap-Latn = cap-Latn-BO +caq-Latn = caq-Latn-IN +car = car-VE = car-Latn = car-Latn-VE +cas = cas-BO = cas-Latn = cas-Latn-BO +cav = cav-BO = cav-Latn = cav-Latn-BO +caw = caw-BO = caw-Latn = caw-Latn-BO +cax = cax-BO = cax-Latn = cax-Latn-BO +cay = cay-CA = cay-Latn = cay-Latn-CA +caz = caz-BO = caz-Latn = caz-Latn-BO +cbb = cbb-CO = cbb-Latn = cbb-Latn-CO +cbc = cbc-CO = cbc-Latn = cbc-Latn-CO +cbd = cbd-CO = cbd-Latn = cbd-Latn-CO +cbg = cbg-CO = cbg-Latn = cbg-Latn-CO +cbi = cbi-EC = cbi-Latn = cbi-Latn-EC +cbj = cbj-BJ = cbj-Latn = cbj-Latn-BJ +cbk-Brai = cbk-Brai-PH +cbk-Latn = cbk-Latn-PH +cbl = cbl-MM = cbl-Latn = cbl-Latn-MM +cbn-Thai = cbn-Thai-TH +cbr = cbr-PE = cbr-Latn = cbr-Latn-PE +cbs = cbs-PE = cbs-Latn = cbs-Latn-PE +cbt = cbt-PE = cbt-Latn = cbt-Latn-PE +cbu = cbu-PE = cbu-Latn = cbu-Latn-PE +cbv = cbv-CO = cbv-Latn = cbv-Latn-CO +cby = cby-CO = cby-Latn = cby-Latn-CO +cca = cca-CO = cca-Latn = cca-Latn-CO +ccc = ccc-PE = ccc-Latn = ccc-Latn-PE +ccd = ccd-BR = ccd-Latn = ccd-Latn-BR +cce-Latn = cce-Latn-MZ +ccg-Latn = ccg-Latn-NG +*cch = cch-NG = cch-Latn = cch-Latn-NG +cco = cco-MX = cco-Latn = cco-Latn-MX +*ccp = *ccp-BD = ccp-Cakm = ccp-Cakm-BD +ccp-Beng = ccp-Beng-IN +*ccp-IN = ccp-Cakm-IN +ccp-Latn = ccp-Latn-BD +cde-Telu = cde-Telu-IN +cdf-Beng = cdf-Beng-IN +cdf-Latn = cdf-Latn-IN +cdh = cdh-IN = cdh-Deva = cdh-Deva-IN +cdh-Takr = cdh-Takr-IN +cdi-Gujr = cdi-Gujr-IN +cdj = cdj-IN = cdj-Deva = cdj-Deva-IN +cdm = cdm-NP = cdm-Deva = cdm-Deva-NP +cdo-Hans = cdo-Hans-CN +cdo-Hant = cdo-Hant-CN +cdo-Latn = cdo-Latn-CN +cdr = cdr-NG = *cdr-Latn = cdr-Latn-NG +cdz-Beng = cdz-Beng-IN +*ce = *ce-RU = ce-Cyrl = ce-Cyrl-RU +ceb = ceb-PH = ceb-Latn = ceb-Latn-PH +ceb-Brai = ceb-Brai-PH +ceg = ceg-PY = ceg-Latn = ceg-Latn-PY +cek = cek-MM = cek-Latn = cek-Latn-MM +cek-x-asangkhongso = cek-MM-x-asangkhongso = cek-Latn-x-asangkhongso = cek-Latn-MM-x-asangkhongso +cek-x-hnise = cek-MM-x-hnise = cek-Latn-x-hnise = cek-Latn-MM-x-hnise +cek-x-kanise = cek-MM-x-kanise = cek-Latn-x-kanise = cek-Latn-MM-x-kanise +cek-x-khongtuu = cek-MM-x-khongtuu = cek-Latn-x-khongtuu = cek-Latn-MM-x-khongtuu +cek-x-lemid = cek-MM-x-lemid = cek-Latn-x-lemid = cek-Latn-MM-x-lemid +cek-x-likhy = cek-MM-x-likhy = cek-Latn-x-likhy = cek-Latn-MM-x-likhy +cek-x-rengcaa = cek-MM-x-rengcaa = cek-Latn-x-rengcaa = cek-Latn-MM-x-rengcaa +cen-Latn = cen-Latn-NG +cfa = cfa-NG = *cfa-Latn = cfa-Latn-NG +cfm = cfm-MM = cfm-Latn = cfm-Latn-MM +cfm-Beng = cfm-Beng-IN +cfm-Latn-x-lente = cfm-Latn-MM-x-lente +cga = cga-PG = cga-Latn = cga-Latn-PG +cgc-Latn = cgc-Latn-PH +*cgg = *cgg-UG = cgg-Latn = cgg-Latn-UG +ch = ch-GU = ch-Latn = ch-Latn-GU +chb = chb-CO = chb-Latn = chb-Latn-CO +chd = chd-MX = chd-Latn = chd-Latn-MX +chf = chf-MX = chf-Latn = chf-Latn-MX +chh = chh-US = chh-Latn = chh-Latn-US +chj = chj-MX = chj-Latn = chj-Latn-MX +chk = chk-FM = chk-Latn = chk-Latn-FM +chl = chl-US = chl-Latn = chl-Latn-US +chm = mhr = chm-RU = mhr-RU = chm-Cyrl = mhr-Cyrl = chm-Cyrl-RU = mhr-Cyrl-RU +chm-Latn = mhr-Latn = chm-Latn-RU = mhr-Latn-RU +chn = chn-US = chn-Latn = chn-Latn-US +cho = cho-US = cho-Latn = cho-Latn-US +chp = chp-CA = chp-Latn = chp-Latn-CA +chp-Cans = chp-Cans-CA +chq = chq-MX = chq-Latn = chq-Latn-MX +*chr = *chr-US = chr-Cher = chr-Cher-US +chr-Latn = chr-Latn-US +chw-Latn = chw-Latn-MZ +chx-Deva = chx-Deva-NP +chy-Latn = chy-Latn-US +chz = chz-MX = chz-Latn = chz-Latn-MX +cic = cic-US = cic-Latn = cic-Latn-US +cih-Deva = cih-Deva-IN +cim-Latn = cim-Latn-IT +cin = cin-BR = cin-Latn = cin-Latn-BR +cip = cip-MX = cip-Latn = cip-Latn-MX +cir = cir-NC = cir-Latn = cir-Latn-NC +ciw-Cans = ciw-Cans-US +ciw-Latn = ciw-Latn-US +ciy = ciy-VE = ciy-Latn = ciy-Latn-VE +cja = cja-KH = cja-Arab = cja-Arab-KH +cja-Cham = cja-Cham-KH +cja-Latn = cja-Latn-KH +cje = cje-VN = cje-Latn = cje-Latn-VN +cjk = cjk-AO = cjk-Latn = cjk-Latn-AO +cjm = cjm-VN = cjm-Cham = cjm-Cham-VN +cjm-Arab = cjm-Arab-VN +cjm-Latn = cjm-Latn-VN +cjn = cjn-PG = cjn-Latn = cjn-Latn-PG +cjo = cjo-PE = cjo-Latn = cjo-Latn-PE +cjp = cjp-CR = cjp-Latn = cjp-Latn-CR +cjs-Cyrl = cjs-Cyrl-RU +cjs-Latn = cjs-Latn-RU +cjv = cjv-PG = *cjv-Latn = cjv-Latn-PG +cjy-Hans = cjy-Hans-CN +cjy-Hant = cjy-Hant-CN +*ckb = *ckb-IQ = *ckb-Arab = ckb-Arab-IQ +*ckb-IR = ckb-Arab-IR +ckb-Latn = ckb-Latn-IQ +ckl = ckl-NG = *ckl-Latn = ckl-Latn-NG +ckn = ckn-MM = ckn-Latn = ckn-Latn-MM +cko = cko-GH = *cko-Latn = cko-Latn-GH +ckr = ckr-PG = ckr-Latn = ckr-Latn-PG +cks = cks-NC = cks-Latn = cks-Latn-NC +ckt-Cyrl = ckt-Cyrl-RU +cku-Latn = cku-Latn-US +ckv-Latn = ckv-Latn-TW +cky = cky-NG = *cky-Latn = cky-Latn-NG +ckz = ckz-GT = ckz-Latn = ckz-Latn-GT +cla = cla-NG = *cla-Latn = cla-Latn-NG +clc = clc-CA = clc-Latn = clc-Latn-CA +cle = cle-MX = cle-Latn = cle-Latn-MX +cli = cli-GH = cli-Latn = cli-Latn-GH +clj = clj-MM = clj-Latn = clj-Latn-MM +clk-Tibt = clk-Tibt-CN +cll = cll-GH = cll-Latn = cll-Latn-GH +clm = clm-US = clm-Latn = clm-Latn-US +clo = clo-MX = clo-Latn = clo-Latn-MX +clt = clt-MM = clt-Latn = clt-Latn-MM +clu-Latn = clu-Latn-PH +cly = cly-MX = cly-Latn = cly-Latn-MX +cma = cma-VN = cma-Latn = cma-Latn-VN +cme = cme-BF = *cme-Latn = cme-Latn-BF +cmg = cmg-MN = cmg-Soyo = cmg-Soyo-MN +cmi = cmi-CO = cmi-Latn = cmi-Latn-CO +cmn-Brai = cmn-Brai-CN +cmo-Khmr = cmo-Khmr-KH +cmo-Latn = cmo-Latn-VN +cmr = cmr-MM = cmr-Latn = cmr-Latn-MM +cmt = cmt-ZA = cmt-Latn = cmt-Latn-ZA +cna-Tibt-x-bodhi = cna-Tibt-IN-x-bodhi +cnb = cnb-MM = cnb-Latn = cnb-Latn-MM +cng-Latn = cng-Latn-CN +cnh = cnh-MM = cnh-Latn = cnh-Latn-MM +cni = cni-PE = cni-Latn = cni-Latn-PE +cnk = cnk-MM = cnk-Latn = cnk-Latn-MM +cnl = cnl-MX = cnl-Latn = cnl-Latn-MX +cnr-Cyrl = cnr-Cyrl-ME +cnr-Latn = cnr-Latn-ME +cns-Latn = cns-Latn-ID +cnt = cnt-MX = cnt-Latn = cnt-Latn-MX +cnw = cnw-MM = cnw-Latn = cnw-Latn-MM +cnx = cnx-GB = cnx-Latn = cnx-Latn-GB +co = co-FR = co-Latn = co-Latn-FR +coa = coa-AU = coa-Latn = coa-Latn-AU +coc = coc-MX = coc-Latn = coc-Latn-MX +cod = cod-PE = cod-Latn = cod-Latn-PE +coe = coe-CO = coe-Latn = coe-Latn-CO +cof = cof-EC = cof-Latn = cof-Latn-EC +cog-Thai = cog-Thai-TH +coh = coh-KE = coh-Latn = coh-Latn-KE +cok = cok-MX = cok-Latn = cok-Latn-MX +col = col-US = col-Latn = col-Latn-US +com-Latn = com-Latn-US +con = con-EC = con-Latn = con-Latn-EC +coo = coo-CA = coo-Latn = coo-Latn-CA +cop = cop-EG = cop-Copt = cop-Copt-EG +cop-Arab = cop-Arab-EG +cop-Grek = cop-Grek-EG +cot = cot-PE = cot-Latn = cot-Latn-PE +cou-Latn = cou-Latn-SN +cox = cox-PE = cox-Latn = cox-Latn-PE +coz = coz-MX = coz-Latn = coz-Latn-MX +cpa = cpa-MX = cpa-Latn = cpa-Latn-MX +cpb = cpb-PE = cpb-Latn = cpb-Latn-PE +cpc = cpc-PE = cpc-Latn = cpc-Latn-PE +cpg-Grek = cpg-Grek-GR +cpi = cpi-NR = cpi-Latn = cpi-Latn-NR +cpn = cpn-GH = cpn-Latn = cpn-Latn-GH +cps = cps-PH = cps-Latn = cps-Latn-PH +cpu = cpu-PE = cpu-Latn = cpu-Latn-PE +cpx-Latn = cpx-Latn-CN +cpy = cpy-PE = cpy-Latn = cpy-Latn-PE +cqd-Latn = cqd-Latn-CN +cr = cwd = cr-CA = cwd-CA = *cr-Cans = cwd-Cans = cr-Cans-CA = cwd-Cans-CA +cr-Latn = cwd-Latn = cr-Latn-CA = cwd-Latn-CA +crc = crc-VU = crc-Latn = crc-Latn-VU +crd = crd-US = crd-Latn = crd-Latn-US +crf = crf-CO = crf-Latn = crf-Latn-CO +crg = crg-US = crg-Latn = crg-Latn-US +crh = crh-UA = crh-Cyrl = crh-Cyrl-UA +crh-Latn = crh-Latn-UA +crj = crj-CA = crj-Cans = crj-Cans-CA +crj-Latn = crj-Latn-CA +crk = crk-CA = crk-Cans = crk-Cans-CA +crk-Latn = crk-Latn-CA +crl = crl-CA = crl-Cans = crl-Cans-CA +crl-Latn = crl-Latn-CA +crm = crm-CA = crm-Cans = crm-Cans-CA +crn = crn-MX = crn-Latn = crn-Latn-MX +cro = cro-US = cro-Latn = cro-Latn-US +crq = crq-AR = crq-Latn = crq-Latn-AR +crs = crs-SC = crs-Latn = crs-Latn-SC +crt = crt-AR = crt-Latn = crt-Latn-AR +crw-Latn = crw-Latn-VN +crx = crx-CA = crx-Latn = crx-Latn-CA +crx-Cans = crx-Cans-CA +*cs = *cs-CZ = cs-Latn = cs-Latn-CZ +cs-Brai = cs-Brai-CZ +csa = csa-MX = csa-Latn = csa-Latn-MX +csb = csb-PL = csb-Latn = csb-Latn-PL +csh = csh-MM = csh-Mymr = csh-Mymr-MM +csh-Latn = csh-Latn-MM +csk-Latn = csk-Latn-SN +csm = csm-US = csm-Latn = csm-Latn-US +cso = cso-MX = cso-Latn = cso-Latn-MX +cst = cst-US = cst-Latn = cst-Latn-US +csv = csv-MM = csv-Latn = csv-Latn-MM +csw = csw-CA = csw-Cans = csw-Cans-CA +csy = csy-MM = csy-Latn = csy-Latn-MM +csz = csz-US = csz-Latn = csz-Latn-US +cta = cta-MX = cta-Latn = cta-Latn-MX +ctc = ctc-US = ctc-Latn = ctc-Latn-US +ctd = ctd-MM = ctd-Pauc = ctd-Pauc-MM +ctd-Latn = ctd-Latn-MM +cte = cte-MX = cte-Latn = cte-Latn-MX +ctg-Arab = ctg-Arab-BD +ctg-Latn = ctg-Latn-BD +cth = cth-MM = cth-Latn = cth-Latn-MM +ctl = ctl-MX = ctl-Latn = ctl-Latn-MX +ctn-Deva = ctn-Deva-NP +cto = cto-CO = cto-Latn = cto-Latn-CO +ctp = ctp-MX = ctp-Latn = ctp-Latn-MX +ctu = ctu-MX = ctu-Latn = ctu-Latn-MX +ctz = ctz-MX = ctz-Latn = ctz-Latn-MX +*cu = *cu-RU = cu-Cyrl = cu-Cyrl-RU +cu-Cyrs = cu-Cyrs-RU +cu-Glag = cu-Glag-BG +cua = cua-VN = cua-Latn = cua-Latn-VN +cub = cub-CO = cub-Latn = cub-Latn-CO +cuc = cuc-MX = cuc-Latn = cuc-Latn-MX +cug = cug-CM = cug-Latn = cug-Latn-CM +cuh = cuh-KE = cuh-Latn = cuh-Latn-KE +cui = cui-CO = cui-Latn = cui-Latn-CO +cuj = cuj-PE = cuj-Latn = cuj-Latn-PE +cuk = cuk-PA = cuk-Latn = cuk-Latn-PA +cul = cul-BR = cul-Latn = cul-Latn-BR +cut = cut-MX = cut-Latn = cut-Latn-MX +cuu-Lana = cuu-Lana-CN +cuv = cuv-CM = cuv-Latn = cuv-Latn-CM +cux = cux-MX = cux-Latn = cux-Latn-MX +cv = cv-RU = cv-Cyrl = cv-Cyrl-RU +cvn = cvn-MX = cvn-Latn = cvn-Latn-MX +cwa = cwa-TZ = cwa-Latn = cwa-Latn-TZ +cwe = cwe-TZ = cwe-Latn = cwe-Latn-TZ +cwt-Latn = cwt-Latn-SN +*cy = *cy-GB = cy-Latn = cy-Latn-GB +cy-Brai = cy-Brai-GB +cya = cya-MX = cya-Latn = cya-Latn-MX +cyb = cyb-BO = cyb-Latn = cyb-Latn-BO +cyo-Latn = cyo-Latn-PH +czh-Hans = czh-Hans-CN +czh-Hant = czh-Hant-CN +czn = czn-MX = czn-Latn = czn-Latn-MX +czt = czt-MM = czt-Latn = czt-Latn-MM +*da = *da-DK = da-Latn = da-Latn-DK +da-Brai = da-Brai-DK +*da-GL = da-Latn-GL +daa = daa-TD = daa-Latn = daa-Latn-TD +dac = dac-PG = dac-Latn = dac-Latn-PG +dad = dad-PG = *dad-Latn = dad-Latn-PG +dae = dae-CM = dae-Latn = dae-Latn-CM +daf = daf-Latn +dag = dag-GH = *dag-Latn = dag-Latn-GH +dah = dah-PG = *dah-Latn = dah-Latn-PG +dai = dai-TD = dai-Latn = dai-Latn-TD +daj = daj-SD = daj-Latn = daj-Latn-SD +dak = dak-US = dak-Latn = dak-Latn-US +dal = dal-KE = dal-Latn = dal-Latn-KE +dao = dao-MM = dao-Latn = dao-Latn-MM +dao-Latn-x-khengdaai = dao-Latn-MM-x-khengdaai +daq-Deva = daq-Deva-IN +dar = dar-RU = dar-Cyrl = dar-Cyrl-RU +*dav = *dav-KE = dav-Latn = dav-Latn-KE +dax = dax-AU = dax-Latn = dax-Latn-AU +dbd = dbd-NG = *dbd-Latn = dbd-Latn-NG +dbf-Latn = dbf-Latn-ID +dbj-Arab = dbj-Arab-MY +dbj-Latn = dbj-Latn-MY +dbl = dbl-AU = dbl-Latn = dbl-Latn-AU +dbq = dbq-CM = *dbq-Latn = dbq-Latn-CM +dby = dby-PG = dby-Latn = dby-Latn-PG +dcc = dcc-IN = dcc-Arab = dcc-Arab-IN +dcc-Deva = dcc-Deva-IN +dcr = dcr-VI = dcr-Latn = dcr-Latn-VI +dda = dda-AU = dda-Latn = dda-Latn-AU +dde = dde-CG = dde-Latn = dde-Latn-CG +ddg = ddg-TL = ddg-Latn = ddg-Latn-TL +ddi = ddi-PG = ddi-Latn = ddi-Latn-PG +ddj = ddj-AU = ddj-Latn = ddj-Latn-AU +ddn = ddn-BJ = *ddn-Latn = ddn-Latn-BJ +ddo-Cyrl = ddo-Cyrl-RU +ddr = ddr-AU = ddr-Latn = ddr-Latn-AU +dds-Latn = dds-Latn-ML +*de = *de-DE = de-Latn = de-Latn-DE +*de-AT = de-Latn-AT +*de-BE = de-Latn-BE +de-Brai = de-Brai-DE +*de-CH = de-Latn-CH +*de-IT = de-Latn-IT +*de-LI = de-Latn-LI +*de-LU = de-Latn-LU +de-Latf = de-Latf-DE +de-Runr = de-Runr-DE +dec = dec-SD = dec-Latn = dec-Latn-SD +ded = ded-PG = *ded-Latn = ded-Latn-PG +def-Arab = def-Arab-IR +deg-Latn = deg-Latn-NG +del = umu = del-US = umu-CA = del-Latn = umu-Latn = del-Latn-US = umu-Latn-CA +den = xsl = den-CA = xsl-CA = den-Latn = xsl-Latn = den-Latn-CA = xsl-Latn-CA +den-Cans = xsl-Cans = den-Cans-CA = xsl-Cans-CA +der-Beng = der-Beng-IN +der-Latn = der-Latn-IN +des = des-BR = des-Latn = des-Latn-BR +dev = dev-PG = dev-Latn = dev-Latn-PG +dez = dez-CD = dez-Latn = dez-Latn-CD +dga = dga-GH = *dga-Latn = dga-Latn-GH +dgc-Latn = dgc-Latn-PH +dgd-Latn = dgd-Latn-BF +dge = dge-PG = dge-Latn = dge-Latn-PG +dgg = dgg-PG = dgg-Latn = dgg-Latn-PG +dgh = dgh-NG = *dgh-Latn = dgh-Latn-NG +dgi = dgi-BF = *dgi-Latn = dgi-Latn-BF +dgk = dgk-CF = dgk-Latn = dgk-Latn-CF +dgl = dgl-SD = *dgl-Arab = dgl-Arab-SD +dgl-Copt-x-oldnubian = dgl-Copt-SD-x-oldnubian +dgl-Latn = dgl-Latn-SD +dgn = dgn-AU = dgn-Latn = dgn-Latn-AU +dgr = dgr-CA = dgr-Latn = dgr-Latn-CA +dgt = dgt-AU = dgt-Latn = dgt-Latn-AU +dgw = dgw-AU = dgw-Latn = dgw-Latn-AU +dgx = dgx-PG = dgx-Latn = dgx-Latn-PG +dgz = dgz-PG = *dgz-Latn = dgz-Latn-PG +dhg = dhg-AU = dhg-Latn = dhg-Latn-AU +dhi-Deva = dhi-Deva-NP +dhl = dhl-AU = dhl-Latn = dhl-Latn-AU +dhm = dhm-AO = dhm-Latn = dhm-Latn-AO +dhn = dhn-IN = dhn-Gujr = dhn-Gujr-IN +dho-Deva = dho-Deva-IN +dhr = dhr-AU = dhr-Latn = dhr-Latn-AU +dhu = dhu-AU = dhu-Latn = dhu-Latn-AU +dhv = dhv-NC = dhv-Latn = dhv-Latn-NC +dhw-Deva = dhw-Deva-NP +dhx = dhx-AU = dhx-Latn = dhx-Latn-AU +dia = dia-PG = dia-Latn = dia-Latn-PG +dib = dib-SS = dib-Latn = dib-Latn-SS +did = did-SS = did-Latn = did-Latn-SS +dif = dif-AU = dif-Latn = dif-Latn-AU +dig = dig-KE = dig-Latn = dig-Latn-KE +dih = dih-MX = dih-Latn = dih-Latn-MX +dil = dil-SD = dil-Latn = dil-Latn-SD +din = dik = din-SS = dik-SS = din-Latn = dik-Latn = din-Latn-SS = dik-Latn-SS +dip = dip-SS = dip-Latn = dip-Latn-SS +dir = dir-NG = dir-Latn = dir-Latn-NG +dis-Beng = dis-Beng-IN +dis-Latn = dis-Latn-IN +dit = dit-AU = dit-Latn = dit-Latn-AU +diu = diu-NA = diu-Latn = diu-Latn-NA +diw = diw-SS = diw-Latn = diw-Latn-SS +dix = dix-VU = dix-Latn = dix-Latn-VU +diz = diz-CD = diz-Latn = diz-Latn-CD +dja = dja-AU = dja-Latn = dja-Latn-AU +djb = djb-AU = djb-Latn = djb-Latn-AU +djc = djc-TD = djc-Latn = djc-Latn-TD +djd = djd-AU = djd-Latn = djd-Latn-AU +*dje = *dje-NE = dje-Latn = dje-Latn-NE +*dje-Arab = dje-Arab-NE +dje-Brai = dje-Brai-NE +djf = djf-AU = djf-Latn = djf-Latn-AU +dji = dji-AU = dji-Latn = dji-Latn-AU +djj = djj-AU = djj-Latn = djj-Latn-AU +djk = djk-SR = djk-Latn = djk-Latn-SR +djk-Afak = djk-Afak-SR +djn = djn-AU = djn-Latn = djn-Latn-AU +djr = djr-AU = djr-Latn = djr-Latn-AU +dju = dju-PG = dju-Latn = dju-Latn-PG +djw = djw-AU = djw-Latn = djw-Latn-AU +dks = dks-SS = dks-Latn = dks-Latn-SS +dkx = dkx-CM = dkx-Latn = dkx-Latn-CM +dlg-Cyrl = dlg-Cyrl-RU +dln-Latn = dln-Latn-IN +dma = dma-GA = dma-Latn = dma-Latn-GA +dmc = dmc-PG = dmc-Latn = dmc-Latn-PG +dmd = dmd-AU = dmd-Latn = dmd-Latn-AU +dmg-Latn = dmg-Latn-MY +dml-Arab = dml-Arab-PK +dmo = dmo-CM = dmo-Latn = dmo-Latn-CM +dmv-Latn = dmv-Latn-MY +dmw = dmw-AU = dmw-Latn = dmw-Latn-AU +dna-Latn = dna-Latn-ID +dnd = dnd-PG = dnd-Latn = dnd-Latn-PG +dng-Cyrl = dng-Cyrl-KG +dni-Latn = dni-Latn-ID +dnj = dnj-CI = *dnj-Latn = dnj-Latn-CI +dnk-Latn = dnk-Latn-ID +dnn-Latn = dnn-Latn-BF +dnr = dnr-PG = dnr-Latn = dnr-Latn-PG +dnt-Latn = dnt-Latn-ID +dnw-Latn = dnw-Latn-ID +dny = dny-BR = dny-Latn = dny-Latn-BR +doa = doa-PG = doa-Latn = doa-Latn-PG +dob = dob-PG = *dob-Latn = dob-Latn-PG +doc-Latn = doc-Latn-CN +dof = dof-PG = dof-Latn = dof-Latn-PG +doi = dgo = doi-IN = dgo-IN = doi-Arab = dgo-Arab = doi-Arab-IN = dgo-Arab-IN +doi-Deva = dgo-Deva = doi-Deva-IN = dgo-Deva-IN +doi-Takr = dgo-Takr = doi-Takr-IN = dgo-Takr-IN +dol = dol-PG = dol-Latn = dol-Latn-PG +don = don-PG = don-Latn = don-Latn-PG +doo = doo-CD = doo-Latn = doo-Latn-CD +dop = dop-BJ = *dop-Latn = dop-Latn-BJ +dor = dor-SB = dor-Latn = dor-Latn-SB +dos-Latn = dos-Latn-BF +dov = dov-ZW = dov-Latn = dov-Latn-ZW +dow = dow-CM = *dow-Latn = dow-Latn-CM +doy = doy-GH = doy-Latn = doy-Latn-GH +drc = drc-PT = drc-Latn = drc-Latn-PT +dre-Tibt = dre-Tibt-NP +drg-Latn = drg-Latn-MY +dri = dri-NG = *dri-Latn = dri-Latn-NG +drl = drl-AU = drl-Latn = drl-Latn-AU +drs = drs-ET = *drs-Ethi = drs-Ethi-ET +drt = drt-NL = drt-Latn = drt-Latn-NL +dru-Latn = dru-Latn-TW +dry-Deva = dry-Deva-NP +*dsb = *dsb-DE = dsb-Latn = dsb-Latn-DE +dsh-Latn = dsh-Latn-ET +dso-Orya = dso-Orya-IN +dsq-Arab = dsq-Arab-ML +dsq-Latn = dsq-Latn-ML +dta-Cyrl = dta-Cyrl-CN +dta-Hans = dta-Hans-CN +dta-Latn = dta-Latn-CN +dta-Mong-x-manchu = dta-Mong-CN-x-manchu +dtb-Latn = dtb-Latn-MY +dtd = dtd-CA = dtd-Latn = dtd-Latn-CA +dth = dth-AU = dth-Latn = dth-Latn-AU +dtm = dtm-ML = dtm-Latn = dtm-Latn-ML +dtp = dtp-MY = dtp-Latn = dtp-Latn-MY +dtr-Latn = dtr-Latn-MY +dts = dts-ML = *dts-Latn = dts-Latn-ML +dty = dty-NP = dty-Deva = dty-Deva-NP +*dua = *dua-CM = dua-Latn = dua-Latn-CM +dub = dub-IN = dub-Gujr = dub-Gujr-IN +duc = duc-PG = *duc-Latn = duc-Latn-PG +dud = dud-NG = *dud-Latn = dud-Latn-NG +due-Latn = due-Latn-PH +duf = duf-NC = duf-Latn = duf-Latn-NC +dug = dug-KE = *dug-Latn = dug-Latn-KE +duh-Deva = duh-Deva-IN +duh-Gujr = duh-Gujr-IN +dui = dui-PG = dui-Latn = dui-Latn-PG +duk = duk-PG = duk-Latn = duk-Latn-PG +duo-Latn = duo-Latn-PH +dur = dur-CM = dur-Latn = dur-Latn-CM +*dus-Deva = dus-Deva-NP +duu = duu-CN = duu-Latn = duu-Latn-CN +duw = duw-ID = duw-Latn = duw-Latn-ID +dux-Latn = dux-Latn-ML +*dv = dv-MV = dv-Thaa = dv-Thaa-MV +dva = dva-PG = dva-Latn = dva-Latn-PG +dwr-Ethi = dwr-Ethi-ET +dwr-Latn = dwr-Latn-ET +dwu = dwu-AU = dwu-Latn = dwu-Latn-AU +dww = dww-PG = *dww-Latn = dww-Latn-PG +dwy = dwy-AU = dwy-Latn = dwy-Latn-AU +dya-Latn = dya-Latn-BF +dyb = dyb-AU = dyb-Latn = dyb-Latn-AU +dyd = dyd-AU = dyd-Latn = dyd-Latn-AU +dyi-Latn = dyi-Latn-CI +dyn = dyn-AU = dyn-Latn = dyn-Latn-AU +*dyo = *dyo-SN = dyo-Latn = dyo-Latn-SN +*dyo-Arab = dyo-Arab-SN +dyu = dyu-BF = *dyu-Latn = dyu-Latn-BF +dyu-Arab = dyu-Arab-CI +dyu-Nkoo = dyu-Nkoo-CI +dyy = dyy-AU = dyy-Latn = dyy-Latn-AU +*dz = *dz-BT = dz-Tibt = dz-Tibt-BT +dze = dze-AU = dze-Latn = dze-Latn-AU +dzg = dzg-TD = *dzg-Latn = dzg-Latn-TD +eaa = eaa-AU = eaa-Latn = eaa-Latn-AU +ebk-Latn = ebk-Latn-PH +ebo = ebo-CG = ebo-Latn = ebo-Latn-CG +ebr-Latn = ebr-Latn-CI +*ebu = *ebu-KE = ebu-Latn = ebu-Latn-KE +*ee = *ee-GH = ee-Latn = ee-Latn-GH +ee-Brai = ee-Brai-GH +*ee-TG = ee-Latn-TG +efi = efi-NG = efi-Latn = efi-Latn-NG +egl = egl-IT = egl-Latn = egl-Latn-IT +ego-Latn = ego-Latn-NG +egy = egy-EG = egy-Egyp = egy-Egyp-EG +eip-Latn = eip-Latn-ID +eit = eit-PG = eit-Latn = eit-Latn-PG +eiv = eiv-PG = eiv-Latn = eiv-Latn-PG +eja-Latn = eja-Latn-GW +eka = eka-NG = *eka-Latn = eka-Latn-NG +ekc = ekc-AU = ekc-Latn = ekc-Latn-AU +ekg-Latn = ekg-Latn-ID +ekl-Latn = ekl-Latn-BD +ekm = ekm-CM = *ekm-Latn = ekm-Latn-CM +eko = eko-MZ = eko-Latn = eko-Latn-MZ +eko-Arab = eko-Arab-MZ +ekr-Latn = ekr-Latn-NG +eky = eky-MM = eky-Kali = eky-Kali-MM +*el = *el-GR = el-Grek = el-Grek-GR +el-Brai = el-Brai-GR +*el-CY = el-Grek-CY +el-Cyrl = el-Cyrl-UA +ele = ele-PG = ele-Latn = ele-Latn-PG +elk = elk-PG = elk-Latn = elk-Latn-PG +elm-Latn = elm-Latn-NG +elo = elo-KE = elo-Latn = elo-Latn-KE +elu = elu-PG = elu-Latn = elu-Latn-PG +ema = ema-NG = *ema-Latn = ema-Latn-NG +emb-Latn = emb-Latn-ID +eme = eme-GF = eme-Latn = eme-Latn-GF +emg-Deva = emg-Deva-NP +emi = emi-PG = *emi-Latn = emi-Latn-PG +emp = emp-PA = emp-Latn = emp-Latn-PA +ems = ems-US = ems-Latn = ems-Latn-US +ems-Cyrl = ems-Cyrl-US +emx = emx-FR = emx-Latn = emx-Latn-FR +*en = *en-US = en-Latn = en-Latn-US +*en-AG = en-Latn-AG +*en-AI = en-Latn-AI +*en-AS = en-Latn-AS +*en-AT = en-Latn-AT +*en-AU = en-Latn-AU +*en-BB = en-Latn-BB +*en-BE = en-Latn-BE +*en-BM = en-Latn-BM +*en-BS = en-Latn-BS +*en-BW = en-Latn-BW +*en-BZ = en-Latn-BZ +en-Brai = en-Brai-GB +*en-CA = en-Latn-CA +*en-CH = en-Latn-CH +*en-CK = en-Latn-CK +*en-CM = en-Latn-CM +*en-CY = en-Latn-CY +*en-DE = en-Latn-DE +*en-DK = en-Latn-DK +*en-DM = en-Latn-DM +en-Dsrt = en-Dsrt-US +*en-ER = en-Latn-ER +*en-FI = en-Latn-FI +*en-FJ = en-Latn-FJ +*en-FM = en-Latn-FM +*en-GB = en-Latn-GB +*en-GD = en-Latn-GD +*en-GG = en-Latn-GG +*en-GH = en-Latn-GH +*en-GI = en-Latn-GI +*en-GM = en-Latn-GM +*en-GU = en-Latn-GU +*en-GY = en-Latn-GY +*en-HK = en-Latn-HK +*en-IE = en-Latn-IE +*en-IL = en-Latn-IL +*en-IM = en-Latn-IM +*en-IN = en-Latn-IN +*en-IO = en-Latn-IO +*en-JE = en-Latn-JE +*en-JM = en-Latn-JM +*en-KE = en-Latn-KE +*en-KI = en-Latn-KI +*en-KY = en-Latn-KY +*en-LC = en-Latn-LC +*en-LR = en-Latn-LR +*en-LS = en-Latn-LS +*en-MG = en-Latn-MG +*en-MH = en-Latn-MH +*en-MO = en-Latn-MO +*en-MP = en-Latn-MP +*en-MS = en-Latn-MS +*en-MT = en-Latn-MT +*en-MU = en-Latn-MU +*en-MW = en-Latn-MW +*en-MY = en-Latn-MY +*en-NA = en-Latn-NA +*en-NF = en-Latn-NF +*en-NG = en-Latn-NG +*en-NL = en-Latn-NL +*en-NR = en-Latn-NR +*en-NU = en-Latn-NU +*en-NZ = en-Latn-NZ +*en-PG = en-Latn-PG +*en-PH = en-Latn-PH +*en-PK = en-Latn-PK +*en-PN = en-Latn-PN +*en-PR = en-Latn-PR +*en-PW = en-Latn-PW +*en-RW = en-Latn-RW +*en-SB = en-Latn-SB +*en-SC = en-Latn-SC +*en-SD = en-Latn-SD +*en-SE = en-Latn-SE +*en-SG = en-Latn-SG +*en-SI = en-Latn-SI +*en-SL = en-Latn-SL +*en-SS = en-Latn-SS +*en-SX = en-Latn-SX +*en-SZ = en-Latn-SZ +en-Shaw = en-Shaw-GB +*en-TC = en-Latn-TC +*en-TK = en-Latn-TK +*en-TO = en-Latn-TO +*en-TT = en-Latn-TT +*en-TV = en-Latn-TV +*en-TZ = en-Latn-TZ +*en-UG = en-Latn-UG +*en-VC = en-Latn-VC +*en-VG = en-Latn-VG +*en-VI = en-Latn-VI +*en-VU = en-Latn-VU +*en-WS = en-Latn-WS +*en-ZA = en-Latn-ZA +*en-ZM = en-Latn-ZM +*en-ZW = en-Latn-ZW +ena = ena-PG = ena-Latn = ena-Latn-PG +enb = enb-KE = enb-Latn = enb-Latn-KE +end-Latn = end-Latn-ID +enf-Cyrl = enf-Cyrl-RU +enl = enl-PY = enl-Latn = enl-Latn-PY +enn = enn-NG = *enn-Latn = enn-Latn-NG +enq = enq-PG = *enq-Latn = enq-Latn-PG +enx = enx-PY = enx-Latn = enx-Latn-PY +*eo = *eo-001 = eo-Latn = eo-Latn-001 +eo-SM = eo-Latn-SM +erg = erg-VU = erg-Latn = erg-Latn-VU +eri = eri-PG = *eri-Latn = eri-Latn-PG +erk = erk-VU = erk-Latn = erk-Latn-VU +err = err-AU = err-Latn = err-Latn-AU +*es = *es-ES = es-Latn = es-Latn-ES +*es-AR = es-Latn-AR +*es-BO = es-Latn-BO +*es-BR = es-Latn-BR +*es-BZ = es-Latn-BZ +es-Brai = es-Brai-ES +*es-CL = es-Latn-CL +*es-CO = es-Latn-CO +*es-CR = es-Latn-CR +*es-CU = es-Latn-CU +*es-DO = es-Latn-DO +*es-EC = es-Latn-EC +*es-GQ = es-Latn-GQ +*es-GT = es-Latn-GT +*es-HN = es-Latn-HN +*es-MX = es-Latn-MX +*es-NI = es-Latn-NI +*es-PA = es-Latn-PA +*es-PE = es-Latn-PE +*es-PH = es-Latn-PH +*es-PR = es-Latn-PR +*es-PY = es-Latn-PY +*es-SV = es-Latn-SV +*es-US = es-Latn-US +*es-UY = es-Latn-UY +*es-VE = es-Latn-VE +ese = ese-BO = ese-Latn = ese-Latn-BO +esg-Deva = esg-Deva-IN +esi = esi-US = esi-Latn = esi-Latn-US +ess-Cyrl = ess-Cyrl-US +ess-Latn = ess-Latn-US +esu = esu-US = esu-Latn = esu-Latn-US +esy-Qabr = esy-Qabr-PH +*et = ekk = *et-EE = ekk-EE = et-Latn = ekk-Latn = et-Latn-EE = ekk-Latn-EE +et-Brai = et-Brai-EE +etn = etn-VU = etn-Latn = etn-Latn-VU +etr = etr-PG = *etr-Latn = etr-Latn-PG +ets-Latn = ets-Latn-NG +ett = ett-IT = ett-Ital = ett-Ital-IT +ett-Latn = ett-Latn-IT +etu = etu-NG = *etu-Latn = etu-Latn-NG +etx = etx-NG = *etx-Latn = etx-Latn-NG +*eu = *eu-ES = eu-Latn = eu-Latn-ES +eve-Cyrl = eve-Cyrl-RU +evn-Cyrl = evn-Cyrl-RU +evn-Latn = evn-Latn-RU +*ewo = *ewo-CM = ewo-Latn = ewo-Latn-CM +ext = ext-ES = ext-Latn = ext-Latn-ES +eyo = eyo-KE = eyo-Latn = eyo-Latn-KE +eza-Latn = eza-Latn-NG +*fa = *fa-IR = fa-Arab = pes-Arab = fa-Arab-IR = pes-Arab-IR +faa = faa-PG = *faa-Latn = faa-Latn-PG +fab = fab-GQ = *fab-Latn = fab-Latn-GQ +fad = fad-PG = fad-Latn = fad-Latn-PG +faf = faf-SB = faf-Latn = faf-Latn-SB +fag = fag-PG = *fag-Latn = fag-Latn-PG +fai = fai-PG = *fai-Latn = fai-Latn-PG +faj = faj-PG = faj-Latn = faj-Latn-PG +fak = fak-CM = fak-Latn = fak-Latn-CM +fal = fal-CM = fal-Latn = fal-Latn-CM +fan = fan-GQ = *fan-Latn = fan-Latn-GQ +fap-Latn = fap-Latn-SN +far = far-SB = far-Latn = far-Latn-SB +fax = fax-ES = fax-Latn = fax-Latn-ES +fay-Arab = fay-Arab-IR +faz-Arab = faz-Arab-IR +fbl-Latn = fbl-Latn-PH +*ff = *ff-SN = ff-Latn = *fuc-Latn = ff-Latn-SN = fuc-Latn-SN +ff-Adlm = ff-Adlm-GN +*ff-Arab = *fuc-Arab = ff-Arab-SN = fuc-Arab-SN +*ff-CM = ff-Latn-CM +*ff-GN = ff-Latn-GN +ffi = ffi-PG = *ffi-Latn = ffi-Latn-PG +ffm = ffm-ML = *ffm-Latn = ffm-Latn-ML +*ffm-Arab = ffm-Arab-ML +*fi = *fi-FI = fi-Latn = fi-Latn-FI +fi-Brai = fi-Brai-FI +fia = fia-SD = *fia-Arab = fia-Arab-SD +fia-Copt-x-oldnubian = fia-Copt-SD-x-oldnubian +fia-Latn = fia-Latn-SD +*fil = *fil-PH = fil-Latn = fil-Latn-PH +fil-Tglg = fil-Tglg-PH +fip = fip-TZ = fip-Latn = fip-Latn-TZ +fir-Latn = fir-Latn-NG +fit = fit-SE = fit-Latn = fit-Latn-SE +fiw = fiw-PG = fiw-Latn = fiw-Latn-PG +fj = fj-FJ = fj-Latn = fj-Latn-FJ +fkk-Latn = fkk-Latn-NG +fkv = fkv-NO = fkv-Latn = fkv-Latn-NO +fla = fla-US = fla-Latn = fla-Latn-US +fln = fln-AU = fln-Latn = fln-Latn-AU +flr = flr-CD = *flr-Latn = flr-Latn-CD +fly = fly-ZA = fly-Latn = fly-Latn-ZA +fmp = fmp-CM = *fmp-Latn = fmp-Latn-CM +fnb = fnb-VU = fnb-Latn = fnb-Latn-VU +fng = fng-ZA = fng-Latn = fng-Latn-ZA +*fo = *fo-FO = fo-Latn = fo-Latn-FO +*fo-DK = fo-Latn-DK +fod = fod-BJ = *fod-Latn = fod-Latn-BJ +foi = foi-PG = foi-Latn = foi-Latn-PG +fon = fon-BJ = *fon-Latn = fon-Latn-BJ +for = for-PG = *for-Latn = for-Latn-PG +fos = fos-TW = fos-Latn = fos-Latn-TW +fpe = fpe-GQ = *fpe-Latn = fpe-Latn-GQ +fqs = fqs-PG = *fqs-Latn = fqs-Latn-PG +*fr = *fr-FR = fr-Latn = fr-Latn-FR +*fr-BE = fr-Latn-BE +*fr-BF = fr-Latn-BF +*fr-BI = fr-Latn-BI +*fr-BJ = fr-Latn-BJ +*fr-BL = fr-Latn-BL +fr-Brai = fr-Brai-FR +*fr-CA = fr-Latn-CA +*fr-CD = fr-Latn-CD +*fr-CF = fr-Latn-CF +*fr-CG = fr-Latn-CG +*fr-CH = fr-Latn-CH +*fr-CI = fr-Latn-CI +*fr-CM = fr-Latn-CM +*fr-DJ = fr-Latn-DJ +*fr-DZ = fr-Latn-DZ +*fr-GN = fr-Latn-GN +*fr-GP = fr-Latn-GP +*fr-GQ = fr-Latn-GQ +*fr-HT = fr-Latn-HT +*fr-KM = fr-Latn-KM +*fr-LU = fr-Latn-LU +*fr-MA = fr-Latn-MA +*fr-MC = fr-Latn-MC +*fr-MF = fr-Latn-MF +*fr-MG = fr-Latn-MG +*fr-ML = fr-Latn-ML +*fr-MQ = fr-Latn-MQ +*fr-MR = fr-Latn-MR +*fr-MU = fr-Latn-MU +*fr-NC = fr-Latn-NC +*fr-NE = fr-Latn-NE +*fr-PF = fr-Latn-PF +*fr-PM = fr-Latn-PM +*fr-RE = fr-Latn-RE +*fr-RW = fr-Latn-RW +*fr-SC = fr-Latn-SC +*fr-SN = fr-Latn-SN +*fr-TD = fr-Latn-TD +*fr-TG = fr-Latn-TG +*fr-TN = fr-Latn-TN +*fr-VU = fr-Latn-VU +*fr-WF = fr-Latn-WF +*fr-YT = fr-Latn-YT +frc = frc-US = frc-Latn = frc-Latn-US +frd-Latn = frd-Latn-ID +frk-Latn = frk-Latn-DE +frm = frm-FR = frm-Latn = frm-Latn-FR +fro = fro-FR = fro-Latn = fro-Latn-FR +frp = frp-FR = frp-Latn = frp-Latn-FR +frq = frq-PG = frq-Latn = frq-Latn-PG +frr = frr-DE = frr-Latn = frr-Latn-DE +frs = frs-DE = frs-Latn = frs-Latn-DE +frt = frt-VU = frt-Latn = frt-Latn-VU +fub = fub-CM = *fub-Arab = fub-Arab-CM +fub-BF = fub-Latn-BF +*fub-Latn = fub-Latn-CM +fud = fud-WF = fud-Latn = fud-Latn-WF +fue = fue-BJ = *fue-Latn = fue-Latn-BJ +fuf = fuf-GN = *fuf-Latn = fuf-Latn-GN +fuf-Adlm = fuf-Adlm-GN +*fuf-Arab = fuf-Arab-GN +fuh = fuh-NE = *fuh-Latn = fuh-Latn-NE +fuh-Arab = fuh-Arab-NE +fun = fun-BR = fun-Latn = fun-Latn-BR +fuq = fuq-NE = *fuq-Latn = fuq-Latn-NE +*fur = *fur-IT = fur-Latn = fur-Latn-IT +fut = fut-VU = fut-Latn = fut-Latn-VU +fuv = fuv-NG = fuv-Latn = fuv-Latn-NG +*fuv-Arab = fuv-Arab-NG +fuy = fuy-PG = *fuy-Latn = fuy-Latn-PG +fvr = fvr-SD = fvr-Latn = fvr-Latn-SD +fwa = fwa-NC = fwa-Latn = fwa-Latn-NC +fwe = fwe-NA = fwe-Latn = fwe-Latn-NA +*fy = *fy-NL = fy-Latn = fy-Latn-NL +*ga = *ga-IE = ga-Latn = ga-Latn-IE +ga-Latg = ga-Latg-IE +ga-Ogam = ga-Ogam-IE +*gaa = gaa-GH = gaa-Latn = gaa-Latn-GH +gab = gab-TD = gab-Latn = gab-Latn-TD +gae = gae-VE = gae-Latn = gae-Latn-VE +gaf = gaf-PG = *gaf-Latn = gaf-Latn-PG +gag = gag-MD = gag-Latn = gag-Latn-MD +gag-Cyrl = gag-Cyrl-MD +gag-Grek = gag-Grek-MD +gah = gah-PG = *gah-Latn = gah-Latn-PG +gai = gai-PG = gai-Latn = gai-Latn-PG +gaj = gaj-PG = *gaj-Latn = gaj-Latn-PG +gal = gal-TL = gal-Latn = gal-Latn-TL +gam = gam-PG = *gam-Latn = gam-Latn-PG +gan = gan-CN = gan-Hans = gan-Hans-CN +gan-Hant = gan-Hant-CN +gan-Latn = gan-Latn-CN +gao = gao-PG = gao-Latn = gao-Latn-PG +gap = gap-PG = gap-Latn = gap-Latn-PG +gar = gar-PG = gar-Latn = gar-Latn-PG +gas-Gujr = gas-Gujr-IN +gat = gat-PG = gat-Latn = gat-Latn-PG +gau-Telu = gau-Telu-IN +gaw = gaw-PG = *gaw-Latn = gaw-Latn-PG +gax = gax-ET = gax-Latn = gax-Latn-ET +gax-Ethi = gax-Ethi-ET +gay = gay-ID = gay-Latn = gay-Latn-ID +gba = gya = gba-CF = gya-CF = gba-Latn = *gya-Latn = gba-Latn-CF = gya-Latn-CF +gbb = gbb-AU = gbb-Latn = gbb-Latn-AU +gbd = gbd-AU = gbd-Latn = gbd-Latn-AU +gbe = gbe-PG = gbe-Latn = gbe-Latn-PG +gbf = gbf-PG = *gbf-Latn = gbf-Latn-PG +gbi-Latn = gbi-Latn-ID +gbj-Orya = gbj-Orya-IN +gbk-Deva = gbk-Deva-IN +gbk-Takr = gbk-Takr-IN +gbl-Deva = gbl-Deva-IN +gbl-Gujr = gbl-Gujr-IN +gbm = gbm-IN = gbm-Deva = gbm-Deva-IN +gbp = gbp-CF = gbp-Latn = gbp-Latn-CF +gbq = gbq-CF = gbq-Latn = gbq-Latn-CF +gbr-Latn = gbr-Latn-NG +gbu = gbu-AU = gbu-Latn = gbu-Latn-AU +gbv = gbv-CF = gbv-Latn = gbv-Latn-CF +gbw = gbw-AU = gbw-Latn = gbw-Latn-AU +gby = gby-NG = *gby-Latn = gby-Latn-NG +gbz = gbz-IR = gbz-Arab = gbz-Arab-IR +gcc = gcc-PG = gcc-Latn = gcc-Latn-PG +gcf = gcf-GP = gcf-Latn = gcf-Latn-GP +gcn = gcn-PG = gcn-Latn = gcn-Latn-PG +gcr = gcr-GF = gcr-Latn = gcr-Latn-GF +gct = gct-VE = gct-Latn = gct-Latn-VE +*gd = *gd-GB = gd-Latn = gd-Latn-GB +gdb-Orya = gdb-Orya-IN +gdb-Telu = gdb-Telu-IN +gdd = gdd-PG = gdd-Latn = gdd-Latn-PG +gde = gde-NG = *gde-Latn = gde-Latn-NG +gdf-Latn = gdf-Latn-NG +gdg-Latn = gdg-Latn-PH +gdh = gdh-AU = gdh-Latn = gdh-Latn-AU +gdj = gdj-AU = gdj-Latn = gdj-Latn-AU +gdl = gdl-ET = gdl-Latn = gdl-Latn-ET +gdl-Ethi = gdl-Ethi-ET +gdn = gdn-PG = *gdn-Latn = gdn-Latn-PG +gdq-Latn = gdq-Latn-YE +gdr = gdr-PG = *gdr-Latn = gdr-Latn-PG +geb = geb-PG = *geb-Latn = geb-Latn-PG +geh = geh-CA = geh-Latn = geh-Latn-CA +gej = gej-TG = *gej-Latn = gej-Latn-TG +gel = gel-NG = *gel-Latn = gel-Latn-NG +ges-Latn = ges-Latn-ID +gev = gev-GA = gev-Latn = gev-Latn-GA +*gez = gez-ET = gez-Ethi = gez-Ethi-ET +gfk = gfk-PG = *gfk-Latn = gfk-Latn-PG +gga = gga-SB = gga-Latn = gga-Latn-SB +gge = gge-AU = gge-Latn = gge-Latn-AU +ggg-Arab = ggg-Arab-PK +ggl = ggl-PG = ggl-Latn = ggl-Latn-PG +ggn = ggn-NP = ggn-Deva = ggn-Deva-NP +ggt = ggt-PG = ggt-Latn = ggt-Latn-PG +ggu-Latn = ggu-Latn-CI +ggw = ggw-PG = ggw-Latn = ggw-Latn-PG +ghc-Latn = ghc-Latn-GB +ghe-Deva = ghe-Deva-NP +ghk = ghk-MM = ghk-Latn = ghk-Latn-MM +ghn = ghn-SB = ghn-Latn = ghn-Latn-SB +ghs = ghs-PG = *ghs-Latn = ghs-Latn-PG +gia = gia-AU = gia-Latn = gia-Latn-AU +gic = gic-ZA = gic-Latn = gic-Latn-ZA +gid = gid-CM = gid-Latn = gid-Latn-CM +gig-Arab = gig-Arab-PK +gih = gih-AU = gih-Latn = gih-Latn-AU +gil = gil-KI = gil-Latn = gil-Latn-KI +gim = gim-PG = *gim-Latn = gim-Latn-PG +gip = gip-PG = gip-Latn = gip-Latn-PG +git = git-CA = git-Latn = git-Latn-CA +giy = giy-AU = giy-Latn = giy-Latn-AU +giz = giz-CM = giz-Latn = giz-Latn-CM +gji-Latn = gji-Latn-NG +gjk = gjk-PK = gjk-Arab = gjk-Arab-PK +gjk-Gujr = gjk-Gujr-PK +gjn = gjn-GH = *gjn-Latn = gjn-Latn-GH +gjr = gjr-AU = gjr-Latn = gjr-Latn-AU +gju = gju-PK = *gju-Arab = gju-Arab-PK +gju-Deva = gju-Deva-IN +gka = gka-PG = gka-Latn = gka-Latn-PG +gkn = gkn-NG = *gkn-Latn = gkn-Latn-NG +gkp = gkp-GN = *gkp-Latn = gkp-Latn-GN +gku = gku-ZA = gku-Latn = gku-Latn-ZA +*gl = *gl-ES = gl-Latn = gl-Latn-ES +glc = glc-TD = glc-Latn = glc-Latn-TD +gld-Cyrl = gld-Cyrl-RU +glk = glk-IR = *glk-Arab = glk-Arab-IR +glw = glw-NG = glw-Latn = glw-Latn-NG +gmb = gmb-SB = gmb-Latn = gmb-Latn-SB +gmg = gmg-PG = gmg-Latn = gmg-Latn-PG +gmh = gmh-DE = gmh-Latn = gmh-Latn-DE +gml = gml-GE = gml-Latf = gml-Latf-GE +gmm = gmm-CM = *gmm-Latn = gmm-Latn-CM +gmu = gmu-PG = gmu-Latn = gmu-Latn-PG +gmv = gmv-ET = *gmv-Ethi = gmv-Ethi-ET +gmv-Latn = gmv-Latn-ET +gmz-Latn = gmz-Latn-NG +gn = gug = gn-PY = gug-PY = gn-Latn = gug-Latn = gn-Latn-PY = gug-Latn-PY +gna-Latn = gna-Latn-BF +gnb-Latn = gnb-Latn-IN +gnd = gnd-CM = *gnd-Latn = gnd-Latn-CM +gng = gng-TG = *gng-Latn = gng-Latn-TG +gni = gni-AU = gni-Latn = gni-Latn-AU +gnk = gnk-BW = gnk-Latn = gnk-Latn-BW +gnm = gnm-PG = gnm-Latn = gnm-Latn-PG +gnn = gnn-AU = gnn-Latn = gnn-Latn-AU +gnq = gnq-MY = gnq-Latn = gnq-Latn-MY +gnt = gnt-PG = gnt-Latn = gnt-Latn-PG +gnu = gnu-PG = gnu-Latn = gnu-Latn-PG +gnw = gnw-BO = gnw-Latn = gnw-Latn-BO +goa-Latn = goa-Latn-CI +gob = gob-CO = gob-Latn = gob-Latn-CO +goc = goc-PG = goc-Latn = goc-Latn-PG +god = god-CI = *god-Latn = god-Latn-CI +gof = gof-ET = *gof-Ethi = gof-Ethi-ET +gof-Latn = gof-Latn-ET +gog = gog-TZ = gog-Latn = gog-Latn-TZ +goh-Latn +goi = goi-PG = goi-Latn = goi-Latn-PG +gok-Deva = gok-Deva-IN +gol = gol-LR = gol-Latn = gol-Latn-LR +gom = gom-IN = gom-Deva = gom-Deva-IN +gom-Knda = gom-Knda-IN +gom-Latn = gom-Latn-IN +gon = gon-IN = gon-Telu = gon-Telu-IN +gon-Deva = gno-Deva = gon-Deva-IN = gno-Deva-IN +goo = goo-FJ = goo-Latn = goo-Latn-FJ +gor = gor-ID = gor-Latn = gor-Latn-ID +gos = gos-NL = gos-Latn = gos-Latn-NL +got = got-UA = got-Goth = got-Goth-UA +gou = gou-CM = gou-Latn = gou-Latn-CM +gpe = gpe-GH = gpe-Latn = gpe-Latn-GH +gpn = gpn-PG = gpn-Latn = gpn-Latn-PG +gqa-Latn = gqa-Latn-NG +gqn = gqn-BR = gqn-Latn = gqn-Latn-BR +gqr = gqr-TD = gqr-Latn = gqr-Latn-TD +gra-Deva = gra-Deva-IN +gra-Gujr = gra-Gujr-IN +grb = gbo = grb-LR = gbo-LR = grb-Latn = *gbo-Latn = grb-Latn-LR = gbo-Latn-LR +grc = grc-CY = grc-Cprt = grc-Cprt-CY +grc-Grek = grc-Grek-GR +grc-Linb = grc-Linb-GR +grg = grg-PG = grg-Latn = grg-Latn-PG +gri = gri-SB = gri-Latn = gri-Latn-SB +grq = grq-PG = grq-Latn = grq-Latn-PG +grt = grt-IN = grt-Beng = grt-Beng-IN +grt-Brai = grt-Brai-IN +grt-Latn = grt-Latn-IN +gru-Ethi = gru-Ethi-ET +grw = grw-PG = *grw-Latn = grw-Latn-PG +grx = grx-PG = grx-Latn = grx-Latn-PG +grz = grz-PG = grz-Latn = grz-Latn-PG +gsl-Latn = gsl-Latn-SN +gsn = gsn-PG = gsn-Latn = gsn-Latn-PG +gso = gso-CF = gso-Latn = gso-Latn-CF +gsp = gsp-PG = gsp-Latn = gsp-Latn-PG +*gsw = *gsw-CH = gsw-Latn = gsw-Latn-CH +*gsw-FR = gsw-Latn-FR +*gsw-LI = gsw-Latn-LI +gta = gta-BR = gta-Latn = gta-Latn-BR +*gu = *gu-IN = gu-Gujr = gu-Gujr-IN +gu-Brai = gu-Brai-IN +gu-Khoj = gu-Khoj-IN +gub = gub-BR = gub-Latn = gub-Latn-BR +guc = guc-CO = guc-Latn = guc-Latn-CO +gud = gud-CI = *gud-Latn = gud-Latn-CI +gue = gue-AU = gue-Latn = gue-Latn-AU +guf = guf-AU = guf-Latn = guf-Latn-AU +guh = guh-CO = guh-Latn = guh-Latn-CO +gui = gui-BO = gui-Latn = gui-Latn-BO +guk = guk-ET = *guk-Latn = guk-Latn-ET +guk-Ethi = guk-Ethi-ET +gul = gul-US = gul-Latn = gul-Latn-US +gum = gum-CO = gum-Latn = gum-Latn-CO +gun = gun-BR = gun-Latn = gun-Latn-BR +guo = guo-CO = guo-Latn = guo-Latn-CO +gup = gup-AU = gup-Latn = gup-Latn-AU +guq = guq-PY = guq-Latn = guq-Latn-PY +gur = gur-GH = *gur-Latn = gur-Latn-GH +gut = gut-CR = gut-Latn = gut-Latn-CR +guu = guu-VE = guu-Latn = guu-Latn-VE +guw = guw-BJ = *guw-Latn = guw-Latn-BJ +gux = gux-BF = *gux-Latn = gux-Latn-BF +*guz = *guz-KE = guz-Latn = guz-Latn-KE +*gv = *gv-IM = gv-Latn = gv-Latn-IM +gva = gva-PY = gva-Latn = gva-Latn-PY +gvc = gvc-BR = gvc-Latn = gvc-Latn-BR +gve = gve-PG = gve-Latn = gve-Latn-PG +gvf = gvf-PG = *gvf-Latn = gvf-Latn-PG +gvj = gvj-BR = gvj-Latn = gvj-Latn-BR +gvl = gvl-TD = gvl-Latn = gvl-Latn-TD +gvn = gvn-AU = gvn-Latn = gvn-Latn-AU +gvo = gvo-BR = gvo-Latn = gvo-Latn-BR +gvp = gvp-BR = gvp-Latn = gvp-Latn-BR +gvr = gvr-NP = gvr-Deva = gvr-Deva-NP +gvs = gvs-PG = *gvs-Latn = gvs-Latn-PG +gwc = gwc-PK = *gwc-Arab = gwc-Arab-PK +gwd = gwd-ET = gwd-Latn = gwd-Latn-ET +gwf-Arab = gwf-Arab-PK +gwi = gwi-CA = gwi-Latn = gwi-Latn-CA +gwj = gwj-BW = gwj-Latn = gwj-Latn-BW +gwr = gwr-UG = gwr-Latn = gwr-Latn-UG +gwt = gwt-Arab +gww = gww-AU = gww-Latn = gww-Latn-AU +gwx = gwx-GH = gwx-Latn = gwx-Latn-GH +gxx-Latn = gxx-Latn-CI +gyb = gyb-PG = gyb-Latn = gyb-Latn-PG +gyd = gyd-AU = gyd-Latn = gyd-Latn-AU +gyi = gyi-CM = *gyi-Latn = gyi-Latn-CM +gym = gym-PA = gym-Latn = gym-Latn-PA +gyn = gyn-GY = gyn-Latn = gyn-Latn-GY +gyr = gyr-BO = gyr-Latn = gyr-Latn-BO +gzi-Arab = gzi-Arab-IR +*ha = *ha-NG = *ha-Latn = *ha-Latn-NG +*ha-Arab = ha-Arab-NG +ha-Brai = ha-Brai-NG +ha-CM = ha-Arab-CM +*ha-GH = *ha-Latn-GH +*ha-Latn-NE +*ha-NE = ha-Arab-NE +ha-SD = ha-Arab-SD +haa = haa-US = haa-Latn = haa-Latn-US +hac-Arab = hac-Arab-IR +had-Latn = had-Latn-ID +hae-Latn = hae-Latn-ET +hag = hag-GH = *hag-Latn = hag-Latn-GH +hah = hah-PG = hah-Latn = hah-Latn-PG +hai = hdn = hai-CA = hdn-CA = hai-Latn = hdn-Latn = hai-Latn-CA = hdn-Latn-CA +haj-Beng = haj-Beng-IN +haj-Latn = haj-Latn-IN +hak = hak-CN = hak-Hans = hak-Hans-CN +hak-Hant = hak-Hant-CN +hak-Latn = hak-Latn-CN +hal = hal-VN = hal-Latn = hal-Latn-VN +ham = ham-PG = *ham-Latn = ham-Latn-PG +han = han-TZ = han-Latn = han-Latn-TZ +hao = hao-PG = hao-Latn = hao-Latn-PG +hap-Latn = hap-Latn-ID +haq = haq-TZ = haq-Latn = haq-Latn-TZ +har-Ethi = har-Ethi-ET +has = has-CA = has-Latn = has-Latn-CA +*haw = *haw-US = haw-Latn = haw-Latn-US +hax = hax-CA = hax-Latn = hax-Latn-CA +hay = hay-TZ = hay-Latn = hay-Latn-TZ +haz = haz-AF = haz-Arab = haz-Arab-AF +hbb = hbb-NG = *hbb-Latn = hbb-Latn-NG +hbn = hbn-SD = hbn-Latn = hbn-Latn-SD +hbo-Hebr = hbo-Hebr-IL +hbu = hbu-TL = hbu-Latn = hbu-Latn-TL +hch = hch-MX = hch-Latn = hch-Latn-MX +hdy = hdy-ET = *hdy-Ethi = hdy-Ethi-ET +hdy-Latn = hdy-Latn-ET +*he = *he-IL = he-Hebr = he-Hebr-IL +he-Brai = he-Brai-IL +hed = hed-TD = hed-Latn = hed-Latn-TD +heg-Latn = heg-Latn-ID +heh = heh-TZ = heh-Latn = heh-Latn-TZ +hei = hei-CA = hei-Latn = hei-Latn-CA +hgw = hgw-PG = hgw-Latn = hgw-Latn-PG +hhi = hhi-PG = hhi-Latn = hhi-Latn-PG +hhy = hhy-PG = *hhy-Latn = hhy-Latn-PG +*hi = *hi-IN = hi-Deva = hi-Deva-IN +hi-Brai = hi-Brai-IN +hi-Newa = hi-Newa-IN +hia = hia-NG = *hia-Latn = hia-Latn-NG +hid = hid-US = hid-Latn = hid-Latn-US +hif = hif-FJ = hif-Latn = hif-Latn-FJ +hif-Deva = hif-Deva-FJ +hig = hig-NG = *hig-Latn = hig-Latn-NG +hih = hih-PG = *hih-Latn = hih-Latn-PG +hil = hil-PH = hil-Latn = hil-Latn-PH +hil-Brai = hil-Brai-PH +hio = hio-BW = hio-Latn = hio-Latn-BW +hir = hir-BR = hir-Latn = hir-Latn-BR +hiw = hiw-VU = hiw-Latn = hiw-Latn-VU +hix = hix-BR = hix-Latn = hix-Latn-BR +hke = hke-CD = hke-Latn = hke-Latn-CD +hkk = hkk-PG = hkk-Latn = hkk-Latn-PG +hla = hla-PG = *hla-Latn = hla-Latn-PG +hlb-Deva = hlb-Deva-IN +hlt = hlt-MM = hlt-Latn = hlt-Latn-MM +hlu = hlu-TR = hlu-Hluw = hlu-Hluw-TR +hmb-Latn = hmb-Latn-ML +hmd = hmd-CN = *hmd-Plrd = hmd-Plrd-CN +hmd-Hmng = hmd-Hmng-CN +hmd-Latn = hmd-Latn-CN +hmj-Bopo = hmj-Bopo-CN +hmn-Bopo = hea-Bopo = hmn-Bopo-CN = hea-Bopo-CN +hmn-Hmng +hmn-Latn +hmq-Bopo = hmq-Bopo-CN +hmr-Latn = hmr-Latn-IN +hms-Latn = hms-Latn-CN +hmt = hmt-PG = *hmt-Latn = hmt-Latn-PG +hmz-Latn = hmz-Latn-CN +hmz-Plrd = hmz-Plrd-CN +hnd = hnd-PK = hnd-Arab = hnd-Arab-PK +hne = hne-IN = hne-Deva = hne-Deva-IN +hnh = hnh-BW = hnh-Latn = hnh-Latn-BW +hni-Latn = hni-Latn-CN +hnj = hnj-LA = hnj-Hmng = hnj-Hmng-LA +hnj-Latn = hnj-Latn-LA +hnj-Plrd = hnj-Plrd-CN +hnj-Thai = hnj-Thai-TH +hnn = hnn-PH = hnn-Latn = hnn-Latn-PH +hnn-Hano = hnn-Hano-PH +hno = hno-PK = *hno-Arab = hno-Arab-PK +hns-Latn = hns-Latn-SR +ho = ho-PG = ho-Latn = ho-Latn-PG +ho-Brai = ho-Brai-PG +hoa = hoa-SB = hoa-Latn = hoa-Latn-SB +hob = hob-PG = hob-Latn = hob-Latn-PG +hoc = hoc-IN = hoc-Deva = hoc-Deva-IN +hoc-Latn = hoc-Latn-IN +hoc-Orya = hoc-Orya-IN +hoc-Telu = hoc-Telu-IN +hoc-Wara = hoc-Wara-IN +hoi = hoi-US = hoi-Latn = hoi-Latn-US +hoj = hoj-IN = hoj-Deva = hoj-Deva-IN +hol = hol-AO = hol-Latn = hol-Latn-AO +hoo = hoo-CD = hoo-Latn = hoo-Latn-CD +hop = hop-US = hop-Latn = hop-Latn-US +hot = hot-PG = *hot-Latn = hot-Latn-PG +how-Hani = how-Hani-CN +*hr = *hr-HR = hr-Latn = hr-Latn-HR +*hr-BA = hr-Latn-BA +hr-Brai = hr-Brai-HR +hra-Latn = hra-Latn-IN +hrc = hrc-PG = hrc-Latn = hrc-Latn-PG +hre-x-1960 = hre-VN-x-1960 = hre-Latn-x-1960 = hre-Latn-VN-x-1960 +hre-x-1968 = hre-VN-x-1968 = hre-Latn-x-1968 = hre-Latn-VN-x-1968 +hro = hro-VN = hro-Latn = hro-Latn-VN +hrt-Syrc = hrt-Syrc-TR +hru-Latn = hru-Latn-IN +hrw = hrw-PG = hrw-Latn = hrw-Latn-PG +hrx = hrx-BR = hrx-Latn = hrx-Latn-BR +hrz-Arab = hrz-Arab-IR +*hsb = *hsb-DE = hsb-Latn = hsb-Latn-DE +hsn = hsn-CN = hsn-Hans = hsn-Hans-CN +hsn-Hant = hsn-Hant-CN +hsn-Nshu = hsn-Nshu-CN +ht = ht-HT = ht-Latn = ht-Latn-HT +hto = hto-CO = hto-Latn = hto-Latn-CO +*hu = *hu-HU = hu-Latn = hu-Latn-HU +hu-Brai = hu-Brai-HU +hub = hub-PE = hub-Latn = hub-Latn-PE +huc = huc-BW = huc-Latn = huc-Latn-BW +hue = hue-MX = hue-Latn = hue-Latn-MX +huf = huf-PG = huf-Latn = huf-Latn-PG +hug = hug-PE = hug-Latn = hug-Latn-PE +huh = huh-CL = huh-Latn = huh-Latn-CL +hui = hui-PG = *hui-Latn = hui-Latn-PG +hul = hul-PG = hul-Latn = hul-Latn-PG +hum = hum-CD = hum-Latn = hum-Latn-CD +hup = hup-US = hup-Latn = hup-Latn-US +hur = hur-CA = hur-Latn = hur-Latn-CA +hus = hus-MX = hus-Latn = hus-Latn-MX +huu = huu-PE = huu-Latn = huu-Latn-PE +huv = huv-MX = huv-Latn = huv-Latn-MX +hux = hux-PE = hux-Latn = hux-Latn-PE +huy-Hebr = huy-Hebr-IL +hve = hve-MX = hve-Latn = hve-Latn-MX +hvk = hvk-NC = hvk-Latn = hvk-Latn-NC +hvn-Latn = hvn-Latn-ID +hvv = hvv-MX = hvv-Latn = hvv-Latn-MX +hwc = hwc-US = hwc-Latn = hwc-Latn-US +hwo-Latn = hwo-Latn-NG +*hy = *hy-AM = hy-Armn = hy-Armn-AM +hy-Brai = hy-Brai-AM +hyw = hyw-AM = hyw-Armn = hyw-Armn-AM +hz = hz-NA = hz-Latn = hz-Latn-NA +*ia = *ia-FR = ia-Latn = ia-Latn-FR +iai = iai-NC = iai-Latn = iai-Latn-NC +ian = ian-PG = *ian-Latn = ian-Latn-PG +iar = iar-PG = *iar-Latn = iar-Latn-PG +iba = iba-MY = iba-Latn = iba-Latn-MY +ibb = ibb-NG = ibb-Latn = ibb-Latn-NG +ibd = ibd-AU = ibd-Latn = ibd-Latn-AU +ibg-Latn = ibg-Latn-PH +ibl-Latn = ibl-Latn-PH +iby = iby-NG = *iby-Latn = iby-Latn-NG +ica = ica-BJ = ica-Latn = ica-Latn-BJ +ich = ich-NG = *ich-Latn = ich-Latn-NG +icr = icr-CO = icr-Latn = icr-Latn-CO +*id = *id-ID = id-Latn = id-Latn-ID +id-Arab = id-Arab-ID +id-Brai = id-Brai-ID +ida = ida-KE = ida-Latn = ida-Latn-KE +idb-Latn = idb-Latn-IN +idd = idd-BJ = idd-Latn = idd-Latn-BJ +idi = idi-PG = *idi-Latn = idi-Latn-PG +idt = idt-TL = idt-Latn = idt-Latn-TL +idu = idu-NG = *idu-Latn = idu-Latn-NG +ie-Latn = ie-Latn-?? +ifa-Latn = ifa-Latn-PH +ifb-Latn = ifb-Latn-PH +ife = ife-TG = *ife-Latn = ife-Latn-TG +ifk-Latn = ifk-Latn-PH +ifm = ifm-CG = ifm-Latn = ifm-Latn-CG +ifu-Latn = ifu-Latn-PH +ify-Latn = ify-Latn-PH +*ig = *ig-NG = ig-Latn = ig-Latn-NG +igb = igb-NG = *igb-Latn = igb-Latn-NG +ige = ige-NG = *ige-Latn = ige-Latn-NG +igg = igg-PG = igg-Latn = igg-Latn-PG +igl-Latn = igl-Latn-NG +igm = igm-PG = igm-Latn = igm-Latn-PG +ign = ign-BO = ign-Latn = ign-Latn-BO +igo = igo-PG = igo-Latn = igo-Latn-PG +*ii = *ii-CN = ii-Yiii = ii-Yiii-CN +ii-Latn = ii-Latn-CN +ijc-Latn = ijc-Latn-NG +ijj = ijj-BJ = ijj-Latn = ijj-Latn-BJ +ijn-Latn = ijn-Latn-NG +ijs-Latn = ijs-Latn-NG +ik = esk = ik-US = esk-US = ik-Latn = esk-Latn = ik-Latn-US = esk-Latn-US +ikk = ikk-NG = *ikk-Latn = ikk-Latn-NG +ikt = ikt-CA = ikt-Latn = ikt-Latn-CA +ikt-Cans = ikt-Cans-CA +ikw = ikw-NG = *ikw-Latn = ikw-Latn-NG +ikx = ikx-UG = *ikx-Latn = ikx-Latn-UG +ikz = ikz-TZ = ikz-Latn = ikz-Latn-TZ +ilb = ilb-ZM = ilb-Latn = ilb-Latn-ZM +ilk-Latn = ilk-Latn-PH +ilm-Latn = ilm-Latn-MY +ilo = ilo-PH = ilo-Latn = ilo-Latn-PH +ilo-Brai = ilo-Brai-PH +ilo-Tglg = ilo-Tglg-PH +ilp-Latn = ilp-Latn-PH +imi = imi-PG = imi-Latn = imi-Latn-PG +imn = imn-PG = imn-Latn = imn-Latn-PG +imo = imo-PG = *imo-Latn = imo-Latn-PG +in = in-ID = in-Latn = in-Latn-ID +inb = inb-CO = inb-Latn = inb-Latn-CO +ing = ing-US = ing-Latn = ing-Latn-US +inh = inh-RU = inh-Cyrl = inh-Cyrl-RU +inh-Arab = inh-Arab-RU +inh-Latn = inh-Latn-RU +inj = inj-CO = inj-Latn = inj-Latn-CO +ino = ino-PG = ino-Latn = ino-Latn-PG +inp = inp-PE = inp-Latn = inp-Latn-PE +int = int-MM = int-Mymr = int-Mymr-MM +io = io-001 = io-Latn = io-Latn-001 +iou = iou-PG = *iou-Latn = iou-Latn-PG +ipi = ipi-PG = ipi-Latn = ipi-Latn-PG +ipo = ipo-PG = ipo-Latn = ipo-Latn-PG +iqu = iqu-PE = iqu-Latn = iqu-Latn-PE +iqw-Latn = iqw-Latn-NG +irh-Latn = irh-Latn-ID +iri = iri-NG = *iri-Latn = iri-Latn-NG +irk = irk-TZ = irk-Latn = irk-Latn-TZ +irn = irn-BR = irn-Latn = irn-Latn-BR +iru-Mlym = iru-Mlym-IN +iru-Taml = iru-Taml-IN +iry-Latn = iry-Latn-PH +*is = *is-IS = is-Latn = is-Latn-IS +isa = isa-PG = isa-Latn = isa-Latn-PG +isc = isc-PE = isc-Latn = isc-Latn-PE +isd-Latn = isd-Latn-PH +ish-Latn = ish-Latn-NG +isi-Latn = isi-Latn-NG +iso-Latn = iso-Latn-NG +isu = isu-CM = isu-Latn = isu-Latn-CM +*it = *it-IT = it-Latn = it-Latn-IT +it-Brai = it-Brai-IT +*it-CH = it-Latn-CH +*it-SM = it-Latn-SM +*it-VA = it-Latn-VA +itb-Latn = itb-Latn-PH +ite = ite-BO = ite-Latn = ite-Latn-BO +itk-Hebr = itk-Hebr-IT +itl-Cyrl = itl-Cyrl-RU +ito = ito-BO = ito-Latn = ito-Latn-BO +itr = itr-PG = itr-Latn = itr-Latn-PG +its-Latn = its-Latn-NG +itv-Latn = itv-Latn-PH +itw-Latn = itw-Latn-NG +itz = itz-GT = itz-Latn = itz-Latn-GT +*iu = ike = iu-CA = ike-CA = iu-Cans = ike-Cans = iu-Cans-CA = ike-Cans-CA +iu-Latn = iu-Latn-CA +ium = ium-CN = ium-Latn = ium-Latn-CN +ium-Hani = ium-Hani-CN +ium-Laoo = ium-Laoo-LA +ium-Thai = ium-Thai-TH +ium-x-1954 = ium-CN-x-1954 = ium-Latn-x-1954 = ium-Latn-CN-x-1954 +ivb-Latn = ivb-Latn-PH +ivv-Latn = ivv-Latn-PH +iw = iw-IL = iw-Hebr = iw-Hebr-IL +iwm = iwm-PG = *iwm-Latn = iwm-Latn-PG +iws = iws-PG = *iws-Latn = iws-Latn-PG +ixc = ixc-MX = ixc-Latn = ixc-Latn-MX +ixl = ixl-GT = ixl-Latn = ixl-Latn-GT +iyo = iyo-CM = iyo-Latn = iyo-Latn-CM +iyx = iyx-CG = iyx-Latn = iyx-Latn-CG +izh = izh-RU = izh-Latn = izh-Latn-RU +izi = izi-Latn +*izr-Latn = izr-Latn-NG +*izz-Latn = izz-Latn-NG +*ja = *ja-JP = ja-Jpan = ja-Jpan-JP +ja-Brai = ja-Brai-JP +jaa = jaa-BR = jaa-Latn = jaa-Latn-BR +jab = jab-NG = *jab-Latn = jab-Latn-NG +jac = jac-GT = jac-Latn = jac-Latn-GT +jad-Arab = jad-Arab-GN +jae = jae-PG = jae-Latn = jae-Latn-PG +jah-Latn = jah-Latn-MY +jaj = jaj-SB = jaj-Latn = jaj-Latn-SB +jal-Latn = jal-Latn-ID +jam = jam-JM = jam-Latn = jam-Latn-JM +jao = jao-AU = jao-Latn = jao-Latn-AU +jas = jas-NC = jas-Latn = jas-Latn-NC +jax-Latn = jax-Latn-ID +jay = jay-AU = jay-Latn = jay-Latn-AU +jaz = jaz-NC = jaz-Latn = jaz-Latn-NC +jbe-Hebr = jbe-Hebr-IL +jbk = jbk-PG = jbk-Latn = jbk-Latn-PG +jbn-Arab = jbn-Arab-LY +jbo = jbo-001 = jbo-Latn = jbo-Latn-001 +jbt = jbt-BR = jbt-Latn = jbt-Latn-BR +jbu = jbu-CM = *jbu-Latn = jbu-Latn-CM +jct-Cyrl = jct-Cyrl-UA +jct-Latn = jct-Latn-UA +jdg-Arab = jdg-Arab-PK +jdt = jdt-RU = jdt-Cyrl = jdt-Cyrl-RU +jdt-Hebr = jdt-Hebr-RU +jdt-Latn = jdt-Latn-AZ +jeb = jeb-PE = jeb-Latn = jeb-Latn-PE +jee-Deva = jee-Deva-NP +jeh = jeh-VN = jeh-Latn = jeh-Latn-VN +jeh-Laoo = jeh-Laoo-LA +jen = jen-NG = *jen-Latn = jen-Latn-NG +jet = jet-PG = jet-Latn = jet-Latn-PG +jgk = jgk-NG = *jgk-Latn = jgk-Latn-NG +*jgo = *jgo-CM = jgo-Latn = jgo-Latn-CM +ji = ji-UA = ji-Hebr = ji-Hebr-UA +jib = jib-NG = *jib-Latn = jib-Latn-NG +jic = jic-HN = jic-Latn = jic-Latn-HN +jig = jig-AU = jig-Latn = jig-Latn-AU +jil = jil-PG = jil-Latn = jil-Latn-PG +jim = jim-CM = jim-Latn = jim-Latn-CM +jit = jit-TZ = jit-Latn = jit-Latn-TZ +jiu-Latn = jiu-Latn-CN +jiv = jiv-EC = jiv-Latn = jiv-Latn-EC +jiy-Latn = jiy-Latn-CN +jje-Hang = jje-Hang-KR +jko = jko-PG = jko-Latn = jko-Latn-PG +jma = jma-PG = jma-Latn = jma-Latn-PG +*jmc = *jmc-TZ = jmc-Latn = jmc-Latn-TZ +jmd-Latn = jmd-Latn-ID +jml = jml-NP = jml-Deva = jml-Deva-NP +jmn = jmn-MM = jmn-Latn = jmn-Latn-MM +jmr = jmr-GH = jmr-Latn = jmr-Latn-GH +jmw = jmw-PG = jmw-Latn = jmw-Latn-PG +jmx = jmx-MX = jmx-Latn = jmx-Latn-MX +jnj-Latn = jnj-Latn-ET +jnl-Deva = jnl-Deva-IN +jns-Deva = jns-Deva-IN +jns-Latn = jns-Latn-IN +jns-Takr = jns-Takr-IN +jor = jor-BO = jor-Latn = jor-Latn-BO +jow-Latn = jow-Latn-ML +jpr-Hebr = jpr-Hebr-IL +jqr = jqr-PE = jqr-Latn = jqr-Latn-PE +jra = jra-VN = *jra-Latn = jra-Latn-VN +jra-Khmr = jra-Khmr-KH +jrb-Hebr = aju-Hebr = jrb-Hebr-IL = aju-Hebr-IL +jru = jru-VE = jru-Latn = jru-Latn-VE +jua = jua-BR = jua-Latn = jua-Latn-BR +juc-Jurc +juk-Latn = juk-Latn-NG +jul-Deva = jul-Deva-NP +jum = jum-SD = jum-Latn = jum-Latn-SD +jun-Orya = jun-Orya-IN +juo-Latn = juo-Latn-NG +jup = jup-BR = jup-Latn = jup-Latn-BR +jur = jur-BR = jur-Latn = jur-Latn-BR +jut = jut-DK = jut-Latn = jut-Latn-DK +jv = jv-ID = jv-Latn = jv-Latn-ID +jv-Java = jv-Java-ID +jvn = jvn-SR = jvn-Latn = jvn-Latn-SR +jw = jw-ID = jw-Latn = jw-Latn-ID +jwi = jwi-GH = jwi-Latn = jwi-Latn-GH +jya-Tibt = jya-Tibt-CN +jye-Hebr = jye-Hebr-IL +*ka = *ka-GE = ka-Geor = ka-Geor-GE +ka-Brai = ka-Brai-GE +ka-Geok = ka-Geok-GE +kaa = kaa-UZ = kaa-Cyrl = kaa-Cyrl-UZ +kaa-Latn = kaa-Latn-UZ +*kab = *kab-DZ = kab-Latn = kab-Latn-DZ +kab-Tfng = kab-Tfng-DZ +kac = kac-MM = kac-Latn = kac-Latn-MM +kad = kad-NG = *kad-Latn = kad-Latn-NG +kah = kah-CF = kah-Latn = kah-Latn-CF +kai = kai-NG = *kai-Latn = kai-Latn-NG +kaj = kaj-NG = *kaj-Latn = kaj-Latn-NG +kak-Latn = kak-Latn-PH +*kam = *kam-KE = kam-Latn = kam-Latn-KE +kao = kao-ML = kao-Latn = kao-Latn-ML +kap-Cyrl = kap-Cyrl-RU +kaq = kaq-PE = kaq-Latn = kaq-Latn-PE +kav = kav-BR = kav-Latn = kav-Latn-BR +kaw-Bali = kaw-Bali-MY +kay = kay-BR = kay-Latn = kay-Latn-BR +kbb = kbb-BR = kbb-Latn = kbb-Latn-BR +kbc = kbc-BR = kbc-Latn = kbc-Latn-BR +kbd = kbd-RU = kbd-Cyrl = kbd-Cyrl-RU +kbe = kbe-AU = kbe-Latn = kbe-Latn-AU +kbg-Tibt-x-hingna = kbg-Tibt-IN-x-hingna +kbh = kbh-CO = kbh-Latn = kbh-Latn-CO +kbk = kbk-PG = kbk-Latn = kbk-Latn-PG +kbl = kbl-TD = kbl-Latn = kbl-Latn-TD +kbm = kbm-PG = *kbm-Latn = kbm-Latn-PG +kbn = kbn-CF = kbn-Latn = kbn-Latn-CF +kbo = kbo-SS = kbo-Latn = kbo-Latn-SS +kbp = kbp-TG = *kbp-Latn = kbp-Latn-TG +kbp-Brai = kbp-Brai-TG +kbq = kbq-PG = *kbq-Latn = kbq-Latn-PG +kbr-Ethi = kbr-Ethi-ET +kbr-Latn = kbr-Latn-ET +kbs = kbs-GA = kbs-Latn = kbs-Latn-GA +kbt = kbt-PG = kbt-Latn = kbt-Latn-PG +kbw = kbw-PG = kbw-Latn = kbw-Latn-PG +kbx = kbx-PG = *kbx-Latn = kbx-Latn-PG +kby = kby-NE = *kby-Arab = kby-Arab-NE +*kby-Latn = kby-Latn-NE +kca-Cyrl = kca-Cyrl-RU +kcb = kcb-PG = kcb-Latn = kcb-Latn-PG +kcg = kcg-NG = *kcg-Latn = kcg-Latn-NG +kck = kck-ZW = kck-Latn = kck-Latn-ZW +kcl = kcl-PG = *kcl-Latn = kcl-Latn-PG +kcn = kcn-UG = kcn-Latn = kcn-Latn-UG +kco = kco-PG = kco-Latn = kco-Latn-PG +kcp = kcp-SD = kcp-Latn = kcp-Latn-SD +kcq-Latn = kcq-Latn-NG +kct = kct-PG = kct-Latn = kct-Latn-PG +kdc = kdc-TZ = kdc-Latn = kdc-Latn-TZ +kdd = kdd-AU = kdd-Latn = kdd-Latn-AU +*kde = *kde-TZ = kde-Latn = kde-Latn-TZ +kdf = kdf-PG = kdf-Latn = kdf-Latn-PG +kdh = kdh-TG = *kdh-Arab = kdh-Arab-TG +*kdh-Latn = kdh-Latn-TG +kdi = kdi-UG = kdi-Latn = kdi-Latn-UG +kdj = kdj-UG = kdj-Latn = kdj-Latn-UG +kdk = kdk-NC = kdk-Latn = kdk-Latn-NC +kdl = kdl-NG = *kdl-Latn = kdl-Latn-NG +kdn = kdn-ZW = kdn-Latn = kdn-Latn-ZW +kdq-Beng = kdq-Beng-IN +kdr-Cyrl = kdr-Cyrl-UA +kdr-Latn = kdr-Latn-LT +kdt = kdt-TH = kdt-Thai = kdt-Thai-TH +kdt-Khmr = kdt-Khmr-KH +kdt-Laoo = kdt-Laoo-LA +*kea = *kea-CV = kea-Latn = kea-Latn-CV +keb = keb-GA = keb-Latn = keb-Latn-GA +kec = kec-SD = kec-Latn = kec-Latn-SD +ked = ked-TZ = ked-Latn = ked-Latn-TZ +kee = kee-US = kee-Latn = kee-Latn-US +keg = keg-SD = keg-Latn = keg-Latn-SD +keh = keh-PG = keh-Latn = keh-Latn-PG +kei-Latn = kei-Latn-ID +kek = kek-GT = kek-Latn = kek-Latn-GT +kel = kel-CD = kel-Latn = kel-Latn-CD +kem = kem-TL = kem-Latn = kem-Latn-TL +ken = ken-CM = *ken-Latn = ken-Latn-CM +keo = keo-UG = keo-Latn = keo-Latn-UG +ker = ker-TD = ker-Latn = ker-Latn-TD +ket-Cyrl = ket-Cyrl-RU +keu-Latn = keu-Latn-TG +kew = kew-PG = kew-Latn = kew-Latn-PG +kex-Deva = kex-Deva-IN +kex-Gujr = kex-Gujr-IN +key-Telu = key-Telu-IN +kez = kez-NG = *kez-Latn = kez-Latn-NG +kfa-Knda = kfa-Knda-IN +kfb-Deva = kfb-Deva-IN +kfc-Telu = kfc-Telu-IN +kfe-Taml = kfe-Taml-IN +kff-Deva = kff-Deva-IN +kff-Latn = kff-Latn-IN +kff-Orya = kff-Orya-IN +kff-Telu = kff-Telu-IN +kfg-Knda = kfg-Knda-IN +kfg-Mlym = kfg-Mlym-IN +kfh-Mlym = kfh-Mlym-IN +kfi-Taml = kfi-Taml-IN +kfk-Deva = kfk-Deva-IN +kfk-Takr = kfk-Takr-IN +kfm-Arab = kfm-Arab-IR +kfo = kfo-CI = kfo-Latn = kfo-Latn-CI +kfq-Deva = kfq-Deva-IN +kfr = kfr-IN = kfr-Deva = kfr-Deva-IN +kfr-Gujr = kfr-Gujr-IN +kfv-Latn = kfv-Latn-IN +kfw-Latn = kfw-Latn-IN +kfx-Deva = kfx-Deva-IN +kfx-Takr = kfx-Takr-IN +kfy = kfy-IN = kfy-Deva = kfy-Deva-IN +kfz-Latn = kfz-Latn-BF +kg = kng = kg-CD = kng-CD = kg-Latn = kng-Latn = kg-Latn-CD = kng-Latn-CD +kgd-Laoo = kgd-Laoo-LA +kgd-Thai = kgd-Thai-LA +kge = kge-ID = kge-Latn = kge-Latn-ID +kgf = kgf-PG = *kgf-Latn = kgf-Latn-PG +kgj = kgj-NP = kgj-Deva = kgj-Deva-NP +kgk = kgk-BR = kgk-Latn = kgk-Latn-BR +kgm = kgm-BR = kgm-Latn = kgm-Latn-BR +kgo = kgo-SD = kgo-Latn = kgo-Latn-SD +kgp = kgp-BR = kgp-Latn = kgp-Latn-BR +kgr-Latn = kgr-Latn-ID +kgs = kgs-AU = kgs-Latn = kgs-Latn-AU +kgu = kgu-PG = kgu-Latn = kgu-Latn-PG +kha = kha-IN = kha-Latn = kha-Latn-IN +kha-Beng = kha-Beng-IN +khb = khb-CN = *khb-Talu = khb-Talu-CN +khb-Lana = khb-Lana-CN +khe-Latn = khe-Latn-ID +khf-Thai = khf-Thai-LA +khg-Tibt = khg-Tibt-CN +khl = khl-PG = khl-Latn = khl-Latn-PG +khn = khn-IN = khn-Deva = khn-Deva-IN +*khq = *khq-ML = khq-Latn = khq-Latn-ML +khr-Deva = khr-Deva-IN +khr-Latn = khr-Latn-IN +khs = khs-PG = *khs-Latn = khs-Latn-PG +kht = kht-IN = kht-Mymr = kht-Mymr-IN +khu = khu-AO = khu-Latn = khu-Latn-AO +khw = khw-PK = *khw-Arab = khw-Arab-PK +khy = khy-CD = khy-Latn = khy-Latn-CD +khz = khz-PG = *khz-Latn = khz-Latn-PG +*ki = *ki-KE = ki-Latn = ki-Latn-KE +kia = kia-TD = kia-Latn = kia-Latn-TD +kib = kib-SD = kib-Latn = kib-Latn-SD +kic = kic-US = kic-Latn = kic-Latn-US +kih = kih-PG = kih-Latn = kih-Latn-PG +kij = kij-PG = *kij-Latn = kij-Latn-PG +kim-Cyrl = kim-Cyrl-RU +kio = kio-US = kio-Latn = kio-Latn-US +kip-Deva = kip-Deva-NP +kis = kis-PG = kis-Latn = kis-Latn-PG +kit = kit-PG = kit-Latn = kit-Latn-PG +kiu = kiu-TR = kiu-Latn = kiu-Latn-TR +kiw = kiw-PG = *kiw-Latn = kiw-Latn-PG +kix-Latn = kix-Latn-IN +kj = kj-NA = kj-Latn = kj-Latn-NA +kj-Brai = kj-Brai-AO +kjb = kjb-GT = kjb-Latn = kjb-Latn-GT +kjc-Latn = kjc-Latn-ID +kjd = kjd-PG = *kjd-Latn = kjd-Latn-PG +kje-Latn = kje-Latn-ID +kjg = kjg-LA = kjg-Laoo = kjg-Laoo-LA +kjg-Latn = kjg-Latn-LA +kjg-Thai = kjg-Thai-TH +kjh-Cyrl = kjh-Cyrl-RU +kji = kji-SB = kji-Latn = kji-Latn-SB +kjl-Deva = kjl-Deva-NP +kjn = kjn-AU = kjn-Latn = kjn-Latn-AU +kjp-Leke = kjp-Leke-MM +kjp-Mymr-x-chekhi = kjp-Mymr-MM-x-chekhi +kjp-Mymr-x-phlouyu = kjp-Mymr-MM-x-phlouyu +kjp-Mymr-x-thiyon = kjp-Mymr-MM-x-thiyon +kjp-Thai = kjp-Thai-TH +kjq = kjq-US = kjq-Latn = kjq-Latn-US +kjs = kjs-PG = *kjs-Latn = kjs-Latn-PG +kjt = kjt-TH = kjt-Thai = kjt-Thai-TH +kju = kju-US = kju-Latn = kju-Latn-US +kjv-Latn = kjv-Latn-?? +kjx = kjx-PG = kjx-Latn = kjx-Latn-PG +kjy = kjy-PG = *kjy-Latn = kjy-Latn-PG +kjz-Tibt-x-uchen = kjz-Tibt-BT-x-uchen +*kk = *kk-KZ = *kk-Cyrl = *kk-Cyrl-KZ +kk-AF = kk-Arab-AF +kk-Brai = kk-Brai-KZ +kk-CN = *kk-Arab = kk-Arab-CN +kk-IR = kk-Arab-IR +kk-Latn = kk-Latn-TR +kk-MN = kk-Arab-MN +kkc = kkc-PG = *kkc-Latn = kkc-Latn-PG +kkh = kkh-MM = kkh-Lana = kkh-Lana-MM +kki = kki-TZ = kki-Latn = kki-Latn-TZ +*kkj = *kkj-CM = kkj-Latn = kkj-Latn-CM +kkk = kkk-SB = kkk-Latn = kkk-Latn-SB +kkl-Latn = kkl-Latn-ID +kko = kko-SD = kko-Latn = kko-Latn-SD +kkp = kkp-AU = kkp-Latn = kkp-Latn-AU +kkt-Deva = kkt-Deva-NP +kkv-Latn = kkv-Latn-ID +kkw = kkw-CG = kkw-Latn = kkw-Latn-CG +kky = kky-AU = kky-Latn = kky-Latn-AU +kkz = kkz-CA = kkz-Latn = kkz-Latn-CA +*kl = *kl-GL = kl-Latn = kl-Latn-GL +klb = klb-MX = klb-Latn = klb-Latn-MX +klc = klc-CM = klc-Latn = klc-Latn-CM +kld = kld-AU = kld-Latn = kld-Latn-AU +kle-Deva = kle-Deva-NP +klg-Latn = klg-Latn-PH +klh = klh-PG = klh-Latn = klh-Latn-PG +kli-Latn = kli-Latn-ID +kll-Latn = kll-Latn-PH +klm = klm-PG = klm-Latn = klm-Latn-PG +*kln = spy = *kln-KE = spy-KE = kln-Latn = *spy-Latn = kln-Latn-KE = spy-Latn-KE +klp = klp-PG = klp-Latn = klp-Latn-PG +klq = klq-PG = *klq-Latn = klq-Latn-PG +klr-Deva = klr-Deva-NP +kls-Arab = kls-Arab-PK +kls-Latn = kls-Latn-PK +klt = klt-PG = *klt-Latn = klt-Latn-PG +klu = klu-LR = klu-Latn = klu-Latn-LR +klv = klv-VU = klv-Latn = klv-Latn-VU +klw-Latn = klw-Latn-ID +klx = klx-PG = *klx-Latn = klx-Latn-PG +*km = *km-KH = km-Khmr = km-Khmr-KH +kma = kma-GH = kma-Latn = kma-Latn-GH +kmb = kmb-AO = kmb-Latn = kmb-Latn-AO +kmc-Hani = kmc-Hani-CN +kmc-Latn = kmc-Latn-CN +kmd-Latn = kmd-Latn-PH +kmf = kmf-PG = kmf-Latn = kmf-Latn-PG +kmg = kmg-PG = kmg-Latn = kmg-Latn-PG +kmh = kmh-PG = *kmh-Latn = kmh-Latn-PG +kmk-Latn = kmk-Latn-PH +kml-Latn = kml-Latn-PH +kmm-Latn = kmm-Latn-IN +kmn = kmn-PG = kmn-Latn = kmn-Latn-PG +kmo = kmo-PG = *kmo-Latn = kmo-Latn-PG +kmp = kmp-CM = kmp-Latn = kmp-Latn-CM +kmq = kmq-ET = kmq-Latn = kmq-Latn-ET +kms = kms-PG = *kms-Latn = kms-Latn-PG +kmt-Latn = kmt-Latn-ID +kmu = kmu-PG = *kmu-Latn = kmu-Latn-PG +kmv = kmv-BR = kmv-Latn = kmv-Latn-BR +kmw = kmw-CD = *kmw-Latn = kmw-Latn-CD +kmx = kmx-PG = kmx-Latn = kmx-Latn-PG +kmy = kmy-NG = kmy-Latn = kmy-Latn-NG +kmz-Arab = kmz-Arab-IR +*kn = *kn-IN = kn-Knda = kn-Knda-IN +kn-Brai = kn-Brai-IN +kna-Latn = kna-Latn-NG +knb-Latn = knb-Latn-PH +kne-Latn = kne-Latn-PH +knf = knf-GW = *knf-Latn = knf-Latn-GW +knf-SN = knf-Latn-SN +knj = knj-GT = knj-Latn = knj-Latn-GT +knk = knk-SL = knk-Latn = knk-Latn-SL +knm = knm-BR = knm-Latn = knm-Latn-BR +knn-Knda = knn-Knda-IN +knn-Latn = knn-Latn-IN +kno = kno-SL = kno-Latn = kno-Latn-SL +knp = knp-CM = *knp-Latn = knp-Latn-CM +knr = knr-PG = knr-Latn = knr-Latn-PG +kns-Latn = kns-Latn-MY +kns-Thai = kns-Thai-TH +knt = knt-BR = knt-Latn = knt-Latn-BR +knv = knv-PG = knv-Latn = knv-Latn-PG +knw = knw-NA = knw-Latn = knw-Latn-NA +knx-Latn = knx-Latn-ID +kny = kny-CD = kny-Latn = kny-Latn-CD +knz-Latn = knz-Latn-BF +*ko = *ko-KR = ko-Kore = ko-Kore-KR +ko-Brai = ko-Brai-KR +*ko-KP = ko-Kore-KP +ko-Latn = ko-Latn-KR +koa = koa-PG = koa-Latn = koa-Latn-PG +koe = koe-SS = koe-Latn = koe-Latn-SS +kog = kog-CO = kog-Latn = kog-Latn-CO +koh = koh-CG = koh-Latn = koh-Latn-CG +koi = koi-RU = koi-Cyrl = koi-Cyrl-RU +koi-Latn = koi-Latn-RU +koi-Perm = koi-Perm-RU +*kok = knn = *kok-IN = knn-IN = kok-Deva = knn-Deva = kok-Deva-IN = knn-Deva-IN +kol = kol-PG = *kol-Latn = kol-Latn-PG +koo = koo-UG = koo-Latn = koo-Latn-UG +kop = kop-PG = kop-Latn = kop-Latn-PG +koq = koq-GA = koq-Latn = koq-Latn-GA +kos = kos-FM = kos-Latn = kos-Latn-FM +kot = kot-CM = kot-Latn = kot-Latn-CM +koy = koy-US = koy-Latn = koy-Latn-US +koz = koz-PG = koz-Latn = koz-Latn-PG +kpc = kpc-CO = kpc-Latn = kpc-Latn-CO +*kpe = xpe = kpe-LR = xpe-LR = kpe-Latn = *xpe-Latn = kpe-Latn-LR = xpe-Latn-LR +kpe-Kpel = xpe-Kpel = kpe-Kpel-LR = xpe-Kpel-LR +kpf = kpf-PG = *kpf-Latn = kpf-Latn-PG +kpg = kpg-FM = kpg-Latn = kpg-Latn-FM +kph = kph-GH = kph-Latn = kph-Latn-GH +kpj = kpj-BR = kpj-Latn = kpj-Latn-BR +kpm = kpm-VN = kpm-Latn = kpm-Latn-VN +kpn = kpn-BR = kpn-Latn = kpn-Latn-BR +kpo = kpo-TG = *kpo-Latn = kpo-Latn-TG +kpq-Latn = kpq-Latn-ID +kpr = kpr-PG = *kpr-Latn = kpr-Latn-PG +kps-Latn = kps-Latn-ID +kpw = kpw-PG = *kpw-Latn = kpw-Latn-PG +kpx = kpx-PG = *kpx-Latn = kpx-Latn-PG +kpy-Cyrl = kpy-Cyrl-RU +kpz = kpz-UG = kpz-Latn = kpz-Latn-UG +kqa = kqa-PG = kqa-Latn = kqa-Latn-PG +kqb = kqb-PG = *kqb-Latn = kqb-Latn-PG +kqc = kqc-PG = kqc-Latn = kqc-Latn-PG +kqd-Syrc = kqd-Syrc-IQ +kqe-Latn = kqe-Latn-PH +kqf = kqf-PG = *kqf-Latn = kqf-Latn-PG +kqi = kqi-PG = kqi-Latn = kqi-Latn-PG +kqj = kqj-PG = kqj-Latn = kqj-Latn-PG +kql = kql-PG = kql-Latn = kql-Latn-PG +kqn = kqn-ZM = kqn-Latn = kqn-Latn-ZM +kqo = kqo-LR = kqo-Latn = kqo-Latn-LR +kqp = kqp-TD = kqp-Latn = kqp-Latn-TD +kqq = kqq-BR = kqq-Latn = kqq-Latn-BR +kqr-Latn = kqr-Latn-MY +kqs = kqs-GN = *kqs-Latn = kqs-Latn-GN +kqu = kqu-ZA = kqu-Latn = kqu-Latn-ZA +kqw = kqw-PG = kqw-Latn = kqw-Latn-PG +kqx = kqx-CM = kqx-Latn = kqx-Latn-CM +kqy = kqy-ET = *kqy-Ethi = kqy-Ethi-ET +kqz = kqz-ZA = kqz-Latn = kqz-Latn-ZA +kr = kr-NG = kr-Latn = *knc-Latn = kr-Latn-NG = knc-Latn-NG +kr-Arab = *knc-Arab = kr-Arab-NG = knc-Arab-NG +kra-Deva = kra-Deva-NP +krc = krc-RU = krc-Cyrl = krc-Cyrl-RU +krd = krd-TL = krd-Latn = krd-Latn-TL +kre = kre-BR = kre-Latn = kre-Latn-BR +krf = krf-VU = krf-Latn = krf-Latn-VU +kri = kri-SL = *kri-Latn = kri-Latn-SL +krj = krj-PH = krj-Latn = krj-Latn-PH +krl = krl-RU = krl-Latn = krl-Latn-RU +krl-Cyrl = krl-Cyrl-RU +krn = krn-LR = krn-Latn = krn-Latn-LR +krr = krr-KH = krr-Khmr = krr-Khmr-KH +krs = krs-SS = *krs-Latn = krs-Latn-SS +krt-Latn = krt-Latn-NE +kru = kru-IN = kru-Deva = kru-Deva-IN +krv = krv-KH = krv-Khmr = krv-Khmr-KH +krw = krw-LR = krw-Latn = krw-Latn-LR +krx-Latn = krx-Latn-SN +*ks = *ks-IN = *ks-Arab = *ks-Arab-IN +ks-Deva = ks-Deva-IN +ks-Latn = ks-Latn-IN +ks-Shrd = ks-Shrd-IN +*ksb = *ksb-TZ = ksb-Latn = ksb-Latn-TZ +ksc-Latn = ksc-Latn-PH +ksd = ksd-PG = *ksd-Latn = ksd-Latn-PG +kse = kse-PG = kse-Latn = kse-Latn-PG +*ksf = *ksf-CM = ksf-Latn = ksf-Latn-CM +ksg = ksg-SB = ksg-Latn = ksg-Latn-SB +*ksh = *ksh-DE = ksh-Latn = ksh-Latn-DE +ksi = ksi-PG = ksi-Latn = ksi-Latn-PG +ksj = ksj-PG = ksj-Latn = ksj-Latn-PG +ksk = ksk-US = ksk-Latn = ksk-Latn-US +ksl = ksl-PG = ksl-Latn = ksl-Latn-PG +ksp = ksp-CF = ksp-Latn = ksp-Latn-CF +ksr = ksr-PG = *ksr-Latn = ksr-Latn-PG +kss = kss-LR = kss-Latn = kss-Latn-LR +kst-Latn = kst-Latn-BF +ksw = ksw-MM = ksw-Mymr = ksw-Mymr-MM +ksw-Latn = ksw-Latn-MM +ksz-Deva = ksz-Deva-IN +ktb = ktb-ET = *ktb-Ethi = ktb-Ethi-ET +ktb-Latn = ktb-Latn-ET +ktd = ktd-AU = ktd-Latn = ktd-Latn-AU +ktj-Latn = ktj-Latn-CI +ktm = ktm-PG = *ktm-Latn = ktm-Latn-PG +ktn = ktn-BR = ktn-Latn = ktn-Latn-BR +kto = kto-PG = *kto-Latn = kto-Latn-PG +ktp-Plrd = ktp-Plrd-CN +ktu = ktu-CD = ktu-Latn = ktu-Latn-CD +ktv = ktv-VN = ktv-Latn = ktv-Latn-VN +ktx = ktx-BR = ktx-Latn = ktx-Latn-BR +ktz = ktz-NA = ktz-Latn = ktz-Latn-NA +*ku = ku-TR = ku-Latn = kmr-Latn = ku-Latn-TR = kmr-Latn-TR +*ku-Arab = *kmr-Arab = ku-Arab-IQ = kmr-Arab-TR +ku-Cyrl = kmr-Cyrl = ku-Cyrl-IQ = kmr-Cyrl-AZ +ku-LB = ku-Arab-LB +kub = kub-NG = *kub-Latn = kub-Latn-NG +kud = kud-PG = *kud-Latn = kud-Latn-PG +kue = kue-PG = *kue-Latn = kue-Latn-PG +kuf = kuf-LA = kuf-Laoo = kuf-Laoo-LA +kuh-Latn = kuh-Latn-NG +kui = kui-BR = kui-Latn = kui-Latn-BR +kuj = kuj-TZ = *kuj-Latn = kuj-Latn-TZ +kum = kum-RU = kum-Cyrl = kum-Cyrl-RU +kum-Arab = kum-Arab-RU +kum-Latn = kum-Latn-RU +kun = kun-ER = *kun-Latn = kun-Latn-ER +kuo = kuo-PG = kuo-Latn = kuo-Latn-PG +kup = kup-PG = *kup-Latn = kup-Latn-PG +kuq = kuq-BR = kuq-Latn = kuq-Latn-BR +kus = kus-GH = *kus-Latn = kus-Latn-GH +kut = kut-CA = kut-Latn = kut-Latn-CA +kuu = kuu-US = kuu-Latn = kuu-Latn-US +kux = kux-AU = kux-Latn = kux-Latn-AU +kuy = kuy-AU = kuy-Latn = kuy-Latn-AU +kuz = kuz-CL = kuz-Latn = kuz-Latn-CL +kv = kpv = kv-RU = kpv-RU = kv-Cyrl = kpv-Cyrl = kv-Cyrl-RU = kpv-Cyrl-RU +kv-Latn = kv-Latn-RU +kv-Perm = kv-Perm-RU +kvb = kvb-ID = kvb-Latn = kvb-Latn-ID +kvc = kvc-PG = kvc-Latn = kvc-Latn-PG +kvg = kvg-PG = *kvg-Latn = kvg-Latn-PG +kvj = kvj-CM = kvj-Latn = kvj-Latn-CM +kvl = kvl-MM = kvl-Latn = kvl-Latn-MM +kvn = kvn-CO = kvn-Latn = kvn-Latn-CO +kvo-Latn = kvo-Latn-ID +kvq-Latn = kvq-Latn-MM +kvq-Mymr = kvq-Mymr-MM +kvr = kvr-ID = kvr-Latn = kvr-Latn-ID +kvr-Rjng = kvr-Rjng-ID +kvv-Latn = kvv-Latn-ID +kvx = kvx-PK = *kvx-Arab = kvx-Arab-PK +*kw = *kw-GB = kw-Latn = kw-Latn-GB +kwa = kwa-BR = kwa-Latn = kwa-Latn-BR +kwd = kwd-SB = kwd-Latn = kwd-Latn-SB +kwe-Latn = kwe-Latn-ID +kwf = kwf-SB = kwf-Latn = kwf-Latn-SB +kwg = kwg-TD = kwg-Latn = kwg-Latn-TD +kwh-Latn = kwh-Latn-ID +kwi = kwi-CO = kwi-Latn = kwi-Latn-CO +kwj = kwj-PG = *kwj-Latn = kwj-Latn-PG +kwk = kwk-CA = kwk-Latn = kwk-Latn-CA +kwm = kwm-NA = kwm-Latn = kwm-Latn-NA +kwn = kwn-NA = kwn-Latn = kwn-Latn-NA +kwo = kwo-PG = *kwo-Latn = kwo-Latn-PG +kws = kws-CD = kws-Latn = kws-Latn-CD +kwv = kwv-TD = kwv-Latn = kwv-Latn-TD +kww = kww-SR = kww-Latn = kww-Latn-SR +kwy = kwy-CD = kwy-Latn = kwy-Latn-CD +kwz = kwz-AO = kwz-Latn = kwz-Latn-AO +kxa = kxa-PG = kxa-Latn = kxa-Latn-PG +kxc = kxc-ET = *kxc-Ethi = kxc-Ethi-ET +kxc-Latn = kxc-Latn-ET +kxd-Arab = kxd-Arab-BN +kxd-Latn = kxd-Latn-BN +kxf-Latn = kxf-Latn-MM +kxf-Mymr = kxf-Mymr-MM +kxi-Latn = kxi-Latn-MY +kxl-Deva = kxl-Deva-NP +kxm = kxm-TH = kxm-Thai = kxm-Thai-TH +kxm-Khmr = kxm-Khmr-TH +kxo = kxo-BR = kxo-Latn = kxo-Latn-BR +kxp = kxp-PK = *kxp-Arab = kxp-Arab-PK +kxp-Gujr = kxp-Gujr-IN +kxp-x-thr = kxp-PK-x-thr = kxp-Arab-x-thr = kxp-Arab-PK-x-thr +kxr = kxr-PG = kxr-Latn = kxr-Latn-PG +kxt = kxt-PG = kxt-Latn = kxt-Latn-PG +kxu-Orya = kxu-Orya-IN +kxv-Orya = kxv-Orya-IN +kxw = kxw-PG = *kxw-Latn = kxw-Latn-PG +kxx = kxx-CG = kxx-Latn = kxx-Latn-CG +kxz = kxz-PG = *kxz-Latn = kxz-Latn-PG +*ky = *ky-KG = *ky-Cyrl = *ky-Cyrl-KG +ky-CN = *ky-Arab = ky-Arab-CN +ky-TR = ky-Latn = ky-Latn-TR +kya = kya-TZ = kya-Latn = kya-Latn-TZ +kyb-Latn = kyb-Latn-PH +kyc = kyc-PG = kyc-Latn = kyc-Latn-PG +kye = kye-GH = *kye-Latn = kye-Latn-GH +kyf-Latn = kyf-Latn-CI +kyg = kyg-PG = kyg-Latn = kyg-Latn-PG +kyh = kyh-US = kyh-Latn = kyh-Latn-US +kyj-Latn = kyj-Latn-PH +kyl = kyl-US = kyl-Latn = kyl-Latn-US +kyq = kyq-TD = kyq-Latn = kyq-Latn-TD +kyr = kyr-BR = kyr-Latn = kyr-Latn-BR +kys-Latn = kys-Latn-MY +kyu = kyu-MM = kyu-Kali = kyu-Kali-MM +kyu-Latn = kyu-Latn-MM +kyu-Mymr = kyu-Mymr-MM +kyw-Beng = kyw-Beng-IN +kyw-Deva = kyw-Deva-IN +kyw-Orya = kyw-Orya-IN +kyx = kyx-PG = *kyx-Latn = kyx-Latn-PG +kyy = kyy-PG = kyy-Latn = kyy-Latn-PG +kyz = kyz-BR = kyz-Latn = kyz-Latn-BR +kzc-Latn = kzc-Latn-CI +kze = kze-PG = kze-Latn = kze-Latn-PG +kzf-Latn = kzf-Latn-ID +kzi-Latn = kzi-Latn-MY +kzo = kzo-GA = kzo-Latn = kzo-Latn-GA +kzr = kzr-CM = *kzr-Latn = kzr-Latn-CM +kzw = kzw-BR = kzw-Latn = kzw-Latn-BR +la = la-VA = la-Latn = la-Latn-VA +laa-Latn = laa-Latn-PH +lab = lab-GR = lab-Lina = lab-Lina-GR +lac = lac-MX = lac-Latn = lac-Latn-MX +lad = lad-IL = lad-Hebr = lad-Hebr-IL +lad-Cyrl = lad-Cyrl-TR +lad-Latn = lad-Latn-TR +lae-Deva = lae-Deva-IN +lae-Tibt = lae-Tibt-IN +*lag = *lag-TZ = lag-Latn = lag-Latn-TZ +lah = pnb = lah-PK = pnb-PK = lah-Arab = pnb-Arab = lah-Arab-PK = pnb-Arab-PK +lah-Khoj = pnb-Khoj = lah-Khoj-PK = pnb-Khoj-PK +lah-Latn = pnb-Latn = lah-Latn-PK = pnb-Latn-PK +lai-Latn = lai-Latn-MW +laj = laj-UG = laj-Latn = laj-Latn-UG +lam = lam-ZM = lam-Latn = lam-Latn-ZM +lap = lap-TD = lap-Latn = lap-Latn-TD +laq = laq-VN = laq-Latn = laq-Latn-VN +lar = lar-GH = lar-Latn = lar-Latn-GH +las = las-TG = *las-Latn = las-Latn-TG +lax-Beng = lax-Beng-IN +lax-Latn = lax-Latn-IN +*lb = *lb-LU = lb-Latn = lb-Latn-LU +lbb = lbb-PG = lbb-Latn = lbb-Latn-PG +lbc-Lisu = lbc-Lisu-CN +lbe = lbe-RU = lbe-Cyrl = lbe-Cyrl-RU +lbf-Deva = lbf-Deva-IN +lbf-Tibt = lbf-Tibt-CN +lbj = lbj-IN = lbj-Tibt = lbj-Tibt-IN +lbn-Laoo = lbn-Laoo-LA +lbn-Latn = lbn-Latn-LA +lbq = lbq-PG = lbq-Latn = lbq-Latn-PG +lbr-Deva = lbr-Deva-NP +lbu = lbu-PG = lbu-Latn = lbu-Latn-PG +lbv = lbv-PG = lbv-Latn = lbv-Latn-PG +lbw = lbw-ID = lbw-Latn = lbw-Latn-ID +lbz = lbz-AU = lbz-Latn = lbz-Latn-AU +lch = lch-AO = lch-Latn = lch-Latn-AO +lcm = lcm-PG = *lcm-Latn = lcm-Latn-PG +lcp = lcp-CN = lcp-Thai = lcp-Thai-CN +ldb = ldb-NG = *ldb-Latn = ldb-Latn-NG +ldi = ldi-CG = ldi-Latn = ldi-Latn-CG +ldm-Latn = ldm-Latn-GN +lea = lea-CD = lea-Latn = lea-Latn-CD +leb = leb-ZM = leb-Latn = leb-Latn-ZM +lec = lec-BO = lec-Latn = lec-Latn-BO +led = led-CD = *led-Latn = led-Latn-CD +lee = lee-BF = *lee-Latn = lee-Latn-BF +lef = lef-GH = lef-Latn = lef-Latn-GH +leh = leh-ZM = leh-Latn = leh-Latn-ZM +lei = lei-PG = lei-Latn = lei-Latn-PG +lek = lek-PG = lek-Latn = lek-Latn-PG +lem = lem-CM = *lem-Latn = lem-Latn-CM +len = len-HN = len-Latn = len-Latn-HN +lep = lep-IN = *lep-Lepc = lep-Lepc-IN +lep-Tibt = lep-Tibt-IN +leq = leq-PG = *leq-Latn = leq-Latn-PG +ler = ler-PG = ler-Latn = ler-Latn-PG +les = les-CD = les-Latn = les-Latn-CD +let = let-PG = let-Latn = let-Latn-PG +leu = leu-PG = *leu-Latn = leu-Latn-PG +lew-Latn = lew-Latn-ID +lex-Latn = lex-Latn-ID +lez = lez-RU = lez-Cyrl = lez-Cyrl-RU +lfn-Latn = lfn-Latn-?? +*lg = *lg-UG = lg-Latn = lg-Latn-UG +lga = lga-SB = lga-Latn = lga-Latn-SB +lgb = lgb-SB = lgb-Latn = lgb-Latn-SB +lgg = lgg-UG = *lgg-Latn = lgg-Latn-UG +lgk = lgk-VU = lgk-Latn = lgk-Latn-VU +lgl = lgl-SB = lgl-Latn = lgl-Latn-SB +lgm = lgm-CD = lgm-Latn = lgm-Latn-CD +lgn = lgn-ET = lgn-Latn = lgn-Latn-ET +lgq = lgq-GH = lgq-Latn = lgq-Latn-GH +lgr = lgr-SB = lgr-Latn = lgr-Latn-SB +lgt = lgt-PG = lgt-Latn = lgt-Latn-PG +lgu = lgu-SB = lgu-Latn = lgu-Latn-SB +lhi-Latn = lhi-Latn-CN +lhm-Deva = lhm-Deva-NP +lht = lht-VU = lht-Latn = lht-Latn-VU +lhu = lhu-CN = lhu-Latn = lhu-Latn-CN +li = li-NL = li-Latn = li-Latn-NL +lia = lia-SL = *lia-Latn = lia-Latn-SL +lib = lib-PG = lib-Latn = lib-Latn-PG +lic-Latn = lic-Latn-CN +lid = lid-PG = *lid-Latn = lid-Latn-PG +lif = lif-NP = lif-Deva = lif-Deva-NP +*lif-Limb = lif-Limb-IN +lig = lig-GH = lig-Latn = lig-Latn-GH +lih = lih-PG = *lih-Latn = lih-Latn-PG +lij = lij-IT = lij-Latn = lij-Latn-IT +lik = lik-CD = lik-Latn = lik-Latn-CD +lil = lil-CA = lil-Latn = lil-Latn-CA +lip = lip-GH = lip-Latn = lip-Latn-GH +liq-Latn = liq-Latn-ET +lis = lis-CN = *lis-Lisu = lis-Lisu-CN +lis-Latn = lis-Latn-CN +liu = liu-SD = liu-Latn = liu-Latn-SD +liv-Latn = liv-Latn-LV +liy = liy-CF = liy-Latn = liy-Latn-CF +lje-Latn = lje-Latn-ID +ljp = ljp-ID = ljp-Latn = ljp-Latn-ID +ljp-Rjng = ljp-Rjng-ID +ljw = ljw-AU = ljw-Latn = ljw-Latn-AU +lka = lka-TL = lka-Latn = lka-Latn-TL +lkb = lkb-KE = lkb-Latn = lkb-Latn-KE +lkd = lkd-BR = lkd-Latn = lkd-Latn-BR +lki = lki-IR = lki-Arab = lki-Arab-IR +lkl = lkl-PG = lkl-Latn = lkl-Latn-PG +lkn = lkn-VU = lkn-Latn = lkn-Latn-VU +lko = lko-KE = lko-Latn = lko-Latn-KE +lkr = lkr-SS = lkr-Latn = lkr-Latn-SS +lks = lks-KE = lks-Latn = lks-Latn-KE +*lkt = *lkt-US = lkt-Latn = lkt-Latn-US +lla-Latn = lla-Latn-NG +llb-Latn = llb-Latn-MZ +llc-Latn = llc-Latn-GN +lld-Latn = lld-Latn-IT +lle = lle-PG = *lle-Latn = lle-Latn-PG +llg-Latn = llg-Latn-ID +lli = lli-CG = lli-Latn = lli-Latn-CG +lll = lll-PG = lll-Latn = lll-Latn-PG +lln = lln-TD = *lln-Latn = lln-Latn-TD +llp = llp-VU = llp-Latn = llp-Latn-VU +llu = llu-SB = llu-Latn = llu-Latn-SB +llx = llx-FJ = llx-Latn = llx-Latn-FJ +lmb = lmb-VU = lmb-Latn = lmb-Latn-VU +lmd = lmd-SD = lmd-Latn = lmd-Latn-SD +lme = lme-TD = lme-Latn = lme-Latn-TD +lmg = lmg-PG = lmg-Latn = lmg-Latn-PG +lmk-Latn = lmk-Latn-IN +lmk-Mymr = lmk-Mymr-IN +lml = lml-VU = lml-Latn = lml-Latn-VU +lmn = lmn-IN = lmn-Telu = lmn-Telu-IN +lmn-Deva = lmn-Deva-IN +lmn-Knda = lmn-Knda-IN +lmo = lmo-IT = lmo-Latn = lmo-Latn-IT +lmp = lmp-CM = *lmp-Latn = lmp-Latn-CM +lmu = lmu-VU = lmu-Latn = lmu-Latn-VU +lmv = lmv-FJ = lmv-Latn = lmv-Latn-FJ +lmw = lmw-US = lmw-Latn = lmw-Latn-US +*ln = *ln-CD = ln-Latn = ln-Latn-CD +*ln-CF = ln-Latn-CF +*ln-CG = ln-Latn-CG +lnb = lnb-NA = lnb-Latn = lnb-Latn-NA +lnd-Latn = lnd-Latn-ID +lni = lni-PG = lni-Latn = lni-Latn-PG +lnl = lnl-CF = lnl-Latn = lnl-Latn-CF +lnm = lnm-PG = lnm-Latn = lnm-Latn-PG +lnn = lnn-VU = lnn-Latn = lnn-Latn-VU +lns = lns-CM = *lns-Latn = lns-Latn-CM +lnu = lnu-NG = *lnu-Latn = lnu-Latn-NG +*lo = *lo-LA = lo-Laoo = lo-Laoo-LA +loa-Latn = loa-Latn-ID +lob-Latn = lob-Latn-BF +loc-Latn = loc-Latn-PH +loe-Latn = loe-Latn-ID +log = log-CD = log-Latn = log-Latn-CD +loh = loh-SS = loh-Latn = loh-Latn-SS +loj = loj-PG = *loj-Latn = loj-Latn-PG +lok = lok-SL = *lok-Latn = lok-Latn-SL +lol = lol-CD = lol-Latn = lol-Latn-CD +lom = lom-LR = lom-Latn = lom-Latn-LR +lom-Loma = lom-Loma-LR +lon-Latn = lon-Latn-MW +loq = loq-CD = loq-Latn = loq-Latn-CD +lor = lor-CI = *lor-Latn = lor-Latn-CI +los = los-PG = los-Latn = los-Latn-PG +lot = lot-SS = lot-Latn = lot-Latn-SS +lou = lou-US = lou-Latn = lou-Latn-US +*loy-Deva = loy-Deva-NP +loy-Tibt = loy-Tibt-NP +loz = loz-ZM = loz-Latn = loz-Latn-ZM +lpa = lpa-VU = lpa-Latn = lpa-Latn-VU +lpo = lpo-CN = *lpo-Plrd = lpo-Plrd-CN +lpo-Lisu = lpo-Lisu-CN +lpx = lpx-SS = lpx-Latn = lpx-Latn-SS +lra-Latn = lra-Latn-MY +*lrc = *lrc-IR = lrc-Arab = lrc-Arab-IR +lri = lri-KE = lri-Latn = lri-Latn-KE +lrl-Arab = lrl-Arab-IR +lrm = lrm-KE = lrm-Latn = lrm-Latn-KE +lro = lro-SD = lro-Latn = lro-Latn-SD +lrt-Latn = lrt-Latn-ID +lrv = lrv-VU = lrv-Latn = lrv-Latn-VU +lrz = lrz-VU = lrz-Latn = lrz-Latn-VU +lsa-Arab = lsa-Arab-IR +lsd-Hebr = lsd-Hebr-IL +lse = lse-CD = lse-Latn = lse-Latn-CD +lsi = lsi-MM = lsi-Latn = lsi-Latn-MM +lsm = lsm-UG = lsm-Latn = lsm-Latn-UG +lsr = lsr-PG = lsr-Latn = lsr-Latn-PG +*lt = *lt-LT = lt-Latn = lt-Latn-LT +lt-Latf = lt-Latf-LT +ltg = ltg-LV = ltg-Latn = ltg-Latn-LV +lth = lth-UG = lth-Latn = lth-Latn-UG +ltn = ltn-BR = ltn-Latn = ltn-Latn-BR +lto = lto-KE = lto-Latn = lto-Latn-KE +lts = lts-KE = lts-Latn = lts-Latn-KE +*lu = *lu-CD = lu-Latn = lu-Latn-CD +lua = lua-CD = lua-Latn = lua-Latn-CD +luc = luc-UG = luc-Latn = luc-Latn-UG +lud-Latn = lud-Latn-RU +lue = lue-ZM = lue-Latn = lue-Latn-ZM +luf = luf-PG = luf-Latn = luf-Latn-PG +lui = lui-US = lui-Latn = lui-Latn-US +luj = luj-CD = luj-Latn = luj-Latn-CD +lul = lul-SS = lul-Latn = lul-Latn-SS +lum = lum-AO = lum-Latn = lum-Latn-AO +lun = lun-ZM = lun-Latn = lun-Latn-ZM +*luo = *luo-KE = luo-Latn = luo-Latn-KE +lup = lup-GA = lup-Latn = lup-Latn-GA +lus-Beng = lus-Beng-IN +lus-Brai = lus-Brai-IN +lus-Latn = lus-Latn-IN +lut = lut-US = lut-Latn = lut-Latn-US +*luy = bxk = *luy-KE = bxk-KE = luy-Latn = bxk-Latn = luy-Latn-KE = bxk-Latn-KE +luz = luz-IR = luz-Arab = luz-Arab-IR +*lv = lvs = *lv-LV = lvs-LV = lv-Latn = lvs-Latn = lv-Latn-LV = lvs-Latn-LV +lv-Brai = lv-Brai-LV +lva = lva-TL = lva-Latn = lva-Latn-TL +lvk = lvk-SB = lvk-Latn = lvk-Latn-SB +lwg = lwg-KE = lwg-Latn = lwg-Latn-KE +lwl = lwl-TH = lwl-Thai = lwl-Thai-TH +lwm-Thai = lwm-Thai-CN +lwo = lwo-SS = lwo-Latn = lwo-Latn-SS +lww = lww-VU = lww-Latn = lww-Latn-VU +lyn = lyn-ZM = lyn-Latn = lyn-Latn-ZM +lzh = lzh-CN = lzh-Hans = lzh-Hans-CN +lzh-Hant = lzh-Hant-CN +lzl = lzl-VU = lzl-Latn = lzl-Latn-VU +lzn = lzn-MM = lzn-Latn = lzn-Latn-MM +lzz = lzz-TR = lzz-Latn = lzz-Latn-TR +lzz-Geor = lzz-Geor-TR +maa = maa-MX = maa-Latn = maa-Latn-MX +mab = mab-MX = mab-Latn = mab-Latn-MX +mad = mad-ID = mad-Latn = mad-Latn-ID +maf = maf-CM = maf-Latn = maf-Latn-CM +mag = mag-IN = mag-Deva = mag-Deva-IN +mai = mai-IN = mai-Deva = mai-Deva-IN +mai-Kthi = mai-Kthi-IN +mai-Newa = mai-Newa-IN +mai-Tirh = mai-Tirh-IN +maj = maj-MX = maj-Latn = maj-Latn-MX +mak = mak-ID = mak-Latn = mak-Latn-ID +mak-Bugi = mak-Bugi-ID +mam = mam-GT = mam-Latn = mam-Latn-GT +man = man-GM = man-Latn = *emk-Latn = man-Latn-GM = emk-Latn-GN +man-Arab = emk-Arab = man-Arab-GN = emk-Arab-GN +man-GN = man-Nkoo = emk-Nkoo = man-Nkoo-GN = emk-Nkoo-GN +maq = maq-MX = maq-Latn = maq-Latn-MX +*mas = *mas-KE = mas-Latn = mas-Latn-KE +*mas-TZ = mas-Latn-TZ +mat = mat-MX = mat-Latn = mat-Latn-MX +mau = mau-MX = mau-Latn = mau-Latn-MX +mav = mav-BR = mav-Latn = mav-Latn-BR +maw = maw-GH = *maw-Latn = maw-Latn-GH +max-Latn = max-Latn-ID +maz = maz-MX = maz-Latn = maz-Latn-MX +mba-Latn = mba-Latn-PH +mbb-Latn = mbb-Latn-PH +mbc = mbc-BR = mbc-Latn = mbc-Latn-BR +mbd-Latn = mbd-Latn-PH +mbf = mbf-SG = mbf-Latn = mbf-Latn-SG +mbh = mbh-PG = *mbh-Latn = mbh-Latn-PG +mbi-Latn = mbi-Latn-PH +mbj = mbj-BR = mbj-Latn = mbj-Latn-BR +mbk = mbk-PG = mbk-Latn = mbk-Latn-PG +mbl = mbl-BR = mbl-Latn = mbl-Latn-BR +mbn = mbn-CO = mbn-Latn = mbn-Latn-CO +mbo = mbo-CM = *mbo-Latn = mbo-Latn-CM +mbp = mbp-CO = mbp-Latn = mbp-Latn-CO +mbq = mbq-PG = *mbq-Latn = mbq-Latn-PG +mbr = mbr-CO = mbr-Latn = mbr-Latn-CO +mbs-Latn = mbs-Latn-PH +mbt-Latn = mbt-Latn-PH +mbu = mbu-NG = *mbu-Latn = mbu-Latn-NG +mbw = mbw-PG = *mbw-Latn = mbw-Latn-PG +mbx = mbx-PG = mbx-Latn = mbx-Latn-PG +mbz = mbz-MX = mbz-Latn = mbz-Latn-MX +mca = mca-PY = mca-Latn = mca-Latn-PY +mcb = mcb-PE = mcb-Latn = mcb-Latn-PE +mcc = mcc-PG = mcc-Latn = mcc-Latn-PG +mcd = mcd-PE = mcd-Latn = mcd-Latn-PE +mce = mce-MX = mce-Latn = mce-Latn-MX +mcf = mcf-PE = mcf-Latn = mcf-Latn-PE +mcg = mcg-VE = mcg-Latn = mcg-Latn-VE +mch = mch-VE = mch-Latn = mch-Latn-VE +mci = mci-PG = *mci-Latn = mci-Latn-PG +mck = mck-AO = mck-Latn = mck-Latn-AO +mcl = mcl-CO = mcl-Latn = mcl-Latn-CO +mcm-Latn = mcm-Latn-MY +mcn-Latn = mcn-Latn-TD +mco = mco-MX = mco-Latn = mco-Latn-MX +mcp = mcp-CM = *mcp-Latn = mcp-Latn-CM +mcq = mcq-PG = *mcq-Latn = mcq-Latn-PG +mcr = mcr-PG = *mcr-Latn = mcr-Latn-PG +mcs-Latn = mcs-Latn-CM +mct-Latn = mct-Latn-CM +mcu = mcu-CM = *mcu-Latn = mcu-Latn-CM +mcv = mcv-PG = mcv-Latn = mcv-Latn-PG +mcw-Latn = mcw-Latn-TD +mcx = mcx-CF = mcx-Latn = mcx-Latn-CF +mcy = mcy-PG = mcy-Latn = mcy-Latn-PG +mcz = mcz-PG = mcz-Latn = mcz-Latn-PG +mda = mda-NG = *mda-Latn = mda-Latn-NG +mdb = mdb-PG = mdb-Latn = mdb-Latn-PG +mdc = mdc-PG = mdc-Latn = mdc-Latn-PG +mdd = mdd-CM = mdd-Latn = mdd-Latn-CM +mde = mde-TD = *mde-Arab = mde-Arab-TD +mde-Latn = mde-Latn-TD +mdf = mdf-RU = mdf-Cyrl = mdf-Cyrl-RU +mdh = mdh-PH = mdh-Latn = mdh-Latn-PH +mdi = mdi-CD = mdi-Latn = mdi-Latn-CD +mdj = mdj-CD = *mdj-Latn = mdj-Latn-CD +mdm = mdm-CD = mdm-Latn = mdm-Latn-CD +mdn = mdn-CF = mdn-Latn = mdn-Latn-CF +mdp = mdp-CD = mdp-Latn = mdp-Latn-CD +mdr = mdr-ID = mdr-Latn = mdr-Latn-ID +mdr-Bugi = mdr-Bugi-ID +mds = mds-PG = mds-Latn = mds-Latn-PG +mdu = mdu-CG = mdu-Latn = mdu-Latn-CG +mdv = mdv-MX = mdv-Latn = mdv-Latn-MX +mdw = mdw-CG = mdw-Latn = mdw-Latn-CG +mdx = mdx-ET = *mdx-Ethi = mdx-Ethi-ET +mdx-Latn = mdx-Latn-ET +mdy-Ethi = mdy-Ethi-ET +mdz = mdz-BR = mdz-Latn = mdz-Latn-BR +meb = meb-PG = meb-Latn = meb-Latn-PG +mec = mec-AU = mec-Latn = mec-Latn-AU +med = med-PG = *med-Latn = med-Latn-PG +mee = mee-PG = *mee-Latn = mee-Latn-PG +meh = meh-MX = meh-Latn = meh-Latn-MX +mej-Latn = mej-Latn-ID +mek = mek-PG = *mek-Latn = mek-Latn-PG +*men = men-SL = men-Latn = men-Latn-SL +men-Mend = men-Mend-SL +meo-Latn = meo-Latn-MY +mep = mep-AU = mep-Latn = mep-Latn-AU +meq-Latn = meq-Latn-CM +*mer = *mer-KE = mer-Latn = mer-Latn-KE +met = met-PG = *met-Latn = met-Latn-PG +meu = meu-PG = *meu-Latn = meu-Latn-PG +mev = mev-LR = mev-Latn = mev-Latn-LR +mey-Arab = mey-Arab-MR +mey-Latn = mey-Latn-MR +mez = mez-US = mez-Latn = mez-Latn-US +mfa = mfa-TH = mfa-Arab = mfa-Arab-TH +mfa-Thai = mfa-Thai-TH +*mfe = *mfe-MU = mfe-Latn = mfe-Latn-MU +mfg-Arab = mfg-Arab-GN +mfh-Latn = mfh-Latn-CM +mfi = mfi-CM = mfi-Arab = mfi-Arab-CM +mfi-Latn = mfi-Latn-CM +mfk-Latn = mfk-Latn-CM +mfm-Latn = mfm-Latn-NG +mfn = mfn-NG = *mfn-Latn = mfn-Latn-NG +mfo = mfo-NG = *mfo-Latn = mfo-Latn-NG +mfq = mfq-TG = *mfq-Latn = mfq-Latn-TG +mfr = mfr-AU = mfr-Latn = mfr-Latn-AU +mft = mft-PG = mft-Latn = mft-Latn-PG +mfu = mfu-AO = mfu-Latn = mfu-Latn-AO +mfv-Latn = mfv-Latn-GW +mfy = mfy-MX = mfy-Latn = mfy-Latn-MX +mfz = mfz-SS = mfz-Latn = mfz-Latn-SS +*mg = plt = *mg-MG = plt-MG = mg-Latn = plt-Latn = mg-Latn-MG = plt-Latn-MG +mg-Brai = plt-Brai = mg-Brai-MG = plt-Brai-MG +mga = mga-IE = mga-Latg = mga-Latg-IE +mgc = mgc-SS = mgc-Latn = mgc-Latn-SS +mgd = mgd-SS = mgd-Latn = mgd-Latn-SS +mge-Latn = mge-Latn-TD +mgg-Latn = mgg-Latn-CM +*mgh = *mgh-MZ = mgh-Latn = mgh-Latn-MZ +mgi-Latn = mgi-Latn-NG +mgl = mgl-PG = *mgl-Latn = mgl-Latn-PG +mgm = mgm-TL = mgm-Latn = mgm-Latn-TL +*mgo = *mgo-CM = mgo-Latn = mgo-Latn-CM +mgp = mgp-NP = mgp-Deva = mgp-Deva-NP +mgp-Qabl = mgp-Qabl-NP +mgq = mgq-TZ = mgq-Latn = mgq-Latn-TZ +mgr = mgr-ZM = mgr-Latn = mgr-Latn-ZM +mgs = mgs-TZ = mgs-Latn = mgs-Latn-TZ +mgt = mgt-PG = mgt-Latn = mgt-Latn-PG +mgu = mgu-PG = mgu-Latn = mgu-Latn-PG +mgy = mgy-TZ = mgy-Latn = mgy-Latn-TZ +mgz = mgz-TZ = mgz-Latn = mgz-Latn-TZ +mh = mh-MH = mh-Latn = mh-Latn-MH +mhb = mhb-GA = mhb-Latn = mhb-Latn-GA +mhc = mhc-MX = mhc-Latn = mhc-Latn-MX +mhf = mhf-PG = mhf-Latn = mhf-Latn-PG +mhg = mhg-AU = mhg-Latn = mhg-Latn-AU +mhi = mhi-UG = *mhi-Latn = mhi-Latn-UG +mhk-Latn = mhk-Latn-CM +mhl = mhl-PG = *mhl-Latn = mhl-Latn-PG +mhm-Latn = mhm-Latn-MZ +mho = mho-ZM = mho-Latn = mho-Latn-ZM +mhq = mhq-US = mhq-Latn = mhq-Latn-US +mhs-Latn = mhs-Latn-ID +mht = mht-VE = mht-Latn = mht-Latn-VE +mhu = mhu-IN = mhu-Latn = mhu-Latn-IN +mhw = mhw-BW = mhw-Latn = mhw-Latn-BW +mhx = mhx-MM = mhx-Latn = mhx-Latn-MM +mhy-Latn = mhy-Latn-ID +*mi = mi-NZ = mi-Latn = mi-Latn-NZ +mia = mia-US = mia-Latn = mia-Latn-US +mib = mib-MX = mib-Latn = mib-Latn-MX +mic = mic-CA = mic-Latn = mic-Latn-CA +mic-Qabg = mic-Qabg-CA +mid-Mand = mid-Mand-IQ +mie = mie-MX = mie-Latn = mie-Latn-MX +mif = mif-CM = *mif-Latn = mif-Latn-CM +mig = mig-MX = mig-Latn = mig-Latn-MX +mih = mih-MX = mih-Latn = mih-Latn-MX +mii = mii-MX = mii-Latn = mii-Latn-MX +mik = mik-US = mik-Latn = mik-Latn-US +mil = mil-MX = mil-Latn = mil-Latn-MX +mim = mim-MX = mim-Latn = mim-Latn-MX +min = min-ID = min-Latn = min-Latn-ID +mio = mio-MX = mio-Latn = mio-Latn-MX +mip = mip-MX = mip-Latn = mip-Latn-MX +miq = miq-NI = miq-Latn = miq-Latn-NI +mir = mir-MX = mir-Latn = mir-Latn-MX +mis = mis-IQ = mis-Hatr = mis-Hatr-IQ +mit = mit-MX = mit-Latn = mit-Latn-MX +miu = miu-MX = miu-Latn = miu-Latn-MX +miw = miw-PG = *miw-Latn = miw-Latn-PG +mix = mix-MX = mix-Latn = mix-Latn-MX +miy = miy-MX = miy-Latn = miy-Latn-MX +miz = miz-MX = miz-Latn = miz-Latn-MX +mjb = mjb-TL = mjb-Latn = mjb-Latn-TL +mjc = mjc-MX = mjc-Latn = mjc-Latn-MX +mjd = mjd-US = mjd-Latn = mjd-Latn-US +mjg-Latn = mjg-Latn-CN +mjh = mjh-TZ = mjh-Latn = mjh-Latn-TZ +mji-Latn = mji-Latn-CN +mjj = mjj-PG = mjj-Latn = mjj-Latn-PG +mjk = mjk-PG = mjk-Latn = mjk-Latn-PG +mjl-Deva = mjl-Deva-IN +mjl-Takr = mjl-Takr-IN +mjm = mjm-PG = mjm-Latn = mjm-Latn-PG +mjn = mjn-PG = mjn-Latn = mjn-Latn-PG +mjt-Beng = mjt-Beng-BD +mjt-Deva = mjt-Deva-IN +mju-Telu = mju-Telu-IN +mjv-Mlym = mjv-Mlym-IN +mjw-Latn = mjw-Latn-IN +mjx-Latn = mjx-Latn-BD +mjz-Deva = mjz-Deva-NP +*mk = *mk-MK = mk-Cyrl = mk-Cyrl-MK +mk-Brai = mk-Brai-MK +mkb-Deva = mkb-Deva-IN +mkc = mkc-PG = mkc-Latn = mkc-Latn-PG +mke-Deva = mke-Deva-IN +mkf-Latn = mkf-Latn-NG +mki = mki-PK = *mki-Arab = mki-Arab-PK +mkj = mkj-FM = mkj-Latn = mkj-Latn-FM +mkl = mkl-BJ = mkl-Latn = mkl-Latn-BJ +mkm = mkm-TH = mkm-Thai = mkm-Thai-TH +mkn-Latn = mkn-Latn-ID +mkp = mkp-PG = *mkp-Latn = mkp-Latn-PG +mkr = mkr-PG = mkr-Latn = mkr-Latn-PG +mks = mks-MX = mks-Latn = mks-Latn-MX +mkt = mkt-NC = mkt-Latn = mkt-Latn-NC +mkv = mkv-VU = mkv-Latn = mkv-Latn-VU +mkw = mkw-CG = *mkw-Latn = mkw-Latn-CG +mkz-Latn = mkz-Latn-TL +*ml = *ml-IN = ml-Mlym = ml-Mlym-IN +*ml-Arab = ml-Arab-IN +ml-Brai = ml-Brai-IN +mla = mla-VU = mla-Latn = mla-Latn-VU +mle = mle-PG = *mle-Latn = mle-Latn-PG +mlf = mlf-LA = mlf-Thai = mlf-Thai-LA +mlf-Latn = mlf-Latn-LA +mlh = mlh-PG = mlh-Latn = mlh-Latn-PG +mlk = mlk-KE = mlk-Latn = mlk-Latn-KE +mll = mll-VU = mll-Latn = mll-Latn-VU +mln = mln-SB = mln-Latn = mln-Latn-SB +mlp = mlp-PG = *mlp-Latn = mlp-Latn-PG +mlq-Arab = mlq-Arab-SN +mlq-Latn = mlq-Latn-SN +mlr-Latn = mlr-Latn-CM +mls = mls-SD = mls-Latn = mls-Latn-SD +mlu = mlu-SB = mlu-Latn = mlu-Latn-SB +mlv = mlv-VU = mlv-Latn = mlv-Latn-VU +mlw-Latn = mlw-Latn-CM +mlx = mlx-VU = mlx-Latn = mlx-Latn-VU +mmc = mmc-MX = mmc-Latn = mmc-Latn-MX +mmd-Hans = mmd-Hans-CN +mmd-Hant = mmd-Hant-CN +mme = mme-VU = mme-Latn = mme-Latn-VU +mmg = mmg-VU = mmg-Latn = mmg-Latn-VU +mmh = mmh-BR = mmh-Latn = mmh-Latn-BR +mmi = mmi-PG = mmi-Latn = mmi-Latn-PG +mmm = mmm-VU = mmm-Latn = mmm-Latn-VU +mmn-Latn = mmn-Latn-PH +mmo = mmo-PG = *mmo-Latn = mmo-Latn-PG +mmp = mmp-PG = mmp-Latn = mmp-Latn-PG +mmq = mmq-PG = mmq-Latn = mmq-Latn-PG +mmr-Latn = mmr-Latn-CN +mmt = mmt-PG = mmt-Latn = mmt-Latn-PG +mmu = mmu-CM = *mmu-Latn = mmu-Latn-CM +mmv = mmv-BR = mmv-Latn = mmv-Latn-BR +mmw = mmw-VU = mmw-Latn = mmw-Latn-VU +mmx = mmx-PG = *mmx-Latn = mmx-Latn-PG +mmy-Latn = mmy-Latn-TD +*mn = khk = *mn-MN = khk-MN = *mn-Cyrl = khk-Cyrl = *mn-Cyrl-MN = khk-Cyrl-MN +mn-Brai = khk-Brai = mn-Brai-MN = khk-Brai-MN +mn-CN = *mn-Mong = khk-Mong = mn-Mong-CN = khk-Mong-MN +mn-Phag = khk-Phag = mn-Phag-MN = khk-Phag-MN +mn-Tibt = khk-Tibt = mn-Tibt-CN = khk-Tibt-CN +mna = mna-PG = *mna-Latn = mna-Latn-PG +mnb-Latn = mnb-Latn-ID +mnc-Mong-x-manchu = mnc-Mong-CN-x-manchu +mnc-Mong-x-oldmanchu = mnc-Mong-CN-x-oldmanchu +mnd = mnd-BR = mnd-Latn = mnd-Latn-BR +mnf = mnf-CM = *mnf-Latn = mnf-Latn-CM +mng = mng-VN = mng-Latn = mng-Latn-VN +mnh = mnh-CD = mnh-Latn = mnh-Latn-CD +mni = mni-IN = mni-Beng = mni-Beng-IN +mni-Brai = mni-Brai-IN +mni-Mtei = mni-Mtei-IN +mnj-Arab = mnj-Arab-AF +mnl = mnl-VU = mnl-Latn = mnl-Latn-VU +mnm = mnm-PG = mnm-Latn = mnm-Latn-PG +mnp-Latn = mnp-Latn-CN +mnr = mnr-US = mnr-Latn = mnr-Latn-US +mns-Cyrl = mns-Cyrl-RU +mnv = mnv-SB = mnv-Latn = mnv-Latn-SB +mnw = mnw-MM = mnw-Mymr = mnw-Mymr-MM +mnx-Latn = mnx-Latn-ID +mnz-Latn = mnz-Latn-ID +moa = moa-CI = *moa-Latn = moa-Latn-CI +moc = moc-AR = moc-Latn = moc-Latn-AR +moe = moe-CA = moe-Latn = moe-Latn-CA +mog-Latn = mog-Latn-ID +moh = moh-CA = moh-Latn = moh-Latn-CA +mop = mop-BZ = mop-Latn = mop-Latn-BZ +mor = mor-SD = mor-Latn = mor-Latn-SD +mos = mos-BF = *mos-Latn = mos-Latn-BF +mos-Brai = mos-Brai-BF +mot = mot-CO = mot-Latn = mot-Latn-CO +mou-Latn = mou-Latn-TD +mov = mov-US = mov-Latn = mov-Latn-US +mox = mox-PG = *mox-Latn = mox-Latn-PG +moy-Latn = moy-Latn-ET +moz-Latn = moz-Latn-TD +mpa = mpa-TZ = mpa-Latn = mpa-Latn-TZ +mpb = mpb-AU = mpb-Latn = mpb-Latn-AU +mpc = mpc-AU = mpc-Latn = mpc-Latn-AU +mpd = mpd-BR = mpd-Latn = mpd-Latn-BR +mpe-Ethi = mpe-Ethi-ET +mpe-Latn = mpe-Latn-ET +mpg-Latn = mpg-Latn-TD +mph = mph-AU = mph-Latn = mph-Latn-AU +mpi-Latn = mpi-Latn-CM +mpj = mpj-AU = mpj-Latn = mpj-Latn-AU +mpl = mpl-PG = mpl-Latn = mpl-Latn-PG +mpm = mpm-MX = mpm-Latn = mpm-Latn-MX +mpn = mpn-PG = mpn-Latn = mpn-Latn-PG +mpo = mpo-PG = mpo-Latn = mpo-Latn-PG +mpp = mpp-PG = *mpp-Latn = mpp-Latn-PG +mpq = mpq-BR = mpq-Latn = mpq-Latn-BR +mpr = mpr-SB = mpr-Latn = mpr-Latn-SB +mps = mps-PG = *mps-Latn = mps-Latn-PG +mpt = mpt-PG = *mpt-Latn = mpt-Latn-PG +mpu = mpu-BR = mpu-Latn = mpu-Latn-BR +mpv = mpv-PG = mpv-Latn = mpv-Latn-PG +mpw = mpw-BR = mpw-Latn = mpw-Latn-BR +mpx = mpx-PG = *mpx-Latn = mpx-Latn-PG +mpz = mpz-TH = mpz-Thai = mpz-Thai-TH +mqb-Latn = mqb-Latn-CM +mqe = mqe-PG = mqe-Latn = mqe-Latn-PG +mqf-Latn = mqf-Latn-ID +mqh = mqh-MX = mqh-Latn = mqh-Latn-MX +mqj-Latn = mqj-Latn-ID +mql = mql-BJ = *mql-Latn = mql-Latn-BJ +mqm = mqm-PF = mqm-Latn = mqm-Latn-PF +mqn-Latn = mqn-Latn-ID +mqq = mqq-MY = mqq-Latn = mqq-Latn-MY +mqu = mqu-SS = mqu-Latn = mqu-Latn-SS +mqv = mqv-PG = mqv-Latn = mqv-Latn-PG +mqw = mqw-PG = mqw-Latn = mqw-Latn-PG +mqx-Latn = mqx-Latn-ID +mqy-Latn = mqy-Latn-ID +mqz = mqz-PG = mqz-Latn = mqz-Latn-PG +*mr = *mr-IN = mr-Deva = mr-Deva-IN +mr-Brai = mr-Brai-IN +mra = mra-TH = mra-Thai = mra-Thai-TH +mrb = mrb-VU = mrb-Latn = mrb-Latn-VU +mrc = mrc-US = mrc-Latn = mrc-Latn-US +mrd = mrd-NP = mrd-Deva = mrd-Deva-NP +mrg-Beng = mrg-Beng-IN +mrg-Deva = mrg-Deva-IN +mrg-Latn = mrg-Latn-IN +mrh-Latn = mrh-Latn-IN +mrj = mrj-RU = mrj-Cyrl = mrj-Cyrl-RU +mrk = mrk-NC = mrk-Latn = mrk-Latn-NC +mrl = mrl-FM = mrl-Latn = mrl-Latn-FM +mrm = mrm-VU = mrm-Latn = mrm-Latn-VU +mrn = mrn-SB = mrn-Latn = mrn-Latn-SB +mro = mro-BD = mro-Mroo = mro-Mroo-BD +mro-Latn = mro-Latn-BD +mrp = mrp-VU = mrp-Latn = mrp-Latn-VU +mrq = mrq-PF = mrq-Latn = mrq-Latn-PF +mrr = mrr-IN = mrr-Deva = mrr-Deva-IN +mrs = mrs-VU = mrs-Latn = mrs-Latn-VU +mrt-Latn = mrt-Latn-NG +mru = mru-RU = mru-Cyrl = mru-Cyrl-RU +mrv = mrv-PF = mrv-Latn = mrv-Latn-PF +mrw-Latn = mrw-Latn-PH +mrz-Latn = mrz-Latn-ID +*ms = zsm = *ms-MY = zsm-MY = *ms-Latn = zsm-Latn = *ms-Latn-MY = zsm-Latn-MY +*ms-Arab = *zsm-Arab = ms-Arab-MY = zsm-Arab-MY +ms-Brai = zsm-Brai = ms-Brai-MY = zsm-Brai-MY +ms-CC = ms-Arab-CC +ms-ID = ms-Arab-ID +*ms-Latn-BN +*ms-Latn-SG +msb-Latn = msb-Latn-PH +msc-Latn = msc-Latn-GN +mse-Latn = mse-Latn-TD +msh = msh-MG = msh-Latn = msh-Latn-MG +msi-Latn = msi-Latn-MY +msk-Latn = msk-Latn-PH +msm-Latn = msm-Latn-PH +msn = msn-VU = msn-Latn = msn-Latn-VU +msp = msp-BR = msp-Latn = msp-Latn-BR +msq = msq-NC = msq-Latn = msq-Latn-NC +msu = msu-PG = msu-Latn = msu-Latn-PG +msv-Latn = msv-Latn-CM +msw-Latn = msw-Latn-GW +msx = msx-PG = msx-Latn = msx-Latn-PG +msy = msy-PG = msy-Latn = msy-Latn-PG +msz = msz-PG = msz-Latn = msz-Latn-PG +*mt = *mt-MT = mt-Latn = mt-Latn-MT +mt-Arab = mt-Arab-MT +mt-Brai = mt-Brai-MT +mta-Latn = mta-Latn-PH +mtc = mtc-PG = mtc-Latn = mtc-Latn-PG +mtd-Latn = mtd-Latn-ID +mte = mte-SB = mte-Latn = mte-Latn-SB +mtf = mtf-PG = *mtf-Latn = mtf-Latn-PG +mtg-Latn = mtg-Latn-ID +mti = mti-PG = *mti-Latn = mti-Latn-PG +mtj-Latn = mtj-Latn-ID +mto = mto-MX = mto-Latn = mto-Latn-MX +mtp = mtp-BO = mtp-Latn = mtp-Latn-BO +mtq = mtq-VN = mtq-Latn = mtq-Latn-VN +mtr = mtr-IN = mtr-Deva = mtr-Deva-IN +mts = mts-PE = mts-Latn = mts-Latn-PE +mtt = mtt-VU = mtt-Latn = mtt-Latn-VU +mtu = mtu-MX = mtu-Latn = mtu-Latn-MX +mtv = mtv-PG = mtv-Latn = mtv-Latn-PG +mtx = mtx-MX = mtx-Latn = mtx-Latn-MX +mty = mty-PG = mty-Latn = mty-Latn-PG +*mua = *mua-CM = mua-Latn = mua-Latn-CM +mue = mue-EC = mue-Latn = mue-Latn-EC +mug-Latn = mug-Latn-CM +muh = muh-SS = muh-Latn = muh-Latn-SS +muk-Tibt = muk-Tibt-NP +mum = mum-PG = mum-Latn = mum-Latn-PG +mur = mur-SS = *mur-Latn = mur-Latn-SS +mus = mus-US = mus-Latn = mus-Latn-US +mut-Deva = mut-Deva-IN +mux = mux-PG = mux-Latn = mux-Latn-PG +muy-Latn = muy-Latn-CM +muz = muz-ET = muz-Ethi = muz-Ethi-ET +mva = mva-PG = *mva-Latn = mva-Latn-PG +mve-Arab-x-sindhi = mve-Arab-PK-x-sindhi +mve-Arab-x-urdu = mve-Arab-PK-x-urdu +mvf-Mong = mvf-Mong-CN +mvf-Phag = mvf-Phag-CN +mvg = mvg-MX = mvg-Latn = mvg-Latn-MX +mvk = mvk-PG = mvk-Latn = mvk-Latn-PG +mvn = mvn-PG = *mvn-Latn = mvn-Latn-PG +mvo = mvo-SB = mvo-Latn = mvo-Latn-SB +mvp-Latn = mvp-Latn-ID +mvq = mvq-PG = mvq-Latn = mvq-Latn-PG +mvt = mvt-VU = mvt-Latn = mvt-Latn-VU +mvv-Latn = mvv-Latn-MY +mvy = mvy-PK = *mvy-Arab = mvy-Arab-PK +mwa = mwa-PG = mwa-Latn = mwa-Latn-PG +mwb = mwb-PG = mwb-Latn = mwb-Latn-PG +mwc = mwc-PG = mwc-Latn = mwc-Latn-PG +mwe = mwe-TZ = mwe-Latn = mwe-Latn-TZ +mwf = mwf-AU = mwf-Latn = mwf-Latn-AU +mwg = mwg-PG = mwg-Latn = mwg-Latn-PG +mwh = mwh-PG = mwh-Latn = mwh-Latn-PG +mwi = mwi-VU = mwi-Latn = mwi-Latn-VU +mwk = mwk-ML = mwk-Latn = mwk-Latn-ML +mwl = mwl-PT = mwl-Latn = mwl-Latn-PT +mwm-Latn = mwm-Latn-TD +mwn = mwn-ZM = mwn-Latn = mwn-Latn-ZM +mwo = mwo-VU = mwo-Latn = mwo-Latn-VU +mwp = mwp-AU = mwp-Latn = mwp-Latn-AU +mwq = mwq-MM = mwq-Latn = mwq-Latn-MM +mwr = dhd = mwr-IN = dhd-IN = mwr-Deva = dhd-Deva = mwr-Deva-IN = dhd-Deva-IN +mwt-Mymr = mwt-Mymr-MM +mwt-Thai = mwt-Thai-TH +mwv = mwv-ID = mwv-Latn = mwv-Latn-ID +mww = mww-CN = mww-Latn = mww-Latn-CN +mww-Hmng = mww-Hmng-CN +mww-Laoo = mww-Laoo-LA +mww-Plrd = mww-Plrd-CN +mww-Thai = mww-Thai-TH +mxa = mxa-MX = mxa-Latn = mxa-Latn-MX +mxb = mxb-MX = mxb-Latn = mxb-Latn-MX +mxc = mxc-ZW = mxc-Latn = mxc-Latn-ZW +mxe = mxe-VU = mxe-Latn = mxe-Latn-VU +mxf-Latn = mxf-Latn-CM +mxg = mxg-AO = mxg-Latn = mxg-Latn-AO +mxj-Latn = mxj-Latn-IN +mxk = mxk-PG = mxk-Latn = mxk-Latn-PG +mxm = mxm-PG = *mxm-Latn = mxm-Latn-PG +mxo = mxo-ZM = mxo-Latn = mxo-Latn-ZM +mxp = mxp-MX = mxp-Latn = mxp-Latn-MX +mxq = mxq-MX = mxq-Latn = mxq-Latn-MX +mxs = mxs-MX = mxs-Latn = mxs-Latn-MX +mxt = mxt-MX = mxt-Latn = mxt-Latn-MX +mxu-Latn = mxu-Latn-CM +mxv = mxv-MX = mxv-Latn = mxv-Latn-MX +mxw = mxw-PG = mxw-Latn = mxw-Latn-PG +mxy = mxy-MX = mxy-Latn = mxy-Latn-MX +*my = *my-MM = my-Mymr = my-Mymr-MM +my-Brai = my-Brai-MM +myb = myb-TD = myb-Latn = myb-Latn-TD +myd = myd-PG = myd-Latn = myd-Latn-PG +mye = mye-GA = mye-Latn = mye-Latn-GA +myf-Latn = myf-Latn-ET +myh = myh-US = myh-Latn = myh-Latn-US +myk = myk-ML = *myk-Latn = myk-Latn-ML +myl-Latn = myl-Latn-ID +mym = mym-ET = *mym-Ethi = mym-Ethi-ET +*mym-Latn = mym-Latn-ET +myp = myp-BR = myp-Latn = myp-Latn-BR +myr = myr-PE = myr-Latn = myr-Latn-PE +myu = myu-BR = myu-Latn = myu-Latn-BR +myv = myv-RU = myv-Cyrl = myv-Cyrl-RU +myw = myw-PG = *myw-Latn = myw-Latn-PG +myx = myx-UG = myx-Latn = myx-Latn-UG +myy = myy-CO = myy-Latn = myy-Latn-CO +myz = myz-IR = myz-Mand = myz-Mand-IR +mza = mza-MX = mza-Latn = mza-Latn-MX +mzb-Arab = mzb-Arab-DZ +mzb-Latn = mzb-Latn-DZ +mzb-Tfng = mzb-Tfng-DZ +mze = mze-PG = mze-Latn = mze-Latn-PG +mzh = mzh-AR = mzh-Latn = mzh-Latn-AR +mzi = mzi-MX = mzi-Latn = mzi-Latn-MX +mzj = mzj-LR = mzj-Latn = mzj-Latn-LR +mzk = mzk-NG = *mzk-Latn = mzk-Latn-NG +mzl = mzl-MX = mzl-Latn = mzl-Latn-MX +mzm = mzm-NG = *mzm-Latn = mzm-Latn-NG +*mzn = *mzn-IR = mzn-Arab = mzn-Arab-IR +mzo = mzo-BR = mzo-Latn = mzo-Latn-BR +mzp = mzp-BO = *mzp-Latn = mzp-Latn-BO +mzq-Latn = mzq-Latn-ID +mzr = mzr-BR = mzr-Latn = mzr-Latn-BR +mzu = mzu-PG = mzu-Latn = mzu-Latn-PG +mzv = mzv-CF = mzv-Latn = mzv-Latn-CF +mzw = mzw-GH = *mzw-Latn = mzw-Latn-GH +mzx = mzx-GY = mzx-Latn = mzx-Latn-GY +mzz = mzz-PG = *mzz-Latn = mzz-Latn-PG +na = na-NR = na-Latn = na-Latn-NR +nab = nab-BR = nab-Latn = nab-Latn-BR +nac = nac-PG = *nac-Latn = nac-Latn-PG +naf = naf-PG = *naf-Latn = naf-Latn-PG +nag-Latn = nag-Latn-IN +nak = nak-PG = *nak-Latn = nak-Latn-PG +nal = nal-PG = nal-Latn = nal-Latn-PG +nam = nam-AU = nam-Latn = nam-Latn-AU +nan = nan-CN = nan-Hans = nan-Hans-CN +nan-Bopo = nan-Bopo-TW +nan-Kana = nan-Kana-TW +nan-Latn = nan-Latn-CN +nap = nap-IT = nap-Latn = nap-Latn-IT +*naq = *naq-NA = naq-Latn = naq-Latn-NA +nas = nas-PG = *nas-Latn = nas-Latn-PG +*nat-Latn = nat-Latn-NG +naw = naw-GH = naw-Latn = naw-Latn-GH +nax = nax-PG = nax-Latn = nax-Latn-PG +nay = nay-AU = nay-Latn = nay-Latn-AU +naz = naz-MX = naz-Latn = naz-Latn-MX +*nb = *nb-NO = nb-Latn = nb-Latn-NO +nba = nba-AO = nba-Latn = nba-Latn-AO +nbc-Latn = nbc-Latn-IN +nbe-Latn = nbe-Latn-IN +nbh-Latn = nbh-Latn-NG +nbi-Latn = nbi-Latn-IN +nbj = nbj-AU = nbj-Latn = nbj-Latn-AU +nbk = nbk-PG = nbk-Latn = nbk-Latn-PG +nbm = nbm-CF = nbm-Latn = nbm-Latn-CF +nbq-Latn = nbq-Latn-ID +nbt-Deva = nbt-Deva-IN +nbt-Latn = nbt-Latn-IN +nbu-Latn = nbu-Latn-IN +nbw = nbw-CD = nbw-Latn = nbw-Latn-CD +nby = nby-PG = nby-Latn = nby-Latn-PG +nca = nca-PG = *nca-Latn = nca-Latn-PG +ncb-Deva = ncb-Deva-IN +ncb-Latn = ncb-Latn-IN +ncc = ncc-PG = ncc-Latn = ncc-Latn-PG +ncd-Deva = ncd-Deva-NP +nce = nce-PG = *nce-Latn = nce-Latn-PG +ncf = ncf-PG = *ncf-Latn = ncf-Latn-PG +ncg = ncg-CA = ncg-Latn = ncg-Latn-CA +nch = nch-MX = nch-Latn = nch-Latn-MX +nci = nci-MX = nci-Latn = nci-Latn-MX +ncj = ncj-MX = ncj-Latn = ncj-Latn-MX +nck = nck-AU = nck-Latn = nck-Latn-AU +ncl = ncl-MX = ncl-Latn = ncl-Latn-MX +ncm = ncm-PG = ncm-Latn = ncm-Latn-PG +ncn = ncn-PG = ncn-Latn = ncn-Latn-PG +nco = nco-PG = *nco-Latn = nco-Latn-PG +ncq = ncq-LA = ncq-Laoo = ncq-Laoo-LA +ncr-Latn = ncr-Latn-CM +nct-Beng = nct-Beng-IN +nct-Latn = nct-Latn-IN +ncu = ncu-GH = *ncu-Latn = ncu-Latn-GH +ncx = ncx-MX = ncx-Latn = ncx-Latn-MX +*nd = *nd-ZW = nd-Latn = nd-Latn-ZW +ndb-Latn = ndb-Latn-CM +ndc = ndc-MZ = ndc-Latn = ndc-Latn-MZ +ndh = ndh-TZ = ndh-Latn = ndh-Latn-TZ +ndi-Latn = ndi-Latn-NG +ndj = ndj-TZ = ndj-Latn = ndj-Latn-TZ +ndm-Latn = ndm-Latn-TD +ndp = ndp-UG = ndp-Latn = ndp-Latn-UG +ndq = ndq-AO = ndq-Latn = ndq-Latn-AO +*nds = *nds-DE = nds-Latn = nds-Latn-DE +ndu-Latn = ndu-Latn-CM +ndv-Latn = ndv-Latn-SN +ndx-Latn = ndx-Latn-ID +ndy = ndy-CF = ndy-Latn = ndy-Latn-CF +ndy-TD = ndy-Latn-TD +ndz = ndz-SS = ndz-Latn = ndz-Latn-SS +*ne = npi = *ne-NP = npi-NP = ne-Deva = npi-Deva = ne-Deva-NP = npi-Deva-NP +ne-Brai = npi-Brai = ne-Brai-NP = npi-Brai-NP +ne-Newa = ne-Newa-NP +neb = neb-CI = *neb-Latn = neb-Latn-CI +nee = nee-NC = nee-Latn = nee-Latn-NC +nej = nej-PG = nej-Latn = nej-Latn-PG +nek = nek-NC = nek-Latn = nek-Latn-NC +nem = nem-NC = nem-Latn = nem-Latn-NC +nen = nen-NC = nen-Latn = nen-Latn-NC +neq = neq-MX = neq-Latn = neq-Latn-MX +net = net-PG = net-Latn = net-Latn-PG +neu-Latn = neu-Latn-?? +new = new-NP = new-Deva = new-Deva-NP +new-Newa = new-Newa-NP +new-Qabb = new-Qabb-NP +nex = nex-PG = nex-Latn = nex-Latn-PG +nez = nez-US = nez-Latn = nez-Latn-US +nfa-Latn = nfa-Latn-ID +nfl = nfl-SB = nfl-Latn = nfl-Latn-SB +nfr = nfr-GH = *nfr-Latn = nfr-Latn-GH +nfu-Latn = nfu-Latn-CM +ng = ng-NA = ng-Latn = ng-Latn-NA +nga = nga-CD = *nga-Latn = nga-Latn-CD +ngb = ngb-CD = *ngb-Latn = ngb-Latn-CD +ngc = ngc-CD = ngc-Latn = ngc-Latn-CD +ngd = ngd-CF = ngd-Latn = ngd-Latn-CF +ngg = ngg-CF = ngg-Latn = ngg-Latn-CF +ngh = ngh-ZA = ngh-Latn = ngh-Latn-ZA +ngi = ngi-NG = ngi-Latn = ngi-Latn-NG +ngj-Latn = ngj-Latn-CM +ngk = ngk-AU = ngk-Latn = ngk-Latn-AU +ngl = ngl-MZ = ngl-Latn = ngl-Latn-MZ +ngm = ngm-FM = ngm-Latn = ngm-Latn-FM +ngo = ngo-TZ = ngo-Latn = ngo-Latn-TZ +ngp = ngp-TZ = ngp-Latn = ngp-Latn-TZ +ngq = ngq-TZ = ngq-Latn = ngq-Latn-TZ +ngr = ngr-SB = ngr-Latn = ngr-Latn-SB +ngt = ngt-LA = ngt-Laoo = ngt-Laoo-LA +ngu = ngu-MX = ngu-Latn = ngu-Latn-MX +ngz = ngz-CG = ngz-Latn = ngz-Latn-CG +nha = nha-AU = nha-Latn = nha-Latn-AU +nhb = nhb-CI = *nhb-Latn = nhb-Latn-CI +nhd = nhd-PY = nhd-Latn = nhd-Latn-PY +nhe = nhe-MX = nhe-Latn = nhe-Latn-MX +nhf = nhf-AU = nhf-Latn = nhf-Latn-AU +nhg = nhg-MX = nhg-Latn = nhg-Latn-MX +nhi = nhi-MX = nhi-Latn = nhi-Latn-MX +nhk = nhk-MX = nhk-Latn = nhk-Latn-MX +nhm = nhm-MX = nhm-Latn = nhm-Latn-MX +nhn = nhn-MX = nhn-Latn = nhn-Latn-MX +nho = nho-PG = nho-Latn = nho-Latn-PG +nhp = nhp-MX = nhp-Latn = nhp-Latn-MX +nhq = nhq-MX = nhq-Latn = nhq-Latn-MX +nhr = nhr-BW = nhr-Latn = nhr-Latn-BW +nht = nht-MX = nht-Latn = nht-Latn-MX +nhu-Latn = nhu-Latn-CM +nhv = nhv-MX = nhv-Latn = nhv-Latn-MX +nhw = nhw-MX = nhw-Latn = nhw-Latn-MX +nhx = nhx-MX = nhx-Latn = nhx-Latn-MX +nhy = nhy-MX = nhy-Latn = nhy-Latn-MX +nhz = nhz-MX = nhz-Latn = nhz-Latn-MX +nia-Latn = nia-Latn-ID +nib = nib-PG = nib-Latn = nib-Latn-PG +nie-Latn = nie-Latn-TD +nif = nif-PG = *nif-Latn = nif-Latn-PG +nih = nih-TZ = nih-Latn = nih-Latn-TZ +nii = nii-PG = *nii-Latn = nii-Latn-PG +nij = nij-ID = nij-Latn = nij-Latn-ID +nim = nim-TZ = nim-Latn = nim-Latn-TZ +nin = nin-NG = *nin-Latn = nin-Latn-NG +nio-Cyrl = nio-Cyrl-RU +niq = niq-KE = niq-Latn = niq-Latn-KE +nir-Latn = nir-Latn-ID +nis = nis-PG = nis-Latn = nis-Latn-PG +nit-Telu = nit-Telu-IN +niu = niu-NU = niu-Latn = niu-Latn-NU +niv-Cyrl = niv-Cyrl-RU +niv-Latn = niv-Latn-RU +niw = niw-PG = niw-Latn = niw-Latn-PG +niy = niy-CD = *niy-Latn = niy-Latn-CD +niz = niz-PG = niz-Latn = niz-Latn-PG +nja-Latn = nja-Latn-NG +njh-Latn = njh-Latn-IN +nji = nji-AU = nji-Latn = nji-Latn-AU +njm-Latn = njm-Latn-IN +njn-Latn = njn-Latn-IN +njo = njo-IN = njo-Latn = njo-Latn-IN +njt = njt-SR = njt-Latn = njt-Latn-SR +nju = nju-AU = nju-Latn = nju-Latn-AU +njx = njx-CG = njx-Latn = njx-Latn-CG +njy-Latn = njy-Latn-CM +njz-Beng = njz-Beng-IN +njz-Latn = njz-Latn-IN +nka = nka-ZM = nka-Latn = nka-Latn-ZM +nkb-Latn = nkb-Latn-IN +nkd-Latn = nkd-Latn-IN +nke = nke-SB = nke-Latn = nke-Latn-SB +nkf-Latn = nkf-Latn-IN +nkg = nkg-PG = nkg-Latn = nkg-Latn-PG +nkh = nkh-IN = nkh-Latn = nkh-Latn-IN +nki-Beng = nki-Beng-IN +nki-Latn = nki-Latn-IN +nkk = nkk-VU = nkk-Latn = nkk-Latn-VU +nkm = nkm-PG = nkm-Latn = nkm-Latn-PG +nkn = nkn-AO = nkn-Latn = nkn-Latn-AO +nko = nko-GH = *nko-Latn = nko-Latn-GH +nkq = nkq-GH = nkq-Latn = nkq-Latn-GH +nkr = nkr-FM = nkr-Latn = nkr-Latn-FM +nku-Latn = nku-Latn-CI +nkw = nkw-CD = nkw-Latn = nkw-Latn-CD +*nl = *nl-NL = nl-Latn = nl-Latn-NL +*nl-AW = nl-Latn-AW +*nl-BE = nl-Latn-BE +*nl-BQ = nl-Latn-BQ +nl-Brai = nl-Brai-NL +*nl-CW = nl-Latn-CW +*nl-SR = nl-Latn-SR +*nl-SX = nl-Latn-SX +nla-Latn = nla-Latn-CM +nlc-Latn = nlc-Latn-ID +nle = nle-KE = nle-Latn = nle-Latn-KE +nlg = nlg-SB = nlg-Latn = nlg-Latn-SB +nlk-Latn = nlk-Latn-ID +nlu = nlu-GH = nlu-Latn = nlu-Latn-GH +nlv = nlv-MX = nlv-Latn = nlv-Latn-MX +nly = nly-AU = nly-Latn = nly-Latn-AU +nlz = nlz-SB = nlz-Latn = nlz-Latn-SB +nma-Latn = nma-Latn-IN +nmb = nmb-VU = nmb-Latn = nmb-Latn-VU +nmc = nmc-TD = nmc-Latn = nmc-Latn-TD +nmd = nmd-GA = nmd-Latn = nmd-Latn-GA +nme-Latn = nme-Latn-IN +nmf-Latn = nmf-Latn-IN +*nmg = *nmg-CM = nmg-Latn = nmg-Latn-CM +nmh-Latn = nmh-Latn-IN +nmk = nmk-VU = nmk-Latn = nmk-Latn-VU +nmm-Deva = nmm-Deva-NP +nmm-Tibt = nmm-Tibt-NP +nmn = nmn-BW = nmn-Latn = nmn-Latn-BW +nmo-Beng = nmo-Beng-IN +nmo-Latn = nmo-Latn-IN +nmq = nmq-ZW = nmq-Latn = nmq-Latn-ZW +nms = nms-VU = nms-Latn = nms-Latn-VU +nmt = nmt-FM = nmt-Latn = nmt-Latn-FM +nmu = nmu-US = nmu-Latn = nmu-Latn-US +nmw = nmw-PG = nmw-Latn = nmw-Latn-PG +nmx = nmx-PG = nmx-Latn = nmx-Latn-PG +nmz = nmz-TG = *nmz-Latn = nmz-Latn-TG +*nn = *nn-NO = nn-Latn = nn-Latn-NO +nna = nna-AU = nna-Latn = nna-Latn-AU +nnb = nnb-CD = nnb-Latn = nnb-Latn-CD +nnc-Latn = nnc-Latn-TD +nnd = nnd-VU = nnd-Latn = nnd-Latn-VU +nne = nne-AO = nne-Latn = nne-Latn-AO +nnf = nnf-PG = *nnf-Latn = nnf-Latn-PG +nng-Beng = nng-Beng-IN +nng-Latn = nng-Latn-IN +*nnh = *nnh-CM = nnh-Latn = nnh-Latn-CM +nnj-Latn = nnj-Latn-ET +nnk = nnk-PG = *nnk-Latn = nnk-Latn-PG +nnl-Latn = nnl-Latn-IN +nnm = nnm-PG = *nnm-Latn = nnm-Latn-PG +nnp-Deva = nnp-Deva-IN +nnp-Latn = nnp-Latn-IN +nnq = nnq-TZ = nnq-Latn = nnq-Latn-TZ +nnu = nnu-GH = nnu-Latn = nnu-Latn-GH +nnw-Latn = nnw-Latn-BF +no = no-NO = no-Latn = no-Latn-NO +noa = noa-CO = noa-Latn = noa-Latn-CO +noc = noc-PG = noc-Latn = noc-Latn-PG +nod = nod-TH = *nod-Lana = nod-Lana-TH +nod-Thai = nod-Thai-TH +noe = noe-IN = noe-Deva = noe-Deva-IN +nof = nof-PG = nof-Latn = nof-Latn-PG +nog-Cyrl = nog-Cyrl-RU +noh = noh-PG = noh-Latn = noh-Latn-PG +noi-Deva = noi-Deva-IN +noj = noj-CO = noj-Latn = noj-Latn-CO +non = non-SE = non-Runr = non-Runr-SE +nop = nop-PG = *nop-Latn = nop-Latn-PG +nos-Yiii-x-traditional = nos-Yiii-CN-x-traditional +not = not-PE = not-Latn = not-Latn-PE +nou = nou-PG = *nou-Latn = nou-Latn-PG +npg = npg-MM = npg-Latn = npg-Latn-MM +nph-Latn = nph-Latn-IN +npl = npl-MX = npl-Latn = npl-Latn-MX +npn = npn-PG = npn-Latn = npn-Latn-PG +npo-Latn = npo-Latn-IN +nps-Latn = nps-Latn-ID +npu-Latn = npu-Latn-IN +npy-Latn = npy-Latn-ID +nqg-Latn = nqg-Latn-BJ +nql = nql-AO = nql-Latn = nql-Latn-AO +nqn = nqn-PG = nqn-Latn = nqn-Latn-PG +nqo = nqo-GN = nqo-Nkoo = nqo-Nkoo-GN +*nr = *nr-ZA = nr-Latn = nr-Latn-ZA +nr-Brai = nr-Brai-ZA +nra = nra-GA = nra-Latn = nra-Latn-GA +nrb = nrb-ER = *nrb-Latn = nrb-Latn-ER +nre-Latn = nre-Latn-IN +nrf = nrf-JE = nrf-Latn = nrf-Latn-JE +nrg = nrg-VU = nrg-Latn = nrg-Latn-VU +nri-Latn = nri-Latn-IN +nrk = nrk-AU = nrk-Latn = nrk-Latn-AU +nrl = nrl-AU = nrl-Latn = nrl-Latn-AU +nrz = nrz-PG = nrz-Latn = nrz-Latn-PG +nsa-Latn = nsa-Latn-IN +nsd-Yiii-x-traditional = nsd-Yiii-CN-x-traditional +nse = nse-ZM = nse-Latn = nse-Latn-ZM +nsk = nsk-CA = nsk-Cans = nsk-Cans-CA +nsk-Latn = nsk-Latn-CA +nsm-Latn = nsm-Latn-IN +nsn = nsn-PG = *nsn-Latn = nsn-Latn-PG +*nso = *nso-ZA = nso-Latn = nso-Latn-ZA +nso-Brai = nso-Brai-ZA +nsq = nsq-US = nsq-Latn = nsq-Latn-US +nss = nss-PG = *nss-Latn = nss-Latn-PG +nst-Latn = nst-Latn-MM +nst-Latn-x-moshanghawa = nst-Latn-MM-x-moshanghawa +nsu = nsu-MX = nsu-Latn = nsu-Latn-MX +nsv-Yiii-x-traditional = nsv-Yiii-CN-x-traditional +nsw = nsw-VU = nsw-Latn = nsw-Latn-VU +nsx = nsx-AO = nsx-Latn = nsx-Latn-AO +nsz = nsz-US = nsz-Latn = nsz-Latn-US +ntj = ntj-AU = ntj-Latn = ntj-Latn-AU +ntk = ntk-TZ = ntk-Latn = ntk-Latn-TZ +ntm = ntm-BJ = *ntm-Latn = ntm-Latn-BJ +nto = nto-CD = nto-Latn = nto-Latn-CD +ntp = ntp-MX = ntp-Latn = ntp-Latn-MX +ntr = ntr-GH = *ntr-Latn = ntr-Latn-GH +ntu = ntu-SB = ntu-Latn = ntu-Latn-SB +ntx = ntx-MM = ntx-Latn = ntx-Latn-MM +nty = nty-VN = nty-Yiii = nty-Yiii-VN +ntz-Arab = ntz-Arab-IR +nua = nua-NC = nua-Latn = nua-Latn-NC +nuc = nuc-BR = nuc-Latn = nuc-Latn-BR +nud = nud-PG = nud-Latn = nud-Latn-PG +nuf = nuf-CN = nuf-Latn = nuf-Latn-CN +nui = nui-GQ = *nui-Latn = nui-Latn-GQ +nuj = nuj-UG = nuj-Latn = nuj-Latn-UG +nuk = nuk-CA = nuk-Latn = nuk-Latn-CA +num = num-TO = num-Latn = num-Latn-TO +nun = nun-MM = nun-Latn = nun-Latn-MM +nup = nup-NG = *nup-Latn = nup-Latn-NG +nuq = nuq-PG = nuq-Latn = nuq-Latn-PG +nur = nur-PG = nur-Latn = nur-Latn-PG +*nus = *nus-SS = nus-Latn = nus-Latn-SS +nut = nut-VN = nut-Latn = nut-Latn-VN +nuv = nuv-BF = *nuv-Latn = nuv-Latn-BF +nuw = nuw-FM = nuw-Latn = nuw-Latn-FM +nux = nux-PG = nux-Latn = nux-Latn-PG +nuy = nuy-AU = nuy-Latn = nuy-Latn-AU +nuz = nuz-MX = nuz-Latn = nuz-Latn-MX +nv = nv-US = nv-Latn = nv-Latn-US +nvh = nvh-VU = nvh-Latn = nvh-Latn-VU +nvm = nvm-PG = nvm-Latn = nvm-Latn-PG +nwb = nwb-CI = *nwb-Latn = nwb-Latn-CI +nwi = nwi-VU = nwi-Latn = nwi-Latn-VU +nwr = nwr-PG = nwr-Latn = nwr-Latn-PG +nxa = nxa-TL = nxa-Latn = nxa-Latn-TL +nxd = nxd-CD = nxd-Latn = nxd-Latn-CD +nxl-Latn = nxl-Latn-ID +nxo = nxo-GA = nxo-Latn = nxo-Latn-GA +nxq = nxq-CN = nxq-Latn = nxq-Latn-CN +nxq-Lisu = nxq-Lisu-CN +nxq-Nkgb = nxq-Nkgb-CN +nxr = nxr-PG = *nxr-Latn = nxr-Latn-PG +*ny = ny-MW = ny-Latn = ny-Latn-MW +ny-Brai = ny-Brai-MW +nyb = nyb-GH = nyb-Latn = nyb-Latn-GH +nyd = nyd-KE = nyd-Latn = nyd-Latn-KE +nye = nye-AO = nye-Latn = nye-Latn-AO +nyf = nyf-KE = nyf-Latn = nyf-Latn-KE +nyh = nyh-AU = nyh-Latn = nyh-Latn-AU +nyi = nyi-SD = nyi-Latn = nyi-Latn-SD +nyk = nyk-AO = nyk-Latn = nyk-Latn-AO +nym = nym-TZ = nym-Latn = nym-Latn-TZ +*nyn = *nyn-UG = nyn-Latn = nyn-Latn-UG +nyo = nyo-UG = nyo-Latn = nyo-Latn-UG +nyq-Arab = nyq-Arab-IR +nyr-Latn = nyr-Latn-MW +nys = nys-AU = nys-Latn = nys-Latn-AU +nyu-Latn = nyu-Latn-MZ +nyy = nyy-TZ = nyy-Latn = nyy-Latn-TZ +nza-Latn = nza-Latn-CM +nzb = nzb-GA = nzb-Latn = nzb-Latn-GA +nzd = nzd-CD = nzd-Latn = nzd-Latn-CD +nzi = nzi-GH = nzi-Latn = nzi-Latn-GH +nzk = nzk-CF = nzk-Latn = nzk-Latn-CF +nzm-Latn = nzm-Latn-IN +nzu = nzu-CG = nzu-Latn = nzu-Latn-CG +nzy-Latn = nzy-Latn-TD +oav-Geor = oav-Geor-GE +obm-Phnx = obm-Phnx-JO +obo-Latn = obo-Latn-PH +obr = obr-MM = obr-Mymr = obr-Mymr-MM +obt = obt-FR = obt-Latn = obt-Latn-FR +*oc = oc-FR = oc-Latn = oc-Latn-FR +oca = oca-PE = oca-Latn = oca-Latn-PE +oco = oco-GB = oco-Latn = oco-Latn-GB +ocu = ocu-MX = ocu-Latn = ocu-Latn-MX +odk-Arab = odk-Arab-PK +odt = odt-NL = odt-Latn = odt-Latn-NL +odu-Latn = odu-Latn-NG +ogc = ogc-NG = *ogc-Latn = ogc-Latn-NG +oge-Geok = oge-Geok-GE +ogo-Latn = ogo-Latn-NG +ohu-Hung = ohu-Hung-HU +ohu-Latn = ohu-Latn-HU +oin = oin-PG = oin-Latn = oin-Latn-PG +oj = ojg = oj-CA = ojg-CA = oj-Latn = ojg-Latn = oj-Latn-CA = ojg-Latn-CA +oj-Cans = ojg-Cans = oj-Cans-CA = ojg-Cans-CA +ojb = ojb-CA = ojb-Latn = ojb-Latn-CA +ojb-Cans = ojb-Cans-CA +ojc = ojc-CA = ojc-Latn = ojc-Latn-CA +ojs = ojs-CA = ojs-Cans = ojs-Cans-CA +ojv = ojv-SB = ojv-Latn = ojv-Latn-SB +ojw = ojw-CA = ojw-Latn = ojw-Latn-CA +ojw-Cans = ojw-Cans-CA +oka = oka-CA = oka-Latn = oka-Latn-CA +oki = oki-KE = oki-Latn = oki-Latn-KE +okk = okk-PG = okk-Latn = okk-Latn-PG +okr = okr-NG = *okr-Latn = okr-Latn-NG +oku-Latn = oku-Latn-CM +okv = okv-PG = *okv-Latn = okv-Latn-PG +ola-Tibt = ola-Tibt-NP +old = old-TZ = old-Latn = old-Latn-TZ +olo-Latn = olo-Latn-RU +olr = olr-VU = olr-Latn = olr-Latn-VU +olt-Latn = olt-Latn-LT +olu = olu-AO = olu-Latn = olu-Latn-AO +*om = gaz = *om-ET = gaz-ET = om-Latn = gaz-Latn = om-Latn-ET = gaz-Latn-ET +om-Ethi = *gaz-Ethi = om-Ethi-ET = gaz-Ethi-ET +oma = oma-US = oma-Latn = oma-Latn-US +omb = omb-VU = omb-Latn = omb-Latn-VU +omg = omg-PE = omg-Latn = omg-Latn-PE +omi = omi-CD = omi-Latn = omi-Latn-CD +omn-Lina +omo = omo-PG = omo-Latn = omo-Latn-PG +omp-Mtei = omp-Mtei-IN +omr-Modi = omr-Modi-IN +omw = omw-PG = omw-Latn = omw-Latn-PG +ona = ona-AR = ona-Latn = ona-Latn-AR +one = one-CA = one-Latn = one-Latn-CA +ong = ong-PG = *ong-Latn = ong-Latn-PG +onj = onj-PG = onj-Latn = onj-Latn-PG +onk = onk-PG = onk-Latn = onk-Latn-PG +onn = onn-PG = *onn-Latn = onn-Latn-PG +ono = ono-CA = ono-Latn = ono-Latn-CA +onp-Deva = onp-Deva-IN +onp-Latn = onp-Latn-IN +onr = onr-PG = onr-Latn = onr-Latn-PG +ons = ons-PG = *ons-Latn = ons-Latn-PG +ont = ont-PG = ont-Latn = ont-Latn-PG +onu = onu-VU = onu-Latn = onu-Latn-VU +onw-x-oldnubian = onw-SD-x-oldnubian = onw-Copt-x-oldnubian = onw-Copt-SD-x-oldnubian +ood = ood-US = ood-Latn = ood-Latn-US +oor = oor-ZA = oor-Latn = oor-Latn-ZA +opm = opm-PG = *opm-Latn = opm-Latn-PG +opo = opo-PG = opo-Latn = opo-Latn-PG +opy = opy-BR = opy-Latn = opy-Latn-BR +*or = ory = *or-IN = ory-IN = or-Orya = ory-Orya = or-Orya-IN = ory-Orya-IN +or-Brai = ory-Brai = or-Brai-IN = ory-Brai-IN +ora = ora-SB = ora-Latn = ora-Latn-SB +orc = orc-KE = orc-Latn = orc-Latn-KE +ore = ore-PE = ore-Latn = ore-Latn-PE +oro = oro-PG = *oro-Latn = oro-Latn-PG +ort-Telu = ort-Telu-IN +oru = oru-PK = *oru-Arab = oru-Arab-PK +orw = orw-BR = orw-Latn = orw-Latn-BR +*os = *os-GE = os-Cyrl = os-Cyrl-GE +os-Geor = os-Geor-RU +os-Latn = os-Latn-RU +*os-RU = os-Cyrl-RU +osa = osa-US = osa-Osge = osa-Osge-US +osc-Ital = osc-Ital-IT +osc-Latn = osc-Latn-IT +osi-Java = osi-Java-ID +osp = osp-ES = osp-Latn = osp-Latn-ES +osu = osu-PG = osu-Latn = osu-Latn-PG +osx = osx-DE = osx-Latn = osx-Latn-DE +ota = ota-TR = *ota-Arab = ota-Arab-TR +otb-Tibt = otb-Tibt-CN +otd-Latn = otd-Latn-ID +ote = ote-MX = ote-Latn = ote-Latn-MX +oti = oti-BR = oti-Latn = oti-Latn-BR +otk = otk-MN = otk-Orkh = otk-Orkh-MN +otl = otl-MX = otl-Latn = otl-Latn-MX +otm = otm-MX = otm-Latn = otm-Latn-MX +otn = otn-MX = otn-Latn = otn-Latn-MX +otq = otq-MX = otq-Latn = otq-Latn-MX +otr = otr-SD = otr-Latn = otr-Latn-SD +ots = ots-MX = ots-Latn = ots-Latn-MX +ott = ott-MX = ott-Latn = ott-Latn-MX +otu = otu-BR = otu-Latn = otu-Latn-BR +otw = otw-CA = otw-Latn = otw-Latn-CA +otx = otx-MX = otx-Latn = otx-Latn-MX +oty-Gran = oty-Gran-IN +otz = otz-MX = otz-Latn = otz-Latn-MX +oub = oub-LR = oub-Latn = oub-Latn-LR +oue = oue-PG = oue-Latn = oue-Latn-PG +oui-Mong +ovd = ovd-SE = ovd-Latn = ovd-Latn-SE +owi = owi-PG = owi-Latn = owi-Latn-PG +owl = owl-GB = owl-Latn = owl-Latn-GB +oyd-Latn = oyd-Latn-ET +oym = oym-BR = oym-Latn = oym-Latn-BR +oyy = oyy-PG = oyy-Latn = oyy-Latn-PG +ozm = ozm-CM = *ozm-Latn = ozm-Latn-CM +*pa = pa-IN = *pa-Guru = *pa-Guru-IN +pa-Khoj = pa-Khoj-IN +pa-PK = *pa-Arab = *pa-Arab-PK +pab = pab-BR = pab-Latn = pab-Latn-BR +pac = pac-VN = pac-Latn = pac-Latn-VN +pac-Laoo-x-diacado = pac-Laoo-LA-x-diacado +pac-x-diacado = pac-VN-x-diacado = pac-Latn-x-diacado = pac-Latn-VN-x-diacado +pad = pad-BR = pad-Latn = pad-Latn-BR +pae = pae-CD = pae-Latn = pae-Latn-CD +paf = paf-BR = paf-Latn = paf-Latn-BR +pag = pag-PH = pag-Latn = pag-Latn-PH +pag-Brai = pag-Brai-PH +pah = pah-BR = pah-Latn = pah-Latn-BR +pak = pak-BR = pak-Latn = pak-Latn-BR +pal = pal-IR = pal-Phli = pal-Phli-IR +pal-Phlp = pal-Phlp-CN +pam = pam-PH = pam-Latn = pam-Latn-PH +pam-Brai = pam-Brai-PH +pao = pao-US = pao-Latn = pao-Latn-US +pap = pap-AW = pap-Latn = pap-Latn-AW +par = par-US = par-Latn = par-Latn-US +pat = pat-PG = pat-Latn = pat-Latn-PG +pau = pau-PW = pau-Latn = pau-Latn-PW +pav = pav-BR = pav-Latn = pav-Latn-BR +paw = paw-US = paw-Latn = paw-Latn-US +pax = pax-BR = pax-Latn = pax-Latn-BR +pay = pay-HN = pay-Latn = pay-Latn-HN +paz = paz-BR = paz-Latn = paz-Latn-BR +pbb = pbb-CO = pbb-Latn = pbb-Latn-CO +pbc = pbc-GY = pbc-Latn = pbc-Latn-GY +pbe = pbe-MX = pbe-Latn = pbe-Latn-MX +pbf = pbf-MX = pbf-Latn = pbf-Latn-MX +pbh = pbh-VE = pbh-Latn = pbh-Latn-VE +pbi = pbi-CM = *pbi-Latn = pbi-Latn-CM +pbo-Latn = pbo-Latn-GW +pbp-Latn = pbp-Latn-GN +pbs = pbs-MX = pbs-Latn = pbs-Latn-MX +pbt-Arab = pbt-Arab-AF +pbv-Latn = pbv-Latn-IN +pby = pby-PG = pby-Latn = pby-Latn-PG +pca = pca-MX = pca-Latn = pca-Latn-MX +pcc-Hani = pcc-Hani-CN +pcc-Latn = pcc-Latn-CN +pcd = pcd-FR = pcd-Latn = pcd-Latn-FR +pce-Mymr = pce-Mymr-MM +pcg-Knda = pcg-Knda-IN +pcg-Mlym = pcg-Mlym-IN +*pcg-Taml = pcg-Taml-IN +pci-Deva = pci-Deva-IN +pci-Orya = pci-Orya-IN +pcj-Telu = pcj-Telu-IN +pck-Latn = pck-Latn-IN +pcm = pcm-NG = *pcm-Latn = pcm-Latn-NG +pcp = pcp-BO = pcp-Latn = pcp-Latn-BO +pda = pda-PG = pda-Latn = pda-Latn-PG +pdc = pdc-US = pdc-Latn = pdc-Latn-US +pdo = pdo-ID = pdo-Latn = pdo-Latn-ID +pdt = pdt-CA = pdt-Latn = pdt-Latn-CA +pdu = pdu-MM = pdu-Latn = pdu-Latn-MM +ped = ped-PG = *ped-Latn = ped-Latn-PG +peg-Orya = peg-Orya-IN +pei = pei-MX = pei-Latn = pei-Latn-MX +pek = pek-PG = pek-Latn = pek-Latn-PG +pem = pem-CD = pem-Latn = pem-Latn-CD +peo = peo-IR = peo-Xpeo = peo-Xpeo-IR +pep = pep-PG = pep-Latn = pep-Latn-PG +peq = peq-US = peq-Latn = peq-Latn-US +pev = pev-VE = pev-Latn = pev-Latn-VE +pex = pex-PG = *pex-Latn = pex-Latn-PG +pez-Latn = pez-Latn-MY +pfa = pfa-FM = pfa-Latn = pfa-Latn-FM +pfe-Latn = pfe-Latn-CM +pfl = pfl-DE = pfl-Latn = pfl-Latn-DE +pga = pga-SS = pga-Latn = pga-Latn-SS +pgd-Khar = pgd-Khar-PK +pgg-Deva = pgg-Deva-IN +pgi = pgi-PG = pgi-Latn = pgi-Latn-PG +pgk = pgk-VU = pgk-Latn = pgk-Latn-VU +pgl = pgl-IE = pgl-Ogam = pgl-Ogam-IE +pgn-Ital = pgn-Ital-IT +phk-Mymr = phk-Mymr-IN +phl = phl-PK = *phl-Arab = phl-Arab-PK +phn = phn-LB = phn-Phnx = phn-Phnx-LB +pho = pho-LA = pho-Laoo = pho-Laoo-LA +phr = phr-PK = phr-Arab = phr-Arab-PK +pi-Deva = pi-Deva-IN +pi-Mymr = pi-Mymr-IN +pi-Sinh = pi-Sinh-IN +pi-Thai = pi-Thai-IN +pia = pia-MX = pia-Latn = pia-Latn-MX +pib = pib-PE = pib-Latn = pib-Latn-PE +pic = pic-GA = pic-Latn = pic-Latn-GA +pid = pid-VE = pid-Latn = pid-Latn-VE +pif = pif-FM = pif-Latn = pif-Latn-FM +pig = pig-PE = pig-Latn = pig-Latn-PE +pii = pii-AU = pii-Latn = pii-Latn-AU +pij = pij-CO = pij-Latn = pij-Latn-CO +pil = pil-BJ = *pil-Latn = pil-Latn-BJ +pin = pin-PG = pin-Latn = pin-Latn-PG +pio = pio-CO = pio-Latn = pio-Latn-CO +pip = pip-NG = *pip-Latn = pip-Latn-NG +pir = pir-BR = pir-Latn = pir-Latn-BR +pis = pis-SB = pis-Latn = pis-Latn-SB +piu = piu-AU = piu-Latn = piu-Latn-AU +piv = piv-SB = piv-Latn = piv-Latn-SB +pix = pix-PG = pix-Latn = pix-Latn-PG +piy-Latn = piy-Latn-NG +piz = piz-NC = piz-Latn = piz-Latn-NC +pjt = pjt-AU = pjt-Latn = pjt-Latn-AU +pka = pka-IN = pka-Brah = pka-Brah-IN +pkb = pkb-KE = pkb-Latn = pkb-Latn-KE +pkg = pkg-PG = pkg-Latn = pkg-Latn-PG +pkh-Deva = pkh-Deva-BD +pkh-Latn = pkh-Latn-BD +pkn = pkn-AU = pkn-Latn = pkn-Latn-AU +pko = pko-KE = pko-Latn = pko-Latn-KE +pkp = pkp-CK = pkp-Latn = pkp-Latn-CK +pkr-Mlym = pkr-Mlym-IN +*pl = *pl-PL = pl-Latn = pl-Latn-PL +pl-Brai = pl-Brai-PL +pla = pla-PG = *pla-Latn = pla-Latn-PG +plb = plb-VU = plb-Latn = plb-Latn-VU +plc-Latn = plc-Latn-PH +pld = pld-GB = pld-Latn = pld-Latn-GB +plg = plg-AR = plg-Latn = plg-Latn-AR +plj-Latn = plj-Latn-NG +plk-Arab = plk-Arab-PK +pll-Mymr = pll-Mymr-MM +pln = pln-CO = pln-Latn = pln-Latn-CO +plo = plo-MX = plo-Latn = plo-Latn-MX +plp-Deva = plp-Deva-NP +pls = pls-MX = pls-Latn = pls-Latn-MX +plu = plu-BR = plu-Latn = plu-Latn-BR +plv-Latn = plv-Latn-PH +plw-Latn = plw-Latn-PH +pma = pma-VU = pma-Latn = pma-Latn-VU +pme = pme-NC = pme-Latn = pme-Latn-NC +pmf-Latn = pmf-Latn-ID +pmq = pmq-MX = pmq-Latn = pmq-Latn-MX +pmr = pmr-PG = pmr-Latn = pmr-Latn-PG +pms = pms-IT = pms-Latn = pms-Latn-IT +pmt = pmt-PF = pmt-Latn = pmt-Latn-PF +pmw = pmw-US = pmw-Latn = pmw-Latn-US +pmx-Latn = pmx-Latn-IN +pmy-Latn = pmy-Latn-ID +pnb-x-landa-pk +pne-Latn = pne-Latn-MY +png = png-NG = *png-Latn = png-Latn-NG +pnh = pnh-CK = pnh-Latn = pnh-Latn-CK +pnk = pnk-BO = pnk-Latn = pnk-Latn-BO +pnn = pnn-PG = *pnn-Latn = pnn-Latn-PG +pno = pno-PE = pno-Latn = pno-Latn-PE +pnr = pnr-PG = pnr-Latn = pnr-Latn-PG +pnt = pnt-GR = pnt-Grek = pnt-Grek-GR +pnt-Cyrl = pnt-Cyrl-GR +pnt-Latn = pnt-Latn-TR +pnv = pnv-AU = pnv-Latn = pnv-Latn-AU +pnw = pnw-AU = pnw-Latn = pnw-Latn-AU +pny-Latn = pny-Latn-CM +pnz = pnz-CF = pnz-Latn = pnz-Latn-CF +poc = poc-GT = poc-Latn = poc-Latn-GT +poe = poe-MX = poe-Latn = poe-Latn-MX +pof = pof-CD = pof-Latn = pof-Latn-CD +pog = pog-BR = pog-Latn = pog-Latn-BR +poh = poh-GT = poh-Latn = poh-Latn-GT +poi = poi-MX = poi-Latn = poi-Latn-MX +pok = pok-BR = pok-Latn = pok-Latn-BR +pom = pom-US = pom-Latn = pom-Latn-US +pon = pon-FM = pon-Latn = pon-Latn-FM +poo = poo-US = poo-Latn = poo-Latn-US +pop = pop-NC = pop-Latn = pop-Latn-NC +poq = poq-MX = poq-Latn = poq-Latn-MX +pos = pos-MX = pos-Latn = pos-Latn-MX +pot = pot-US = pot-Latn = pot-Latn-US +pov-Latn = pov-Latn-GW +pow = pow-MX = pow-Latn = pow-Latn-MX +poy = poy-TZ = poy-Latn = poy-Latn-TZ +ppe = ppe-PG = ppe-Latn = ppe-Latn-PG +ppi = ppi-MX = ppi-Latn = ppi-Latn-MX +ppk-Latn = ppk-Latn-ID +ppl = ppl-SV = ppl-Latn = ppl-Latn-SV +ppn = ppn-PG = ppn-Latn = ppn-Latn-PG +ppo = ppo-PG = *ppo-Latn = ppo-Latn-PG +ppq = ppq-PG = ppq-Latn = ppq-Latn-PG +pps = pps-MX = pps-Latn = pps-Latn-MX +ppt = ppt-PG = ppt-Latn = ppt-Latn-PG +pqm = pqm-CA = pqm-Latn = pqm-Latn-CA +pra = pra-PK = pra-Khar = pra-Khar-PK +prd = prd-IR = prd-Arab = prd-Arab-IR +prf-Latn = prf-Latn-PH +*prg = *prg-001 = prg-Latn = prg-Latn-001 +pri = pri-NC = pri-Latn = pri-Latn-NC +prk-Latn = prk-Latn-MM +prm = prm-PG = prm-Latn = prm-Latn-PG +prq = prq-PE = prq-Latn = prq-Latn-PE +prr = prr-BR = prr-Latn = prr-Latn-BR +prs-Arab = prs-Arab-AF +prt = prt-TH = prt-Thai = prt-Thai-TH +prw = prw-PG = prw-Latn = prw-Latn-PG +prx-Arab = prx-Arab-IN +prx-Tibt = prx-Tibt-IN +*ps = pbu = *ps-AF = pbu-AF = ps-Arab = pbu-Arab = ps-Arab-AF = pbu-Arab-AF +psa-Latn = psa-Latn-ID +pse-Latn = pse-Latn-ID +psi-Arab = psi-Arab-AF +psm = psm-BO = psm-Latn = psm-Latn-BO +psq = psq-PG = psq-Latn = psq-Latn-PG +pss = pss-PG = *pss-Latn = pss-Latn-PG +pst-Arab = pst-Arab-PK +psu-Brah = psu-Brah-IN +psu-Deva = psu-Deva-IN +psw = psw-VU = psw-Latn = psw-Latn-VU +*pt = *pt-BR = pt-Latn = pt-Latn-BR +*pt-AO = pt-Latn-AO +pt-Brai = pt-Brai-PT +*pt-CH = pt-Latn-CH +*pt-CV = pt-Latn-CV +*pt-GW = pt-Latn-GW +*pt-LU = pt-Latn-LU +*pt-MO = pt-Latn-MO +*pt-MZ = pt-Latn-MZ +*pt-PT = pt-Latn-PT +*pt-ST = pt-Latn-ST +*pt-TL = pt-Latn-TL +pta = pta-PY = pta-Latn = pta-Latn-PY +pth = pth-BR = pth-Latn = pth-Latn-BR +pti = pti-AU = pti-Latn = pti-Latn-AU +pto = pto-BR = pto-Latn = pto-Latn-BR +ptp = ptp-PG = *ptp-Latn = ptp-Latn-PG +ptr = ptr-VU = ptr-Latn = ptr-Latn-VU +ptu-Latn = ptu-Latn-ID +ptv = ptv-VU = ptv-Latn = ptv-Latn-VU +pua = pua-MX = pua-Latn = pua-Latn-MX +pub-Latn = pub-Latn-IN +pue-latan-ar +pug-Latn = pug-Latn-BF +pui = pui-CO = pui-Latn = pui-Latn-CO +pum-Deva = pum-Deva-NP +pup = pup-PG = pup-Latn = pup-Latn-PG +pur = pur-BR = pur-Latn = pur-Latn-BR +puu = puu-GA = puu-Latn = puu-Latn-GA +puw = puw-FM = puw-Latn = puw-Latn-FM +pux = pux-PG = pux-Latn = pux-Latn-PG +pwa = pwa-PG = *pwa-Latn = pwa-Latn-PG +pwg = pwg-PG = pwg-Latn = pwg-Latn-PG +pwm-Latn = pwm-Latn-PH +pwn-Latn = pwn-Latn-TW +pwo-Mymr = pwo-Mymr-MM +pww-Thai = pww-Thai-TH +pxm = pxm-MX = pxm-Latn = pxm-Latn-MX +pym = pym-NG = pym-Latn = pym-Latn-NG +pyn = pyn-BR = pyn-Latn = pyn-Latn-BR +pyu-Hani = pyu-Hani-TW +pyu-Latn = pyu-Latn-TW +pyy = pyy-MM = pyy-Latn = pyy-Latn-MM +pzn = pzn-MM = pzn-Latn = pzn-Latn-MM +*qu = quz = *qu-PE = quz-PE = qu-Latn = quz-Latn = qu-Latn-PE = quz-Latn-PE +*qu-BO = qu-Latn-BO +*qu-EC = qu-Latn-EC +qua = qua-US = qua-Latn = qua-Latn-US +qub = qub-PE = qub-Latn = qub-Latn-PE +quc = quc-GT = quc-Latn = quc-Latn-GT +qud = qud-EC = qud-Latn = qud-Latn-EC +quf = quf-PE = quf-Latn = quf-Latn-PE +qug = qug-EC = qug-Latn = qug-Latn-EC +quh = quh-BO = quh-Latn = quh-Latn-BO +qui = qui-US = qui-Latn = qui-Latn-US +quk = quk-PE = quk-Latn = quk-Latn-PE +qul = qul-BO = qul-Latn = qul-Latn-BO +qum = qum-GT = qum-Latn = qum-Latn-GT +qup = qup-PE = qup-Latn = qup-Latn-PE +qur = qur-PE = qur-Latn = qur-Latn-PE +qus = qus-AR = qus-Latn = qus-Latn-AR +quv = quv-GT = quv-Latn = quv-Latn-GT +quw = quw-EC = quw-Latn = quw-Latn-EC +qux = qux-PE = qux-Latn = qux-Latn-PE +quy = quy-PE = quy-Latn = quy-Latn-PE +qva = qva-PE = qva-Latn = qva-Latn-PE +qvc = qvc-PE = qvc-Latn = qvc-Latn-PE +qve = qve-PE = qve-Latn = qve-Latn-PE +qvh = qvh-PE = qvh-Latn = qvh-Latn-PE +qvi = qvi-EC = qvi-Latn = qvi-Latn-EC +qvj = qvj-EC = qvj-Latn = qvj-Latn-EC +qvl = qvl-PE = qvl-Latn = qvl-Latn-PE +qvm = qvm-PE = qvm-Latn = qvm-Latn-PE +qvn = qvn-PE = qvn-Latn = qvn-Latn-PE +qvo = qvo-PE = qvo-Latn = qvo-Latn-PE +qvp = qvp-PE = qvp-Latn = qvp-Latn-PE +qvs = qvs-PE = qvs-Latn = qvs-Latn-PE +qvw = qvw-PE = qvw-Latn = qvw-Latn-PE +qvz = qvz-EC = qvz-Latn = qvz-Latn-EC +qwa = qwa-PE = qwa-Latn = qwa-Latn-PE +qwc = qwc-PE = qwc-Latn = qwc-Latn-PE +qwh = qwh-PE = qwh-Latn = qwh-Latn-PE +qws = qws-PE = qws-Latn = qws-Latn-PE +qxa = qxa-PE = qxa-Latn = qxa-Latn-PE +qxc = qxc-PE = qxc-Latn = qxc-Latn-PE +qxh = qxh-PE = qxh-Latn = qxh-Latn-PE +qxl = qxl-EC = qxl-Latn = qxl-Latn-EC +qxn = qxn-PE = qxn-Latn = qxn-Latn-PE +qxo = qxo-PE = qxo-Latn = qxo-Latn-PE +qxp = qxp-PE = qxp-Latn = qxp-Latn-PE +qxq-Arab = qxq-Arab-IR +qxr = qxr-EC = qxr-Latn = qxr-Latn-EC +qxt = qxt-PE = qxt-Latn = qxt-Latn-PE +qxu = qxu-PE = qxu-Latn = qxu-Latn-PE +qxw = qxw-PE = qxw-Latn = qxw-Latn-PE +raa-Deva = raa-Deva-NP +rab-Deva = rab-Deva-NP +rad-Latn = rad-Latn-VN +raf-Deva = raf-Deva-NP +rag = rag-KE = rag-Latn = rag-Latn-KE +rah-Beng = rah-Beng-IN +rah-Latn = rah-Latn-IN +rai = rai-PG = *rai-Latn = rai-Latn-PG +raj = mup = raj-IN = mup-IN = raj-Deva = mup-Deva = raj-Deva-IN = mup-Deva-IN +raj-Latn +rak = rak-PG = rak-Latn = rak-Latn-PG +ram = ram-BR = ram-Latn = ram-Latn-BR +rao = rao-PG = *rao-Latn = rao-Latn-PG +rap = rap-CL = rap-Latn = rap-Latn-CL +rar = rar-CK = rar-Latn = rar-Latn-CK +rav-Deva = rav-Deva-NP +raw = raw-MM = raw-Latn = raw-Latn-MM +raw-Latn-x-daruzerwang = raw-Latn-MM-x-daruzerwang +raw-Latn-x-longminorth = raw-Latn-MM-x-longminorth +raw-Latn-x-longmisouth = raw-Latn-MM-x-longmisouth +raw-Latn-x-tangsarreast = raw-Latn-MM-x-tangsarreast +raw-Latn-x-tangsarrwest = raw-Latn-MM-x-tangsarrwest +ray = ray-PF = ray-Latn = ray-Latn-PF +rbb = rbb-MM = rbb-Mymr = rbb-Mymr-MM +rcf = rcf-RE = rcf-Latn = rcf-Latn-RE +rdb-Arab = rdb-Arab-IR +rea = rea-PG = rea-Latn = rea-Latn-PG +rej = rej-ID = rej-Latn = rej-Latn-ID +rej-Rjng = rej-Rjng-ID +rel = rel-KE = *rel-Latn = rel-Latn-KE +ren = ren-VN = ren-Latn = ren-Latn-VN +res = res-NG = *res-Latn = res-Latn-NG +rey = rey-BO = rey-Latn = rey-Latn-BO +rga = rga-VU = rga-Latn = rga-Latn-VU +rgn = rgn-IT = rgn-Latn = rgn-Latn-IT +rgr = rgr-PE = rgr-Latn = rgr-Latn-PE +rgu-Latn = rgu-Latn-ID +rhg = rhg-MM = *rhg-Arab = rhg-Arab-MM +rhg-Latn = rhg-Latn-MM +rhg-Rohg = rhg-Rohg-MM +rhp = rhp-PG = rhp-Latn = rhp-Latn-PG +ria = ria-IN = ria-Latn = ria-Latn-IN +rif = rif-MA = rif-Tfng = rif-Tfng-MA +rif-Arab = rif-Arab-MA +rif-Latn = rif-Latn-MA +rif-NL = rif-Latn-NL +ril = ril-MM = ril-Latn = ril-Latn-MM +rim = rim-TZ = rim-Latn = rim-Latn-TZ +rit = rit-AU = rit-Latn = rit-Latn-AU +rji-Deva = rji-Deva-NP +rjs = rjs-NP = rjs-Deva = rjs-Deva-NP +rkb = rkb-BR = rkb-Latn = rkb-Latn-BR +rkh = rkh-CK = rkh-Latn = rkh-Latn-CK +rki-Mymr = rki-Mymr-MM +rkm-Latn = rkm-Latn-BF +rkt = rkt-BD = rkt-Beng = rkt-Beng-BD +*rm = *rm-CH = rm-Latn = rm-Latn-CH +rma = rma-NI = rma-Latn = rma-Latn-NI +rmb = rmb-AU = rmb-Latn = rmb-Latn-AU +rmc-Latn = rmc-Latn-SK +rmd = rmd-DK = rmd-Latn = rmd-Latn-DK +rme = rme-GB = rme-Latn = rme-Latn-GB +rmf = rmf-FI = rmf-Latn = rmf-Latn-FI +rmk = rmk-PG = rmk-Latn = rmk-Latn-PG +rml-Cyrl = rml-Cyrl-BY +rml-Latn = rml-Latn-PL +rmn-Cyrl = rmn-Cyrl-BG +rmn-Grek = rmn-Grek-GR +rmn-Latn = rmn-Latn-RS +rmo = rmo-CH = rmo-Latn = rmo-Latn-CH +rmp = rmp-PG = rmp-Latn = rmp-Latn-PG +rmq = rmq-ES = rmq-Latn = rmq-Latn-ES +rmt = rmt-IR = rmt-Arab = rmt-Arab-IR +rmu = rmu-SE = rmu-Latn = rmu-Latn-SE +rmw = rmw-GB = rmw-Latn = rmw-Latn-GB +rmz-Mymr = rmz-Mymr-IN +*rn = *rn-BI = rn-Latn = rn-Latn-BI +rn-Brai = rn-Brai-BI +rna = rna-Latn +rnd = rnd-CD = rnd-Latn = rnd-Latn-CD +rng = rng-MZ = rng-Latn = rng-Latn-MZ +rnl-Latn = rnl-Latn-IN +*ro = *ro-RO = ro-Latn = ro-Latn-RO +ro-Brai = ro-Brai-RO +ro-Cyrl = ro-Cyrl-MD +*ro-MD = ro-Latn-MD +rob = rob-ID = rob-Latn = rob-Latn-ID +roe = roe-PG = roe-Latn = roe-Latn-PG +*rof = *rof-TZ = rof-Latn = rof-Latn-TZ +rog = rog-VN = rog-Latn = rog-Latn-VN +rol-Latn = rol-Latn-PH +rom-Cyrl = rmy-Cyrl = rom-Cyrl-RO = rmy-Cyrl-BG +rom-Latn = rmy-Latn = rom-Latn-RO = rmy-Latn-RO +roo = roo-PG = *roo-Latn = roo-Latn-PG +rop = rop-AU = rop-Latn = rop-Latn-AU +row = row-ID = row-Latn = row-Latn-ID +rpn = rpn-VU = rpn-Latn = rpn-Latn-VU +rpt = rpt-PG = rpt-Latn = rpt-Latn-PG +rri = rri-SB = rri-Latn = rri-Latn-SB +rro = rro-PG = *rro-Latn = rro-Latn-PG +rtm = rtm-FJ = rtm-Latn = rtm-Latn-FJ +*ru = *ru-RU = ru-Cyrl = ru-Cyrl-RU +*ru-BY = ru-Cyrl-BY +ru-Brai = ru-Brai-RU +*ru-KG = ru-Cyrl-KG +*ru-KZ = ru-Cyrl-KZ +*ru-MD = ru-Cyrl-MD +*ru-UA = ru-Cyrl-UA +rub = rub-UG = rub-Latn = rub-Latn-UG +ruc = ruc-UG = ruc-Latn = ruc-Latn-UG +rue = rue-UA = rue-Cyrl = rue-Cyrl-UA +rue-Latn = rue-Latn-SK +ruf = ruf-TZ = ruf-Latn = ruf-Latn-TZ +rug = rug-SB = rug-Latn = rug-Latn-SB +ruk-Latn = ruk-Latn-NG +rup-Grek = rup-Grek-GR +rup-Latn = rup-Latn-RO +ruq-Latn = ruq-Latn-GR +rut-Cyrl = rut-Cyrl-RU +rut-Latn = rut-Latn-AZ +ruu-Latn = ruu-Latn-MY +*rw = *rw-RW = rw-Latn = rw-Latn-RW +rw-Brai = rw-Brai-RW +rwa = rwa-PG = rwa-Latn = rwa-Latn-PG +*rwk = *rwk-TZ = rwk-Latn = rwk-Latn-TZ +rwm = rwm-UG = rwm-Latn = rwm-Latn-UG +rwo = rwo-PG = *rwo-Latn = rwo-Latn-PG +rwr-Deva = rwr-Deva-IN +rxd = rxd-AU = rxd-Latn = rxd-Latn-AU +ryu = ryu-JP = ryu-Kana = ryu-Kana-JP +sa = sa-IN = *sa-Deva = sa-Deva-IN +sa-Mymr = sa-Mymr-IN +sa-Newa = sa-Newa-IN +sa-Shrd = sa-Shrd-IN +sa-Sinh = sa-Sinh-IN +saa-Latn = saa-Latn-TD +sab = sab-PA = sab-Latn = sab-Latn-PA +sac = sac-US = sac-Latn = sac-Latn-US +sad = sad-TZ = sad-Latn = sad-Latn-TZ +sae = sae-BR = sae-Latn = sae-Latn-BR +saf = saf-GH = *saf-Latn = saf-Latn-GH +*sah = *sah-RU = sah-Cyrl = sah-Cyrl-RU +saj-Latn = saj-Latn-ID +sak = sak-GA = sak-Latn = sak-Latn-GA +sam-Hebr = sam-Hebr-PS +sam-Samr = sam-Samr-PS +*saq = *saq-KE = saq-Latn = saq-Latn-KE +sar = sar-BO = sar-Latn = sar-Latn-BO +sas = sas-ID = sas-Latn = sas-Latn-ID +sas-Bali = sas-Bali-ID +sat = sat-IN = sat-Latn = sat-Latn-IN +sat-Beng = sat-Beng-IN +sat-Deva = sat-Deva-NP +sat-Olck = sat-Olck-IN +sat-Orya = sat-Orya-IN +sav = sav-SN = sav-Latn = sav-Latn-SN +*sav-Arab = sav-Arab-SN +saw-Latn = saw-Latn-ID +sax = sax-VU = sax-Latn = sax-Latn-VU +say-Latn = say-Latn-NG +saz = saz-IN = saz-Saur = saz-Saur-IN +saz-Deva = saz-Deva-IN +saz-Taml = saz-Taml-IN +saz-Telu = saz-Telu-IN +sba = sba-TD = *sba-Latn = sba-Latn-TD +sbb = sbb-SB = sbb-Latn = sbb-Latn-SB +sbc = sbc-PG = sbc-Latn = sbc-Latn-PG +sbd-Latn = sbd-Latn-BF +sbe = sbe-PG = *sbe-Latn = sbe-Latn-PG +sbh = sbh-PG = sbh-Latn = sbh-Latn-PG +sbi = sbi-PG = sbi-Latn = sbi-Latn-PG +sbk = sbk-TZ = sbk-Latn = sbk-Latn-TZ +sbl-Latn = sbl-Latn-PH +*sbp = *sbp-TZ = sbp-Latn = sbp-Latn-TZ +sbq = sbq-PG = sbq-Latn = sbq-Latn-PG +sbu-Deva = sbu-Deva-IN +sbu-Tibt = sbu-Tibt-IN +sbw = sbw-GA = sbw-Latn = sbw-Latn-GA +sby = sby-ZM = sby-Latn = sby-Latn-ZM +sc = src = sc-IT = src-IT = sc-Latn = src-Latn = sc-Latn-IT = src-Latn-IT +sce-Arab = sce-Arab-CN +sce-Latn = sce-Latn-CN +scf = scf-PA = scf-Latn = scf-Latn-PA +sch-Latn = sch-Latn-IN +sci = sci-LK = sci-Latn = sci-Latn-LK +sck = sck-IN = sck-Deva = sck-Deva-IN +sck-Beng = sck-Beng-IN +scl = scl-PK = *scl-Arab = scl-Arab-PK +scn = scn-IT = scn-Latn = scn-Latn-IT +sco = sco-GB = sco-Latn = sco-Latn-GB +scp-Deva = scp-Deva-NP +scs = scs-CA = scs-Latn = scs-Latn-CA +scs-Cans = scs-Cans-CA +*sd = *sd-PK = *sd-Arab = sd-Arab-PK +sd-Deva = sd-Deva-IN +sd-Guru = sd-Guru-IN +sd-Khoj = sd-Khoj-IN +sd-Sind = sd-Sind-IN +sda-Latn = sda-Latn-ID +sdc = sdc-IT = sdc-Latn = sdc-Latn-IT +sdh = sdh-IR = sdh-Arab = sdh-Arab-IR +sdk = sdk-PG = sdk-Latn = sdk-Latn-PG +sdm-Latn = sdm-Latn-ID +sdn-Latn = sdn-Latn-IT +sdo-Latn = sdo-Latn-MY +sdr-Beng = sdr-Beng-BD +sdr-Latn = sdr-Latn-BD +*se = *se-NO = se-Latn = se-Latn-NO +se-Cyrl = se-Cyrl-NO +*se-FI = se-Latn-FI +*se-SE = se-Latn-SE +sea-Latn = sea-Latn-MY +sec = sec-CA = sec-Latn = sec-Latn-CA +sed = sed-VN = sed-Latn = sed-Latn-VN +see = see-US = see-Latn = see-Latn-US +sef = sef-CI = *sef-Latn = sef-Latn-CI +*seh = *seh-MZ = seh-Latn = seh-Latn-MZ +sei = sei-MX = sei-Latn = sei-Latn-MX +sej = sej-PG = sej-Latn = sej-Latn-PG +sek = sek-CA = sek-Latn = sek-Latn-CA +sek-Cans = sek-Cans-CA +sel-Cyrl = sel-Cyrl-RU +seo = seo-PG = seo-Latn = seo-Latn-PG +sep-Latn = sep-Latn-BF +ser = ser-US = ser-Latn = ser-Latn-US +*ses = *ses-ML = ses-Latn = ses-Latn-ML +set-Latn = set-Latn-ID +sev-Latn = sev-Latn-CI +sew = sew-PG = sew-Latn = sew-Latn-PG +sey = sey-EC = sey-Latn = sey-Latn-EC +sez = sez-MM = sez-Latn = sez-Latn-MM +sfm-Plrd = sfm-Plrd-CN +sfw = sfw-GH = sfw-Latn = sfw-Latn-GH +*sg = *sg-CF = sg-Latn = sg-Latn-CF +sga = sga-IE = sga-Ogam = sga-Ogam-IE +sga-Latn = sga-Latn-IE +sgb-Latn = sgb-Latn-PH +sgc = sgc-KE = sgc-Latn = sgc-Latn-KE +sgd = sgd-PH = sgd-Latn = sgd-Latn-PH +*sgh-Arab = sgh-Arab-AF +sgh-Cyrl = sgh-Cyrl-TJ +sgh-Latn = sgh-Latn-TJ +sgj = sgj-IN = sgj-Deva = sgj-Deva-IN +sgn-MY-mm +sgp-Latn = sgp-Latn-IN +sgr-Arab = sgr-Arab-IR +sgs = sgs-LT = sgs-Latn = sgs-Latn-LT +sgw = sgw-ET = *sgw-Ethi = sgw-Ethi-ET +sgz = sgz-PG = *sgz-Latn = sgz-Latn-PG +sh-Latn = sh-Latn-RS +shb = shb-BR = shb-Latn = shb-Latn-BR +*she-Latn = she-Latn-ET +shg = shg-BW = shg-Latn = shg-Latn-BW +shh = shh-US = shh-Latn = shh-Latn-US +*shi = shi-MA = *shi-Tfng = *shi-Tfng-MA +shi-Arab = shi-Arab-MA +*shi-Latn = *shi-Latn-MA +shj = shj-SD = shj-Latn = shj-Latn-SD +shk = shk-SS = *shk-Latn = shk-Latn-SS +shm-Arab = shm-Arab-IR +shn = shn-MM = *shn-Mymr = shn-Mymr-MM +shn-Mymr-x-taimau = shn-Mymr-MM-x-taimau +shn-Tale-x-taimauold = shn-Tale-MM-x-taimauold +shn-Thai = shn-Thai-TH +shp = shp-PE = shp-Latn = shp-Latn-PE +shq = shq-ZM = shq-Latn = shq-Latn-ZM +shr = shr-CD = shr-Latn = shr-Latn-CD +shs = shs-CA = shs-Latn = shs-Latn-CA +shu = shu-TD = *shu-Arab = shu-Arab-TD +*shu-Latn = shu-Latn-TD +shw = shw-SD = shw-Latn = shw-Latn-SD +shy-Arab = shy-Arab-DZ +shy-Latn = shy-Latn-DZ +shy-Tfng = shy-Tfng-DZ +shz-Latn = shz-Latn-ML +*si = *si-LK = si-Sinh = si-Sinh-LK +si-Brai = si-Brai-LK +*sid = sid-ET = sid-Latn = sid-Latn-ET +sid-Ethi = sid-Ethi-ET +sie = sie-ZM = sie-Latn = sie-Latn-ZM +sif-Latn = sif-Latn-BF +sig = sig-GH = *sig-Latn = sig-Latn-GH +sih = sih-NC = sih-Latn = sih-Latn-NC +sij = sij-PG = sij-Latn = sij-Latn-PG +sik = sik-BR = sik-Latn = sik-Latn-BR +sil = sil-GH = *sil-Latn = sil-Latn-GH +sim = sim-PG = *sim-Latn = sim-Latn-PG +sip-Tibt = sip-Tibt-IN +siq = siq-PG = siq-Latn = siq-Latn-PG +siu = siu-PG = siu-Latn = siu-Latn-PG +siv = siv-PG = siv-Latn = siv-Latn-PG +siw = siw-PG = siw-Latn = siw-Latn-PG +six = six-PG = six-Latn = six-Latn-PG +sja = sja-CO = sja-Latn = sja-Latn-CO +sjd-Cyrl = sjd-Cyrl-RU +sjl-Latn = sjl-Latn-IN +sjm-Latn = sjm-Latn-PH +sjo-Cyrl = sjo-Cyrl-CN +sjo-Latn = sjo-Latn-CN +sjo-Mong-x-manchu = sjo-Mong-CN-x-manchu +sjo-Mong-x-sibe = sjo-Mong-CN-x-sibe +sjp-Deva = sjp-Deva-IN +sjr = sjr-PG = *sjr-Latn = sjr-Latn-PG +sju = sju-SE = sju-Latn = sju-Latn-SE +sjw = sjw-US = sjw-Latn = sjw-Latn-US +*sk = *sk-SK = sk-Latn = sk-Latn-SK +sk-Brai = sk-Brai-SK +ska = ska-US = ska-Latn = ska-Latn-US +skc = skc-PG = *skc-Latn = skc-Latn-PG +skd = skd-US = skd-Latn = skd-Latn-US +ske = ske-VU = ske-Latn = ske-Latn-VU +skf = skf-BR = skf-Latn = skf-Latn-BR +skm = skm-PG = skm-Latn = skm-Latn-PG +skn-Latn = skn-Latn-PH +skr = skr-PK = *skr-Arab = skr-Arab-PK +skr-Deva = skr-Deva-PK +skr-Guru = skr-Guru-PK +skr-Khoj = skr-Khoj-PK +sks = sks-PG = *sks-Latn = sks-Latn-PG +skt = skt-CD = skt-Latn = skt-Latn-CD +sku = sku-VU = sku-Latn = sku-Latn-VU +skv-Latn = skv-Latn-ID +skx-Latn = skx-Latn-ID +sky = sky-SB = sky-Latn = sky-Latn-SB +*sl = *sl-SI = sl-Latn = sl-Latn-SI +sl-Brai = sl-Brai-SI +slc = slc-CO = slc-Latn = slc-Latn-CO +sld = sld-BF = *sld-Latn = sld-Latn-BF +slh = slh-US = slh-Latn = slh-Latn-US +sli = sli-PL = sli-Latn = sli-Latn-PL +slj = slj-BR = slj-Latn = slj-Latn-BR +sll = sll-PG = *sll-Latn = sll-Latn-PG +slm-Latn = slm-Latn-PH +slu-Latn = slu-Latn-ID +slw = slw-PG = slw-Latn = slw-Latn-PG +slx = slx-CD = slx-Latn = slx-Latn-CD +sly = sly-ID = sly-Latn = sly-Latn-ID +sm = sm-WS = sm-Latn = sm-Latn-WS +sma = sma-SE = sma-Latn = sma-Latn-SE +smb = smb-PG = smb-Latn = smb-Latn-PG +smd = smd-AO = smd-Latn = smd-Latn-AO +smf = smf-PG = smf-Latn = smf-Latn-PG +smg = smg-PG = smg-Latn = smg-Latn-PG +smh-Yiii-x-traditional = smh-Yiii-CN-x-traditional +smj = smj-SE = smj-Latn = smj-Latn-SE +smk-Latn = smk-Latn-PH +sml-Latn = sml-Latn-PH +*smn = *smn-FI = smn-Latn = smn-Latn-FI +smp = smp-IL = smp-Samr = smp-Samr-IL +smp-Arab = smp-Arab-PS +smp-Hebr = smp-Hebr-PS +smq = smq-PG = *smq-Latn = smq-Latn-PG +sms = sms-FI = sms-Latn = sms-Latn-FI +smt-Latn = smt-Latn-IN +smx = smx-CD = smx-Latn = smx-Latn-CD +smy-Arab = smy-Arab-IR +smz = smz-PG = smz-Latn = smz-Latn-PG +*sn = *sn-ZW = sn-Latn = sn-Latn-ZW +sn-Brai = sn-Brai-ZW +snc = snc-PG = *snc-Latn = snc-Latn-PG +sne-Latn = sne-Latn-MY +snf-Latn = snf-Latn-SN +sng = sng-CD = sng-Latn = sng-Latn-CD +sng-Brai = sng-Brai-CD +snk = snk-ML = *snk-Latn = snk-Latn-ML +*snk-Arab = snk-Arab-ML +snl-Latn = snl-Latn-PH +snn = snn-CO = snn-Latn = snn-Latn-CO +sno = sno-US = sno-Latn = sno-Latn-US +snp = snp-PG = *snp-Latn = snp-Latn-PG +snq = snq-GA = snq-Latn = snq-Latn-GA +snr = snr-PG = snr-Latn = snr-Latn-PG +sns = sns-VU = sns-Latn = sns-Latn-VU +snv-Latn = snv-Latn-MY +snw = snw-GH = snw-Latn = snw-Latn-GH +snx = snx-PG = *snx-Latn = snx-Latn-PG +sny = sny-PG = *sny-Latn = sny-Latn-PG +snz = snz-PG = snz-Latn = snz-Latn-PG +*so = *so-SO = so-Latn = so-Latn-SO +*so-Arab = so-Arab-SO +*so-DJ = so-Latn-DJ +*so-ET = so-Latn-ET +*so-KE = so-Latn-KE +so-Osma = so-Osma-SO +soa = soa-TH = soa-Tavt = soa-Tavt-TH +soa-Thai = soa-Thai-TH +sob-Latn = sob-Latn-ID +soc = soc-CD = soc-Latn = soc-Latn-CD +sog-Sogo +sok = sok-TD = *sok-Latn = sok-Latn-TD +sol = sol-PG = sol-Latn = sol-Latn-PG +sop = sop-CD = sop-Latn = sop-Latn-CD +soq = soq-PG = *soq-Latn = soq-Latn-PG +sor-Latn = sor-Latn-TD +sou = sou-TH = sou-Thai = sou-Thai-TH +sov = sov-PW = sov-Latn = sov-Latn-PW +sow = sow-PG = sow-Latn = sow-Latn-PG +sox-Latn = sox-Latn-CM +soy = soy-BJ = *soy-Latn = soy-Latn-BJ +soz = soz-TZ = soz-Latn = soz-Latn-TZ +spc = spc-VE = spc-Latn = spc-Latn-VE +spd = spd-PG = *spd-Latn = spd-Latn-PG +spe = spe-PG = spe-Latn = spe-Latn-PG +spk = spk-PG = spk-Latn = spk-Latn-PG +spl = spl-PG = *spl-Latn = spl-Latn-PG +spm = spm-PG = spm-Latn = spm-Latn-PG +spn = spn-PY = spn-Latn = spn-Latn-PY +spo = spo-US = spo-Latn = spo-Latn-US +spp-Latn = spp-Latn-ML +spq = spq-PE = spq-Latn = spq-Latn-PE +sps = sps-PG = *sps-Latn = sps-Latn-PG +spt = spt-IN = spt-Tibt = spt-Tibt-IN +spv-Orya = spv-Orya-IN +*sq = als = *sq-AL = als-AL = sq-Latn = als-Latn = sq-Latn-AL = als-Latn-AL +sq-Brai = sq-Brai-AL +sq-Elsa = sq-Elsa-AL +sq-Grek = als-Grek = sq-Grek-GR = als-Grek-GR +*sq-MK = sq-Latn-MK +sqm = sqm-CF = sqm-Latn = sqm-Latn-CF +sqt-Arab = sqt-Arab-YE +sqt-Latn = sqt-Latn-YE +squ = squ-CA = squ-Latn = squ-Latn-CA +*sr = sr-RS = *sr-Cyrl = *sr-Cyrl-RS +sr-Brai = sr-Brai-RS +*sr-Cyrl-BA +*sr-Cyrl-ME +*sr-Cyrl-XK +*sr-Latn = *sr-Latn-RS +*sr-Latn-BA +*sr-Latn-XK +sr-ME = *sr-Latn-ME +sr-RO = sr-Latn-RO +sr-RU = sr-Latn-RU +sr-TR = sr-Latn-TR +sra = sra-PG = sra-Latn = sra-Latn-PG +srb = srb-IN = srb-Sora = srb-Sora-IN +srb-Latn = srb-Latn-IN +srb-Orya = srb-Orya-IN +srb-Telu = srb-Telu-IN +sre-Latn = sre-Latn-ID +srf = srf-PG = srf-Latn = srf-Latn-PG +sri = sri-CO = sri-Latn = sri-Latn-CO +srl-Latn = srl-Latn-ID +srm = srm-SR = srm-Latn = srm-Latn-SR +srn = srn-SR = *srn-Latn = srn-Latn-SR +sro-Latn = sro-Latn-IT +srq = srq-BO = srq-Latn = srq-Latn-BO +srr = srr-SN = *srr-Latn = srr-Latn-SN +*srr-Arab = srr-Arab-SN +srs = srs-CA = srs-Latn = srs-Latn-CA +sru = sru-BR = sru-Latn = sru-Latn-BR +srx = srx-IN = srx-Deva = srx-Deva-IN +srx-Takr = srx-Takr-IN +sry = sry-PG = sry-Latn = sry-Latn-PG +*ss = *ss-ZA = ss-Latn = ss-Latn-ZA +*ss-SZ = ss-Latn-SZ +ssb-Latn = ssb-Latn-PH +ssc = ssc-TZ = ssc-Latn = ssc-Latn-TZ +ssd = ssd-PG = *ssd-Latn = ssd-Latn-PG +sse-Arab = sse-Arab-PH +sse-Latn = sse-Latn-PH +ssf-Latn = ssf-Latn-TW +ssg = ssg-PG = *ssg-Latn = ssg-Latn-PG +ssj = ssj-PG = ssj-Latn = ssj-Latn-PG +ssl = ssl-GH = ssl-Latn = ssl-Latn-GH +ssn = ssn-KE = ssn-Latn = ssn-Latn-KE +sso = sso-PG = sso-Latn = sso-Latn-PG +sss-Laoo = sss-Laoo-LA +sss-Thai = sss-Thai-TH +sst = sst-PG = sst-Latn = sst-Latn-PG +ssu = ssu-PG = ssu-Latn = ssu-Latn-PG +ssv = ssv-VU = ssv-Latn = ssv-Latn-VU +ssx = ssx-PG = ssx-Latn = ssx-Latn-PG +*ssy = *ssy-ER = ssy-Latn = ssy-Latn-ER +ssy-Ethi = ssy-Ethi-ET +ssz = ssz-PG = ssz-Latn = ssz-Latn-PG +*st = st-ZA = st-Latn = st-Latn-ZA +*st-LS = st-Latn-LS +sta = sta-ZM = sta-Latn = sta-Latn-ZM +stb-Latn = stb-Latn-PH +ste-Latn = ste-Latn-ID +stf = stf-PG = stf-Latn = stf-Latn-PG +sth = sth-IE = sth-Latn = sth-Latn-IE +sti = sti-VN = sti-Latn = sti-Latn-VN +stk = stk-PG = *stk-Latn = stk-Latn-PG +stm = stm-PG = stm-Latn = stm-Latn-PG +stn = stn-SB = stn-Latn = stn-Latn-SB +sto = sto-CA = sto-Latn = sto-Latn-CA +stp = stp-MX = stp-Latn = stp-Latn-MX +stq = stq-DE = stq-Latn = stq-Latn-DE +str = str-CA = str-Latn = str-Latn-CA +stt = stt-VN = stt-Latn = stt-Latn-VN +stv-Ethi = stv-Ethi-ET +stw = stw-FM = stw-Latn = stw-Latn-FM +su = su-ID = su-Latn = su-Latn-ID +su-Arab = su-Arab-ID +*su-Java = su-Java-ID +*su-Sund = su-Sund-ID +sua = sua-PG = *sua-Latn = sua-Latn-PG +sub = sub-CD = sub-Latn = sub-Latn-CD +suc-Latn = suc-Latn-PH +sue = sue-PG = *sue-Latn = sue-Latn-PG +sug = sug-PG = sug-Latn = sug-Latn-PG +sui = sui-PG = sui-Latn = sui-Latn-PG +suj = suj-TZ = suj-Latn = suj-Latn-TZ +suk = suk-TZ = suk-Latn = suk-Latn-TZ +*suq-Ethi = suq-Ethi-ET +*suq-Latn = suq-Latn-ET +sur = sur-NG = *sur-Latn = sur-Latn-NG +sus = sus-GN = *sus-Latn = sus-Latn-GN +*sus-Arab = sus-Arab-GN +suv-Beng = suv-Beng-IN +suv-Deva = suv-Deva-IN +suv-Latn = suv-Latn-IN +suy = suy-BR = suy-Latn = suy-Latn-BR +suz-Deva = suz-Deva-NP +*sv = *sv-SE = sv-Latn = sv-Latn-SE +sv-Brai = sv-Brai-SE +*sv-FI = sv-Latn-FI +sva-Cyrl = sva-Cyrl-GE +sva-Geor = sva-Geor-GE +sva-Latn = sva-Latn-GE +svb = svb-PG = svb-Latn = svb-Latn-PG +svc = svc-VC = svc-Latn = svc-Latn-VC +svm-Latn = svm-Latn-IT +svs = svs-SB = svs-Latn = svs-Latn-SB +*sw = swh = *sw-TZ = swh-TZ = sw-Latn = swh-Latn = sw-Latn-TZ = swh-Latn-TZ +*sw-Arab = sw-Arab-TZ +*sw-KE = sw-Latn-KE +*sw-UG = sw-Latn-UG +swb = swb-YT = swb-Arab = swb-Arab-YT +swb-Latn = swb-Latn-YT +*swc = swc-CD = swc-Latn = swc-Latn-CD +swg = swg-DE = swg-Latn = swg-Latn-DE +swh-Brai = swh-Brai-TZ +swi-Hani = swi-Hani-CN +swj = swj-GA = swj-Latn = swj-Latn-GA +swk-Latn = swk-Latn-MW +swm = swm-PG = swm-Latn = swm-Latn-PG +swo = swo-BR = swo-Latn = swo-Latn-BR +swp = swp-PG = *swp-Latn = swp-Latn-PG +swv = swv-IN = swv-Deva = swv-Deva-IN +swx = swx-BR = swx-Latn = swx-Latn-BR +sxb = sxb-KE = sxb-Latn = sxb-Latn-KE +sxe = sxe-GA = sxe-Latn = sxe-Latn-GA +sxn = sxn-ID = sxn-Latn = sxn-Latn-ID +sxu-Latn = sxu-Latn-DE +sxw = sxw-BJ = *sxw-Latn = sxw-Latn-BJ +syb-Latn = syb-Latn-PH +syc-Syrc = syc-Syrc-TR +syi = syi-GA = syi-Latn = syi-Latn-GA +syk = syk-NG = syk-Latn = syk-Latn-NG +syl = syl-BD = syl-Beng = syl-Beng-BD +syl-Latn = syl-Latn-BD +*syl-Sylo = syl-Sylo-BD +syn-Syrc = syn-Syrc-IR +syo = syo-KH = syo-Latn = syo-Latn-KH +*syr = cld = syr-IQ = cld-IQ = syr-Syrc = cld-Syrc = syr-Syrc-IQ = cld-Syrc-IQ +syw-Deva = syw-Deva-NP +syx = syx-GA = syx-Latn = syx-Latn-GA +szb = szb-ID = szb-Latn = szb-Latn-ID +szg = szg-CD = szg-Latn = szg-Latn-CD +szl = szl-PL = szl-Latn = szl-Latn-PL +szv-Latn = szv-Latn-CM +szw-Latn = szw-Latn-ID +*ta = *ta-IN = ta-Taml = ta-Taml-IN +ta-Brai = ta-Brai-IN +*ta-LK = ta-Taml-LK +*ta-MY = ta-Taml-MY +*ta-SG = ta-Taml-SG +taa = taa-US = taa-Latn = taa-Latn-US +tab = tab-RU = tab-Cyrl = tab-Cyrl-RU +tac = tac-MX = tac-Latn = tac-Latn-MX +tae = tae-BR = tae-Latn = tae-Latn-BR +taf = taf-BR = taf-Latn = taf-Latn-BR +taj = taj-NP = taj-Deva = taj-Deva-NP +taj-Tibt-x-tamhig = taj-Tibt-BT-x-tamhig +tal = tal-NG = *tal-Latn = tal-Latn-NG +tan = tan-NG = *tan-Latn = tan-Latn-NG +tao-Latn = tao-Latn-TW +tap = tap-CD = tap-Latn = tap-Latn-CD +taq = taq-ML = *taq-Latn = taq-Latn-ML +taq-Tfng = taq-Tfng-ML +tar = tar-MX = tar-Latn = tar-Latn-MX +tau = tau-US = tau-Latn = tau-Latn-US +tav = tav-CO = tav-Latn = tav-Latn-CO +taw = taw-PG = taw-Latn = taw-Latn-PG +tay-Hans = tay-Hans-TW +tay-Hant = tay-Hant-TW +tay-Latn = tay-Latn-TW +taz = taz-SD = taz-Latn = taz-Latn-SD +tba = tba-BR = tba-Latn = tba-Latn-BR +tbb = tbb-BR = tbb-Latn = tbb-Latn-BR +tbc = tbc-PG = *tbc-Latn = tbc-Latn-PG +tbd = tbd-PG = *tbd-Latn = tbd-Latn-PG +tbe = tbe-SB = tbe-Latn = tbe-Latn-SB +tbf = tbf-PG = *tbf-Latn = tbf-Latn-PG +tbg = tbg-PG = *tbg-Latn = tbg-Latn-PG +tbi = tbi-SD = tbi-Latn = tbi-Latn-SD +tbj = tbj-PG = tbj-Latn = tbj-Latn-PG +tbk-Latn = tbk-Latn-PH +tbk-Tagb = tbk-Tagb-PH +tbl-Latn = tbl-Latn-PH +tbn = tbn-CO = tbn-Latn = tbn-Latn-CO +tbo = tbo-PG = *tbo-Latn = tbo-Latn-PG +tbs = tbs-PG = tbs-Latn = tbs-Latn-PG +tbt = tbt-CD = tbt-Latn = tbt-Latn-CD +tbv = tbv-PG = tbv-Latn = tbv-Latn-PG +tbw = tbw-PH = tbw-Latn = tbw-Latn-PH +tbw-Tagb = tbw-Tagb-PH +tbx = tbx-PG = tbx-Latn = tbx-Latn-PG +tby-Latn = tby-Latn-ID +tbz = tbz-BJ = *tbz-Latn = tbz-Latn-BJ +tca = tca-BR = tca-Latn = tca-Latn-BR +tcb = tcb-US = tcb-Latn = tcb-Latn-US +tcc = tcc-TZ = tcc-Latn = tcc-Latn-TZ +tcd = tcd-GH = tcd-Latn = tcd-Latn-GH +tce = tce-CA = tce-Latn = tce-Latn-CA +tcf = tcf-MX = tcf-Latn = tcf-Latn-MX +tci = tci-PG = *tci-Latn = tci-Latn-PG +tck = tck-GA = tck-Latn = tck-Latn-GA +tcp = tcp-MM = tcp-Latn = tcp-Latn-MM +tcs = tcs-AU = tcs-Latn = tcs-Latn-AU +tcu = tcu-MX = tcu-Latn = tcu-Latn-MX +tcw = tcw-MX = tcw-Latn = tcw-Latn-MX +tcx-Taml = tcx-Taml-IN +tcy = tcy-IN = tcy-Knda = tcy-Knda-IN +tcy-x-in-tulu +tcz-Latn = tcz-Latn-IN +tda-Arab = tda-Arab-NE +tda-Latn = tda-Latn-NE +tda-Tfng = tda-Tfng-NE +tdb-Beng = tdb-Beng-IN +tdb-Deva = tdb-Deva-IN +tdb-Kthi = tdb-Kthi-IN +tdc = tdc-CO = tdc-Latn = tdc-Latn-CO +tdd = tdd-CN = *tdd-Tale = tdd-Tale-CN +tdd-MM = tdd-Tale-MM +tdg = tdg-NP = tdg-Deva = tdg-Deva-NP +tdg-Tibt = tdg-Tibt-NP +tdh = tdh-NP = tdh-Deva = tdh-Deva-NP +tdm = tdm-GY = tdm-Latn = tdm-Latn-GY +tdn-Latn = tdn-Latn-ID +tdt = tdt-TL = tdt-Latn = tdt-Latn-TL +tdx = tdx-MG = tdx-Latn = tdx-Latn-MG +*te = *te-IN = te-Telu = te-Telu-IN +te-Brai = te-Brai-IN +tec = tec-KE = tec-Latn = tec-Latn-KE +ted = ted-CI = *ted-Latn = ted-Latn-CI +tee = tee-MX = tee-Latn = tee-Latn-MX +teg = teg-GA = teg-Latn = teg-Latn-GA +teh = teh-AR = teh-Latn = teh-Latn-AR +tei = tei-PG = tei-Latn = tei-Latn-PG +tek = tek-CD = tek-Latn = tek-Latn-CD +*tem = tem-SL = tem-Latn = tem-Latn-SL +ten = ten-CO = ten-Latn = ten-Latn-CO +*teo = *teo-UG = teo-Latn = teo-Latn-UG +*teo-KE = teo-Latn-KE +teq = teq-SD = teq-Latn = teq-Latn-SD +ter = ter-BR = ter-Latn = ter-Latn-BR +tes-Java = tes-Java-ID +tet = tet-TL = tet-Latn = tet-Latn-TL +tew = tew-US = tew-Latn = tew-Latn-US +tex = tex-SS = tex-Latn = tex-Latn-SS +tey = tey-SD = tey-Latn = tey-Latn-SD +tfi = tfi-BJ = *tfi-Latn = tfi-Latn-BJ +tfn = tfn-US = tfn-Latn = tfn-Latn-US +tfr = tfr-PA = tfr-Latn = tfr-Latn-PA +*tg = *tg-TJ = tg-Cyrl = tg-Cyrl-TJ +tg-Hebr = tg-Hebr-UZ +tg-Latn = tg-Latn-TJ +tg-PK = tg-Arab = tg-Arab-PK +tga = tga-KE = tga-Latn = tga-Latn-KE +tgb-Latn = tgb-Latn-MY +tgc = tgc-PG = *tgc-Latn = tgc-Latn-PG +tgi = tgi-PG = tgi-Latn = tgi-Latn-PG +tgo = tgo-PG = *tgo-Latn = tgo-Latn-PG +tgp = tgp-VU = tgp-Latn = tgp-Latn-VU +tgs = tgs-VU = tgs-Latn = tgs-Latn-VU +tgt = tgt-PH = tgt-Latn = tgt-Latn-PH +tgu = tgu-PG = *tgu-Latn = tgu-Latn-PG +tgv = tgv-BR = tgv-Latn = tgv-Latn-BR +tgw-Latn = tgw-Latn-CI +tgx = tgx-CA = tgx-Latn = tgx-Latn-CA +*th = *th-TH = th-Thai = th-Thai-TH +th-Brai = th-Brai-TH +thd = thd-AU = thd-Latn = thd-Latn-AU +the-Deva = the-Deva-NP +thf-Deva = thf-Deva-NP +thh = thh-MX = thh-Latn = thh-Latn-MX +thk = thk-KE = thk-Latn = thk-Latn-KE +thl = thl-NP = thl-Deva = thl-Deva-NP +thp = thp-CA = thp-Latn = thp-Latn-CA +thq = thq-NP = thq-Deva = thq-Deva-NP +thr = thr-NP = thr-Deva = thr-Deva-NP +ths-Deva = ths-Deva-NP +tht = tht-CA = tht-Latn = tht-Latn-CA +thu = thu-SS = thu-Latn = thu-Latn-SS +thv-Arab = thv-Arab-DZ +thv-Tfng = thv-Tfng-DZ +thz-Latn = thz-Latn-NE +thz-Tfng = thz-Tfng-NE +*ti = *ti-ET = ti-Ethi = ti-Ethi-ET +*ti-ER = ti-Ethi-ER +tic = tic-SD = tic-Latn = tic-Latn-SD +tif = tif-PG = *tif-Latn = tif-Latn-PG +*tig = tig-ER = tig-Ethi = tig-Ethi-ER +tih-Latn = tih-Latn-MY +tii = tii-CD = tii-Latn = tii-Latn-CD +tij-Deva = tij-Deva-NP +tik = tik-CM = *tik-Latn = tik-Latn-CM +tim = tim-PG = *tim-Latn = tim-Latn-PG +tio = tio-PG = *tio-Latn = tio-Latn-PG +tis = tis-PH = tis-Latn = tis-Latn-PH +tit = tit-CO = tit-Latn = tit-Latn-CO +tiu-Latn = tiu-Latn-PH +tiv = tiv-NG = *tiv-Latn = tiv-Latn-NG +tiw = tiw-AU = tiw-Latn = tiw-Latn-AU +tix = tix-US = tix-Latn = tix-Latn-US +tiy-Latn = tiy-Latn-PH +tjl-Mymr = tjl-Mymr-MM +tjw = tjw-AU = tjw-Latn = tjw-Latn-AU +*tk = *tk-TM = tk-Latn = tk-Latn-TM +tk-Arab = tk-Arab-AF +tk-Cyrl = tk-Cyrl-TM +tka = tka-BR = tka-Latn = tka-Latn-BR +tkb-Deva = tkb-Deva-IN +tkd = tkd-TL = tkd-Latn = tkd-Latn-TL +tke-Latn = tke-Latn-MZ +tkf = tkf-BR = tkf-Latn = tkf-Latn-BR +tkg = tkg-MG = tkg-Latn = tkg-Latn-MG +tkl = tkl-TK = tkl-Latn = tkl-Latn-TK +tkp = tkp-SB = tkp-Latn = tkp-Latn-SB +tkr = tkr-AZ = tkr-Latn = tkr-Latn-AZ +tkr-Cyrl = tkr-Cyrl-RU +tks-Arab = tks-Arab-IR +tkt = tkt-NP = tkt-Deva = tkt-Deva-NP +tku = tku-MX = tku-Latn = tku-Latn-MX +tkv = tkv-PG = tkv-Latn = tkv-Latn-PG +tkw = tkw-SB = tkw-Latn = tkw-Latn-SB +tl = tl-PH = tl-Latn = tl-Latn-PH +tl-Brai = tl-Brai-PH +tl-Tglg = tl-Tglg-PH +tla = tla-MX = tla-Latn = tla-Latn-MX +tlb-Latn = tlb-Latn-ID +tlc = tlc-MX = tlc-Latn = tlc-Latn-MX +tld-Latn = tld-Latn-ID +tlf = tlf-PG = *tlf-Latn = tlf-Latn-PG +tli-Cyrl = tli-Cyrl-US +tli-Latn = tli-Latn-US +tlj = tlj-UG = tlj-Latn = tlj-Latn-UG +tll = tll-CD = tll-Latn = tll-Latn-CD +tlm = tlm-VU = tlm-Latn = tlm-Latn-VU +tlp = tlp-MX = tlp-Latn = tlp-Latn-MX +tlq = tlq-MM = tlq-Latn = tlq-Latn-MM +tlr = tlr-SB = tlr-Latn = tlr-Latn-SB +tls = tls-VU = tls-Latn = tls-Latn-VU +tlx = tlx-PG = *tlx-Latn = tlx-Latn-PG +tly = tly-AZ = tly-Latn = tly-Latn-AZ +tly-Arab = tly-Arab-AZ +tly-Cyrl = tly-Cyrl-AZ +tmb = tmb-VU = tmb-Latn = tmb-Latn-VU +tmc-Latn = tmc-Latn-TD +tmd = tmd-PG = tmd-Latn = tmd-Latn-PG +tme = tme-BR = tme-Latn = tme-Latn-BR +tmf = tmf-PY = tmf-Latn = tmf-Latn-PY +tmh = ttq = tmh-NE = ttq-NE = tmh-Latn = *ttq-Latn = tmh-Latn-NE = ttq-Latn-NE +tmh-Arab = *ttq-Arab = tmh-Arab-NE = ttq-Arab-NE +tmh-Tfng = *ttq-Tfng = tmh-Tfng-NE = ttq-Tfng-NE +tmi = tmi-VU = tmi-Latn = tmi-Latn-VU +tmk-Deva = tmk-Deva-NP +tmq = tmq-PG = tmq-Latn = tmq-Latn-PG +tmt = tmt-VU = tmt-Latn = tmt-Latn-VU +tmu-Latn = tmu-Latn-ID +tmy = tmy-PG = *tmy-Latn = tmy-Latn-PG +*tn = *tn-ZA = tn-Latn = tn-Latn-ZA +*tn-BW = tn-Latn-BW +tna = tna-BO = tna-Latn = tna-Latn-BO +tnb = tnb-CO = tnb-Latn = tnb-Latn-CO +tnc = tnc-CO = tnc-Latn = tnc-Latn-CO +tnd = tnd-CO = tnd-Latn = tnd-Latn-CO +tng-Latn = tng-Latn-TD +tnh = tnh-PG = *tnh-Latn = tnh-Latn-PG +tnk = tnk-VU = tnk-Latn = tnk-Latn-VU +tnl = tnl-VU = tnl-Latn = tnl-Latn-VU +tnm-Latn = tnm-Latn-ID +tnn = tnn-VU = tnn-Latn = tnn-Latn-VU +tno = tno-BO = tno-Latn = tno-Latn-BO +tnp = tnp-VU = tnp-Latn = tnp-Latn-VU +tnr-Latn = tnr-Latn-SN +tns = tns-PG = tns-Latn = tns-Latn-PG +tnt-Latn = tnt-Latn-ID +tnv-Cakm = tnv-Cakm-BD +tnx = tnx-SB = tnx-Latn = tnx-Latn-SB +*to = *to-TO = to-Latn = to-Latn-TO +tob = tob-AR = tob-Latn = tob-Latn-AR +toc = toc-MX = toc-Latn = toc-Latn-MX +tod-Latn = tod-Latn-GN +tof = tof-PG = *tof-Latn = tof-Latn-PG +tog = tog-MW = tog-Latn = tog-Latn-MW +toh-Latn = toh-Latn-MZ +toi = toi-ZM = toi-Latn = toi-Latn-ZM +toj = toj-MX = toj-Latn = toj-Latn-MX +tol = tol-US = tol-Latn = tol-Latn-US +tom-Latn = tom-Latn-ID +too = too-MX = too-Latn = too-Latn-MX +top = top-MX = top-Latn = top-Latn-MX +toq = toq-SS = *toq-Latn = toq-Latn-SS +tos = tos-MX = tos-Latn = tos-Latn-MX +tow = tow-US = tow-Latn = tow-Latn-US +tox = tox-PW = tox-Latn = tox-Latn-PW +tpa = tpa-PG = tpa-Latn = tpa-Latn-PG +tpc = tpc-MX = tpc-Latn = tpc-Latn-MX +tpe-Beng = tpe-Beng-BD +tpe-Latn = tpe-Latn-BD +tpg-Latn = tpg-Latn-ID +tpi = tpi-PG = tpi-Latn = tpi-Latn-PG +tpj = tpj-PY = tpj-Latn = tpj-Latn-PY +tpk = tpk-BR = tpk-Latn = tpk-Latn-BR +tpl = tpl-MX = tpl-Latn = tpl-Latn-MX +tpm = tpm-GH = *tpm-Latn = tpm-Latn-GH +tpp = tpp-MX = tpp-Latn = tpp-Latn-MX +tpr = tpr-BR = tpr-Latn = tpr-Latn-BR +tpt = tpt-MX = tpt-Latn = tpt-Latn-MX +tpu-Khmr = tpu-Khmr-KH +tpv = tpv-MP = tpv-Latn = tpv-Latn-MP +tpx = tpx-MX = tpx-Latn = tpx-Latn-MX +tpy = tpy-BR = tpy-Latn = tpy-Latn-BR +tpz = tpz-PG = *tpz-Latn = tpz-Latn-PG +tqb = tqb-BR = tqb-Latn = tqb-Latn-BR +tql = tql-VU = tql-Latn = tql-Latn-VU +tqm = tqm-PG = tqm-Latn = tqm-Latn-PG +tqn = tqn-US = tqn-Latn = tqn-Latn-US +tqo = tqo-PG = *tqo-Latn = tqo-Latn-PG +tqp = tqp-PG = tqp-Latn = tqp-Latn-PG +tqt = tqt-MX = tqt-Latn = tqt-Latn-MX +tqu = tqu-SB = tqu-Latn = tqu-Latn-SB +*tr = *tr-TR = tr-Latn = tr-Latn-TR +tr-Arab = tr-Arab-TR +tr-Brai = tr-Brai-TR +*tr-CY = tr-Latn-CY +tr-Cyrl = tr-Cyrl-BG +tr-Grek = tr-Grek-TR +trb = trb-PG = trb-Latn = trb-Latn-PG +trc = trc-MX = trc-Latn = trc-Latn-MX +trg-Hebr = trg-Hebr-IL +trh = trh-PG = trh-Latn = trh-Latn-PG +tri = tri-SR = tri-Latn = tri-Latn-SR +trn = trn-BO = trn-Latn = trn-Latn-BO +tro-Latn = tro-Latn-IN +trp-Beng = trp-Beng-IN +trp-Latn = trp-Latn-IN +trq = trq-MX = trq-Latn = trq-Latn-MX +trr = trr-PE = trr-Latn = trr-Latn-PE +trs = trs-MX = trs-Latn = trs-Latn-MX +tru = tru-TR = tru-Latn = tru-Latn-TR +tru-Syrc = tru-Syrc-TR +*trv = trv-TW = trv-Latn = trv-Latn-TW +trw = trw-PK = *trw-Arab = trw-Arab-PK +try-Latn = try-Latn-IN +trz = trz-BR = trz-Latn = trz-Latn-BR +*ts = *ts-ZA = ts-Latn = ts-Latn-ZA +ts-Brai = ts-Brai-ZA +tsa = tsa-CG = tsa-Latn = tsa-Latn-CG +tsb = tsb-ET = tsb-Latn = tsb-Latn-ET +tsc = tsc-MZ = tsc-Latn = tsc-Latn-MZ +tsd = tsd-GR = tsd-Grek = tsd-Grek-GR +tsf = tsf-NP = tsf-Deva = tsf-Deva-NP +tsg = tsg-PH = tsg-Latn = tsg-Latn-PH +tsg-Arab = tsg-Arab-PH +tsi = tsi-CA = tsi-Latn = tsi-Latn-CA +tsj = tsj-BT = tsj-Tibt = tsj-Tibt-BT +tsq = tsq-TH +tsr = tsr-VU = tsr-Latn = tsr-Latn-VU +tsu-Latn = tsu-Latn-TW +tsv = tsv-GA = tsv-Latn = tsv-Latn-GA +tsw = tsw-NG = *tsw-Latn = tsw-Latn-NG +tsx = tsx-PG = tsx-Latn = tsx-Latn-PG +tsz = tsz-MX = tsz-Latn = tsz-Latn-MX +*tt = *tt-RU = tt-Cyrl = tt-Cyrl-RU +tt-Latn = tt-Latn-RU +ttc = ttc-GT = ttc-Latn = ttc-Latn-GT +ttd = ttd-PG = *ttd-Latn = ttd-Latn-PG +tte = tte-PG = *tte-Latn = tte-Latn-PG +tth = tth-LA = tth-Laoo = tth-Laoo-LA +ttj = ttj-UG = ttj-Latn = ttj-Latn-UG +ttk = ttk-CO = ttk-Latn = ttk-Latn-CO +ttl = ttl-ZM = ttl-Latn = ttl-Latn-ZM +ttm = ttm-CA = ttm-Latn = ttm-Latn-CA +tto = tto-LA = tto-Laoo = tto-Laoo-LA +ttr = ttr-NG = *ttr-Latn = ttr-Latn-NG +tts = tts-TH = tts-Thai = tts-Thai-TH +ttt = ttt-AZ = ttt-Latn = ttt-Latn-AZ +ttt-Cyrl = ttt-Cyrl-AZ +ttu = ttu-PG = ttu-Latn = ttu-Latn-PG +ttv = ttv-PG = ttv-Latn = ttv-Latn-PG +tty-Latn = tty-Latn-ID +tua = tua-PG = tua-Latn = tua-Latn-PG +tub = tub-US = tub-Latn = tub-Latn-US +tuc = tuc-PG = tuc-Latn = tuc-Latn-PG +tud = tud-BR = tud-Latn = tud-Latn-BR +tue = tue-CO = tue-Latn = tue-Latn-CO +tuf = tuf-CO = tuf-Latn = tuf-Latn-CO +tuh = tuh-PG = tuh-Latn = tuh-Latn-PG +tui-Latn = tui-Latn-CM +tul = tul-NG = *tul-Latn = tul-Latn-NG +tum = tum-MW = tum-Latn = tum-Latn-MW +tuo = tuo-BR = tuo-Latn = tuo-Latn-BR +tuq = tuq-TD = *tuq-Latn = tuq-Latn-TD +tus = tus-CA = tus-Latn = tus-Latn-CA +tuu = tuu-US = tuu-Latn = tuu-Latn-US +tuv = tuv-KE = tuv-Latn = tuv-Latn-KE +tux = tux-BR = tux-Latn = tux-Latn-BR +tuy = tuy-KE = tuy-Latn = tuy-Latn-KE +tuz-Latn = tuz-Latn-BF +tva = tva-SB = tva-Latn = tva-Latn-SB +tvd = tvd-NG = *tvd-Latn = tvd-Latn-NG +tvk = tvk-VU = tvk-Latn = tvk-Latn-VU +tvl = tvl-TV = tvl-Latn = tvl-Latn-TV +tvo-Latn = tvo-Latn-ID +tvs = tvs-KE = tvs-Latn = tvs-Latn-KE +tvu = tvu-CM = *tvu-Latn = tvu-Latn-CM +tvw-Latn = tvw-Latn-ID +twb-Latn = twb-Latn-PH +twd = twd-NL = twd-Latn = twd-Latn-NL +twf = twf-US = twf-Latn = twf-Latn-US +twh = twh-VN = *twh-Latn = twh-Latn-VN +twh-Tavt = twh-Tavt-VN +twl-Latn = twl-Latn-MZ +twm-Deva = twm-Deva-IN +two = two-BW = two-Latn = two-Latn-BW +twp = twp-PG = twp-Latn = twp-Latn-PG +*twq = *twq-NE = twq-Latn = twq-Latn-NE +twr = twr-MX = twr-Latn = twr-Latn-MX +twt = twt-BR = twt-Latn = twt-Latn-BR +twu-Latn = twu-Latn-ID +tww = tww-PG = tww-Latn = tww-Latn-PG +twx-Latn = twx-Latn-MZ +twy-Latn = twy-Latn-ID +txa-Latn = txa-Latn-MY +txg = txg-CN = txg-Tang = txg-Tang-CN +txi = txi-BR = txi-Latn = txi-Latn-BR +txn-Latn = txn-Latn-ID +txo-Beng = txo-Beng-IN +txo-Deva = txo-Deva-IN +txq-Latn = txq-Latn-ID +txs-Latn = txs-Latn-ID +txt-Latn = txt-Latn-ID +txu = txu-BR = txu-Latn = txu-Latn-BR +txx-Latn = txx-Latn-MY +txy = txy-MG = txy-Latn = txy-Latn-MG +ty = ty-PF = ty-Latn = ty-Latn-PF +tya = tya-PG = tya-Latn = tya-Latn-PG +tye-Latn = tye-Latn-NG +tyi = tyi-CG = tyi-Latn = tyi-Latn-CG +tyj-Latn = tyj-Latn-VN +tyj-x-taiyo = tyj-VN-x-taiyo = tyj-Qaaw-x-taiyo = tyj-Qaaw-VN-x-taiyo +tyn-Latn = tyn-Latn-ID +tyr = tyr-VN = tyr-Tavt = tyr-Tavt-VN +tyt-Latn = tyt-Latn-VN +tyt-Tavt = tyt-Tavt-VN +tyu = tyu-BW = tyu-Latn = tyu-Latn-BW +tyv = tyv-RU = tyv-Cyrl = tyv-Cyrl-RU +tyx = tyx-CG = tyx-Latn = tyx-Latn-CG +tyz = tyz-VN = tyz-Latn = tyz-Latn-VN +tzh = tzh-MX = tzh-Latn = tzh-Latn-MX +tzj = tzj-GT = tzj-Latn = tzj-Latn-GT +*tzm = *tzm-MA = tzm-Latn = tzm-Latn-MA +tzm-Arab = tzm-Arab-MA +tzm-Tfng = tzm-Tfng-MA +tzn-Latn = tzn-Latn-ID +tzo = tzo-MX = tzo-Latn = tzo-Latn-MX +tzx = tzx-PG = tzx-Latn = tzx-Latn-PG +uam = uam-BR = uam-Latn = uam-Latn-BR +uar = uar-PG = uar-Latn = uar-Latn-PG +ubi-Latn = ubi-Latn-TD +ubl-Latn = ubl-Latn-PH +ubr = ubr-PG = ubr-Latn = ubr-Latn-PG +ubu = ubu-PG = *ubu-Latn = ubu-Latn-PG +ude-Cyrl = ude-Cyrl-RU +udi-Cyrl = udi-Cyrl-AZ +udl-Latn = udl-Latn-CM +udm = udm-RU = udm-Cyrl = udm-Cyrl-RU +udm-Latn = udm-Latn-RU +udu = udu-SD = udu-Latn = udu-Latn-SD +ufi = ufi-PG = ufi-Latn = ufi-Latn-PG +*ug = *ug-CN = ug-Arab = ug-Arab-CN +ug-KZ = ug-Cyrl = ug-Cyrl-KZ +ug-Latn = ug-Latn-CN +ug-MN = ug-Cyrl-MN +uga = uga-SY = uga-Ugar = uga-Ugar-SY +uge = uge-SB = uge-Latn = uge-Latn-SB +uhn-Latn = uhn-Latn-ID +uis = uis-PG = uis-Latn = uis-Latn-PG +uiv-Latn = uiv-Latn-CM +*uk = *uk-UA = uk-Cyrl = uk-Cyrl-UA +ukg = ukg-PG = ukg-Latn = ukg-Latn-PG +ukk = ukk-MM = ukk-Latn = ukk-Latn-MM +ule = ule-AR = ule-Latn = ule-Latn-AR +uli = uli-FM = uli-Latn = uli-Latn-FM +ulk = ulk-AU = ulk-Latn = ulk-Latn-AU +ulu-Latn = ulu-Latn-ID +ulw = ulw-NI = ulw-Latn = ulw-Latn-NI +uma = uma-US = uma-Latn = uma-Latn-US +umb = umb-AO = umb-Latn = umb-Latn-AO +umm-Latn = umm-Latn-NG +umn = umn-MM = umn-Latn = umn-Latn-MM +umo = umo-BR = umo-Latn = umo-Latn-BR +ump = ump-AU = ump-Latn = ump-Latn-AU +ums-Latn = ums-Latn-ID +una = una-PG = una-Latn = una-Latn-PG +ung = ung-AU = ung-Latn = ung-Latn-AU +unk = unk-BR = unk-Latn = unk-Latn-BR +unn = unn-AU = unn-Latn = unn-Latn-AU +unr = unr-IN = unr-Beng = unr-Beng-IN +unr-Latn = unr-Latn-IN +unr-NP = unr-Deva = unr-Deva-NP +unr-Orya = unr-Orya-IN +unu = unu-PG = unu-Latn = unu-Latn-PG +unx = unx-IN = unx-Beng = unx-Beng-IN +unx-Deva = unx-Deva-IN +upi = upi-PG = upi-Latn = upi-Latn-PG +upv = upv-VU = upv-Latn = upv-Latn-VU +*ur = *ur-PK = ur-Arab = ur-Arab-PK +ur-Brai = ur-Brai-PK +*ur-IN = ur-Arab-IN +ur-Latn = ur-Latn-PK +ura = ura-PE = ura-Latn = ura-Latn-PE +urb = urb-BR = urb-Latn = urb-Latn-BR +ure = ure-BO = ure-Latn = ure-Latn-BO +urg = urg-PG = urg-Latn = urg-Latn-PG +urh-Latn = urh-Latn-NG +uri = uri-PG = *uri-Latn = uri-Latn-PG +urk = urk-TH = urk-Thai = urk-Thai-TH +urm = urm-PG = urm-Latn = urm-Latn-PG +uro = uro-PG = uro-Latn = uro-Latn-PG +urp = urp-BR = urp-Latn = urp-Latn-BR +urr = urr-VU = urr-Latn = urr-Latn-VU +urt = urt-PG = *urt-Latn = urt-Latn-PG +uru = uru-BR = uru-Latn = uru-Latn-BR +urw = urw-PG = *urw-Latn = urw-Latn-PG +urx = urx-PG = urx-Latn = urx-Latn-PG +ury-Latn = ury-Latn-ID +urz = urz-BR = urz-Latn = urz-Latn-BR +usa = usa-PG = *usa-Latn = usa-Latn-PG +usi-Beng = usi-Beng-BD +usi-Latn = usi-Latn-BD +usp = usp-GT = usp-Latn = usp-Latn-GT +usu = usu-PG = usu-Latn = usu-Latn-PG +ute = ute-US = ute-Latn = ute-Latn-US +utp = utp-SB = utp-Latn = utp-Latn-SB +utr = utr-NG = *utr-Latn = utr-Latn-NG +utu = utu-PG = utu-Latn = utu-Latn-PG +uum-Cyrl = uum-Cyrl-GE +uum-Grek = uum-Grek-GE +uun-Latn = uun-Latn-TW +uur = uur-VU = uur-Latn = uur-Latn-VU +uve = uve-NC = uve-Latn = uve-Latn-NC +uvh = uvh-PG = *uvh-Latn = uvh-Latn-PG +uvl = uvl-PG = *uvl-Latn = uvl-Latn-PG +uwa = uwa-AU = uwa-Latn = uwa-Latn-AU +*uz = uzn = uz-UZ = uzn-UZ = *uz-Latn = uzn-Latn = *uz-Latn-UZ = uzn-Latn-UZ +uz-AF = *uz-Arab = uzn-Arab = *uz-Arab-AF = uzn-Arab-AF +uz-Brai = uzn-Brai = uz-Brai-UZ = uzn-Brai-UZ +uz-CN = uz-Cyrl-CN +*uz-Cyrl = uzn-Cyrl = *uz-Cyrl-UZ = uzn-Cyrl-UZ +uz-Sogd = uzn-Sogd = uz-Sogd-CN = uzn-Sogd-CN +uzs-Arab = uzs-Arab-AF +vaa-Taml = vaa-Taml-IN +vaf-Arab = vaf-Arab-IR +vag = vag-GH = *vag-Latn = vag-Latn-GH +vah-Deva = vah-Deva-IN +*vai = vai-LR = *vai-Vaii = *vai-Vaii-LR +*vai-Latn = *vai-Latn-LR +val = val-PG = val-Latn = val-Latn-PG +vam = vam-PG = vam-Latn = vam-Latn-PG +van = van-PG = van-Latn = van-Latn-PG +vao = vao-VU = vao-Latn = vao-Latn-VU +vap-Latn = vap-Latn-IN +var = var-MX = var-Latn = var-Latn-MX +vas-Deva = vas-Deva-IN +vas-Gujr = vas-Gujr-IN +vav-Deva = vav-Deva-IN +vav-Gujr = vav-Gujr-IN +vay-Deva = vay-Deva-NP +*ve = *ve-ZA = ve-Latn = ve-Latn-ZA +ve-Brai = ve-Brai-ZA +vec = vec-IT = *vec-Latn = vec-Latn-IT +vem-Latn = vem-Latn-NG +vep = vep-RU = vep-Latn = vep-Latn-RU +ver-Latn = ver-Latn-NG +*vi = *vi-VN = vi-Latn = vi-Latn-VN +vi-Brai = vi-Brai-VN +vi-Hani = vi-Hani-VN +vic = vic-SX = vic-Latn = vic-Latn-SX +vid = vid-TZ = vid-Latn = vid-Latn-TZ +vif = vif-CG = vif-Latn = vif-Latn-CG +vil = vil-AR = vil-Latn = vil-Latn-AR +viv = viv-PG = *viv-Latn = viv-Latn-PG +vkl-Latn = vkl-Latn-ID +vkm = vkm-BR = vkm-Latn = vkm-Latn-BR +vkp-Deva = vkp-Deva-IN +vkp-Latn = vkp-Latn-IN +vku = vku-AU = vku-Latn = vku-Latn-AU +vlp = vlp-VU = vlp-Latn = vlp-Latn-VU +vls = vls-BE = vls-Latn = vls-Latn-BE +vma = vma-AU = vma-Latn = vma-Latn-AU +vmc = vmc-MX = vmc-Latn = vmc-Latn-MX +vmf = vmf-DE = vmf-Latn = vmf-Latn-DE +vmg = vmg-PG = vmg-Latn = vmg-Latn-PG +vmj = vmj-MX = vmj-Latn = vmj-Latn-MX +vmk-Latn = vmk-Latn-MZ +vmm = vmm-MX = vmm-Latn = vmm-Latn-MX +vmp = vmp-MX = vmp-Latn = vmp-Latn-MX +vmq = vmq-MX = vmq-Latn = vmq-Latn-MX +vmw = vmw-MZ = vmw-Latn = vmw-Latn-MZ +vmx = vmx-MX = vmx-Latn = vmx-Latn-MX +vmy = vmy-MX = vmy-Latn = vmy-Latn-MX +vmz = vmz-MX = vmz-Latn = vmz-Latn-MX +vnk = vnk-SB = vnk-Latn = vnk-Latn-SB +vnm = vnm-VU = vnm-Latn = vnm-Latn-VU +vnp = vnp-VU = vnp-Latn = vnp-Latn-VU +*vo = *vo-001 = vo-Latn = vo-Latn-001 +vot = vot-RU = vot-Latn = vot-Latn-RU +vra = vra-VU = vra-Latn = vra-Latn-VU +vro = vro-EE = vro-Latn = vro-Latn-EE +vrs = vrs-SB = vrs-Latn = vrs-Latn-SB +vrt = vrt-VU = vrt-Latn = vrt-Latn-VU +vum = vum-GA = vum-Latn = vum-Latn-GA +*vun = *vun-TZ = vun-Latn = vun-Latn-TZ +vut = vut-CM = *vut-Latn = vut-Latn-CM +*wa = wa-BE = wa-Latn = wa-Latn-BE +waa = waa-US = waa-Latn = waa-Latn-US +wab = wab-PG = wab-Latn = wab-Latn-PG +wac = wac-US = wac-Latn = wac-Latn-US +wad-Latn = wad-Latn-ID +*wae = *wae-CH = wae-Latn = wae-Latn-CH +waf = waf-BR = waf-Latn = waf-Latn-BR +wag = wag-PG = wag-Latn = wag-Latn-PG +waj = waj-PG = *waj-Latn = waj-Latn-PG +wal = wal-ET = *wal-Ethi = wal-Ethi-ET +*wal-Latn = wal-Latn-ET +wam = wam-US = wam-Latn = wam-Latn-US +wan = wan-CI = *wan-Latn = wan-Latn-CI +wap = wap-GY = wap-Latn = wap-Latn-GY +waq = waq-AU = waq-Latn = waq-Latn-AU +war = war-PH = war-Latn = war-Latn-PH +war-Brai = war-Brai-PH +was = was-US = was-Latn = was-Latn-US +wat = wat-PG = wat-Latn = wat-Latn-PG +wau = wau-BR = wau-Latn = wau-Latn-BR +waw = waw-BR = waw-Latn = waw-Latn-BR +wax = wax-PG = wax-Latn = wax-Latn-PG +way = way-SR = way-Latn = way-Latn-SR +waz = waz-PG = waz-Latn = waz-Latn-PG +wba = wba-VE = wba-Latn = wba-Latn-VE +wbf-Latn = wbf-Latn-BF +wbi = wbi-TZ = wbi-Latn = wbi-Latn-TZ +wbj = wbj-TZ = wbj-Latn = wbj-Latn-TZ +wbl-Arab = wbl-Arab-AF +wbl-Cyrl = wbl-Cyrl-TJ +wbl-Latn = wbl-Latn-PK +wbm-Latn = wbm-Latn-CN +wbp = wbp-AU = wbp-Latn = wbp-Latn-AU +wbq = wbq-IN = wbq-Telu = wbq-Telu-IN +wbr = wbr-IN = wbr-Deva = wbr-Deva-IN +wbt = wbt-AU = wbt-Latn = wbt-Latn-AU +wbv = wbv-AU = wbv-Latn = wbv-Latn-AU +wca = wca-BR = wca-Latn = wca-Latn-BR +wci = wci-TG = *wci-Latn = wci-Latn-TG +wdd = wdd-GA = wdd-Latn = wdd-Latn-GA +wdg = wdg-PG = wdg-Latn = wdg-Latn-PG +wdj = wdj-AU = wdj-Latn = wdj-Latn-AU +wec-Latn = wec-Latn-CI +wed = wed-PG = wed-Latn = wed-Latn-PG +weg = weg-AU = weg-Latn = weg-Latn-AU +weh-Latn = weh-Latn-CM +wei = wei-PG = wei-Latn = wei-Latn-PG +weo-Latn = weo-Latn-ID +wep-Latn = wep-Latn-DE +wer = wer-PG = *wer-Latn = wer-Latn-PG +wes-Latn = wes-Latn-CM +weu-Latn = weu-Latn-MM +wew-Latn = wew-Latn-ID +wgb = wgb-PG = wgb-Latn = wgb-Latn-PG +wgi = wgi-PG = *wgi-Latn = wgi-Latn-PG +wgy = wgy-AU = wgy-Latn = wgy-Latn-AU +whg = whg-PG = *whg-Latn = whg-Latn-PG +whk = whk-ID = whk-Latn = whk-Latn-ID +wib = wib-BF = *wib-Latn = wib-Latn-BF +wic = wic-US = wic-Latn = wic-Latn-US +wig = wig-AU = wig-Latn = wig-Latn-AU +wih = wih-AU = wih-Latn = wih-Latn-AU +wii = wii-PG = wii-Latn = wii-Latn-PG +wij = wij-AU = wij-Latn = wij-Latn-AU +wik = wik-AU = wik-Latn = wik-Latn-AU +wim = wim-AU = wim-Latn = wim-Latn-AU +win = win-US = win-Latn = win-Latn-US +wir = wir-BR = wir-Latn = wir-Latn-BR +wiu = wiu-PG = *wiu-Latn = wiu-Latn-PG +wiv = wiv-PG = *wiv-Latn = wiv-Latn-PG +wiy = wiy-US = wiy-Latn = wiy-Latn-US +wja = wja-NG = *wja-Latn = wja-Latn-NG +wji = wji-NG = *wji-Latn = wji-Latn-NG +wla = wla-PG = wla-Latn = wla-Latn-PG +wlg = wlg-AU = wlg-Latn = wlg-Latn-AU +wlm = wlm-GB = wlm-Latn = wlm-Latn-GB +wlo-Arab = wlo-Arab-ID +wlr = wlr-VU = wlr-Latn = wlr-Latn-VU +wls = wls-WF = wls-Latn = wls-Latn-WF +wlv = wlv-AR = wlv-Latn = wlv-Latn-AR +wlw-Latn = wlw-Latn-ID +wlx = wlx-GH = wlx-Latn = wlx-Latn-GH +wmb = wmb-AU = wmb-Latn = wmb-Latn-AU +wmc = wmc-PG = wmc-Latn = wmc-Latn-PG +wmd = wmd-BR = wmd-Latn = wmd-Latn-BR +wme-Deva = wme-Deva-NP +wmh = wmh-TL = wmh-Latn = wmh-Latn-TL +wmo = wmo-PG = wmo-Latn = wmo-Latn-PG +wms-Latn = wms-Latn-ID +wmt = wmt-AU = wmt-Latn = wmt-Latn-AU +wmw-Arab = wmw-Arab-MZ +wmw-Latn = wmw-Latn-MZ +wmx = wmx-PG = wmx-Latn = wmx-Latn-PG +wnb = wnb-PG = wnb-Latn = wnb-Latn-PG +wnc = wnc-PG = *wnc-Latn = wnc-Latn-PG +wni = wni-KM = wni-Arab = wni-Arab-KM +wni-Latn = wni-Latn-KM +wno-Latn = wno-Latn-ID +wnp = wnp-PG = wnp-Latn = wnp-Latn-PG +wnu = wnu-PG = *wnu-Latn = wnu-Latn-PG +wnw = wnw-US = wnw-Latn = wnw-Latn-US +wny = wny-AU = wny-Latn = wny-Latn-AU +*wo = *wo-SN = *wo-Latn = wo-Latn-SN +*wo-Arab = wo-Arab-SN +woa = woa-AU = woa-Latn = woa-Latn-AU +wob = wob-CI = *wob-Latn = wob-Latn-CI +woc = woc-PG = woc-Latn = woc-Latn-PG +wod-Latn = wod-Latn-ID +woe = woe-FM = woe-Latn = woe-Latn-FM +woe-Wole = woe-Wole-FM +wof-Latn = wof-Latn-GM +wog = wog-PG = wog-Latn = wog-Latn-PG +won = won-CD = won-Latn = won-Latn-CD +woo-Latn = woo-Latn-ID +wos = wos-PG = *wos-Latn = wos-Latn-PG +wpc = wpc-VE = wpc-Latn = wpc-Latn-VE +wra = wra-PG = wra-Latn = wra-Latn-PG +wrk = wrk-AU = wrk-Latn = wrk-Latn-AU +wrl = wrl-AU = wrl-Latn = wrl-Latn-AU +wrm = wrm-AU = wrm-Latn = wrm-Latn-AU +wro = wro-AU = wro-Latn = wro-Latn-AU +wrr = wrr-AU = wrr-Latn = wrr-Latn-AU +wrs = wrs-PG = *wrs-Latn = wrs-Latn-PG +wrv = wrv-PG = wrv-Latn = wrv-Latn-PG +wsg-Telu = wsg-Telu-IN +wsi = wsi-VU = wsi-Latn = wsi-Latn-VU +wsk = wsk-PG = *wsk-Latn = wsk-Latn-PG +wsr = wsr-PG = wsr-Latn = wsr-Latn-PG +wss = wss-GH = wss-Latn = wss-Latn-GH +wsu = wsu-BR = wsu-Latn = wsu-Latn-BR +wtf = wtf-PG = wtf-Latn = wtf-Latn-PG +wti-Latn = wti-Latn-ET +wtk = wtk-PG = wtk-Latn = wtk-Latn-PG +wtm = wtm-IN = wtm-Deva = wtm-Deva-IN +wua = wua-AU = wua-Latn = wua-Latn-AU +wub = wub-AU = wub-Latn = wub-Latn-AU +wul-Latn = wul-Latn-ID +wum = wum-GA = wum-Latn = wum-Latn-GA +wut = wut-PG = wut-Latn = wut-Latn-PG +wuu = wuu-CN = wuu-Hans = wuu-Hans-CN +wuu-Hant = wuu-Hant-CN +wuu-Latn = wuu-Latn-CN +wuv = wuv-PG = *wuv-Latn = wuv-Latn-PG +wux = wux-AU = wux-Latn = wux-Latn-AU +wwa = wwa-BJ = *wwa-Latn = wwa-Latn-BJ +wwo = wwo-VU = wwo-Latn = wwo-Latn-VU +wya = wya-US = wya-Latn = wya-Latn-US +wyb = wyb-AU = wyb-Latn = wyb-Latn-AU +wym = wym-PL = wym-Latn = wym-Latn-PL +wyr = wyr-BR = wyr-Latn = wyr-Latn-BR +wyy = wyy-FJ = wyy-Latn = wyy-Latn-FJ +xai = xai-BR = xai-Latn = xai-Latn-BR +xaj = xaj-BR = xaj-Latn = xaj-Latn-BR +xal-Cyrl = xal-Cyrl-RU +xal-Mong-x-todo = xal-Mong-CN-x-todo +xam = xam-ZA = xam-Latn = xam-Latn-ZA +xan-Ethi = xan-Ethi-ET +xat = xat-BR = xat-Latn = xat-Latn-BR +xav = xav-BR = xav-Latn = xav-Latn-BR +xaw = xaw-US = xaw-Latn = xaw-Latn-US +xbi = xbi-PG = *xbi-Latn = xbi-Latn-PG +xbm = xbm-FR = xbm-Latn = xbm-Latn-FR +xbr-Latn = xbr-Latn-ID +xbw = xbw-BR = xbw-Latn = xbw-Latn-BR +xby = xby-AU = xby-Latn = xby-Latn-AU +xcr = xcr-TR = xcr-Cari = xcr-Cari-TR +xda = xda-AU = xda-Latn = xda-Latn-AU +xdo = xdo-AO = xdo-Latn = xdo-Latn-AO +xed-Latn = xed-Latn-CM +xeg = xeg-ZA = xeg-Latn = xeg-Latn-ZA +xer = xer-BR = xer-Latn = xer-Latn-BR +xes = xes-PG = xes-Latn = xes-Latn-PG +xet = xet-BR = xet-Latn = xet-Latn-BR +xeu = xeu-PG = xeu-Latn = xeu-Latn-PG +xgu = xgu-AU = xgu-Latn = xgu-Latn-AU +*xh = xh-ZA = xh-Latn = xh-Latn-ZA +xh-Brai = xh-Brai-ZA +xii = xii-ZA = xii-Latn = xii-Latn-ZA +xin = xin-GT = xin-Latn = xin-Latn-GT +xir = xir-BR = xir-Latn = xir-Latn-BR +xis-Orya = xis-Orya-IN +xiy = xiy-BR = xiy-Latn = xiy-Latn-BR +xkd-Latn = xkd-Latn-ID +xkf-Tibt-x-uchen = xkf-Tibt-BT-x-uchen +xkj-Arab = xkj-Arab-IR +xkl-Latn = xkl-Latn-ID +xkr = xkr-BR = xkr-Latn = xkr-Latn-BR +xkt = xkt-GH = xkt-Latn = xkt-Latn-GH +xkv = xkv-BW = xkv-Latn = xkv-Latn-BW +xkx = xkx-PG = xkx-Latn = xkx-Latn-PG +xkz-Latn = xkz-Latn-BT +xkz-Tibt = xkz-Tibt-BT +xla = xla-PG = *xla-Latn = xla-Latn-PG +xlc = xlc-TR = xlc-Lyci = xlc-Lyci-TR +xld = xld-TR = xld-Lydi = xld-Lydi-TR +xmd-Latn = xmd-Latn-CM +xmf = xmf-GE = xmf-Geor = xmf-Geor-GE +xmg-Qabh = xmg-Qabh-CM +xmh = xmh-AU = xmh-Latn = xmh-Latn-AU +xmm-Latn = xmm-Latn-ID +xmn = xmn-CN = xmn-Mani = xmn-Mani-CN +xmo = xmo-BR = xmo-Latn = xmo-Latn-BR +xmr = xmr-SD = xmr-Merc = xmr-Merc-SD +xmv = xmv-MG = xmv-Latn = xmv-Latn-MG +xmw = xmw-MG = xmw-Latn = xmw-Latn-MG +xmy = xmy-AU = xmy-Latn = xmy-Latn-AU +xmz-Latn = xmz-Latn-ID +xna = xna-SA = xna-Narb = xna-Narb-SA +xnn-Latn = xnn-Latn-PH +xnr = xnr-IN = xnr-Deva = xnr-Deva-IN +xny = xny-AU = xny-Latn = xny-Latn-AU +xnz-Arab = xnz-Arab-EG +xnz-Copt-x-oldnubian = xnz-Copt-EG-x-oldnubian +xnz-Latn = xnz-Latn-EG +*xog = *xog-UG = xog-Latn = xog-Latn-UG +xoi = xoi-PG = xoi-Latn = xoi-Latn-PG +xok = xok-BR = xok-Latn = xok-Latn-BR +xom = xom-SD = xom-Latn = xom-Latn-SD +xon = xon-GH = *xon-Latn = xon-Latn-GH +xon-Brai = xon-Brai-GH +xoo = xoo-BR = xoo-Latn = xoo-Latn-BR +xop = xop-PG = xop-Latn = xop-Latn-PG +xor = xor-BR = xor-Latn = xor-Latn-BR +xow = xow-PG = xow-Latn = xow-Latn-PG +xpg-Grek = xpg-Grek-TR +xpk = xpk-BR = xpk-Latn = xpk-Latn-BR +xpn = xpn-BR = xpn-Latn = xpn-Latn-BR +xpr = xpr-IR = xpr-Prti = xpr-Prti-IR +xra = xra-BR = xra-Latn = xra-Latn-BR +xrb = xrb-BF = *xrb-Latn = xrb-Latn-BF +xre = xre-BR = xre-Latn = xre-Latn-BR +xri = xri-BR = xri-Latn = xri-Latn-BR +xru = xru-AU = xru-Latn = xru-Latn-AU +xrw = xrw-PG = xrw-Latn = xrw-Latn-PG +xsa = xsa-YE = xsa-Sarb = xsa-Sarb-YE +xsb = xsb-PH = xsb-Latn = xsb-Latn-PH +xsi = xsi-PG = *xsi-Latn = xsi-Latn-PG +xsm = xsm-BF = *xsm-Latn = xsm-Latn-BF +xsp = xsp-PG = xsp-Latn = xsp-Latn-PG +xsr = xsr-NP = xsr-Deva = xsr-Deva-NP +xsr-Tibt = xsr-Tibt-CN +xsu = xsu-VE = xsu-Latn = xsu-Latn-VE +xsy-Latn = xsy-Latn-TW +xta = xta-MX = xta-Latn = xta-Latn-MX +xtb = xtb-MX = xtb-Latn = xtb-Latn-MX +xtc = xtc-SD = xtc-Latn = xtc-Latn-SD +xtd = xtd-MX = xtd-Latn = xtd-Latn-MX +xte-Latn = xte-Latn-ID +xti = xti-MX = xti-Latn = xti-Latn-MX +xtj = xtj-MX = xtj-Latn = xtj-Latn-MX +xtl = xtl-MX = xtl-Latn = xtl-Latn-MX +xtm = xtm-MX = xtm-Latn = xtm-Latn-MX +xtn = xtn-MX = xtn-Latn = xtn-Latn-MX +xtp = xtp-MX = xtp-Latn = xtp-Latn-MX +xts = xts-MX = xts-Latn = xts-Latn-MX +xtt = xtt-MX = xtt-Latn = xtt-Latn-MX +xtu = xtu-MX = xtu-Latn = xtu-Latn-MX +xtw = xtw-BR = xtw-Latn = xtw-Latn-BR +xty = xty-MX = xty-Latn = xty-Latn-MX +xub-Knda = xub-Knda-IN +xub-Mlym = xub-Mlym-IN +xub-Taml = xub-Taml-IN +xum-Ital = xum-Ital-IT +xum-Latn = xum-Latn-IT +xuo-Latn = xuo-Latn-TD +xuu = xuu-NA = xuu-Latn = xuu-Latn-NA +xve-Ital-IT +xvo = xvo-IT = xvo-Latn = xvo-Latn-IT +xwa = xwa-BR = xwa-Latn = xwa-Latn-BR +xwe = xwe-BJ = *xwe-Latn = xwe-Latn-BJ +xxb = xxb-GH = xxb-Latn = xxb-Latn-GH +xxk-Latn = xxk-Latn-ID +xxr = xxr-BR = xxr-Latn = xxr-Latn-BR +xyl = xyl-BR = xyl-Latn = xyl-Latn-BR +xyy = xyy-AU = xyy-Latn = xyy-Latn-AU +yaa = yaa-PE = yaa-Latn = yaa-Latn-PE +yab = yab-BR = yab-Latn = yab-Latn-BR +yac-Latn = yac-Latn-ID +yad = yad-PE = yad-Latn = yad-Latn-PE +yae = yae-VE = yae-Latn = yae-Latn-VE +yaf = yaf-CD = yaf-Latn = yaf-Latn-CD +yag = yag-CL = yag-Latn = yag-Latn-CL +yah-Cyrl = yah-Cyrl-TJ +yah-Latn = yah-Latn-TJ +yai = yai-TJ = yai-Cyrl = yai-Cyrl-TJ +yak = yak-US = yak-Latn = yak-Latn-US +yal-Arab = yal-Arab-GN +yal-Latn = yal-Latn-GN +yam = yam-CM = *yam-Latn = yam-Latn-CM +yan = yan-NI = yan-Latn = yan-Latn-NI +yao = yao-MZ = yao-Latn = yao-Latn-MZ +yap = yap-FM = yap-Latn = yap-Latn-FM +yaq = yaq-MX = yaq-Latn = yaq-Latn-MX +yar = yar-VE = yar-Latn = yar-Latn-VE +yas = yas-CM = *yas-Latn = yas-Latn-CM +yat = yat-CM = *yat-Latn = yat-Latn-CM +yau = yau-VE = yau-Latn = yau-Latn-VE +*yav = *yav-CM = yav-Latn = yav-Latn-CM +yaw = yaw-BR = yaw-Latn = yaw-Latn-BR +yax = yax-AO = yax-Latn = yax-Latn-AO +yay = yay-NG = *yay-Latn = yay-Latn-NG +yaz = yaz-NG = *yaz-Latn = yaz-Latn-NG +yba = yba-NG = *yba-Latn = yba-Latn-NG +ybb = ybb-CM = *ybb-Latn = ybb-Latn-CM +ybh-Deva = ybh-Deva-NP +ybi-Deva = ybi-Deva-NP +ybm = ybm-PG = ybm-Latn = ybm-Latn-PG +ybn = ybn-BR = ybn-Latn = ybn-Latn-BR +ybo = ybo-PG = ybo-Latn = ybo-Latn-PG +ybx = ybx-PG = ybx-Latn = ybx-Latn-PG +yby = yby-PG = *yby-Latn = yby-Latn-PG +ycn = ycn-CO = ycn-Latn = ycn-Latn-CO +yde = yde-PG = yde-Latn = yde-Latn-PG +ydg-Arab = ydg-Arab-PK +ydk = ydk-PG = ydk-Latn = ydk-Latn-PG +yea-Knda = yea-Knda-IN +yea-Mlym = yea-Mlym-IN +yee = yee-PG = yee-Latn = yee-Latn-PG +yer = yer-NG = *yer-Latn = yer-Latn-NG +yes-Latn = yes-Latn-NG +yeu-Telu = yeu-Telu-IN +yev = yev-PG = yev-Latn = yev-Latn-PG +yey = yey-BW = yey-Latn = yey-Latn-BW +ygl = ygl-PG = ygl-Latn = ygl-Latn-PG +ygm = ygm-PG = ygm-Latn = ygm-Latn-PG +ygp-Plrd = ygp-Plrd-CN +ygr = ygr-PG = *ygr-Latn = ygr-Latn-PG +ygu = ygu-AU = ygu-Latn = ygu-Latn-AU +ygw = ygw-PG = *ygw-Latn = ygw-Latn-PG +yhd-Hebr = yhd-Hebr-IL +*yi = ydd = *yi-001 = yi-Hebr = ydd-001 = ydd-Hebr = yi-Hebr-001 = ydd-Hebr-001 +yia = yia-AU = yia-Latn = yia-Latn-AU +yig-Yiii-x-traditional = yig-Yiii-CN-x-traditional +yih-Hebr = yih-Hebr-DE +yii = yii-AU = yii-Latn = yii-Latn-AU +yij = yij-AU = yij-Latn = yij-Latn-AU +yim-Latn = yim-Latn-IN +yis = yis-PG = yis-Latn = yis-Latn-PG +yka-Arab = yka-Arab-PH +yka-Latn = yka-Latn-PH +ykg-Cyrl = ykg-Cyrl-RU +ykk = ykk-PG = ykk-Latn = ykk-Latn-PG +ykm = ykm-PG = ykm-Latn = ykm-Latn-PG +yko = yko-CM = *yko-Latn = yko-Latn-CM +ykr = ykr-PG = ykr-Latn = ykr-Latn-PG +yky = yky-CF = yky-Latn = yky-Latn-CF +yla = yla-PG = yla-Latn = yla-Latn-PG +ylb = ylb-PG = ylb-Latn = ylb-Latn-PG +yle = yle-PG = *yle-Latn = yle-Latn-PG +ylg = ylg-PG = ylg-Latn = ylg-Latn-PG +yli-Latn = yli-Latn-ID +yll = yll-PG = yll-Latn = yll-Latn-PG +ylu = ylu-PG = ylu-Latn = ylu-Latn-PG +yly = yly-NC = yly-Latn = yly-Latn-NC +ymb = ymb-PG = ymb-Latn = ymb-Latn-PG +yml = yml-PG = *yml-Latn = yml-Latn-PG +ymm = ymm-SO = ymm-Latn = ymm-Latn-SO +ymn-Latn = ymn-Latn-ID +ymo = ymo-PG = ymo-Latn = ymo-Latn-PG +ymp = ymp-PG = ymp-Latn = ymp-Latn-PG +ynk-Cyrl = ynk-Cyrl-RU +ynl = ynl-PG = ynl-Latn = ynl-Latn-PG +yns = yns-CD = yns-Latn = yns-Latn-CD +ynu = ynu-CO = ynu-Latn = ynu-Latn-CO +*yo = *yo-NG = yo-Latn = yo-Latn-NG +*yo-Arab = yo-Arab-NG +*yo-BJ = yo-Latn-BJ +yo-Brai = yo-Brai-NG +yog-Latn = yog-Latn-PH +yok = yok-US = yok-Latn = yok-Latn-US +yom = yom-CD = yom-Latn = yom-Latn-CD +yon = yon-PG = *yon-Latn = yon-Latn-PG +yra = yra-PG = yra-Latn = yra-Latn-PG +yrb = yrb-PG = *yrb-Latn = yrb-Latn-PG +yre = yre-CI = *yre-Latn = yre-Latn-CI +yrk-Cyrl = yrk-Cyrl-RU +yrl = yrl-BR = yrl-Latn = yrl-Latn-BR +yrm = yrm-AU = yrm-Latn = yrm-Latn-AU +yro = yro-BR = yro-Latn = yro-Latn-BR +yrw = yrw-PG = yrw-Latn = yrw-Latn-PG +yry = yry-AU = yry-Latn = yry-Latn-AU +ysd-Yiii = ysd-Yiii-CN +ysn-Yiii-x-traditional = ysn-Yiii-CN-x-traditional +yss = yss-PG = *yss-Latn = yss-Latn-PG +ysy-Plrd = ysy-Plrd-CN +ytw = ytw-PG = ytw-Latn = ytw-Latn-PG +yua = yua-MX = yua-Latn = yua-Latn-MX +yuc = yuc-US = yuc-Latn = yuc-Latn-US +yud-Hebr = yud-Hebr-IL +*yue = *yue-HK = *yue-Hant = *yue-Hant-HK +yue-Brai = yue-Brai-CN +yue-CN = *yue-Hans = *yue-Hans-CN +yue-Latn = yue-Latn-CN +yuf = yuf-US = yuf-Latn = yuf-Latn-US +yui = yui-CO = yui-Latn = yui-Latn-CO +yuj = yuj-PG = *yuj-Latn = yuj-Latn-PG +yum = yum-US = yum-Latn = yum-Latn-US +yun-Latn = yun-Latn-NG +yup = yup-CO = yup-Latn = yup-Latn-CO +yuq = yuq-BO = yuq-Latn = yuq-Latn-BO +yur = yur-US = yur-Latn = yur-Latn-US +yut = yut-PG = *yut-Latn = yut-Latn-PG +yuw = yuw-PG = *yuw-Latn = yuw-Latn-PG +yuz = yuz-BO = yuz-Latn = yuz-Latn-BO +yva-Latn = yva-Latn-ID +ywa = ywa-PG = ywa-Latn = ywa-Latn-PG +ywg = ywg-AU = ywg-Latn = ywg-Latn-AU +ywn = ywn-BR = ywn-Latn = ywn-Latn-BR +ywq-Plrd = ywq-Plrd-CN +ywq-Yiii-x-traditional = ywq-Yiii-CN-x-traditional +ywr = ywr-AU = ywr-Latn = ywr-Latn-AU +yyu = yyu-PG = yyu-Latn = yyu-Latn-PG +za = zyb = za-CN = zyb-CN = za-Latn = zyb-Latn = za-Latn-CN = zyb-Latn-CN +za-Hans = zyb-Hans = za-Hans-CN = zyb-Hans-CN +zaa = zaa-MX = zaa-Latn = zaa-Latn-MX +zab = zab-MX = zab-Latn = zab-Latn-MX +zac = zac-MX = zac-Latn = zac-Latn-MX +zad = zad-MX = zad-Latn = zad-Latn-MX +zae = zae-MX = zae-Latn = zae-Latn-MX +zaf = zaf-MX = zaf-Latn = zaf-Latn-MX +zag = zag-SD = zag-Latn = zag-Latn-SD +zaj = zaj-TZ = zaj-Latn = zaj-Latn-TZ +zak = zak-TZ = zak-Latn = zak-Latn-TZ +zam = zam-MX = zam-Latn = zam-Latn-MX +zao = zao-MX = zao-Latn = zao-Latn-MX +zap = zai = zap-MX = zai-MX = zap-Latn = zai-Latn = zap-Latn-MX = zai-Latn-MX +zaq = zaq-MX = zaq-Latn = zaq-Latn-MX +zar = zar-MX = zar-Latn = zar-Latn-MX +zas = zas-MX = zas-Latn = zas-Latn-MX +zat = zat-MX = zat-Latn = zat-Latn-MX +zau-Tibt = zau-Tibt-IN +zav = zav-MX = zav-Latn = zav-Latn-MX +zaw = zaw-MX = zaw-Latn = zaw-Latn-MX +zax = zax-MX = zax-Latn = zax-Latn-MX +zay-Ethi = zay-Ethi-ET +*zay-Latn = zay-Latn-ET +zbl = zbl-?? = zbl-Blis = zbl-Blis-?? +zbw-Latn = zbw-Latn-MY +zca = zca-MX = zca-Latn = zca-Latn-MX +zch-Hani = zch-Hani-CN +zdj = zdj-KM = *zdj-Arab = zdj-Arab-KM +zdj-Latn = zdj-Latn-KM +zea = zea-NL = zea-Latn = zea-Latn-NL +zeg = zeg-PG = zeg-Latn = zeg-Latn-PG +zeh-Hani = zeh-Hani-CN +zen-Tfng = zen-Tfng-MR +zga = zga-TZ = zga-Latn = zga-Latn-TZ +zgb-Hani = zgb-Hani-CN +*zgh = *zgh-MA = zgh-Tfng = zgh-Tfng-MA +zgm-Hani = zgm-Hani-CN +zgn-Hani = zgn-Hani-CN +zgr = zgr-PG = zgr-Latn = zgr-Latn-PG +*zh = cmn = zh-CN = cmn-CN = *zh-Hans = cmn-Hans = *zh-Hans-CN = cmn-Hans-CN +zh-AU = zh-Hant-AU +zh-BN = zh-Hant-BN +zh-Bopo = cmn-Bopo = zh-Bopo-TW = cmn-Bopo-TW +zh-GB = zh-Hant-GB +zh-GF = zh-Hant-GF +zh-HK = *zh-Hant-HK +zh-Hanb = zh-Hanb-TW +*zh-Hans-HK +*zh-Hans-MO +*zh-Hans-SG +zh-ID = zh-Hant-ID +zh-Latn = cmn-Latn = zh-Latn-CN = cmn-Latn-CN +zh-MO = *zh-Hant-MO +zh-MY = zh-Hant-MY +zh-PA = zh-Hant-PA +zh-PF = zh-Hant-PF +zh-PH = zh-Hant-PH +zh-Phag = zh-Phag-CN +zh-SR = zh-Hant-SR +zh-TH = zh-Hant-TH +zh-TW = *zh-Hant = cmn-Hant = *zh-Hant-TW = cmn-Hant-TW +zh-US = zh-Hant-US +zh-VN = zh-Hant-VN +zhd-Hani = zhd-Hani-CN +zhd-Latn = zhd-Latn-VN +zhn-Hani = zhn-Hani-CN +zhn-Latn = zhn-Latn-CN +zhx = zhx-CN = zhx-Nshu = zhx-Nshu-CN +zia = zia-PG = *zia-Latn = zia-Latn-PG +zik = zik-PG = zik-Latn = zik-Latn-PG +zim-Latn = zim-Latn-TD +zin = zin-TZ = zin-Latn = zin-Latn-TZ +ziw = ziw-TZ = ziw-Latn = ziw-Latn-TZ +zkd-Latn = zkd-Latn-MM +zkp = zkp-BR = zkp-Latn = zkp-Latn-BR +zkt-Kitl-CN +zkt-Kits-CN +zlj-Hani = zlj-Hani-CN +zlj-Latn = zlj-Latn-CN +zlm = zlm-TG = zlm-Latn = zlm-Latn-TG +*zlm-Arab = zlm-Arab-MY +zln-Hani = zln-Hani-CN +zlq-Hani = zlq-Hani-CN +zma = zma-AU = zma-Latn = zma-Latn-AU +zmb = zmb-CD = zmb-Latn = zmb-Latn-CD +zmd = zmd-AU = zmd-Latn = zmd-Latn-AU +zme = zme-AU = zme-Latn = zme-Latn-AU +zmf = zmf-CD = zmf-Latn = zmf-Latn-CD +zmg = zmg-AU = zmg-Latn = zmg-Latn-AU +zmi = zmi-MY = zmi-Latn = zmi-Latn-MY +zmj = zmj-AU = zmj-Latn = zmj-Latn-AU +zmm = zmm-AU = zmm-Latn = zmm-Latn-AU +zmn = zmn-GA = zmn-Latn = zmn-Latn-GA +zmo = zmo-SD = zmo-Latn = zmo-Latn-SD +zmp = zmp-CD = zmp-Latn = zmp-Latn-CD +zmr = zmr-AU = zmr-Latn = zmr-Latn-AU +zmt = zmt-AU = zmt-Latn = zmt-Latn-AU +zmy = zmy-AU = zmy-Latn = zmy-Latn-AU +zmz = zmz-CD = zmz-Latn = zmz-Latn-CD +zna-Latn = zna-Latn-TD +zne = zne-CD = *zne-Latn = zne-Latn-CD +znk = znk-AU = znk-Latn = znk-Latn-AU +zoc = zoc-MX = zoc-Latn = zoc-Latn-MX +zoh = zoh-MX = zoh-Latn = zoh-Latn-MX +zom-Latn = zom-Latn-IN +zoo = zoo-MX = zoo-Latn = zoo-Latn-MX +zoq = zoq-MX = zoq-Latn = zoq-Latn-MX +zor = zor-MX = zor-Latn = zor-Latn-MX +zos = zos-MX = zos-Latn = zos-Latn-MX +zpa = zpa-MX = zpa-Latn = zpa-Latn-MX +zpb = zpb-MX = zpb-Latn = zpb-Latn-MX +zpc = zpc-MX = zpc-Latn = zpc-Latn-MX +zpd = zpd-MX = zpd-Latn = zpd-Latn-MX +zpe = zpe-MX = zpe-Latn = zpe-Latn-MX +zpf = zpf-MX = zpf-Latn = zpf-Latn-MX +zpg = zpg-MX = zpg-Latn = zpg-Latn-MX +zph = zph-MX = zph-Latn = zph-Latn-MX +zpi = zpi-MX = zpi-Latn = zpi-Latn-MX +zpj = zpj-MX = zpj-Latn = zpj-Latn-MX +zpk = zpk-MX = zpk-Latn = zpk-Latn-MX +zpl = zpl-MX = zpl-Latn = zpl-Latn-MX +zpm = zpm-MX = zpm-Latn = zpm-Latn-MX +zpn = zpn-MX = zpn-Latn = zpn-Latn-MX +zpo = zpo-MX = zpo-Latn = zpo-Latn-MX +zpp = zpp-MX = zpp-Latn = zpp-Latn-MX +zpq = zpq-MX = zpq-Latn = zpq-Latn-MX +zpr = zpr-MX = zpr-Latn = zpr-Latn-MX +zps = zps-MX = zps-Latn = zps-Latn-MX +zpt = zpt-MX = zpt-Latn = zpt-Latn-MX +zpu = zpu-MX = zpu-Latn = zpu-Latn-MX +zpv = zpv-MX = zpv-Latn = zpv-Latn-MX +zpw = zpw-MX = zpw-Latn = zpw-Latn-MX +zpx = zpx-MX = zpx-Latn = zpx-Latn-MX +zpy = zpy-MX = zpy-Latn = zpy-Latn-MX +zpz = zpz-MX = zpz-Latn = zpz-Latn-MX +zqe-Hani = zqe-Hani-CN +zqe-Latn = zqe-Latn-CN +zrg-Orya = zrg-Orya-IN +zrg-Telu = zrg-Telu-IN +zrn-Latn = zrn-Latn-TD +zro = zro-EC = zro-Latn = zro-Latn-EC +zrs-Latn = zrs-Latn-ID +zsa = zsa-PG = zsa-Latn = zsa-Latn-PG +zsr = zsr-MX = zsr-Latn = zsr-Latn-MX +zsu = zsu-PG = zsu-Latn = zsu-Latn-PG +zte = zte-MX = zte-Latn = zte-Latn-MX +ztg = ztg-MX = ztg-Latn = ztg-Latn-MX +ztl = ztl-MX = ztl-Latn = ztl-Latn-MX +ztm = ztm-MX = ztm-Latn = ztm-Latn-MX +ztn = ztn-MX = ztn-Latn = ztn-Latn-MX +ztp = ztp-MX = ztp-Latn = ztp-Latn-MX +ztq = ztq-MX = ztq-Latn = ztq-Latn-MX +zts = zts-MX = zts-Latn = zts-Latn-MX +ztt = ztt-MX = ztt-Latn = ztt-Latn-MX +ztu = ztu-MX = ztu-Latn = ztu-Latn-MX +ztx = ztx-MX = ztx-Latn = ztx-Latn-MX +zty = zty-MX = zty-Latn = zty-Latn-MX +*zu = *zu-ZA = zu-Latn = zu-Latn-ZA +zu-Brai = zu-Brai-ZA +zuh = zuh-PG = zuh-Latn = zuh-Latn-PG +zun = zun-US = zun-Latn = zun-Latn-US +zyg-Hani = zyg-Hani-CN +zyg-Nshu = zyg-Nshu-CN +zyj-Hani = zyj-Hani-CN +zyj-Latn = zyj-Latn-CN +zyn-Hani = zyn-Hani-CN +zyp = zyp-MM = zyp-Latn = zyp-Latn-MM +zza = diq = zza-TR = diq-TR = zza-Latn = diq-Latn = zza-Latn-TR = diq-Latn-TR +zza-Arab = zza-Arab-TR +zzj-Hani = zzj-Hani-CN diff --git a/resources/standards-data/alltags/readme.md b/resources/standards-data/alltags/readme.md new file mode 100644 index 0000000000..2a6b6903be --- /dev/null +++ b/resources/standards-data/alltags/readme.md @@ -0,0 +1,13 @@ +# alltags.txt + +This file is retrieved from https://raw.githubusercontent.com/silnrsi/sldr/master/extras/alltags.txt + +* We could use GitHub API to check for newer version as libpalaso code (Sldr.cs) does, but it's probably + not worth the extra effort right now. + +This file lists implicit script tags for language tags and equivalent BCP 47 tags per SLDR (and hence CLDR). We +use this to build up good clean BCP 47 tags for adding languages to Windows. + +## File Format + +The file format is documented at https://github.com/silnrsi/sldr/blob/master/doc/alltags.md diff --git a/windows/src/buildtools/build_standards_data/Keyman.Console.BuildStandardsData.pas b/windows/src/buildtools/build_standards_data/Keyman.Console.BuildStandardsData.pas index 4fb15d0b59..a9647db5d8 100644 --- a/windows/src/buildtools/build_standards_data/Keyman.Console.BuildStandardsData.pas +++ b/windows/src/buildtools/build_standards_data/Keyman.Console.BuildStandardsData.pas @@ -9,7 +9,8 @@ implementation uses Keyman.System.BuildISO6393Registry, Keyman.System.BuildLanguageSubtagRegistry, - Keyman.System.BuildLCIDToBCP47Registry; + Keyman.System.BuildLCIDToBCP47Registry, + Keyman.System.BuildLibPalasoAllTags; procedure Run; begin @@ -50,6 +51,11 @@ begin writeln('Building '+ParamStr(3)); TBuildLCIDToBCP47Registry.Build(ParamStr(2), ParamStr(3)); end + else if ParamStr(1) = 'alltags' then + begin + writeln('Building '+ParamStr(3)); + TBuildLibPalasoAllTags.Build(ParamStr(2), ParamStr(3)); + end else begin writeln('Invalid parameter'); diff --git a/windows/src/buildtools/build_standards_data/Keyman.System.BuildISO6393Registry.pas b/windows/src/buildtools/build_standards_data/Keyman.System.BuildISO6393Registry.pas index 50228070a4..52a17fd751 100644 --- a/windows/src/buildtools/build_standards_data/Keyman.System.BuildISO6393Registry.pas +++ b/windows/src/buildtools/build_standards_data/Keyman.System.BuildISO6393Registry.pas @@ -42,7 +42,7 @@ var begin FISO6393 := TStringList.Create; try - FISO6393.LoadfromFile(ISO6393File); + FISO6393.LoadfromFile(ISO6393File, TEncoding.UTF8); FResult := TStringList.Create; try @@ -86,7 +86,7 @@ begin FResult.Add(''); FResult.Add('end.'); - FResult.SaveToFile(DestinationFile); + FResult.SaveToFile(DestinationFile, TEncoding.UTF8); finally FResult.Free; end; diff --git a/windows/src/buildtools/build_standards_data/Keyman.System.BuildLCIDToBCP47Registry.pas b/windows/src/buildtools/build_standards_data/Keyman.System.BuildLCIDToBCP47Registry.pas index 0b5781d1dc..e813ccf7fa 100644 --- a/windows/src/buildtools/build_standards_data/Keyman.System.BuildLCIDToBCP47Registry.pas +++ b/windows/src/buildtools/build_standards_data/Keyman.System.BuildLCIDToBCP47Registry.pas @@ -26,7 +26,7 @@ var begin with TStringList.Create do try - LoadFromFile(MapFile); + LoadFromFile(MapFile, TEncoding.UTF8); FResult := TStringList.Create; try @@ -69,7 +69,7 @@ begin FResult.Add(''); FResult.Add('end.'); - FResult.SaveToFile(DestinationFile); + FResult.SaveToFile(DestinationFile, TEncoding.UTF8); finally FResult.Free; end; diff --git a/windows/src/buildtools/build_standards_data/Keyman.System.BuildLanguageSubtagRegistry.pas b/windows/src/buildtools/build_standards_data/Keyman.System.BuildLanguageSubtagRegistry.pas index 5b7fdf99cd..8330a4ff00 100644 --- a/windows/src/buildtools/build_standards_data/Keyman.System.BuildLanguageSubtagRegistry.pas +++ b/windows/src/buildtools/build_standards_data/Keyman.System.BuildLanguageSubtagRegistry.pas @@ -133,7 +133,7 @@ begin FResult.Add(''); FResult.Add('end.'); - FResult.SaveToFile(DestinationFile); + FResult.SaveToFile(DestinationFile, TEncoding.UTF8); finally FResult.Free; FLanguages.Free; @@ -187,7 +187,7 @@ begin FResult.Add(''); FResult.Add('end.'); - FResult.SaveToFile(DestinationFile); + FResult.SaveToFile(DestinationFile, TEncoding.UTF8); finally FResult.Free; end; @@ -196,7 +196,7 @@ end; constructor TBuildLanguageSubtagRegistry.Create(ASubtagRegistryFile: string); begin FSubtagRegistry := TStringList.Create; - FSubtagRegistry.LoadFromFile(ASubtagRegistryFile); + FSubtagRegistry.LoadFromFile(ASubtagRegistryFile, TEncoding.UTF8); FSubtagRegistry.Add('%%'); // Force final entry to be processed end; diff --git a/windows/src/buildtools/build_standards_data/Keyman.System.BuildLibPalasoAllTags.pas b/windows/src/buildtools/build_standards_data/Keyman.System.BuildLibPalasoAllTags.pas new file mode 100644 index 0000000000..a6dc7c8b10 --- /dev/null +++ b/windows/src/buildtools/build_standards_data/Keyman.System.BuildLibPalasoAllTags.pas @@ -0,0 +1,90 @@ +unit Keyman.System.BuildLibPalasoAllTags; + +interface + +type + TBuildLibPalasoAllTags = class + class procedure Build(AllTagsFile, DestinationFile: string); + end; + +implementation + +uses + System.Classes, + System.StrUtils, + System.SysUtils; + +{ TBuildLibPalasoAllTags } + +class procedure TBuildLibPalasoAllTags.Build(AllTagsFile, + DestinationFile: string); +var + FAllTags: TStringList; + FResult: TStringList; + i, j: Integer; + s: string; + items: TArray; + t: string; +begin + FAllTags := TStringList.Create; + try + FAllTags.LoadfromFile(AllTagsFile, TEncoding.UTF8); + FResult := TStringList.Create; + try + + FResult.Add('unit Keyman.System.Standards.LibPalasoAllTagsRegistry;'); + FResult.Add(''); + FResult.Add('interface'); + FResult.Add(''); + FResult.Add('// File-Date: '+FormatDateTime('yyyy-mm-dd hh:nn:ss', Now)); + FResult.Add('// Extracted from https://raw.githubusercontent.com/silnrsi/sldr/master/extras/alltags.txt'); + FResult.Add('// Generated by build_standards_data'); + FResult.Add(''); + FResult.Add('uses'); + FResult.Add(' System.Generics.Collections;'); + FResult.Add(''); + FResult.Add('type'); + FResult.Add(' TLibPalasoAllTagsMap = class'); + FResult.Add(' public'); + FResult.Add(' class procedure Fill(dict: TDictionary>);'); + FResult.Add(' end;'); + FResult.Add(''); + FResult.Add('implementation'); + FResult.Add(''); + FResult.Add('{ TLibPalasoAllTagsMap }'); + FResult.Add(''); + FResult.Add('class procedure TLibPalasoAllTagsMap.Fill(dict: TDictionary>);'); + FResult.Add('begin'); + + for i := 0 to FAllTags.Count - 1 do + begin + // Line format: ignore '*' + s := FAllTags[i]; + items := s.Split([' ','=','*'], TStringSplitOptions.ExcludeEmpty); + if Length(items) = 0 then + Continue; + t := Format(' dict.Add(''%s'', [', [items[0]]); + for j := 1 to High(items) do + begin + if j > 1 then + t := t + ', '; + t := t + Format('''%s''', [items[j]]); + end; + t := t + ']);'; + FResult.Add(t); + end; + + FResult.Add('end;'); + FResult.Add(''); + FResult.Add('end.'); + + FResult.SaveToFile(DestinationFile, TEncoding.UTF8); + finally + FResult.Free; + end; + finally + FAllTags.Free; + end; +end; + +end. diff --git a/windows/src/buildtools/build_standards_data/Makefile b/windows/src/buildtools/build_standards_data/Makefile index 7fc8505b67..9e298d5a7a 100644 --- a/windows/src/buildtools/build_standards_data/Makefile +++ b/windows/src/buildtools/build_standards_data/Makefile @@ -21,12 +21,16 @@ SUPPRESS_PAS=$(STANDARDS_OUT_PATH)\Keyman.System.Standards.BCP47SuppressScriptRe LCID_DATA=$(STANDARDS_DATA_PATH)\windows-lcid-to-bcp-47\map_clean_win.txt LCID_PAS=$(STANDARDS_OUT_PATH)\Keyman.System.Standards.LCIDToBCP47Registry.pas +ALLTAGS_DATA=$(STANDARDS_DATA_PATH)\alltags\alltags.txt +ALLTAGS_PAS=$(STANDARDS_OUT_PATH)\Keyman.System.Standards.LibPalasoAllTagsRegistry.pas + build: $(DELPHI_MSBUILD) build_standards_data.dproj $(WIN32_TARGET_PATH)\build_standards_data.exe iso6393 $(ISO6393_DATA) $(ISO6393_PAS) $(WIN32_TARGET_PATH)\build_standards_data.exe suppress $(SUPPRESS_DATA) $(SUPPRESS_PAS) $(WIN32_TARGET_PATH)\build_standards_data.exe subtag $(SUBTAG_DATA) $(SUBTAG_PAS) $(WIN32_TARGET_PATH)\build_standards_data.exe lcid $(LCID_DATA) $(LCID_PAS) + $(WIN32_TARGET_PATH)\build_standards_data.exe alltags $(ALLTAGS_DATA) $(ALLTAGS_PAS) clean: def-clean -rd /s/q Win32 diff --git a/windows/src/buildtools/build_standards_data/build_standards_data.dpr b/windows/src/buildtools/build_standards_data/build_standards_data.dpr index ef5f7bc807..64798cecb3 100644 --- a/windows/src/buildtools/build_standards_data/build_standards_data.dpr +++ b/windows/src/buildtools/build_standards_data/build_standards_data.dpr @@ -9,7 +9,8 @@ uses Keyman.System.BuildLanguageSubtagRegistry in 'Keyman.System.BuildLanguageSubtagRegistry.pas', Keyman.System.BuildISO6393Registry in 'Keyman.System.BuildISO6393Registry.pas', Keyman.Console.BuildStandardsData in 'Keyman.Console.BuildStandardsData.pas', - Keyman.System.BuildLCIDToBCP47Registry in 'Keyman.System.BuildLCIDToBCP47Registry.pas'; + Keyman.System.BuildLCIDToBCP47Registry in 'Keyman.System.BuildLCIDToBCP47Registry.pas', + Keyman.System.BuildLibPalasoAllTags in 'Keyman.System.BuildLibPalasoAllTags.pas'; begin try diff --git a/windows/src/buildtools/build_standards_data/build_standards_data.dproj b/windows/src/buildtools/build_standards_data/build_standards_data.dproj index ad861c5d22..352c78dc26 100644 --- a/windows/src/buildtools/build_standards_data/build_standards_data.dproj +++ b/windows/src/buildtools/build_standards_data/build_standards_data.dproj @@ -92,6 +92,7 @@ + Cfg_2 Base @@ -557,7 +558,6 @@ - False True False diff --git a/windows/src/desktop/kmshell/install/UfrmInstallKeyboardLanguage.pas b/windows/src/desktop/kmshell/install/UfrmInstallKeyboardLanguage.pas index f56f065f18..20c91ded06 100644 --- a/windows/src/desktop/kmshell/install/UfrmInstallKeyboardLanguage.pas +++ b/windows/src/desktop/kmshell/install/UfrmInstallKeyboardLanguage.pas @@ -102,9 +102,14 @@ type Rect: TRect; State: TGridDrawState); private type TLanguageGridRowType = (lgrtNormal, lgrtSuggested, lgrtHeading); + TCustomLanguage = record + FullName, LanguageName, ScriptName, RegionName: string; + Tag: string; + end; private FKeyboard: IKeymanKeyboardInstalled; FLanguages: TInstLanguageList; + FCustomLanguage: TCustomLanguage; procedure SetKeyboard(const Value: IKeymanKeyboardInstalled); procedure AddLocale(lpLocaleString: PWideChar); procedure EnableControls; @@ -122,6 +127,9 @@ uses System.Types, Vcl.Themes, + Keyman.System.CanonicalLanguageCodeUtils, + Keyman.System.LanguageCodeUtils, + BCP47Tag, GetOSVersion, kmint, @@ -248,7 +256,7 @@ var begin FLanguageVariant := gridLanguageVariants.Objects[0, gridLanguageVariants.Row] as TInstLanguageVariant; if not Assigned(FLanguageVariant) - then FCode := gridLanguageVariants.Cells[0, gridLanguageVariants.Row] // Using a custom code + then FCode := FCustomLanguage.Tag // Using a custom code else FCode := FLanguageVariant.Code; if not kmcom.SystemInfo.IsAdministrator then @@ -340,7 +348,9 @@ procedure TfrmInstallKeyboardLanguage.FillLanguageGrid; var n: Integer; FLanguage: TInstLanguage; + FVariant: TInstLanguageVariant; FText: string; + FFoundCustomTag: Boolean; procedure AddRow(IsSuggested: Boolean; const Name, LocalName, Script, Code: string; Item: TInstLanguage); begin @@ -367,28 +377,51 @@ begin gridLanguages.RowCount := FLanguages.Count + 3; - FText := editSearch.Text; + FText := Trim(editSearch.Text); n := 1; + FFoundCustomTag := False; + for FLanguage in FLanguages do begin if FLanguage.Matches(FText) then begin AddRow(FLanguage.IsSuggested, FLanguage.Name, FLanguage.LocalName, FLanguage.Script, FLanguage.Code, FLanguage); + if SameText(FText, FLanguage.Code) then + FFoundCustomTag := True; + for FVariant in FLanguage.Variants do + if SameText(FText, FVariant.Code) then + FFoundCustomTag := True; end; end; - if IsValidLocaleName(PChar(FText)) and not (GetOs = osWin7) then + if IsValidLocaleName(PChar(FText)) and not (GetOs = osWin7) and not FFoundCustomTag then begin // Adding custom locales supported with Win8 and later - with TBCP47Tag.Create(FText) do - try - if Tag <> '' then - AddRow(False, Tag, Tag, Script, Tag, nil); - finally - Free; - end; + FText := TCanonicalLanguageCodeUtils.FindBestTag(FText); + if FText <> '' then + with TBCP47Tag.Create(FText) do + try + // Let's lookup the lang - script - region and get a good name + FCustomLanguage.Tag := Tag; + if not TLanguageCodeUtils.BCP47Languages.TryGetValue(Language, FCustomLanguage.LanguageName) then + FCustomLanguage.LanguageName := ''; + if not TLanguageCodeUtils.BCP47Scripts.TryGetValue(Script, FCustomLanguage.ScriptName) then + FCustomLanguage.ScriptName := ''; + if not TLanguageCodeUtils.BCP47Regions.TryGetValue(Region, FCustomLanguage.RegionName) then + FCustomLanguage.RegionName := ''; + FCustomLanguage.FullName := TLanguageCodeUtils.LanguageName(FCustomLanguage.LanguageName, + FCustomLanguage.ScriptName, ''); + AddRow( + False, + FCustomLanguage.FullName, + FCustomLanguage.FullName, + FCustomLanguage.ScriptName, + FCustomLanguage.Tag, nil); + finally + Free; + end; end; gridLanguages.RowCount := n; @@ -423,17 +456,12 @@ begin begin // We have a custom language tag gridLanguageVariants.RowCount := 2; - with TBCP47Tag.Create(gridLanguages.Cells[0, gridLanguages.Row]) do - try - gridLanguageVariants.Objects[0, 1] := nil; - gridLanguageVariants.Cells[0, 1] := Tag; - gridLanguageVariants.Cells[1, 1] := Region; - gridLanguageVariants.Cells[2, 1] := Tag; - gridLanguageVariants.Cells[3, 1] := Region; - gridLanguageVariants.Cells[4, 1] := Tag; - finally - Free; - end; + gridLanguageVariants.Objects[0, 1] := nil; + gridLanguageVariants.Cells[0, 1] := FCustomLanguage.FullName; + gridLanguageVariants.Cells[1, 1] := FCustomLanguage.RegionName; + gridLanguageVariants.Cells[2, 1] := ''; + gridLanguageVariants.Cells[3, 1] := ''; + gridLanguageVariants.Cells[4, 1] := FCustomLanguage.Tag; end else begin diff --git a/windows/src/desktop/kmshell/kmshell.dpr b/windows/src/desktop/kmshell/kmshell.dpr index c9e69f55ce..db2fadbcee 100644 --- a/windows/src/desktop/kmshell/kmshell.dpr +++ b/windows/src/desktop/kmshell/kmshell.dpr @@ -153,7 +153,10 @@ uses Keyman.System.Standards.LCIDToBCP47Registry in '..\..\global\delphi\standards\Keyman.System.Standards.LCIDToBCP47Registry.pas', kmxfileconsts in '..\..\global\delphi\general\kmxfileconsts.pas', Keyman.System.UpdateCheckResponse in '..\..\global\delphi\general\Keyman.System.UpdateCheckResponse.pas', - Keyman.System.Standards.BCP47SubtagRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SubtagRegistry.pas'; + Keyman.System.Standards.BCP47SubtagRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SubtagRegistry.pas', + Keyman.System.Standards.LibPalasoAllTagsRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.LibPalasoAllTagsRegistry.pas', + Keyman.System.CanonicalLanguageCodeUtils in '..\..\global\delphi\general\Keyman.System.CanonicalLanguageCodeUtils.pas', + Keyman.System.Standards.BCP47SuppressScriptRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SuppressScriptRegistry.pas'; {$R VERSION.RES} {$R manifest.res} diff --git a/windows/src/desktop/kmshell/kmshell.dproj b/windows/src/desktop/kmshell/kmshell.dproj index 9ac34fa303..0b1eee4ac7 100644 --- a/windows/src/desktop/kmshell/kmshell.dproj +++ b/windows/src/desktop/kmshell/kmshell.dproj @@ -296,6 +296,9 @@ + + + Cfg_2 @@ -391,15 +394,15 @@ true - + - .\ + kmshell.exe true - + - kmshell.exe + .\ true diff --git a/windows/src/desktop/kmshell/kmshell.res b/windows/src/desktop/kmshell/kmshell.res index 6f392546a5ce05751e3dd14d920f009bc86af5b1..7ded6630a8f3ffafb9b91e4a20ef46f1f264cc06 100644 GIT binary patch delta 15 WcmZoLZ!n)w!eVtsS88Jghco~y%mokt delta 15 WcmZoLZ!n)w!qWcyk>th-4ru^0Dh4b7 diff --git a/windows/src/global/delphi/general/Keyman.System.CanonicalLanguageCodeUtils.pas b/windows/src/global/delphi/general/Keyman.System.CanonicalLanguageCodeUtils.pas new file mode 100644 index 0000000000..9f70577a20 --- /dev/null +++ b/windows/src/global/delphi/general/Keyman.System.CanonicalLanguageCodeUtils.pas @@ -0,0 +1,99 @@ +unit Keyman.System.CanonicalLanguageCodeUtils; + +interface + +type + TCanonicalLanguageCodeUtils = class + class function FindBestTag(const Tag: string): string; + end; + +implementation + +uses + BCP47Tag, + Keyman.System.LanguageCodeUtils, + System.SysUtils; + +// +// Find a language code with appropriate script and region subtags +// +// 1. if suppress-script is present and equal to the script of the tag, remove script +// 2. otherwise, if suppress-script is not present, and no script is given, find +// appropriate script from alltags. +// 3. finally, if no appropriate script is given, return '', because we'll need user +// to figure out the script themselves +// +class function TCanonicalLanguageCodeUtils.FindBestTag(const Tag: string): string; +var + t: TBCP47Tag; + script: string; +var + v: TArray; + + function GetBestTagFromArray(a: TArray): string; + var + i: Integer; + begin + for i := High(a) downto 0 do + begin + with TBCP47Tag.Create(a[i]) do + try + if not IsCanonical then + Continue; + finally + Free; + end; + Exit(a[i]); + end; + Result := ''; + end; +begin + if Tag = '' then + Exit(''); + + t := TBCP47Tag.Create(Tag); + try + if t.Tag = '' then + Exit(''); + if TLanguageCodeUtils.SuppressScripts.TryGetValue(t.Language, script) then + begin + if SameText(t.Script, script) then + begin + // The script should be suppressed because it is known to Windows (**really?) + // We won't do a region check because this is not really required. + t.Script := ''; + Exit(t.Tag); + end; + end; + + // + // Lookup the full tag first. + // + if TLanguageCodeUtils.AllTags.TryGetValue(t.Tag, v) then + Exit(GetBestTagFromArray(v)); + + // + // Full tag not found, so reduce to Lang-Script + // + if (t.Script <> '') and TLanguageCodeUtils.AllTags.TryGetValue(t.Language+'-'+t.Script, v) then + Exit(GetBestTagFromArray(v)); + + // + // Check Lang-Region + // + if (t.Region <> '') and TLanguageCodeUtils.AllTags.TryGetValue(t.Language+'-'+t.Region, v) then + Exit(GetBestTagFromArray(v)); + + // + // Finally, check just Lang + // + if TLanguageCodeUtils.AllTags.TryGetValue(t.Language, v) then + Exit(GetBestTagFromArray(v)); + finally + t.Free; + end; + + Result := ''; +end; + +end. diff --git a/windows/src/global/delphi/general/Keyman.System.LanguageCodeUtils.pas b/windows/src/global/delphi/general/Keyman.System.LanguageCodeUtils.pas index 8e6a5a3df2..b95f1aa26c 100644 --- a/windows/src/global/delphi/general/Keyman.System.LanguageCodeUtils.pas +++ b/windows/src/global/delphi/general/Keyman.System.LanguageCodeUtils.pas @@ -15,13 +15,19 @@ type FBCP47Languages: TDictionary; FBCP47Scripts: TDictionary; FBCP47Regions: TDictionary; + FSuppressScripts: TDictionary; + FAllTags: TDictionary>; class procedure BuildISO6393ToBCP47; static; class procedure BuildLCIDToBCP47; static; class procedure BuildSubtagRegistry; static; + class procedure BuildAllTagsRegistry; static; class function GetBCP47Languages: TDictionary; static; class function GetBCP47Regions: TDictionary; static; class function GetBCP47Scripts: TDictionary; static; + class function GetAllTags: TDictionary>; static; + class function GetSuppressScripts: TDictionary; static; + class procedure BuildSuppressScripts; static; public class function TranslateISO6393ToBCP47(codes: TStringDynArray): TStringDynArray; overload; static; class function TranslateISO6393ToBCP47(code: string): string; overload; static; // single code @@ -38,15 +44,20 @@ type class property BCP47Languages: TDictionary read GetBCP47Languages; class property BCP47Scripts: TDictionary read GetBCP47Scripts; class property BCP47Regions: TDictionary read GetBCP47Regions; + class property AllTags: TDictionary> read GetAllTags; + class property SuppressScripts: TDictionary read GetSuppressScripts; end; implementation uses + System.Classes, System.SysUtils, Keyman.System.Standards.BCP47SubtagRegistry, + Keyman.System.Standards.BCP47SuppressScriptRegistry, Keyman.System.Standards.ISO6393ToBCP47Registry, Keyman.System.Standards.LCIDToBCP47Registry, + Keyman.System.Standards.LibPalasoAllTagsRegistry, utilstr; @@ -63,8 +74,7 @@ end; class function TLanguageCodeUtils.TranslateISO6393ToBCP47(code: string): string; begin - if not Assigned(FISO6393ToBCP47) then - BuildISO6393ToBCP47; + BuildISO6393ToBCP47; if not FISO6393ToBCP47.TryGetValue(code, Result) then Result := code; @@ -96,23 +106,37 @@ end; class function TLanguageCodeUtils.TranslateWindowsLanguagesToBCP47(code: Integer): string; begin - if not Assigned(FLCIDToBCP47) then - BuildLCIDToBCP47; + BuildLCIDToBCP47; if not FLCIDToBCP47.TryGetValue(code, Result) then Result := ''; end; +class procedure TLanguageCodeUtils.BuildAllTagsRegistry; +begin + if not Assigned(FAllTags) then + begin + FAllTags := TDictionary>.Create; + TLibPalasoAllTagsMap.Fill(FAllTags); + end; +end; + class procedure TLanguageCodeUtils.BuildISO6393ToBCP47; begin - FISO6393ToBCP47 := TDictionary.Create; - TISO6393ToBCP47Map.Fill(FISO6393ToBCP47); + if not Assigned(FISO6393ToBCP47) then + begin + FISO6393ToBCP47 := TDictionary.Create; + TISO6393ToBCP47Map.Fill(FISO6393ToBCP47); + end; end; class procedure TLanguageCodeUtils.BuildLCIDToBCP47; begin - FLCIDToBCP47 := TDictionary.Create; - TLCIDToBCP47Map.Fill(FLCIDToBCP47); + if not Assigned(FLCIDToBCP47) then + begin + FLCIDToBCP47 := TDictionary.Create; + TLCIDToBCP47Map.Fill(FLCIDToBCP47); + end; end; class procedure TLanguageCodeUtils.BuildSubtagRegistry; @@ -145,6 +169,12 @@ begin end; end; +class function TLanguageCodeUtils.GetAllTags: TDictionary>; +begin + BuildAllTagsRegistry; + Result := FAllTags; +end; + class function TLanguageCodeUtils.GetBCP47Languages: TDictionary; begin BuildSubtagRegistry; @@ -157,6 +187,31 @@ begin Result := FBCP47Scripts; end; +class function TLanguageCodeUtils.GetSuppressScripts: TDictionary; +begin + BuildSuppressScripts; + Result := FSuppressScripts; +end; + +class procedure TLanguageCodeUtils.BuildSuppressScripts; +var + FScripts: TStringList; + i: Integer; +begin + if not Assigned(FSuppressScripts) then + begin + FSuppressScripts := TDictionary.Create; + FScripts := TStringList.Create; + try + FScripts.Text := SuppressScriptSubtagRegistry; + for i := 0 to FScripts.Count - 1 do + FSuppressScripts.Add(FScripts.Names[i], FScripts.ValueFromIndex[i]); + finally + FScripts.Free; + end; + end; +end; + class function TLanguageCodeUtils.LanguageName(const LanguageName, ScriptName, RegionName: string): string; begin Result := LanguageName; @@ -204,5 +259,6 @@ finalization FreeAndNil(TLanguageCodeUtils.FBCP47Languages); FreeAndNil(TLanguageCodeUtils.FBCP47Regions); FreeAndNil(TLanguageCodeUtils.FBCP47Scripts); + FreeAndNil(TLanguageCodeUtils.FAllTags); end. -- GitLab From a89376871617e34bd8e80068594dc5a888d904e1 Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Mon, 7 May 2018 14:39:12 +0700 Subject: [PATCH 080/356] Incorporates Developer and corrects the application of the KMW side. --- web/source/kmwcallback.ts | 29 +++++++++++++++---- .../TIKE/compile/CompileKeymanWeb.pas | 6 +++- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/web/source/kmwcallback.ts b/web/source/kmwcallback.ts index 84057bab42..00f0467186 100644 --- a/web/source/kmwcallback.ts +++ b/web/source/kmwcallback.ts @@ -83,15 +83,17 @@ namespace com.keyman { ['t']: 'n'; } - class ContextBeep { + class StoreBeep { /** Discriminant field - 'b' for `beep` */ ['t']: 'b'; } - type ContextNonCharEntry = RuleDeadkey | ContextAny | RuleIndex | ContextEx | ContextNul | ContextBeep ; + type ContextNonCharEntry = RuleDeadkey | ContextAny | RuleIndex | ContextEx | ContextNul ; type ContextEntry = RuleChar | ContextNonCharEntry; + type StoreNonCharEntry = RuleDeadkey | StoreBeep; + /** * Cache of context storing and retrieving return values from KC * Must be reset prior to each keystroke and after any text changes @@ -513,9 +515,6 @@ namespace com.keyman { mismatch = true; } break; - case 'b': - this.beep(Ptarg); - break; default: assertNever(r); } @@ -776,11 +775,29 @@ namespace com.keyman { indexOutput(Pdn: number, Ps: KeyboardStore, Pn: number, Pelem: HTMLElement): void { this.resetContextCache(); + var assertNever = function(x: never): never { + // Could be accessed by improperly handwritten calls to `fullContextMatch`. + throw new Error("Unexpected object in fullContextMatch specification: " + x); + } + var indexChar = this._Index(Ps, Pn); if(indexChar !== "") { if(typeof indexChar == 'string' ) { this.output(Pdn,Pelem,indexChar); //I3319 - } else { + } else if(indexChar['t']) { + var storeEntry = indexChar as StoreNonCharEntry; + + switch(storeEntry.t) { + case 'b': // Beep commands may appear within stores. + this.beep(Pelem); + break; + case 'd': + this.deadkeyOutput(Pdn, Pelem, indexChar['d']); + break; + default: + assertNever(storeEntry); + } + } else { // For keyboards developed during 10.0's alpha phase - t:'d' was assumed. this.deadkeyOutput(Pdn, Pelem, indexChar['d']); } } diff --git a/windows/src/developer/TIKE/compile/CompileKeymanWeb.pas b/windows/src/developer/TIKE/compile/CompileKeymanWeb.pas index b10ba0e035..d45c8ca344 100644 --- a/windows/src/developer/TIKE/compile/CompileKeymanWeb.pas +++ b/windows/src/developer/TIKE/compile/CompileKeymanWeb.pas @@ -1111,7 +1111,11 @@ begin begin if rec.Code = CODE_DEADKEY then begin - Result := Result + Format('{d:%d}', [rec.Deadkey.DeadKey]); + Result := Result + Format('{t:''d'',d:%d}', [rec.Deadkey.DeadKey]); + end + else if rec.Code = CODE_BEEP then + begin + Result := Result + '{t:''b''}' end else //if rec.Code = CODE_EXTENDED then begin -- GitLab From c593a45e7d8d01ac476c31e7c809fb274fbf388b Mon Sep 17 00:00:00 2001 From: darcywong00 Date: Mon, 7 May 2018 14:47:11 +0700 Subject: [PATCH 081/356] Update string handling for PackageProcessor Fixes #819 * If package version undefined, use "1.0" * Keyman Developer won't allow undefined package name, but just in case return package ID from the filename * Check for null before String.toLowerCase() * Added package processor test for undefined version --- .../tavultesoft/kmapro/PackageActivity.java | 11 ++------ .../kmea/packages/PackageProcessor.java | 16 +++++++----- .../kmea/packages/PackageProcessorTest.java | 24 ++++++++++++++++++ .../test_resources/v/gff_amh_7_test_json.kmp | Bin 0 -> 488668 bytes 4 files changed, 35 insertions(+), 16 deletions(-) create mode 100644 android/KMEA/test_resources/v/gff_amh_7_test_json.kmp 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 dc35ae42eb..3923c72311 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); @@ -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; 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 040d355786..b1ab91a87e 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; @@ -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/test/java/com/tavultesoft/kmea/packages/PackageProcessorTest.java b/android/KMEA/app/src/test/java/com/tavultesoft/kmea/packages/PackageProcessorTest.java index d82409d276..4ddadc43f6 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/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 GIT binary patch literal 488668 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�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%0AdOpo2MU;X;`8BE?QJyGDV%wF&1Rm{?}gn-OLg znfj-3-K`Z{oCFYdN(h|ESg@M)B}sc&ZR9Hg$Ikw;$aYElAH8~M2lyTM)7GIHgfngk zAj@_tW|Q|9j3@eJWx(5|lqvFh;GdT%B*M(F?gq;mvz?d39<)-gim>Iw_$S@LvimAwQ=cIXA7I_E{{ESkcI`j1yjvroBCf)x~c{SokVFSWPn7K1^ z6Sq?nX5}P5AG7l(<2DQaadR7L z-dX&TGJM~0#H1&7V$yH_qwY}=d{0M&9s8WmC@>KKXJ&8e;_7S$wEHh|Ft&!{U;!`# z{tNi|nSOaWnlVW_*t?3GxtKUxIl4MH{~uKZ+L~KsXE+%I7uK!iSF^K^krOm7?EdNLU zo8`Z@|9ZkP$+!Y-txQDhEo{vI%y3LyVAnd{UW%yQ0>C5lonT9G>}F=6~eDHMy5zWg#egoF57tUNl8W)9b^VhRHnbYM_ASi)s*C8y&pqoX=$D!rM|8d&4; zkBlO8bLXRX_v7nMVD6=0XvYTGX3nPOYx9EuIuunDsu_}{JYXl-lp-mhY8TpJAqqY{ z_T=#N2@uL;*l=h3bIWl<92UAuQmhdllji{}Jr$)c3THnqd|+H>Pda@mL#^Cx^j>L9 zg&wOsC2f9APta<@L!*a#fDMhA6X9=uAB<+2dZ5+XGkI5)YusjtF9N2~)1#<)dRNp=yzQ`Sskx$}S4sXt<&$s~4xPAF6U^2< z>nV z7qr@UCv-TLa&Tb-izS_wAsO@|?1hDbGe5XI4F(C2_Oz8Bly3Q6U#2Cd zeUu-HEa7s61I9)?5qq?B1zw8?(S7kaKBX-ag^vN{iNjedFc{RU*E2o2*-4s(Fyy_MZh@}3 z$gO+4&FI^4z0fY-81K06nB&{PH=d}t0X*Lz?F35fN9x}a1S2KPolSQjy%-K-ZTk_o zbgwV3)Za;fKU5-~#>L^&lyc)7M<(|aMP}lqu^llT$#0Mk9mdIxXn9mAN_6oJQtH4b ze8cN3e+#IY>dX!kbIn>j(?rOLroh<}Wxnw(Tdm_%ON6{9OR`RklQZXxJ0B6}=K=)Y zK>w(nzz(6`J5cZvA9DG~Mig;HR_r0L)n#Z^`x7rc1RAB_#b!8l!7VdFntL|43a^Zw z?)x`~A3*!z@w$o4Bjh8O za0~gEe(_Ak6aEuPbG~HrJY)ZfPgzuzW*TpdQ#u3nPXfuEqMQ=FO1;8vZLhw2k>frZ zLro&}ll9GY=ym#!UfHTjm8UAKN_*8WVK?C?K6OPxNUw{Ko%Dh_|F(S>44FpsQ)#Tx zFB4~$hnu6W*T^OA1ZTcSBMKea#_5M6AI)pi?|y!nS`q058VjxvOdoK8h#lqLih7z| zsX8>ScZjQfk4&?pu_OC~VGjAC1Md-hBR5VFA!71~$fzsOxOgLuv_DPt@Lv)QFn(|k z0m>bOC(YU2A^Cv1gblz%#Jt!MNGJY3$tp*NM|%oyJioZ!kQX-pZsa3-wk&btA~M4# zjl>*#s+#I#TT^_au;;_K4ow-EYqI(G-NVa;&FNFXNA#^;j(B{52XG}IOifF9nwtOY z)acFE5?lIT{yg{D-enYu<-CQZP_k$=rj*f4@>1Q5D=m|G?Ff}LK7E;3>()a#2Nb?9 z_ByS#RIDYkG?*5uc9D>%(2z*R2-n8$AD?-oM|u-6;0drX>?k9j_VY}`H8c~v#sKoU z0;a5>6n+5@Cqn3DXIe~oNat6?#jSHUj+>|=^8GPmXr2&QtMnwp#C8qAuhE5oJ)ZS& z1CYz(Q0;E9ip)%~*)n0|T}gpgb9TWdG==`&gJGZ^>>_)~R{2(iuijhA{n%uF1Lhg) z{9pb0r~u(H;M(mWCNnnipT3~#wvgwP;O}M;CT}C;u0RCVxgw-1$s!~0=mGn-Ap-jF z)Gd$}y%2j)KX07pgdgEC=J@mi;v%sE9;EpP%=uoti*pH!fl3GA_&~RAta!0W*&{KQ zjIy}~)V0LuLIG=w8xTG|P``IVZ)AEY#cNF(`{CSrZ@T&2az-(Dj&kCgFaa;(%81;? zWH0b9)G#9tJ7_{bm`TJCTbxAf6}sIKh}7BXnUzG2>4$Zsu0qseYm%$08BYZ7fdTH) zM8r9<6*dcDJEcH|OHD!g7KRiZ-K=ap{EJKLDmC>~%;SkhaVvfeRf5=1F=OUEY~LNy z_|0S2bvupdjbRtb5QDOna`kG}0hAcouHkE7055BfhWKz^9z<;P6actk1v_LVMD7-l zOZAU9ZR6AMG$qjGsLxT>OYt0o>f}qIoJQs12JP!S-!1B!-he*%R?I0}wrJnbME4Jk&kA`_zTIYH()H&vs8&%4z??y?a2SVqaL6LGo9<0%Dpa;4&pI<3A{@2c!DG|H{5%UpQ9<` zSvm(2Eb+Mxgx>EY5XPjkXs435*-wJ7e!u}mtm08tE0M!WVeHnuH>h;!-pVWk`)gB3 z3;=qtJZ7k*tsxB@`n32BRgsf}#xX90t2lOet`!sYyApgA<9(fUtO~sZzv)QODdhz` z=v?fJxorvxKZ*G(2t`1;;70v%)S)=z%ZW6pW(aZ`n-*89w-s|$f(!t*Y#}UwQUsC>TrYgwY?e9#x!-( zN{{{3-R>vUpL+JZP`jT@mo+2c(?qrHHw8d2=CB8`qA2&P`|Xg^r#Z;QsKsBOA7Qc< z3lGf-ksP=GJkUcjj=z2*C7q-;QSl4!VF`yIM|hDhZoWkm(!6tiga7@YG!w=Zs;KTKZ63p&?;YM+^b$l4jr)ll_##?q z*FjJqcTcaAk*&;psIQ-@ie=d?Uz&N4H2K9&cF0)iOVk?JwGSW@2Af?Ma7LPJZo>xS zaC__bq*w83SEv#`Q*#stEt6O`I95FzF-sjY2;??5M~PrjFzY2at(nJT6PVSeE#b_2 zgT8>4QqJ0lrtC*;j(bC}gOUpLQ=(K6!8d-6v58IPzYU1`+-nUqnYX`fAV}|5`BoZZ zaM$_DXU&me^x#&@n}iwCPJJVMJmomSb_~P>LHh>dbPDpqEXO{hn^sB`xjq#; zBrxoN{Og0VPHf6qh&Jw@(LtaN<`>g}_iQ-%oE^imJL|wY(lE)%@IdWSGTj)23;s&N zjLm#%K@0fm$Pq|I>$!Ld`d>=NC?Ro(JwHk7n-zpCf#_5Cw4r` zDUcinGzaQHoRLYsO!N+al7eH3_y`%b_KWBmA+hR$F2YV9PIKU9Gdl&oWly^YuY&y( zNKnyKVYO%0P;9o!fCg~Qd_tOkGCA9fjgh&fmNN`)1y2s3W-NP6y@$+htz{rZlwg_ZZScNj--BMR%OruDPO^v zJ#bX(h}Lkd=4z)i7+5z`54}yyE+3|KEs40na)sEh9W`qC`h9hYCTE?>BCuY~B#R;{ zx=8!5ly99oq2}0hGi;7B*J;ll}^sozr&MsB7G9>Q4aXQDT3O< z0}oOU*hpQWUoP*v>5s6OsdiHEWC}*1nzC0Ol?Iv<}6~wjJ`oju|rLX*tnWh z1CeIugn?On9^JKtjh`TFnnbr-F@Td~Hmr1lvsugg!6lYjj)fCmvr$h;yOiWZ$Q~2p zLk+1Ckim5Tazzv^w;H_7FZc&T_(^4oInQHm2Pjm-iC>f3wc;P%%ylK;A8z@s|6-|FvXe$8jgJZJs{UG+$A}@2yw#RJk87q--?b9*7Bk` z(1u`K2=?&p+k2G#gy3bO(3ud;$spIxw{3xPA$$mmpzx}2U({jzY==@y)}av1nOh7T zdoz}7JMx@t*_hd>*>5wHEx!mEYf@HK>teh|_EwN=Bsp~1i3(4bz#P%ktmC3e#TX+sS8t<2CL zNH2bW#|V5+Z~5|jhX~{e6n(RdiUpO#%>Jo%BRP!n)r{M^w!Tn=&^Bs39mP znuF=7!`+HH8F)+esLtQr5b7Q-#}&8j^>w%kvzKX>t|0g(h=B18lm6}*gl28^d>h;J zbmd8v8mYsyaV>5MZ9r9zkbEeqd8}KHNfLwEOppN8xSN#2p}qJ?C)iJa9`ayAMX^2c z^2@gVHptK1J!<0E=)LqMZf;chR|kL{#(z{WZ?V5H=#gbe1|vR6z${WsNceGi(MZqd z#ed5;b0mm4Ga-vGAy4%1Lr@@3*bxVNlRzkj?(|YT^g#MLO!zv05+i<9H3M&@juRmK z`v}kmn94}*H6*K#{}PyDFSlcSe)JPUjTMl;*6giLumm|L=a5dRXGf5hscj?cE5f+gA{v^$TgIk-YS~aD{R^^AsB}p2IY5 z0?W9vmrv-uIGaZ4O()bcjfuuR^GvC&noyulb^?VGzlbNk{ThGtH-vPbd1R>YzDe*5 zun^;;!Z{f-V?`5u<)4KTzFLx4Og)86Jt<5*nN2+brrd$M5+dU;($@w1@ghS3P>6F7 zi1E;fZIFm^!QpQrLpgw&N}RXEAkT{UxzsPxiG42LbFR-FhgXlj{WAZdFaM!}-T6Ie z_fPC~cEneMjXt&Ks(cyT(3F8}R(`pD)_oUNf<*!VM1BZD3@5q`YGaHfC3(U*JUGqd zV+-h=>H93i!R%uVwDH8_Hf6IFOvDQqDe7<38+EnHx#3pPRz{`e%=Hf8luWIjgb}vP z449+n>EGDnrr+5Bqy zzvO$}J~6BZfYRY&p#LEKS7ET>!^$9KweWCj zfRGd`r7VAa-Z(9d(3p+|#TpuQd__^NQ~MSpPn?@%uOpKU>VXNh7|BOnKlIPDPA@to zG8J4`juH!WF(<#HbXuA~TE7(M1ZT}Wst=h>Q_Zpy`S7vQa13F zl}ullznR>1Qq^)LM(0Q|la*z1#KPEre@rVv@(8bmI{0RTN?xqTu-WwPPt0vciuz&9 zZJRORBQ*Xa4W9VP40IKaI2cZ-L5Ulo`leY}c@efRnh@#jC0t?WFl zAn){#B`U1n+SOrfIjXi}RxV5z`s>#aC+r=lNMi8NjoealdN+mGWFM%bC2IjwVpcCt zyLbfR&#^VL8ZOZly!zjRZ8V7FV>|4ezmc4`RSQVV-A!YRMBU#B#(R-J z0k66%-vKHx@mvnwmVpM|h|&60{fK1_JMDincN({Dc6}B`2ko>>J>Q~MQW$kpcc^PG zj6$+pAq1eXmzL8|qrzmMU5=TEC+w zTNfuUEOlMRz9pV`!Vn@-8PDE#Gk{@H& z3C%uF{<&z*VLqtm=O;IwHCJzt;dr$zLgKB!gFD}lJMLgk;43ykn%SWtBZi}gi>_{}iVkHKX@sVoNBsS~=fxQ?W z!Dw^>+ibpNmVMR~vBO2Sy=V=}NgqVrAATdajKRHqQpoqkIeA|ing#6fx{LyIU#DxO zSCt%5UJPHj8DlqjEM4+kL$z8GymbF=D=j&zZHS#cq8)fV^DT2EWZxvUlGdNMy?d%FyqE(Zl$KF&Kj8J{ghB`? zHxA=aH14A0WMz`FEwadwV3arsdBgazUt7HP$YZwzCwhv9@xTX_WX*(R?pvVOv=ney zOiaP=^AUy6t*Ya@sesHu}mqhtZ0|{!0;4BX{1f zl{g^c`KPC_<1@0isJx{GR+1Tll~FtLm#H;HQUvrI5Ms{Wvg8ko=dxbBg1OXJYvZf> zr`-B4Lu4@m)dOMWkxFqnki&<&_33;fgL#xldW$HFi)akF!(PbO{ka>_`x$_0DbNng zv5_v_9{!%!&-h_fCc#vUp($5nz|oaT9`a2G_oyAzFT@2goe{uqbQLKKX$#mXDbw(GEZ%NByd6+ zW1Yl#K$&G4Z&b=F@)RdxyLQETIfrmFe`F1SnlAIl@RBw@MzU4hU5b)SiqtkE{*_F% zm{`?aauIbU4qk+L?6vTa(PQ^<8O3?WYwrOSA1G&;_LdXAO0i(}dKFYmHM*i5RNV$ZnuS#+i^b;i9J`wIHFq%yh_Z2*1Syq;|ZrJs^q?(zX zoEtTElsHzn7AHyt1NCD~u2r6!J;qNlc)(mPRI6;f_sRP;EtU4?2Wjs~=Zj}gghs?r zCt4ROoB{94H?j~G{H9m_dXd#HjlWCyPPV6E?TFw7FJ+wD0`e>RUv@I(_;URm?^7*x zp4mUUDoJ$ec^2BBi9B*1>jaGrG_llu7~mn+eXE$LF%z65(CR+Cl6LZ_PWl5f-E5hMN9igXv437)9?B%})wHQg;+6Ph;iu+M&sN9!2pG;PLQ>}*h3 zBML3-asZ)mZw%WFpSn(yWLBNnNBbs#DUq#HGbwfq^OXkE;D#N1_Tot+)tVybjKm

rB3~r-~G&BWSUL@LXKz3tG+&UAR47eCMY;gU!zQXWJEmf5PNbW2^xN7sNki_*T0?*Q}(SVk!)aNgxi5GCRIP})yGaobl?^a zQmhVQm9)Btt)ASe@#42~Q4$SuCSPA#5=rL zwAe{}tVGqxGr@`wSO-6j^QE|Wf4JCSHK$j6{-&tHM+=nu>p7sy^vkPbY}9E=R=8gn96$b6i$PiRIJj*c*b*rE)D zzmfRa+GY9h4q$)vu!^el*9Y4@=iTSr|CLZgQo$gqdG%2nAbjyzFR%=Zf{xB(W}&8` zHl{OIG-M;_5Aq1V*139J$NGFR1(V?QqD){UF$KF;#6`cPHx{?DeAv0n`@=o1xA-~cant#T9!N`-=iwaZ865LSR%SX!fRMT}Y<+N=x~1x@as^pwd$pcYx)Xzr!Z4!6E7MpA(EY0@ zV(qWE|NMde*%NHgFN|(L?)HgJ!f{J}L$D@&ki$KA&RHj^G5nuxk0aymgm9U+(lh+; z9$CH|F?AU&R?}{AYKY>tC-v>>D?9<5(~h+Zhb)(9d8`r~QA5&Ox`NV$&D8082iS|^ zoQE4cf!rSi{eY4dpn8c4bux#!7V+`nJsiO6>T3=4s4`mqV8qp)PKNgfl2oABgcF%Q zYIyZx#WDSo-H9Vbm!L1#N7+O0we!YpCNO*iqB1Z(C{#x@`uIVo@oTLHMzBmNs{&b0 z?PU;ItjG*(&l=4Zm9;eOokK6`b^B7BzQwEb=rEs_)8)j$LGltK_0J823#aY}z(c&g zUfXZ`2Xf};==>$^h&_JOLNQNZ@#$^g&#YwRcw_&djCy_V{{8G0k&P3yP{dA;umAhO zyWOen`_BSo+`|WZ0E^!8x*^t60fzt6kv}RJ$(3t)@Ddcq!%2z&CHQ9uijWu=7}SqK z>V=G^Ncrw0WC(U&`k&~*fX;1$kM7_Jz1Xi%NL}9ObK=pGf~-X-plKc5Zj{g5@0ncr zk@HjVD~yk@=|OoRBHkDip!fh*{C3O01C!2{$GwX2F%r{23C2qT5`XMaUIHLYDja9^wfumfiJkdc&WCp?cY{ z!5zk5`0hC4S+b5k=37RFBA6vna~bxu(@Qk}-d<(v3)yX5ziev_wnbqIOD%`zUT@!) zi^Sn%xmi+uDO{NDR8G}zePNZ_3+3t7Dfg)=e8<=d2Z^pKf|1WV{+3?pu(sx{+I9*j zhcJ+qr?#2~gti)wEu+m40((zj0;~C|>u)*?4rV@UW0uXxZj9ceir;1=4fRSkYqjoX zPJQgS^fXpAJ|(w;XeCuPjb}AIwddNZ&nkb-XW!)j)o+Vs)l~at7!5Yhcl3s=H$dB@i-3m7D774y8^BQxuLsrpH&LvIeB-<;ZRF9%U(WUx0%lzpBx5GwTN5-p1x2tS7~wnW76R0vv%b|R;>-~D#~lx^Swdgj8Fkl%1Wzc z+m-GDrMDo&l6@hF#<##>89E*9$R*}2VQu^-BOE?{8NfH7mJ8u!Sc%R+#+oKI2~)mS z1z#n}xwPa;1D*y=TEk^qYlgP2oj?BPz)!_wbo4*~3q&dCaLL;nlS}9sV@Bnk^a!+* zA08q#pWi=a*5=8ZK;==cA*#5LQ$K(8wERiFKDnS!X#GQdg$*@IJ5R~c z$bl4bMeKq^Jbygm$^S0`BmkmpCE|@Z1i>a`ZXlgoNZopRnnCA!N^aGmhN>z^rrDm(OAvM zO4CZ8)BJN6u6XV8-pd>H?Cq67&Gr%|Tsv~==B+Nv?H5I_-_6Dba{am$$^igP&!x({ z?i$}Few)js3w3X3W*x7m?eK%;WOXSm3f~&~WboXHYOE*nhgR#--jGvT%g6y%(^fwHF#|fA-&x$XN-$n{bl@LN9Mwy;Yl||q7i$@6#Jzn^IPwkO zzJgFyJ8@wos#+C{Z^{i#Tsb*#_yRF@4^ydg*hMd$&NHWG1i$r~QB0WEEl;OD`?ZRR zZ?bP3Hg+{ZG7;e~HeV94X5q7mk=Mw;$I3$3SiQ7r>zpgNX^sAnr10nDB|I)x$HAOO z-dUB+)nWsDgd)ByU5?tO4%3~*X=--EXDUW-)9DJ}IoCy_wNqEk?^W;hbi@;@h5FIZ zJ;Ko4ZY;jK6nJIJ2CuQMsjjuw*}k!Aa6@98=7?=^c6>HdBwVDmk2!$Dl4H|Rv2jf~ zCIiV_?@rm=l8AI4-oCvLI)=b;l&0zg?aSXw zH|#E7VDMz~blrgzKe!?nNF{jm9QpE@j3QO%tg1vFEL%8wIDc$aux~OiPL*+t6Wua? zmpt(al@w|3j5jI#$2viyn`0LQpqygYmqVwj>U+;*-rv#k^M9{zb4pWv>}il((!t1cdoxK#4hR&E z2dhx2sN{TQ`A3Yemr`?o4RByjkoj_5Dk7Dsw3IU+E-9YDrV@K~`^5TG`gCTM=eTGg zDV|54sCy>!X%&(hk1m5O?xm-c@3#sD=n&fL+rB$X^n*RQDNV~0J(a)zqxe3QR#(aFN(N7mgN$|KTD^&0qQaU|ES}BIr z(2<3g=lBCjtw+%sT|W~n8#=5R;JMwC)ldfs3}#qy~y|MWRu3G z)JQUEl}RpyfN5-Hs=A4F>&DkupQuZd(LJr~hWL2rz^!kUn1Wt2v+jjUpL(MWT!N#? zD|d}FC`(y&fra%SYA0W3*kEi(`6vXIM|J0n9ex3GPEwNDkgCC}C8C}v3rClf2$Jec zZ=w*ks8Z8Qr7ldT(&%Y)7N?vuLMzxqMlo=sEaXOY(nD{5;LAr4y2< zI6L#^X&jZEdnQNWYoGb+tO?X6AxZ)u%MTjCBTrRci_tONG0Woh!+pY3dHE$d43oL~ zkT7y8dmVGconS2lum~ox<%ybls#+Hk1ttPz=W`p`Z^cYYY9=04Cz3{v{<;yN6YUQD zJw!u4?Zhx|xNmL$!KLF#Axzt!q}#ugz#N;6Ew!XP<6O*eKhp2=xzY4n8LD2G3;Pgy=!%9f1!QJH|yiylBqM8wYQ#&0%_ zotvG>O~u86qc|SLYDh>kn%l}kS)PrGC*R^~-IbASk^g{3|>jAg~CuTTw*oZ%65Hfj&l%*11V^QM}9div}l} zz5KI`<%z9;Q^|z`fJ2JgRE4(hN~8NRxN|URF3Te4wU$yfRG8%4zhE#TOo;0%u^{{E;xE4g8SaqHmc7eAEvG`$WL1Ru0 zg4hOnU0grT?hi#4Z|_G>mEV}yNez}dKi&>Ua~CBl3C9%mdTMEZ4D78FD|gha#UpMml% zy8Rt&15}(QW7`Vq4fJ2DTOr~pO5h_htLSJf{J)Y|pcYP8xwRQr-!f_d<(0H!`nay_ zV2z_BimWWlYep>c*-Yi4v!0cqh=0NKFf}?=;F((ywF_ z%H&#Hl}_JT?i0~o%2Y&nzsb~b0j0q%y=$J*_Zj*0<~WtNldi&JIQbz$jZ7dXq$V^WGmyfQ zV^aMi5ke*)tW&QbYx(!Wj>YR8Qn}wsVrS~1(`i@qS1OoeeWbZ#=4?C({1CXa5b)@! zyEAPHw8H9_1kZNd5=2~AM*co6MsqfW8Zco#Cl+~Xz=HO|_AZGgt?t>)9g;*Bk19r; zV#YsJ)y>_8a0w^Xx)8zVZSZ3V;5cTWITHiVYH>_9MgOw?Yj7Py4K7C*{RP|tvxtZ4 z-d?N215q;PIGcz+cp>tUqJQz;BG0A3rNF1bqQEg=JheF1OTT77AwuX;L z)uoYl=CrdiVeS$@5Fw{t*6=*2b+Sff&3v>NG~pzl9`6$7+p7pq`S*5txppYkH_QwIOu2dBi&9?RA}~+&)jAUhd?p|*N#PO9?U|{ zI~sJ{dhBtWJ<#hZIt=d*2Hg!o_jz1qEk=o9yt+8w%^Z6{PQXL-VM!MsVC(+Yh3v}VnL&yq|X zhOQQfrWRFQyYvG44hT-W(q5CQzggMVs&s8Z`X8ACKplpXizrb(!PFRa31ZH)D3II? zCY2PXf>}v0F$$zp7Im(amjbt7LR86UGfJGK+|Ue+f&?XT914Z1e?k&iUHrk3IVHMX zx-U4HIqOIvB-zQk{4LdX{6h0h7ZfHIIL9_?LS!;vFy)80>?waZ1s9O=lbn&1>;OVp zcJ!b8(3FLe%z1l{GBxMzpy#EW1Q3n=(l#-?=yIIqOxEy5nl^6?WFOv$H5D(j%m;hg zXZeg&?R-F*_xc3EQVrFidA^31^`o(Lvbj~&M-j=MTx}_xU?qrv!t8}5J*siUUHp5u zZDBI*mpqQFV71QGP#$}PGgl=NJD`#eLbFeVuV~XIw>XljmL0jw{?FM`c;IO*oP!FD zOy;CnB2-GcLxG&g^2gjbjoeLBqunlvN>%Qh|34?73wU81oq|~PlF{ZlFraM~yWPPp)`xS>12|b-PybruD z^i_p%nqc=P>m|ksJNFw!J0{zGcg|(c$X-Mc%-~A5#;S+(zvdDNsSKXi@97w>d?cPH z4+gsJ7Y}VaydMJtRa)@Hb>+1CG1xVU4cT7z7q4x7-b0}6Z-71A&0E*!4QY zM`c`3-=vQ^D7QHDlO6dS4Nz-N)*=wN8QeTZsD?gU=r z1MY|k)9_>1Omnz}jQ4qST`ivUFV>D&40Dxs!(V%W1 z8AMab=&`rdZhiio!bPgL#{1U4FS(E!TJMSxv;>FdkzD^wb6gO$h=H;%8lTQ8W*f1* zmZE-bC+y3pL7Jt?uc#pEl0*kL)#c0klI{R+g(uhJ^9KF~hR^t0 z=GpnMB z2t%im*H_dYks6?Ab{B1^-|%*h7a*^kE<1}ze$whkqk5jR@TetMkx)Y%-D^ojNOML2 zQH*9_PEG14?!YNO;EX%P3;dcdShtpw2Ya$cDkUH!?KzmZJho|i)xdy&SwvS-{aF5x zu8a147Y-ICg^Bcb#~y;zfk&bVSlKJ+e`4?pG;mdzp9mBMhsBDU1~R(J=;%r4Xg%wu zuI#y`uYGBjDy&RbWF1=DmE?FmrSEEOEN?J%sSIp{)K1cSRoCUcwqpW;Kc}OZ_4SO^ zmVADHZ7Ds-XckL1%4rwTwB6Uj>?j%^_mIJ?Shw{e`;$H3{D}MzbXSEUj9$EDt+8)k zA6yp_oZ+K3b(V|fD%Z1C$k=|cxb}FfFGzVC*P+hQ6C29D;>q4Z-6ro2yGx-rPv(S% zsy@^^mG5mFBW>ARYX+H><8(E>`AWH7H~uc$s*4{`H!&Empgn0aZz{jxy8KLXy~_p1 z$sC&qdD9W62K_^iT{}Bb=FH4W*Ur*T-^kfWHdZVDuPlb6g=g|K;`Gk7K~T zJ!)`Ckisn?a$-m?=EaMEGly}T!YnIhajB{J-c{&^91SY}Losg{1H-=so;?GaHJoLE zFIu76NSHl6)b?B7A{cpI;RT16X6dJAnehEgM7~SG@=WD7RQ(8)vEmya43Kr;mG?Il zgv%QyBde`sqq5?>Go(%V%Y58nIk^w!3issc%&TBj5lAx#Er^Neqp~1Km;*G2G;{L9 z3*U--Hg8dpNe3eGf#!-YYEl5RWItcMy4b6%nA50Q07L9@0Sf*hUUL@&;)fv8I|-g$ zZ%1R*@Zn@?dDDjB7W?4}>=TGU-n*)|v(@}@Bl>y0o8=NdYTC+^nLqV)v{`K+u1b^S5LcW%Z8dFUv30Sh~EW`VdlTmAtRKKw*Pk zV9*9xI!qZOru2$AXn;9Y&Co}UH2!hDDqaN?C8=5KRkL!}!h?q}0@E6sgl(^nD&Nh3 zWLW_BH=+I~T}`O1|2u&H`akqA#&Ds3u7}VH(as{Lfq2OkyDgt+@ zWJMh}6`m*p52{di0P)I(HXuqzNHVix6BAV%4z*%RTu*SS+R_qwng9>rJf@DDkAevP zWFS%eMH!JIF>#FomkfAl6z(PB|5ktN+d>*bXL7rU%ODoVnq7={J98`k>O=w>8~=o3 z|GgmUOUF>}DN~PQc0lEr)!lR&3ii?%E~0y*mWiS`qN^)z_u&?G2&lWrZ@J2Xyn}#g zC~vE?z0=xyyt^N)oCUG`MA7^v_RT$FM-gqn%KTTf#c_t|`tq4KPjHX-Sn2B;!LIsw z)=wfPT(!(U+Z$=7D&A6{%-Jw>h>H8JHXt3;^2k1rH@!_-d#sqatD?FzeXkyO$RvE~ zEDnVg6N^cuxq|=^Tt3p6lkPd_gPRj^8mp-VmYpXJXcUt?eaGpm%t>zdkJ}HAB{2SQ zYwPZLySJCEV8k1Sy(#CzamY$f@;O5)rph?ja5A&f+n!R08LO{D+s<-aGkpz{Fuxfcx3LbTgpOFxx-1J(os{b+o`9`!q2l_a zVqxA_{#f5HHn)Lck}Pbx#N|D}(l3muph4{(uJ^N;KzB_NRG3!bZYmg$YNmp(1 z7e?Po`K_e!r*WSdZe-Y&U5i$7@)C?r&}5)8^1!lNGxFs26U|!au;H!H0=;W5@@+_1 zbmD|PE*lesVjXS)8#wjju(WhLc$XT=|IY%UI^mh_0HjiW@H}G%7ssy~-x`)^r<^%d zwimbvYL;?7AQs7H;r(9Xhv93OARfl4Z?E`wBpJj;rWmPQq}oUZE7;Xc^+e{eKFj*@ zp+4m+=!=G|d@`3h`7GiOBY9&vY&sY2%^8_LQ4GpwiP2(3R0jMW*aHcioOhe3?v_SB)~_|p1gIwTg~w}a$qnkk=8>=*v6V5hEig{OZ% zxo9$SO6q+2PkpRL<<(CzC5wd1S>(_suR3!m3`L= zwWl;u#pmj{fha*hr}AIisIifWu!G@rpZi6ws^UYy^hhsiip+8RE3>W7GNrrpGB9wN6Au+ zq+T))9i+)mJL7!oce_8TI4qhbFRN8DIiXGQtL12JHq-f)9j-Zeb~4r>5WReSui| zfOGuogc`76g+olyb-1Rm+DTUn5E~2;lY~Qxh%ynobAYSYRfsg?+$2r)! zvkGKp9m`ZvC_!_J{Q^0SHqFof;Kcf69?9Q6u0XPQ5SW!DOQltI9De6`Uk zhT)1mkg>PdXFe?Y@jmSyJKo_?`|1;F^~l#U0hDGX`3RmB_qpYI$@-|dj%=;HBmC4p4GP|QIVFK(AEBNFl$HWk5Ywk$Pe^;)aXK$q&tz`;aPgZ9B{rR}b=V;4m z$V<^4Z#NhF0D#@t>2JzsS?sh6+z>h{H|s=a-DoeHH3T*|7b@QRT{>N@xGS>Qs^8<* zOYdm9C{<2Z!$yo_kv#k`FHXw_t&rVEmmjyaczaX6B?4B21-i5Un&WtHh1>x0f*M%u8@_zT=H?)$T#m3HTMe}*Ehsyv~zZ_?CSxHkaFM)U9z`+s+Iab4)l#JvmN~2$*{u{HGr}kKHbNUNZdJ4*5^*>|0I& zMNtlU|NZ-YjsJ3hOCIdww-tjWTZ4-${msw**_mlNan;D}Xt$`_bd|r}>+f#Dm^PkB zo2t*m(@SVB`py4EwbXn;bM=pVcj3BYdOjD(f$)cVF4kX)nh|zUBHW`PRRe&_$v>bmS#!Toep z(?92T+zgsw9CIP=M5X+W_NWK&dBfsO`q35MF~~JNx1W_1PyZTp0x0lg$69|!+`jWU zkEr!zwh8Bff7pU#fn^GMeSZ-6bIvw#^qj7j z>MmMXYxpw}c(!$BFMRiTd#_+{$n6f2xUt`csz z|EK%G!pO|V`G0XgYPz94RhQp6eP=p0uUst1n;bmMnUkf+$6?nE2LK{R03%CxjBtZ28i%>B$+v(dF!+OV%>Cop#^)>>THyAc{ksD-jqg+DvwPf-C!<*CNvDx-Tc)=>Cj;A`XtG*=-Ph zH$C;(6z(BFLD$z@>ANi}5IhcIsKyfy$LqAXKThcS7=RRBV$|vXGkwoa_pTSQJi|p@ zsR;*p+?_TcH1&jh2&=B&aCGbKYeOXd)#|cePtyI_&o)wQtxnV3t{pvyFZ^Crr1Wzb zSEG5j-Xw%_t=H)zN+;kJyX^AOaLvzkq=*Ha0XI0d5e-iZ`vW1kP&kvMe53Sh1;#V8 zG#R+qC{ntZy}+6TwdK!%3LCj{Y{bCKbMeCWM2gSJK4Df#)Sk(+!u3SK6M=5T2E=Ki z3jaNWMji1Nol`X(#qC7siJ=$iIRkZt5L06LAYmW!$Wr8JEHr&Ffy$nrUO$|Z4#A#_ zpNH;7pA~VERG=v3gy6fKh$G~QHs2lV1?`BKgKTH?!IX03&|9`U_a5f?m5Ng&`rpX??9Hu7tcz@b`L@^#$jd! zanIMD8TF5Bp3#2b+BmWKLlFd?YP>n%mfEvyM79DM@PV!Q;Nppn-gENCtwrHAm`MOE zftRj@KMQ|}Twyp4-Fbrz3}0NLWc6AJZKi+7vc z9MMcx2Vv8TA?K-{XfQ_!fN%4Q0}hcre?#|sH+$aLUBE4J9+)J;J592=|IAlV?S8v0o$q+K@0&`fFdM4bJO|6p$gd4A<0jplviMcn}}1Yy0sNOlSiHApaBZHxt%;wOGLtCR? z8D5EAG4Dxawp2J4Dp$hpXg++OEuMZJ#@o)9u z`j%*EFgjsvp*7U73m0k`uS!qX1~~yJ^`|gv)#Fy081QA;m!p4xOn5VAYs~CT{HJS& zPcfnUA|NwpGT7E7GAfUDr?|Tlc;iE2^Q+C&i*yvx2?zs-Psa^3Y4Q~KN0eS7-mn_u ztO$9pLqFkc%<511K{CI2RApNCksg>`_+0#6C@Ru6Llj(m#_AJ>^N7%0vDMuKIw18w z$U1_rMD1+RUeP*1?tVx;*!FywJFwCj9sc>uLCQvcq2v#Fge-Z2&YJ!iKPHVr2pq;6 z;%ANaQRL|TGyX>EPk=xYn{S9e+7t<2kxK5(i=Q%wBMa0AuvFy1BZ)(#u_rqn13A(9 zK~?$7BpGE;OqVeL-TX}4%Y5e30CGbrM!1+InDqsrK?vCidG!50)ud|da_h(wG>dO8 zJ+GT0h<9{afxa>VdDmQ+tq9Hy%>r}t zfJdZ0aRp5O3)+e6I`b>|OP>;aPbZGhRLW=#P3nTseQ#*aowVNp{f&##3^&4ywcA^2lI0bhi@G~1FK zrW;!eg7t~*5B)TMdoQ1`xj64b7(cic^aF!%X2qJx69uuh8+27Oxs&uw*9gKN99URd zAU0c6J+}+wu$YOYn%NPGJ0ow_DI}6B?$Q`<@vRx6Zm}AC~hvDRfH3wt|A&_~M(n}hZbom}x;N;6X#s}P(thgB~T9p$#9 z#@u>A?!x{;VvtU_SaUN?nGU{o?@?nbYg0+?i&3;t-(RcGw5B+R#yck$5uM*Qo9!vV z5owN}S;Rxhh$XpeB zcN$^2=8{Wks#At)^5FJ@1LGN~jf}JyX)&>h_T)Ke} zC-(Tx6G@Lp5pW~E!sWm2#sB~}St)CIG_`xra>Jk<44e z8&{Fk1Q`Yv+yz6);y=yKl2GQzIUv+9CVBOTWwX-ka4GI3I%!1U4@H_icPSq`+ynwB z#fKZ*w0Y&RlFyUo;|FBz3w%*$-jzIZy=L)pz)eUCyaD(9 zfhRm}DngoYu(EJcDv+HJX|NWbY2l=r*1CUc z=DN()8+;V9TA{5LDhS-DfWD_F!{tGkQ?S}7#3>kxF72p~C zvZ|=86vhwdRIeKjnLmg=Y&M=du6%=jq;N)@vJybe!Ef$J%@Tl@&rDKSk{u%pm!6=O zU$w~)DCz@6Jc*yOQv5riBQpOG?egqR**}GlfJBQXurb;lzW@X_KIJ14mKfbL%hDJ4 zv6{KsPhC*o!(PFm)(>f5mIrJwgs}27?>jwD6jBMYTyJ3?1|28p39|>=&jo~DYl1Ja z3G5Dx3u2gvBrG6^TM(AU2$=!OIP-nii!{jD&mE`-M4L6s3w~^4ImSDn3w^OYy9IL7 zf_9KQg(v+*IZPiJ0Cv0w#)Ke}H{$d74oO({{CYZh8`2GT;PZITr+5?oW)HA?W$`$E z%+B~b;e+#V&u{)+Fw3y=S)dOh3B;JtiK6TQa&Z%i8;ls@)v11d&Nz&QXpkBMthWgP zN)#r(8Gbbr?H9OU7x-Zp*zsS946CZe*sz^$p)zR|&aRy^r)ge?(UfAmEbMz0WCSaO zA_Qg(e0>h|(9R2Y1lvnd_6H5^0)Cmtee~-$VT!eebU8L$LXd5>rlitX$_2B*9kS4X z=juW0>K(6SOF<%HKQbY)>k_WiV=7shUqBO~cc2efx4D3uVs?cC5&}m=2T=uP1!1#^M!lnyfu3E)|uv9)M(u`NQ%&bOdetcC%W$;xC-35Edt%%I}$mfonpR$?j9 zRiapHZC9PF1evtO7=6j+RGMgK$cN+1#KFR}q#}+lzHLlwZ}@FAyNmirPnNzT{h$Vf z3yiuT=kJ;IrrsWOz4QBX^u=r3o_PEzk=d-hUSuv(Um$O8Y*m|l2k)-`5jUsOYekF( z+6L+Z*6eqpNRgR32FexuD=!E*R*WMQO+W#b7y5u5#yyIin}NEHRkRLOCP^WNvXY|_ z#1Qo8P3zNi*~i=X!L0?R4Aurs!3JuxAmo)$0b(I4kI2Dy_O^73_Jt!sB}xI(2F5JC zf(3Gf3&prVe*d5c(ytUKZ|+c}So9cQeMl-wG|r(P`Ha55F{UlQxS%;A1T$~yU|GVt ziFLoRSPfeVTNPWqw$Kr#+fTEc^lznC#i)x}xwbeg^yI|BJ~|SR5j+0q`{W7IlUyTZG=%4_pL-eGtKftN_)7 z>`xLw{1{(U{9sMt|Emqe4b16zXhp40_;h+{`L16YS7yogF3$&wBEYGsv#uxX!OKwaxnDI)EKJ;);MCDZ%OU%G{`ALfCH=oo{>)P|Y1Ype=62R#SZU&xUu zcE$?ii}j!J;pis>(+qw zpft)wMxO}J{9rJ@$j`3qvnuO_LMDa5&%xiV3lTHUISvl|nGF2N2mTfS`G^4d$P4sW4(vS*YN@6Gm#!!!YF}f`sSHKZx?Jr$ zSY>#)9Q}NL_U?uhxwVW&{z#dV6Zu+4GATx?R5+MbB=LntD2x6sC{Km5fK+)#G=orC zB*ey%y$(7P2&v@xnmu6nSF~`45fWzc{jBbbKWk|9lmGrk;0eL$gQkq@3`l(d8aLE@^ zYEk$UH?V+*xXrKGiC&}^V#M7~1F1sx0ZbZgzSj_Cn2SfeOn$eZc zH%tJT|MFMkf;5-&0~ZJK_3igmD`Qu9><4QWlXvfT*(thC=r_A`h|_oKcXCeZcQS0q zbH5;<#8ndQ~V6-)}GD5#;x3 z8ox|LP+c$Y{-=o`fVi0 z(jFSGaL_~zvKmCHe5q2UYIn36 z5}Gm^ti|jYlXX7YU3BJ16RT-zv!tb@GX&lMHHZy`ol%z5V>cD2oxS+dXUBj}}fm};H?6t2YU+Gdyh9-X#cI_fv z>GWE&Mr71Wei60jGxYJTQ{Wl2UiwrSikD@C|3=I=mc83Wq>s~JL#B_(WC_b)Z${v6 z?#zAV_PXm{RU3W&KK#3WGJ$KZAIhYObp3t;tg#xF}JB z=(J0zcm6Uo?)L)`NUTRLTtm$YHXfUI6*~k3T&~vd3K|`bV20wbbEh=IHCTc^W-Y2z zCTB~RXDv8unDCSxt!4bOHIE-WR&uDA>RJ0(Ygjv6C`NC#|HF%(o`u|nO`6&3+(x`>7zLS)d&j5(#70m!8v9jN++fgTKWO3U>i!8*js3%+sp`v3)izaapPsxqQY zjB=c`xBBsE6AUr>f@Q+7Y7%S)nk4k2ZsV+s8b^YdITir1{@uTQ;2XT;AQl8i1S7UA zNvSKZw=22lfD?l7=@)rXw88Q{S&x9`m&yZWQ6rp1AdbT$pT#pu5HE--#^h4tedS$3 z8QwE48L_!L9z#Oull)ssk2G6u9$%`6R|2Rf!c2$C04ZYxTN^5>Co?~?$rLdlioy$e z9a?Xiy6s?Ff*VesOt0h|xZ1liU$Jd?Brhh!zT)o*;W!7IFMPGx>XxF3w1+Df@0KbR z4?bJsiCi8;U4vuq3exP64HCH}R&N_QTww&qtc*%EgGtanbVpzjYs9YngQ$#i<(?Jd zfX<2QT|Ir`+Nq0)qHSpbLyKO&dT69|f;C{u{^{#4FnZryCyV%3JXgM2trBdfVAY1z z+SG${%f19jt}GbDCbw|+r@6Opa{ihy&ZsE;I?KPUb5~AIF9@4j2EU4fdc zZ1}O*0?=gOnuEs^kY`SHVEJ^d=rz(SmG`?V{n_!b#(rP=;|%#X_V*bly&unArlNBJ zxdL938Ve?M1yL{%S_>qW%n-WfmeaA3DyHFh!7KfMOXkFl-_6&W-KEZCrZlshr!V4E zZWi}$Pvi7JtoChLHc8m#WW1vT)#*U2f7K-e(H)r0%`)z41@ptV+PXO|>4JJ23@W_k ze*qIf?7u(LzN7s}%j(cDp8pKb02N$nG|W`X8l6sk71O7muOMbL86UkwY+BLyA*!2A z83^|Rk6M^WbyZDeh0R(ZFnen3Rb^!pT{X~Q^qQDlJ24UdVdh~sWZJBl9Su1~t2j0RpIQzYl#!oYMzx?*0 zfyeKMF_gm?7Aj*%%7w*jiE28>K<6eHgazyqwFU-|^N<<7&zfV0?+yZYSgLJyo7pNN zp}MBVTwPUEPRj3HvFpLioBz6I@9coHc`LWPqoMp8*?HjX6l%;Va1Xq^^ZbIgN0nu7$U2x%bJf?zBHw{{La zTZfdInR865MO_@`egcKm>xPgidIoo?u<9hQrAxxabwPJ0C6XXA7(S;6Cs7{PwdF9| zbG`#)z}XHIr+nU_Fud|_>}*F4)nOB`q^Z&rum()To-yFhTJiae?pFNIx%eL$1?4Q$rY^Tq7ZJklFB%d>D{s4!Sac!C*Bcp>a@d)+=a z!&@T8ur}gw+MR?Cu%@NR&%2i50t2LMI!F~_X(@KAATW#8rO2s)K(Re&P@+Id$+ea$ z^LXH4yUkQU_)xGYGG4UXDl2Nn*O;n`faO9#fhRL>*|50l!L1M6{F|jOUVGI`P05~` z4ZiY3VY0Zkv3hzH+4B)@nOnd2<;K018YlHP+j`OyRG6M;$dG7kbt z&H=f2z?co)BNxbyF2_E{83&6TvV&|wHz8uEx8N(l2UO#IC3G@l`x4F;oZs!kZU8+RM`8Cj##eu5O@vw7skQnN*% zITdJiDU&&gO-c0m=-2r3SWF>&PlqL3X)3VU?AAc_WKvBLK<9rB&kR^nmt{!T1e-<( zyTVi0S0DbWzjuOIB8(? z*=)r^N|+%$De$s%DZ5y8seQ3yjcS8wgZV-2Lx%fI2ek(cuW_&0f981C{;uPU^d*U;4r_E{iIs~;{>(F|uoYR~;?7Jkv;UvWFa_XGCo^cY6ci5>+vatGL7=~Ic z7wGEx)L1>tRLVM$bM12Cz0N~U;yl4r0^)8R!bImA#<$9P#Q(X)(rH;|*=}Ji!&s0l zbf4UXBw6Z{m@a9bL?q`){3YmQJ(lHyPO^?{C%ee=38)dY3)w8zex%=V;08FMm8#9Wgj+nl#L zp}yUa>KD0fFBx6}Vbs&x0TiQ#LJTv3YJ{q*fKusvULZoCqNZj%bD;C z_Iz*o-bmQ_<^%iRPt1Jm%gK1@+C@`cn9F<>##8XUPhR`j#-8J^ytRAPsvjNAoSPty zqlVc$Smg_Wo)vi3aiqzf8Pp}!be}P$OV+EKG*h+BLH12GE-s!>ELU|^y;*gp>R%cG zRpEN|_RyB{rwWf3o+y8<{B-Da`1j?14SpQf%}^B&<6DNJQ4tN3vqPs6I5Esr9c4Jt zhHb-m?@_NDi&uHU@gEZP#nF>^H3Dma{Ew_{1sagu3JrjgLunn>4ddNVUe;Gec9-od zBV|y2v{Tp)a~~!j$Qro{@2eWAB2}Q@CO;!vp0^N-vyuv&k1i5Oq0T53ix8XzRSu#j zHriV^+A(SdwWr9Sn)0|WqA{|3Fc1n92EqZB=fZ|aL<7Pl&Xz63J|m<8+M=acqb}zY zOR-4>1unpWaT{}mp^v*B~r`Y>DP8Wu$rB@vN z+_7uY*FMo$Z^*B&hgY@Wka@3{=r?g2g z8yVS%OLW*OfWXC!n&UC6)9Mkc)3dxz539-}n*~*YAgELfEAToM^6RnwBz_R=Q!U;r z>p9G;RXnfaSe=eN34SvJl5C}{RjZ8*-pd?f2s4cTB|C7Pvb>DA3*^-qBV*)c0SivU zx7JWkN}*5+77!#q6saX!my9bm)~Gnvn=&O$%7W=HkFj8A(WGKup#x#3Y3o7;U? z__lM~`R(3Y*jv3qHK`6PU=~P=0&6^*xXqq^GT<8UJi}&^!d9j0HM`7)= z)PM!qQ#YzGG)R3aW%^a+F%Hm$XeK9UWPLC0CB4#h_&Rc(#Dm14f(GOaxOuX64ZF^~ z+}F)@d%2Ewu*Zaez)}w8c>(lh-V)3+FYs;=W;S1vS>2A+58SxuhB@muZ&_C!auvm! zXKy^bXXjPVVwRir)Ul#HHxI8l)>kxsUWF$n2C5Ekzvj2KWdbo$?rZ~E90u-mpeXuU zF4?Hwr1`$#I`zBZkHcWN<890qc8l#sJDXBPd5#G=qfVZYI>8VE*>OyY;7G)XL8=cq z5J!!ZA)_ArJS zku`<8f4K7(tG51P=aT1c$HsrJ8T*BK+SJM!i+0?+EwYGP9oDz}=+zy|&ZM8Z<*Cbt zu=g0Ao@pCv?4Q^5rz!DA?>+Dz30A=@@B#P3D$t@Ajw3dEX2{~6%qhEvkZ`In$CRk2 zAX(p~-=}{azee7{?~pTkKq=N@q?h#!;aGMU-yypgQot~TW%Qgpt(yBY<{{$$jDgLE z@qNekX|dL+<4%x|5JUbV>kuolGTX}TV>$L&@*&dY@lI{=vx>MrPc>*v9F5f}{#CzW z+e>-oRd3)n@HcQb@NAxOK|}Te9xVYY4&eZpaYE5A$?r0$ZhTi}XHQ~&rI(u(`OkCg z%kJ_nE%mau0>2Fazd2C^RpKr3iFR-dD*cruMe8cJ1pBmox;|H*`?_#nWT5g%$9~u2 z;UV1-*E5lmMK5b!*8Wa!6Oab;dg4+S+4Oc-SRXbt<6H3c`Wp>TBEv*fiQ2+$<_Bz# zMV>Btx^kF3ruta>SKY^kkBdI8C>HeUqFR*16Dqhy71FtiSS1kciY?A_Wi+zrz4dC4 z>uTV93JFMyAd5v*Emsq{x~qC$^_gn6I`k}5Ft7$nU=3&zcGq=Wf{OG}b3A4% zTZ-bQvK*`Dd7bJVVLTzUOm+vtFPK)Q4YQLJOYusY3G2jpM1(?9k+|I%)wH z;I3ASUR|KBtsFOXednsfFq_M=A21WSHQ?=(qmPcNRmKD%RLo3BR9D3lb%~ZlXJV^* zr+U9`zv~gVI-=6)4UA}GxPYI>icQ9o9PZUZi#jUaYfgyjbOd0Ogn* z7#ujD2ZN11{#$%}5x+T$5Y#Cze4901DHg`fP8IeqU9>z^9w=#g@v&bnnO=YC59_UY zUcvGY_TSO7dGhwV=O)5yJ%!`u&FuN{)op8L+`szK9p~%glmhX3q};nfTpIB0L4M*m zOcc3k#(p31c@bzQHX4Isx~&ei668OAPISWK9Aa7e()4y4kV6ZapeCD`^9Z9rGymxQ%t;X&SiSRwhIV~c(n$qfltTdN}Ssf zP!_+IFi(#C^RnQ?rI`f_oRyRD`yu>JvSZ%Z$8(a=?|t|we&y|!B7a;6hmDTJ9qeUa z-Fx#KE*xgd1ErlpMfbAjXZr4HPB%{_b29|iIGwlo)SBa)VH<%LKQR2q<1R7?Vk4g7) zQ4fQM$?2n}SX#v5FjIeYmwvCF=!coO94}Clg9u|>As#$r!hTboiI`k6n2YL^bn+07*c$zs9aFL+Ij>Ku+EDf^}yJ(QOvGscBYrp6omulBl{f z7gCW>SpigFf93a2{_x@c_qJ^sz4wOKH~Uv+&YjF0IzDg=*Zt&c-hHj6t!B|r!y0QGNd;NdWGyVkAs-Xz{7{#N8R ziJJ=g#d|IHSzmL%=6y?4IZWmPua6O|xZicNk3?0x-;KbI^1JnckUik^M-2u&aYk)6 zr1GR%%ov$Pvt&+~Wiw|U&i?Tj#i4mdh_2Deb=Ba*NFm%EqJ9z+3fOszg)Fe^j7A#L zrgl&(I#DDGc%_hc(L#Pta7ms9u~=&Mm=b~s(i{6iA&TPLP%tHvbQ=q3;BonkRxw-< z@fke}vC9g9*W_P_-4^G<3+ShYbq_FmPh~Ylud>wz&UQdz%~lcI@gl%FGKmOOU8r(l zq0Lh?yOKn40#AD3;0u|Jzu&&_BV3XB<+;V{!{Y<%nYG)c((pj$x!+_yc zu@g6XDX*6x#2x{RSK=DEPOe_%`M&3Y#FLJLiIa&l)vATgZoXUCuG+5dW56NLOm z4wRP0fT8w#-5+^8UX}WwO2r?nqdOx=5QP?jfp2{%w<_P-RDQ5D<}ZuGt7}~cC6Lyq z-Hdx)Yjro6hDcVVB)7Btsu%MVhc1#YAi*K4srBTBz_*l`8dBT2|71GR{*&0%9cog?od`L zJGA2~nSesSZwN@&5~T1!T(Y64iVuek2J_qnnYYF0gb&xRPE4+kZv5(#L?R~HU4`=# ztkqa#t*nTy;KABVy4QGD0rqybs6rB#z z>nV_4Rk%Z*uVJT_6K9btN<@d~BvOrB(^Ye|s@u`+yt-t!W4ANyNISJ<@lD!(E#s&u zceU1Z*WAKB&7P@Yb<9oLks4;Y%I9}G{uwm;-S$AJN|9$niaf(Z;FmPZ4dd=FwL2U^ zK3d8cqCqu|`F%P{6Q6>9A5YN_wzsL(yxUBS<`y%dYjL|dYi7+XrIQ&Jh4RpDq+aZyPT!|Ni2VPn8F5lep2B*ZjjNFRbgl)w*C7x86S8#a{XJzc8BlFv7*Xhw<#kzy|X-KbINn@45S* zea*Mj`|IZtz4H=p!TK{hGT;BjeG69(-u3gDo7YXSSlkSV%=!D~Y<%PCzrUCnxhoRJ zH?OPG^imjnapgfhH55Zb)!r#wXPtQz~Dbi4QIQzv> zN|A8YaQ182Op{g0s;E*(RAqq%vV|5~a8RLLP+3XA;p|7UvXp{K!=S5P1gpynPzn$S zC`UR7)c|z>DX_=1lTcw{`6N>A(GXM@SFEr%!1(&~QzgK0D&j`oh|&1{*vPm<%q{nH zPun-`)U-3xSj)6M9=WC!k_0$T8wdvdZciXs<#(3{f=zz+qxO z+}O#){D>o0Lz)1IU>N)k->^F1G&{l|80wdQeb=g7W}LJIKa^SaO^#Xft!7ka1c7tj z0nTY4X?ge>!*d3*7UAt^Be}+~DY3bFOU?6|6MEHE2%Fiaa?|pf8nS?_Abn(qyqnx7 z59yB>PE?*~_^tkT6?(H4GX}yFu3{(Zuh@eQ;(dl+Rj9OJ(;&j>{A!=R1ch;2U8inQ z--2GLdKZ0GWmIdO+61m9mGTt1wdpbZ2-z^_~e|N=QRqFgsOCW9x`cl58Mk}%=h#`TPB8ScCcJK~Wal~CT zv4~JYj=ih|)Gz2!T*~-Z$}J~(z2N4lybA>5es?qwOw~_vr#O~%b4Eq}`Tg#qKxkrB zt$QN)&_RQ~0L%>VUZ^=eKT%bXNK_%Lud3&o5~#k4t<_^f{{T%84Bdw34a5);SV6Ga zoCh7Li4&vIqDi&2#l?|>MGm{2=eZ)nsZw{ahD0LH_HnqI!`v{LAnRm(tDf}faaxb{ z!{kf3G;UP1o>5tqMrExUgCKV4Qq7B9WqtehG&VhpQz(FzU?=Fl*d^bxRK5VdrpG^Q=AS=JI;qw`~*9C?Q>gjE0lhyIc zvikUxvIe%Jy(32VZ8bFxo4!sX6(lRbvpyy!WzmqtAaw=}NdzT>N^WFOq`8s95am6A zSgbv_AA|Gue{N$J|35A+Q_XlZUU6?}nSs!wsO9+lH9uZ7c1>-ir8-lptgrI1=f1VR zrj*A^{f>f-xOlR=q{5FsE1kZ2mhC7xmoZ+`4r;u};fPe>H#5!OT4QTh1s%CHCNIw{ zv8=`7rBRt;386HnP9ov zaxXbevP7^1gJzLRzF>e#z98dws{^3|zuOfEnaw6lNYETCFq?zHVf-W6Sac9;)M`xJ zE|po$5XzrA^E{JD5)+~=z={AoHZNR=Yl;91(5zwIUvai(b3WV z{4T#aiId8;NkL3evx+iHRBd*ei*X%Fnp@CJb0=DCUWcwUZ!tfBpTsBeQS;C7f3W%Q z1XGRNj(TFar-5E@B-tm1eC9erU2@-`j(*+K^cy|i&?WltZ;0s1xUjK&_Ui=m(DyE+s zcQcbb;np~QCjpjw;n&x>BQ1$cG`^_NHgVEK??i6a*8*eM<}V3{tEAqqcCd|K|KviB zIn-2YQG=fZ@|um&|I-4M;;WCNav;|owbk+RjgAfO4W6yh?((}l!e+-ag(srFcmLk= zULo%+63e5JWH?zgF`6h}Ty#ZIcX?mA_7#L(o?=h4=XcKEySXQ#`1Qhf?e7)7Tl7x! zlS1AjhrCgh!S7ZDg4pjC0wEBB)<6h(rP2~_v@X;VBB79AEdejfN>qZ%j9j8C;gVh5 zF3vThJnvhfax9mp%gNsIk@8dJOnE6*gcnxi6jp>64jK&#M;VktgCe{Pd&{g=DcIEPbsBDYT1Ja~98N1+j6&Bk)j&L+mY>!mpLJtH* z&XP(Tc7yHojo&q6{$^S9!4eBiWP?6wA__=;gcTbQ#d2G~y6utC<+sEw z*x8mZEZ$L|rLSFX@R<@7ELkjH3M319fs|i#$vm0JgqTIDp@%5caG zfpSWH;h?&N-i*m_#B)^cM+ysz@;9#n5;7Ga3~SFM=C&o28zRh2D@X4c$h?yI%gWvJ zxAfxy?7$j)W9F00mSgK~x$S#LpIzTSGx-x^`Z1lvtr%KSTfYRmUjSeF_RLk8H@?i= z%>MPdM>6TmGlM&J{0OK1`B>j(YBBX?|HN`YhY4hn>@?q1ijCMvv6`&TTQp2%2>%K`HPFoDktN~q>fEE6TXB$5tvjpsd~D8 zddYn4Lj59fVe!J4*N^?gUFolO*UWd!cg}aUS6o(kS=D9Lm(?sDZ(y|AVvE*Y9MVd) z6N?kIz2;uaj>3C|d*k;do`{b`UnqGcHd1@8w%`)g1UFho+=uX+nBeU=zl$a7tM4D@ zaeLSK-9Fz5FD1MUwG#0mJcbY-9mj;CbaxBOzF-x`{s@i? zi;4733^efXEyvH7|Ghj5qC=imEtkIu83vV0 zWK9KGxnaRS6O<;dXw>3?ubK?3;8{9YQPwBmdgcCQAu@R zv1c^Tx;2Ff!4i#VOVyRA*hqzj1p*-fSxuR)5@~g%u_6&fh|y475;lVvQN{U6jPfp{ z5?nYv!X2o$gIYk#v@7+i#APvR0b!6~s3&)Tt{ab0BQ)IC$CWn`4tder{*;-=CdW<^QS6=@r6ZSKHCG z+kQB{wkY%H9kb3ny>{~iyDOjp7c{6)} z4WU+)fm+cJ>Y&}`kNK!fGSD}WPxN*A_W4-f2@*xN?5DDp>JOWuIc)ItA!&I>ZnNin z2UQb3FeA0q^aF!hV-+Acc2>;o0-aYVgJf+rz=f(06;(oAJS@IO_fIjs(qzf)@`V0N z^ed*N5VEij8zWkaf7SfwL955dUZ5)ek2yT z60Hf2<9LCOS_vCK5-t>?MTOCDc_J|t%ZWLl7Z&^4qOFPb{CZ)1bbU#8q7V1+HwZUG z`%3x}drKYxZ);!TCGT&&XA;tle812iWw1cpI7c{tL~{F4wA_tyB=kAFZeL*p92Q{5 zf})~`pi)uOFjy3YT+|V<$D=|*6%~pi4$d!vm*n^RD9P=%;p~5oP`cVK*qk&W8x@KL zWtEyJJCp=ACoecH-}YIQFn>j&Hd0%ZyCQ)*I(mBOLdCr}rr4NV z_Ka)*;}S>B+B!r72Q?~nNg)@(xIa3qOJ2AuK`*3Gvk-XXzl{d0ScQtwNLM<>IfH>Y zh2M3#md{OPj(Z|=OUFhiCuMG#5}#QRA&tIx%Ovc^nv}PuhMN^GU$|s!EOYPzTj6># zVR=PJ6AqV_7G9od#y`5e+*9fVF3bKsGnF-G?x%ko4TdsPBMs!Kb@26lntgjnNrp27Rtjat(GhZ zD=RjPbd}UI(3;I;L8Xm0f&3qj&}CXl32&w3u2kAqCIuxH$`qqfQo}3dmB_~ymnN!o zvKl_Blf7OVnxINIoPA67(MCEQyWN2uN~uF>;Sj?dDLAWEuG`^NX$*pdf-`WlW`=e~b@TX!+8L7;X;*1) zRNtVvL2I0EyWU3pb)9vjOI3-gQsu>ERVT3<>5wiva!j4nMYTztVsX`0i@H`Fks;{P zF_IE((y_XfgSsij+GLBP)3MIM#2wom#PI`IVsyrdl$;_k?QVMAu&f&JHq1m+0#D5JG;1^V$q<`>;!n8;5wZr~!UwC(zmBZ)4q%VxaB5f2tNg9xV ztROS}N$W6PCHvg*Ms>3b?1YH%9Mb#KbYWIZOB2 zFYG3K(E;2=?{bTyJ$0jW_aSCV(l)VJJh$!!869|Z?bL)fDaZVviKkUh^n^Ie_z5)= z2(MOYRD=%%r6A#}wMnr0ycQ2KTa13a2M0qFxuge8P*q8|x=L&Ih#qVRLQu=6JV@E{ zr%E|zQpQS3=*34^)v&rj8G|Nn8>}V=hlWE{-2obE%2N_5PS952D#bE{mU zmjSfeq(jms?EoIi?JjLn1Ed@urLhKL4a91Q)fYX-3qNoh+rt;`r;V?v8K1jL$y@E; zK6AI*tjd`JJ!P;eeuar1!Yg-6$h2DvYbJGG<17C8r;Fy*g(D;$3CGiWw_GyOW7gP> zqRyJ?UOBE7-&5MsxNyR(8?G`rue-8gT;tUX3wNvx21{$pE2_#C?k@IEiQSla?fQuY zf<86j?#4TCN6J~+m7LxQD?j^H_AGOpyA9b;A^vr48bvlO~u|#bdX8tUj3S>1jD*($stkwqFiJ;hOb??V=#+tHD z-;a%mufU=mmvHAd`9S?320j7r(Rb*(K8}lo5j`8_7dQyzUOJqAAE9|j{OuW9q|-&h zCPg5?!XKfjH}d_xk-IA4mN$zL{3w5nKPvpy&vKCleMgNH*~n~SZ({n{$Cv{uVVZzz zRRu-*dW)~1(P7si)@?�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

diff --git a/windows/src/developer/TIKE/xml/kmw/packages.html b/windows/src/developer/TIKE/xml/kmw/packages.html new file mode 100644 index 0000000000..726c29f2f7 --- /dev/null +++ b/windows/src/developer/TIKE/xml/kmw/packages.html @@ -0,0 +1,143 @@ + + + + + + + + + + + + + Keyman Developer Keyboard Package Installation Site + + + + + +

Available Packages for Installation

+ +

Clicking the package links below will download and install the package into the Keyman app on this device.

+ +
    +
+ +

You can add more packages to this list by opening the package source in the Package Editor and clicking + [Test Online].

+ + + + + diff --git a/windows/src/developer/inst/kmdev.wxs b/windows/src/developer/inst/kmdev.wxs index f8f993aac3..dfa5f4274f 100644 --- a/windows/src/developer/inst/kmdev.wxs +++ b/windows/src/developer/inst/kmdev.wxs @@ -154,6 +154,8 @@ + + @@ -351,7 +353,7 @@ - + -- GitLab From cad4213ec6d0c374083bf6e8f1640cae84555c02 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 28 May 2018 15:47:22 +0700 Subject: [PATCH 167/356] Fixes #885. Fixes #891. Canonicalizes, as far as possible, new language IDs as keyboards added to package --- windows/src/buildtools/buildpkg/buildpkg.dpr | 3 +- .../src/buildtools/buildpkg/buildpkg.dproj | 1 + windows/src/developer/TIKE/Tike.dpr | 3 +- windows/src/developer/TIKE/Tike.dproj | 1 + ...n.Developer.UI.UfrmSelectBCP47Language.pas | 20 +++++++++ windows/src/developer/TIKE/main/mrulist.pas | 1 + windows/src/developer/kmcomp/kmcomp.dpr | 3 +- windows/src/developer/kmcomp/kmcomp.dproj | 1 + .../global/delphi/general/CompilePackage.pas | 43 +++++++++++++++++++ ...yman.System.CanonicalLanguageCodeUtils.pas | 2 +- ...man.System.PackageInfoRefreshKeyboards.pas | 31 +++++++++++-- 11 files changed, 102 insertions(+), 7 deletions(-) diff --git a/windows/src/buildtools/buildpkg/buildpkg.dpr b/windows/src/buildtools/buildpkg/buildpkg.dpr index 45dd56b935..97727d2481 100644 --- a/windows/src/buildtools/buildpkg/buildpkg.dpr +++ b/windows/src/buildtools/buildpkg/buildpkg.dpr @@ -71,7 +71,8 @@ uses BCP47Tag in '..\..\global\delphi\general\BCP47Tag.pas', Keyman.System.Standards.BCP47SubtagRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SubtagRegistry.pas', Keyman.System.Standards.BCP47SuppressScriptRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SuppressScriptRegistry.pas', - Keyman.System.Standards.LibPalasoAllTagsRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.LibPalasoAllTagsRegistry.pas'; + Keyman.System.Standards.LibPalasoAllTagsRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.LibPalasoAllTagsRegistry.pas', + Keyman.System.CanonicalLanguageCodeUtils in '..\..\global\delphi\general\Keyman.System.CanonicalLanguageCodeUtils.pas'; begin Run; diff --git a/windows/src/buildtools/buildpkg/buildpkg.dproj b/windows/src/buildtools/buildpkg/buildpkg.dproj index ddb6a6ee90..269405e474 100644 --- a/windows/src/buildtools/buildpkg/buildpkg.dproj +++ b/windows/src/buildtools/buildpkg/buildpkg.dproj @@ -159,6 +159,7 @@ + Cfg_2 Base diff --git a/windows/src/developer/TIKE/Tike.dpr b/windows/src/developer/TIKE/Tike.dpr index 06266ba6ea..120a716131 100644 --- a/windows/src/developer/TIKE/Tike.dpr +++ b/windows/src/developer/TIKE/Tike.dpr @@ -267,7 +267,8 @@ uses Keyman.Developer.System.HelpTopics in 'help\Keyman.Developer.System.HelpTopics.pas', Keyman.System.Standards.BCP47SubtagRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SubtagRegistry.pas', Keyman.System.Standards.BCP47SuppressScriptRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SuppressScriptRegistry.pas', - Keyman.System.Standards.LibPalasoAllTagsRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.LibPalasoAllTagsRegistry.pas'; + Keyman.System.Standards.LibPalasoAllTagsRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.LibPalasoAllTagsRegistry.pas', + Keyman.System.CanonicalLanguageCodeUtils in '..\..\global\delphi\general\Keyman.System.CanonicalLanguageCodeUtils.pas'; {$R *.RES} {$R ICONS.RES} diff --git a/windows/src/developer/TIKE/Tike.dproj b/windows/src/developer/TIKE/Tike.dproj index 5da953e29f..14a5079e9b 100644 --- a/windows/src/developer/TIKE/Tike.dproj +++ b/windows/src/developer/TIKE/Tike.dproj @@ -507,6 +507,7 @@ + Cfg_2 diff --git a/windows/src/developer/TIKE/dialogs/languages/Keyman.Developer.UI.UfrmSelectBCP47Language.pas b/windows/src/developer/TIKE/dialogs/languages/Keyman.Developer.UI.UfrmSelectBCP47Language.pas index 43778a92df..c351e6d600 100644 --- a/windows/src/developer/TIKE/dialogs/languages/Keyman.Developer.UI.UfrmSelectBCP47Language.pas +++ b/windows/src/developer/TIKE/dialogs/languages/Keyman.Developer.UI.UfrmSelectBCP47Language.pas @@ -75,6 +75,7 @@ uses System.Generics.Collections, Keyman.Developer.System.HelpTopics, + Keyman.System.CanonicalLanguageCodeUtils, Keyman.System.KMXFileLanguages, Keyman.System.LanguageCodeUtils, utilexecute; @@ -151,9 +152,28 @@ begin end; procedure TfrmSelectBCP47Language.cbLanguageTagChange(Sender: TObject); +var + t: string; begin inherited; tag.Language := TKMXFileLanguages.TranslateISO6393ToBCP47(cbLanguageTag.Text); + t := TCanonicalLanguageCodeUtils.FindBestTag(Tag.Tag); + if t <> '' then + begin + with TBCP47Tag.Create(t) do + try + cbScriptTag.Text := Script; + Self.tag.Script := Script; + finally + Free; + end; + end + else + begin + cbScriptTag.Text := ''; + tag.Script := ''; + end; + FCustomLanguageName := False; // Always reset when entering a language tag. RefreshLanguageName; end; diff --git a/windows/src/developer/TIKE/main/mrulist.pas b/windows/src/developer/TIKE/main/mrulist.pas index e11ba86b8d..fb24356423 100644 --- a/windows/src/developer/TIKE/main/mrulist.pas +++ b/windows/src/developer/TIKE/main/mrulist.pas @@ -196,3 +196,4 @@ begin end; end. + diff --git a/windows/src/developer/kmcomp/kmcomp.dpr b/windows/src/developer/kmcomp/kmcomp.dpr index 3ccf588b83..b12cccac38 100644 --- a/windows/src/developer/kmcomp/kmcomp.dpr +++ b/windows/src/developer/kmcomp/kmcomp.dpr @@ -102,7 +102,8 @@ uses Keyman.System.RegExGroupHelperRSP19902 in '..\..\global\delphi\general\Keyman.System.RegExGroupHelperRSP19902.pas', Keyman.System.Standards.BCP47SubtagRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SubtagRegistry.pas', Keyman.System.Standards.BCP47SuppressScriptRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SuppressScriptRegistry.pas', - Keyman.System.Standards.LibPalasoAllTagsRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.LibPalasoAllTagsRegistry.pas'; + Keyman.System.Standards.LibPalasoAllTagsRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.LibPalasoAllTagsRegistry.pas', + Keyman.System.CanonicalLanguageCodeUtils in '..\..\global\delphi\general\Keyman.System.CanonicalLanguageCodeUtils.pas'; {$R icons.RES} {$R version.res} diff --git a/windows/src/developer/kmcomp/kmcomp.dproj b/windows/src/developer/kmcomp/kmcomp.dproj index 209617708c..4880a38555 100644 --- a/windows/src/developer/kmcomp/kmcomp.dproj +++ b/windows/src/developer/kmcomp/kmcomp.dproj @@ -205,6 +205,7 @@ + Cfg_2 Base diff --git a/windows/src/global/delphi/general/CompilePackage.pas b/windows/src/global/delphi/general/CompilePackage.pas index e69345c39a..e984d51d4c 100644 --- a/windows/src/global/delphi/general/CompilePackage.pas +++ b/windows/src/global/delphi/general/CompilePackage.pas @@ -40,6 +40,7 @@ uses System.IniFiles, System.Zip, + BCP47Tag, OnlineConstants, VisualKeyboard, utilfiletypes, @@ -48,6 +49,7 @@ uses kmxfile, KeymanDeveloperOptions, + Keyman.System.CanonicalLanguageCodeUtils, Keyman.System.PackageInfoRefreshKeyboards, RedistFiles, @@ -75,6 +77,7 @@ type function Compile: Boolean; procedure CheckForDangerousFiles; procedure CheckKeyboardVersions; + procedure CheckKeyboardLanguages; end; function DoCompilePackage(pack: TKPSFile; AMessageEvent: TCompilePackageMessageEvent; ASilent: Boolean; const AOutputFileName: string): Boolean; // I4688 @@ -128,6 +131,7 @@ begin CheckForDangerousFiles; CheckKeyboardVersions; + CheckKeyboardLanguages; GetTempPath(260, buf); FTempPath := buf; @@ -378,5 +382,44 @@ begin end; end; +const + SKKeyboardPackageLanguageNonCanonical = 'The keyboard %0:s has a non-canonical language ID "%1:s" (%2:s), should be "%3:s".'; + +procedure TCompilePackage.CheckKeyboardLanguages; +var + k: TPackageKeyboard; + l: TPackageKeyboardLanguage; + NewID: string; + Tag, NewTag: TBCP47Tag; +begin + for k in pack.Keyboards do + begin + for l in k.Languages do + begin + Tag := TBCP47Tag.Create(l.ID); + NewID := TCanonicalLanguageCodeUtils.FindBestTag(l.ID); + if NewID = '' then + begin + // We don't have enough data to validate this tag + Continue; + end; + + NewTag := TBCP47Tag.Create(NewID); + try + if (Tag.Script = '') and (NewTag.Script <> '') then + begin + // Only give non-canonical warning if the script tag is missing but should + // be present. + NewTag.Region := Tag.Region; // We don't care about region, don't give unhelpful info to developer + WriteMessage(plsWarning, Format(SKKeyboardPackageLanguageNonCanonical, [k.ID, l.ID, l.Name, NewTag.Tag])); + end; + finally + NewTag.Free; + Tag.Free; + end; + end; + end; +end; + end. diff --git a/windows/src/global/delphi/general/Keyman.System.CanonicalLanguageCodeUtils.pas b/windows/src/global/delphi/general/Keyman.System.CanonicalLanguageCodeUtils.pas index 9f70577a20..c787e61eb0 100644 --- a/windows/src/global/delphi/general/Keyman.System.CanonicalLanguageCodeUtils.pas +++ b/windows/src/global/delphi/general/Keyman.System.CanonicalLanguageCodeUtils.pas @@ -57,7 +57,7 @@ begin Exit(''); if TLanguageCodeUtils.SuppressScripts.TryGetValue(t.Language, script) then begin - if SameText(t.Script, script) then + if SameText(t.Script, script) or (t.Script = '') then begin // The script should be suppressed because it is known to Windows (**really?) // We won't do a region check because this is not really required. diff --git a/windows/src/global/delphi/packages/Keyman.System.PackageInfoRefreshKeyboards.pas b/windows/src/global/delphi/packages/Keyman.System.PackageInfoRefreshKeyboards.pas index 47629be6c6..ee5b6239e5 100644 --- a/windows/src/global/delphi/packages/Keyman.System.PackageInfoRefreshKeyboards.pas +++ b/windows/src/global/delphi/packages/Keyman.System.PackageInfoRefreshKeyboards.pas @@ -51,9 +51,11 @@ uses BCP47Tag, + Keyman.System.CanonicalLanguageCodeUtils, Keyman.System.KMXFileLanguages, Keyman.System.KeyboardJSInfo, Keyman.System.KeyboardUtils, + Keyman.System.LanguageCodeUtils, kmxfile; const @@ -239,6 +241,7 @@ var codes: TStringDynArray; lang: TPackageKeyboardLanguage; i: Integer; + s, t: string; begin // k.Languages.Clear; @@ -248,10 +251,32 @@ begin codes := TKMXFileLanguages.GetKMXFileBCP47Codes(f.FileName); for i := 0 to High(codes) do begin + t := TCanonicalLanguageCodeUtils.FindBestTag(codes[i]); + if t = '' then + // We won't add codes that are unrecognised + Continue; + lang := TPackageKeyboardLanguage.Create(f.Package); - lang.ID := codes[i]; - // TODO: BCP47: Lookup default names - lang.Name := codes[i]; + + with TBCP47Tag.Create(t) do + try + Region := ''; + lang.ID := Tag; + + if not TLanguageCodeUtils.BCP47Languages.TryGetValue(Language, lang.Name) then + begin + lang.Name := Language; + end; + + if Script <> '' then + begin + if TLanguageCodeUtils.BCP47Languages.TryGetValue(Script, s) then + lang.Name := lang.Name + ' ('+s+')'; + end; + finally + Free; + end; + k.Languages.Add(lang); end; except -- GitLab From 89ee7bc3ee68f0b5eac2558084603582e798724d Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 29 May 2018 08:03:25 +0700 Subject: [PATCH 168/356] Fix unit tests --- .../KeyboardPackageVersionsTestSuite.dpr | 3 ++- .../KeyboardPackageVersionsTestSuite.dproj | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/windows/src/unit-tests/keyboard-package-versions/KeyboardPackageVersionsTestSuite.dpr b/windows/src/unit-tests/keyboard-package-versions/KeyboardPackageVersionsTestSuite.dpr index 28e34a4b85..5b81f55aa5 100644 --- a/windows/src/unit-tests/keyboard-package-versions/KeyboardPackageVersionsTestSuite.dpr +++ b/windows/src/unit-tests/keyboard-package-versions/KeyboardPackageVersionsTestSuite.dpr @@ -91,7 +91,8 @@ uses BCP47Tag in '..\..\global\delphi\general\BCP47Tag.pas', Keyman.System.Standards.BCP47SubtagRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SubtagRegistry.pas', Keyman.System.Standards.BCP47SuppressScriptRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.BCP47SuppressScriptRegistry.pas', - Keyman.System.Standards.LibPalasoAllTagsRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.LibPalasoAllTagsRegistry.pas'; + Keyman.System.Standards.LibPalasoAllTagsRegistry in '..\..\global\delphi\standards\Keyman.System.Standards.LibPalasoAllTagsRegistry.pas', + Keyman.System.CanonicalLanguageCodeUtils in '..\..\global\delphi\general\Keyman.System.CanonicalLanguageCodeUtils.pas'; var runner : ITestRunner; diff --git a/windows/src/unit-tests/keyboard-package-versions/KeyboardPackageVersionsTestSuite.dproj b/windows/src/unit-tests/keyboard-package-versions/KeyboardPackageVersionsTestSuite.dproj index 6d0a3c8876..941ab65d8d 100644 --- a/windows/src/unit-tests/keyboard-package-versions/KeyboardPackageVersionsTestSuite.dproj +++ b/windows/src/unit-tests/keyboard-package-versions/KeyboardPackageVersionsTestSuite.dproj @@ -179,6 +179,7 @@ + Cfg_2 Base -- GitLab From b79a2596a14c43c865fa17280cfd176c66f740cd Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 29 May 2018 08:49:41 +0700 Subject: [PATCH 169/356] Fixes #5611. Avoid crashing if a kvk file is invalid in a package. --- .../processes/package/kpinstallpackage.pas | 17 +++++++++++++---- .../engine/kmcomapi/util/keymanerrorcodes.pas | 10 ++++++---- .../global/delphi/general/kmcomapi_errors.pas | 7 ++++--- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas b/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas index 1effcaf77c..4f6d085a00 100644 --- a/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas +++ b/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas @@ -59,6 +59,8 @@ uses Windows, Classes, System.Zip, + System.Win.ComObj, + custinterfaces, Unicode, SysUtils, @@ -261,12 +263,19 @@ begin for i := 0 to inf.Files.Count - 1 do begin if inf.Files[i].FileType = ftVisualKeyboard then - with TKPInstallVisualKeyboard.Create(Context) do + begin try - Execute(FTempOutPath + inf.Files[i].FileName, ''); - finally - Free; + with TKPInstallVisualKeyboard.Create(Context) do + try + Execute(FTempOutPath + inf.Files[i].FileName, ''); + finally + Free; + end; + except + on E:EOleException do + WarnFmt(KMN_W_InstallPackage_KVK_Error, VarArrayOf([PackageName, inf.Files[i].FileName, E.Message])); end; + end; end; { Install start menu items } diff --git a/windows/src/engine/kmcomapi/util/keymanerrorcodes.pas b/windows/src/engine/kmcomapi/util/keymanerrorcodes.pas index 35732c4774..19abac2996 100644 --- a/windows/src/engine/kmcomapi/util/keymanerrorcodes.pas +++ b/windows/src/engine/kmcomapi/util/keymanerrorcodes.pas @@ -1,4 +1,4 @@ -{This file has been autogenerated by C:\keyman\10.0\src\buildtools\stockeditor\StockEditor.exe - COMMessages at 20/03/2017 11:01:55} +{This file has been autogenerated by C:\Projects\keyman\open\windows\bin\buildtools\stockeditor.exe - COMMessages at 29/05/2018 08:48:24} unit keymanerrorcodes; interface @@ -61,10 +61,11 @@ const KMN_E_RecompileMnemonicLayout_mcompileUnexpected = KMN_E_BASE + $29; KMN_W_KeyboardInstall_InvalidIcon = KMN_W_BASE + $2A; KMN_W_TSF_COMError = KMN_W_BASE + $2B; + KMN_W_InstallPackage_KVK_Error = KMN_W_BASE + $2C; { End Message Identifiers } - KMN_E_LAST = $A000022B; - KMN_W_LAST = $2000022B; + KMN_E_LAST = $A000022C; + KMN_W_LAST = $2000022C; const KeymanErrors: array[KMN_E_BASE and $FFFF..KMN_E_LAST and $FFFF] of TKeymanErrorInfo = ( @@ -112,7 +113,8 @@ const {KMN_E_RecompileMnemonicLayout_mcompileError} (Message: 'The keyboard %2:s was not generated because mcompile failed with error %0:d: %1:s'; Source: 'RecompileMnemonicKeyboard'; HelpContext: 0; Args: 'Error Code,Log Text,Keyboard filename'), // The keyboard %2:s was not generated because mcompile failed with error %0:d: %1:s {KMN_E_RecompileMnemonicLayout_mcompileUnexpected} (Message: 'The keyboard %0:s was not generated due to an unknown error.'; Source: 'RecompileMnemonicLayout'; HelpContext: 0; Args: 'Keyboard filename'), // The keyboard %0:s was not generated due to an unknown error. {KMN_W_KeyboardInstall_InvalidIcon} (Message: 'The icon for keyboard %0:s was not converted due to an error: %1:s'; Source: 'InstallKeyboard'; HelpContext: 0; Args: 'Keyboard name,Error String'), // The icon for keyboard %0:s was not converted due to an error: %1:s - {KMN_W_TSF_COMError} (Message: 'Error %0:s updating TSF'; Source: 'TSF'; HelpContext: 0; Args: 'Error message') // Error %0:s updating TSF + {KMN_W_TSF_COMError} (Message: 'Error %0:s updating TSF'; Source: 'TSF'; HelpContext: 0; Args: 'Error message'), // Error %0:s updating TSF + {KMN_W_InstallPackage_KVK_Error} (Message: 'The visual keyboard %1:s for %0:s could not be installed because of an error: %2:s'; Source: 'InstallPackage'; HelpContext: 0; Args: 'Keyboard filename,Visual Keyboard filename, Error message') // The visual keyboard %1:s for %0:s could not be installed because of an error: %2:s { End Message Info } ); diff --git a/windows/src/global/delphi/general/kmcomapi_errors.pas b/windows/src/global/delphi/general/kmcomapi_errors.pas index 20e40ad20c..42115e4de9 100644 --- a/windows/src/global/delphi/general/kmcomapi_errors.pas +++ b/windows/src/global/delphi/general/kmcomapi_errors.pas @@ -1,4 +1,4 @@ -{This file has been autogenerated by C:\keyman\10.0\src\buildtools\stockeditor\StockEditor.exe - COMMessages at 20/03/2017 11:01:55} +{This file has been autogenerated by C:\Projects\keyman\open\windows\bin\buildtools\stockeditor.exe - COMMessages at 29/05/2018 08:48:24} unit kmcomapi_errors; interface @@ -61,10 +61,11 @@ const KMN_E_RecompileMnemonicLayout_mcompileUnexpected = KMN_E_BASE + $29; KMN_W_KeyboardInstall_InvalidIcon = KMN_W_BASE + $2A; KMN_W_TSF_COMError = KMN_W_BASE + $2B; + KMN_W_InstallPackage_KVK_Error = KMN_W_BASE + $2C; { End Message Identifiers } - KMN_E_LAST = $A000022B; - KMN_W_LAST = $2000022B; + KMN_E_LAST = $A000022C; + KMN_W_LAST = $2000022C; implementation -- GitLab From 1b091c15c6adc61dcd53ca90a7a55d6c2989f2a9 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 30 May 2018 08:15:13 +0700 Subject: [PATCH 170/356] Fixes sillsdev/keyman-issues#5613. Keyboard Options dialog no longer crashes on save. --- .../src/engine/keyman32/keyboardoptions.cpp | 4 ++-- .../keyboardoptions/keymankeyboardoptions.pas | 22 ++++++++++++++----- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 595ae25df5..ea5ea8bea4 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -134,12 +134,12 @@ BOOL IntLoadKeyboardOptions(LPCSTR key, LPINTKEYBOARDINFO kp) RegistryReadOnly r(HKEY_CURRENT_USER); if(r.OpenKeyReadOnly(REGSZ_KeymanActiveKeyboards) && r.OpenKeyReadOnly(kp->Name) && r.OpenKeyReadOnly(key)) { - WCHAR buf[255]; + WCHAR buf[256]; int n = 0; while(r.GetValueNames(buf, sizeof(buf) / sizeof(buf[0]), n)) { buf[255] = 0; - WCHAR val[255]; + WCHAR val[256]; if(r.ReadString(buf, val, sizeof(val) / sizeof(val[0])) && val[0]) { val[255] = 0; diff --git a/windows/src/engine/kmcomapi/com/keyboardoptions/keymankeyboardoptions.pas b/windows/src/engine/kmcomapi/com/keyboardoptions/keymankeyboardoptions.pas index ad8059db22..d52c01f08e 100644 --- a/windows/src/engine/kmcomapi/com/keyboardoptions/keymankeyboardoptions.pas +++ b/windows/src/engine/kmcomapi/com/keyboardoptions/keymankeyboardoptions.pas @@ -84,13 +84,23 @@ var begin Result := nil; - if VarType(Index) = varOleStr - then i := IndexOf(Index) - else i := Index; + if VarType(Index) = varOleStr then + begin + i := IndexOf(Index); + if i < 0 then + i := FKeyboardOptions.Add(TKeymanKeyboardOption.Create(Context, FKeyboardID, Index, '')); + end + else + begin + i := Index; + if (i < 0) or (i >= Get_Count) then + begin + ErrorFmt(KMN_E_Collection_InvalidIndex, VarArrayOf([Index])); + Exit; + end; + end; - if (i < Get_Count) and (i >= 0) - then Result := FKeyboardOptions[i] as IKeymanKeyboardOption - else ErrorFmt(KMN_E_Collection_InvalidIndex, VarArrayOf([Index])); + Result := FKeyboardOptions[i] as IKeymanKeyboardOption; end; function TKeymanKeyboardOptions.IndexOf(const Name: WideString): Integer; -- GitLab From 2324131671b1b828b33835cc500a2e9fc72a24de Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 30 May 2018 10:17:08 +0700 Subject: [PATCH 171/356] Fixes #912. BCP47 import will now use first description for a subtag rather than the last. --- .../Keyman.System.BuildLanguageSubtagRegistry.pas | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/windows/src/buildtools/build_standards_data/Keyman.System.BuildLanguageSubtagRegistry.pas b/windows/src/buildtools/build_standards_data/Keyman.System.BuildLanguageSubtagRegistry.pas index 8330a4ff00..539e6c9a1e 100644 --- a/windows/src/buildtools/build_standards_data/Keyman.System.BuildLanguageSubtagRegistry.pas +++ b/windows/src/buildtools/build_standards_data/Keyman.System.BuildLanguageSubtagRegistry.pas @@ -39,6 +39,8 @@ var FID: string; FDescription: string; begin + FDescription := ''; + for i := 0 to FSubtagRegistry.Count-1 do begin line := Trim(FSubtagRegistry[i]); @@ -54,6 +56,7 @@ var FRegions.Add(FID + '=' + FDescription); end; FType := ''; + FDescription := ''; Continue; end; @@ -68,7 +71,7 @@ var FType := value else if code = 'Subtag' then FID := value - else if code = 'Description' then + else if (code = 'Description') and (FDescription = '') then FDescription := value; end; end; -- GitLab From 657f4ec76a6ed666ea8b244c9eb9610cccd3e69e Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 31 May 2018 09:53:52 +0700 Subject: [PATCH 172/356] Fixup email support link in help for Windows --- windows/src/desktop/help/basic/traymenu.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/src/desktop/help/basic/traymenu.xml b/windows/src/desktop/help/basic/traymenu.xml index 5b8fe11d23..3e195a0dbf 100644 --- a/windows/src/desktop/help/basic/traymenu.xml +++ b/windows/src/desktop/help/basic/traymenu.xml @@ -120,7 +120,7 @@ - If the Keyman icon is not in the hidden notifications area and not on the Windows Taskbar near the clock, make sure Keyman Desktop has been started. If you still cannot locate the Keyman icon and menu, contact Keyman Support for further assistance. + If the Keyman icon is not in the hidden notifications area and not on the Windows Taskbar near the clock, make sure Keyman Desktop has been started. If you still cannot locate the Keyman icon and menu, visit the SIL Keyman Community for further assistance. Related Topics -- GitLab From 19e9ca1cdb1ffa8b9b66f3f7495db04381de9fd7 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 31 May 2018 10:38:20 +0700 Subject: [PATCH 173/356] history.md updates --- windows/src/desktop/history.md | 31 ++++++++++++++++++++++++++++++- windows/src/developer/history.md | 29 +++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/windows/src/desktop/history.md b/windows/src/desktop/history.md index 58f479e370..02924f0ba1 100644 --- a/windows/src/desktop/history.md +++ b/windows/src/desktop/history.md @@ -1,6 +1,35 @@ # Keyman Desktop Version History -## 2018-04-16 10.0.1091.0 beta +## 2018-06-01 10.0.1100.0 beta +* Fixes email link in Keyman help + +## 2018-05-31 10.0.1099.0 beta +* Fixes a problem where "Castilian" was shown instead of "Spanish" in language configuration (#918) +* Fixes a crash when the Keyboard Options dialog is closed (#916) + +## 2018-05-30 10.0.1098.0 beta +* Prevents a crash if an invalid .kvk file is found in a package (#915) + +## 2018-05-29 10.0.1097.0 beta +* Fixes incorrect icons in the Hotkeys tab in Keyman Configuration (#906) +* Ensure language tags are correct when installing a keyboard (#892) + +## 2018-05-28 10.0.1096.0 beta +* No changes in Keyman Desktop + +## 2018-05-28 10.0.1095.0 beta +* No changes in Keyman Desktop + +## 2018-05-26 10.0.1094.0 beta +* No changes in Keyman Desktop + +## 2018-05-25 10.0.1093.0 beta +* No changes in Keyman Desktop + +## 2018-05-22 10.0.1092.0 beta +* No changes in Keyman Desktop + +## 2018-05-17 10.0.1091.0 beta * Fixes Ctrl+Alt simulation regression (#835) ## 2018-05-11 10.0.1090.0 beta diff --git a/windows/src/developer/history.md b/windows/src/developer/history.md index 30bbc33251..cf49b5a9a9 100644 --- a/windows/src/developer/history.md +++ b/windows/src/developer/history.md @@ -1,5 +1,34 @@ # Keyman Developer Version History +## 2018-06-01 10.0.1100.0 beta +* No changes to Keyman Developer + +## 2018-05-31 10.0.1099.0 beta +* No changes to Keyman Developer + +## 2018-05-30 10.0.1098.0 beta +* Validate and lookup language names automatically in package editor (#911) +* Feature: add .kmp download links from debug web server (#910) + +## 2018-05-29 10.0.1097.0 beta +* Prevent a crash when attempting to load an invalid project file (#909) +* Hide debug status panel in Test Mode (#908) + +## 2018-05-28 10.0.1096.0 beta +* Fix for crash in regression testing restart (#907) + +## 2018-05-28 10.0.1095.0 beta +* Renames touch layout extension from -layout.js to .keyman-touch-layout (#897) + +## 2018-05-26 10.0.1094.0 beta +* Check that build succeeded before attempting to start debugger (#900) + +## 2018-05-25 10.0.1093.0 beta +* Make longpress slash darker in touch layout editor (#898) + +## 2018-05-22 10.0.1092.0 beta +* No changes to Keyman Developer + ## 2018-05-17 10.0.1091.0 beta * No changes to Keyman Developer -- GitLab From 3b6c6b755469d2d43135b40b15a5d90f8f9f02c3 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 31 May 2018 14:41:50 +0700 Subject: [PATCH 174/356] Fixes #899. Don't left-trim comment lines in source. --- windows/src/developer/TIKE/main/KeyboardParser.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/src/developer/TIKE/main/KeyboardParser.pas b/windows/src/developer/TIKE/main/KeyboardParser.pas index 02f4db9b3a..bf8afa4446 100644 --- a/windows/src/developer/TIKE/main/KeyboardParser.pas +++ b/windows/src/developer/TIKE/main/KeyboardParser.pas @@ -750,7 +750,7 @@ procedure TKeyboardParser_Comment.InitLine(ALine: WideString); begin inherited InitLine(ALine); Assert(WideSameText(GetTag(ALine), 'c')); - Value := Trim(ALine); + FValue := Trim(ALine); end; constructor TKeyboardParser_Comment.CreateNew(AValue: WideString; ANew: Boolean); -- GitLab From a187daeb5bf98bbf6b6987b5d948f7b0c9e269d1 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 31 May 2018 14:49:40 +0700 Subject: [PATCH 175/356] Fixes #921. Open packages page now opens browser --- windows/src/developer/TIKE/child/UfrmPackageEditor.dfm | 4 ++-- windows/src/developer/TIKE/child/UfrmPackageEditor.pas | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/windows/src/developer/TIKE/child/UfrmPackageEditor.dfm b/windows/src/developer/TIKE/child/UfrmPackageEditor.dfm index 271a338b3c..6cb2fa7a7e 100644 --- a/windows/src/developer/TIKE/child/UfrmPackageEditor.dfm +++ b/windows/src/developer/TIKE/child/UfrmPackageEditor.dfm @@ -1152,9 +1152,9 @@ inherited frmPackageEditor: TfrmPackageEditor object cmdOpenDebugHost: TButton Left = 12 Top = 198 - Width = 189 + Width = 221 Height = 25 - Caption = 'Open &debugger in local browser' + Caption = 'Open packages page in local &browser' TabOrder = 2 OnClick = cmdOpenDebugHostClick end diff --git a/windows/src/developer/TIKE/child/UfrmPackageEditor.pas b/windows/src/developer/TIKE/child/UfrmPackageEditor.pas index dc62ba1030..fa0dd67c39 100644 --- a/windows/src/developer/TIKE/child/UfrmPackageEditor.pas +++ b/windows/src/developer/TIKE/child/UfrmPackageEditor.pas @@ -986,7 +986,7 @@ end; procedure TfrmPackageEditor.cmdOpenDebugHostClick(Sender: TObject); begin - TUtilExecute.URL(lbDebugHosts.Items[lbDebugHosts.ItemIndex] + 'packages.html'); + TUtilExecute.URL(lbDebugHosts.Items[lbDebugHosts.ItemIndex] + '/packages.html'); end; procedure TfrmPackageEditor.cmdOpenFileClick(Sender: TObject); // I4687 -- GitLab From aa81dc16b61bcf98cb895de3d79969e53b3df004 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Thu, 31 May 2018 11:42:51 -0400 Subject: [PATCH 176/356] [Mac] #675 - Double-clicking KMP shows config window with msg visible --- .../Keyman4MacIM.xcodeproj/project.pbxproj | 4 + .../KMConfigurationWindowController.h | 3 + .../KMConfigurationWindowController.m | 111 ++++++++++++++---- mac/Keyman4MacIM/Keyman4MacIM/KMPackage.h | 3 + mac/Keyman4MacIM/Keyman4MacIM/KMPackage.m | 110 +++++++---------- 5 files changed, 142 insertions(+), 89 deletions(-) diff --git a/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj b/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj index e514392163..2778f288cd 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj +++ b/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj @@ -54,6 +54,7 @@ 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 */; }; @@ -184,6 +185,7 @@ 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 = ""; }; @@ -286,6 +288,7 @@ 9874C31E1B536847000BB543 /* info.png */, 9874C31F1B536847000BB543 /* keyman.png */, 9874C3201B536847000BB543 /* SideImage.bmp */, + E21E645720C04EA7000D6274 /* logo.png */, ); path = Images; sourceTree = ""; @@ -550,6 +553,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 */, diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.h b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.h index f77887b175..adc7343bd6 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 fcf07a277c..68de881b89 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m @@ -19,6 +19,7 @@ @property (nonatomic, strong) NSTimer *reloadTimer; @property (nonatomic, strong) NSDate *lastReloadDate; @property (nonatomic, strong) NSAlert *deleteAlertView; +@property (nonatomic, strong) NSAlert *confirmKmpInstallAlertView; @end @implementation KMConfigurationWindowController @@ -382,6 +383,46 @@ [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 { if (_reloadTimer == nil) { TimerTarget *timerTarget = [[TimerTarget alloc] init]; @@ -436,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 if (returnCode == NSAlertSecondButtonReturn) { - // Cancel + // 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 { + 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/KMPackage.h b/mac/Keyman4MacIM/Keyman4MacIM/KMPackage.h index 906bb53720..b558a89c64 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMPackage.h +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMPackage.h @@ -13,7 +13,10 @@ #import "KMInputMethodAppDelegate.h" @interface KMPackage : NSDocument +-(NSString *) getOrigKmpFilename; +-(NSString *) getTempKmpFilename; +-(void) releaseTempKMPFile; @end #endif /* KMPackage_h */ diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMPackage.m b/mac/Keyman4MacIM/Keyman4MacIM/KMPackage.m index ea769c701a..b36e6ef4c7 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMPackage.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMPackage.m @@ -8,12 +8,22 @@ #import #import "KMPackage.h" +#import "KMConfigurationWindowController.h" @implementation KMPackage const NSInteger kUnexpectedFileAsscociationType = 42; -BOOL _installingKmp = NO; -NSString *filename = nil; +NSString *filenameTempKMP = nil; +NSString *filename = nil; // This is the filename from the FileWrapper (if any) + + +-(NSString *) getOrigKmpFilename { + return filename; +} + +-(NSString *) getTempKmpFilename { + return filenameTempKMP; +} + (BOOL)autosavesInPlace { return NO; @@ -23,37 +33,28 @@ NSString *filename = nil; // they decide to install it or cancel the installation. It also gets called one time up-front // when Keyman first loads. - (void)makeWindowControllers { - // The first part of this conditional ensures that the config window is created, - // even if we are not going to display it. If this doesn't happen, then when the - // user tries to open the config window manually via the menu, it won't work. - if ([self.AppDelegate configWindow] != nil && _installingKmp) { - if ([self.AppDelegate debugMode]) - NSLog(@"Attempting to display configuration window..."); - - [[self.AppDelegate configWindow] showWindow:nil]; - _installingKmp = NO; - } + if ([self.AppDelegate debugMode]) + NSLog(@"KMP - in KMPackage.makeWindowControllers"); + if (filename != nil) { // Should be true every time except maybe the very first time (when loading). - // Since we aren't really opening this file as a document, after reading it (or deciding not to) - // we need to close this document so the controller doesn't hold onto it. Otherwise, if the user - // double-clicks the same KMP file a second time it will just assume we want to open the window - // to display the already open document, rather than attempting to read it again. - if ([self.AppDelegate debugMode]) - NSLog(@"Closing document to release presenter..."); - [self close]; filename = nil; + [self closeIfFilesAreReleased]; } } -- (KMInputMethodAppDelegate *)AppDelegate { - return (KMInputMethodAppDelegate *)[NSApp delegate]; +-(void) closeIfFilesAreReleased { + // Since we aren't really opening this file as a document, after reading it (or deciding not to) + // we need to close this document so the controller doesn't hold onto it. Otherwise, if the user + // double-clicks the same KMP file a second time it will just assume we want to open the window + // to display the already open document, rather than attempting to read it again. + if ([self.AppDelegate debugMode]) + NSLog(@"Closing document to release presenter..."); + if (filename == nil && filenameTempKMP == nil) + [self close]; } -- (NSString *)pathForTemporaryKmpFile:(NSString *)kmpFilename -{ - NSString * result = [NSTemporaryDirectory() stringByAppendingPathComponent:kmpFilename]; - assert(result != nil); - return result; +- (KMInputMethodAppDelegate *)AppDelegate { + return (KMInputMethodAppDelegate *)[NSApp delegate]; } -(BOOL)readFromFileWrapper:(NSFileWrapper *)fileWrapper ofType:(NSString *)typeName error:(NSError * _Nullable __autoreleasing *)outError { @@ -74,54 +75,25 @@ NSString *filename = nil; return NO; } - // If the following is set to NO, then it will prevent displaying the config window when - // makeWindowControllers gets called. (Unfortunately, something about the document infrastructure - // in macOS will cause it to be displayed if it has not yet been displayed, even if the user cancels - // the installation. This is a bug that should be fixed, but no solution is yet apparent.) - _installingKmp = [self userConfirmsInstallationOfPackageFile:filename]; - if (!_installingKmp) { - if ([self.AppDelegate debugMode]) - NSLog(@"Keyman Package file installation cancelled by user."); - return YES; // Returning NO causes the system to report a failure to the user. - } - - NSString *tempFile = [self pathForTemporaryKmpFile:filename]; - NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:tempFile]; + filenameTempKMP = [NSTemporaryDirectory() stringByAppendingPathComponent:filename]; + assert(filenameTempKMP != nil); + NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:filenameTempKMP]; if (![fileWrapper writeToURL:fileURL options:NSFileWrapperWritingAtomic originalContentsURL:nil error:outError]) { + filenameTempKMP = nil; return NO; } - - BOOL didUnzip = [self.AppDelegate unzipFile:tempFile]; - - if (!didUnzip && outError != NULL) { - NSDictionary *errorDictionary = @{ NSLocalizedDescriptionKey : @"Failed to unzip Keyman Package" }; - *outError = [[NSError alloc] initWithDomain:@"Keyman" code:kUnexpectedFileAsscociationType userInfo:errorDictionary]; - } - [[NSFileManager defaultManager] removeItemAtPath:tempFile error:nil]; - return didUnzip; + + KMConfigurationWindowController *configWindowController = (KMConfigurationWindowController *)[self.AppDelegate configWindow]; + [configWindowController handleRequestToInstallPackage:self]; + + return YES; // Even if the user decides not to, we need to return Yes to prevent displaying an error message. } --(BOOL)userConfirmsInstallationOfPackageFile:(NSString *)fileName { - NSAlert *alert = [[NSAlert alloc] init]; - [alert addButtonWithTitle:NSLocalizedString(@"Yes", @"Alert button")]; - [alert addButtonWithTitle:NSLocalizedString(@"No", @"Alert button")]; - [alert setMessageText:NSLocalizedString(@"Install Keyman Package?", @"Alert message text when user double-clicks a KMP file.")]; - NSString *info = 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."); - info = [NSString localizedStringWithFormat:info, fileName]; - [alert setInformativeText:info]; - [alert setAlertStyle:NSInformationalAlertStyle]; - - if ([self.AppDelegate debugMode]) - NSLog(@"Asking user to confirm installation..."); - - // Attempted the following (with and without the first line) to try to - // get Keyman to be active foreground app so the alert message would not - // appear behind other window(s). Unfortunately, it doesn't work, probably - // because of Keyman being an input method. -// [[self.AppDelegate configWindow] showWindow:nil]; -// [[NSRunningApplication currentApplication] activateWithOptions:0]; - BOOL result = [alert runModal] == NSAlertFirstButtonReturn; - return result; +-(void) releaseTempKMPFile { + assert(filenameTempKMP != nil); + [[NSFileManager defaultManager] removeItemAtPath:filenameTempKMP error:nil]; + filenameTempKMP = nil; + [self closeIfFilesAreReleased]; } // This tells the system that we aren't reading the Keyman Package file lazily. -- GitLab From 9a5a92be08a74775691e92655fd2a9439328109b Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Thu, 31 May 2018 11:48:40 -0400 Subject: [PATCH 177/356] [Mac] Updated history.md for #675 (PR#929) --- mac/history.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mac/history.md b/mac/history.md index e8574959b9..098753f7cf 100644 --- a/mac/history.md +++ b/mac/history.md @@ -1,5 +1,8 @@ # Keyman for macOS Version History +## 2018-06-01 10.0.44 beta +* Improved double-clicking KMP (#929) + ## 2018-05-28 10.0.43 beta * Error-reporting improvements (settings modified to upload symbols for Engine (#884) -- GitLab From 70b1af08c3bfeb3e1e4aee125efbd10e949f6d90 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Thu, 31 May 2018 16:25:27 -0400 Subject: [PATCH 178/356] [Mac] #872 - Added Pages and Keynote as legacy apps This allows them to retain font/style information when a character sequence causes the character(s) holding that info to be replaced. --- mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m index eb23f5edd5..7b847a25aa 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m @@ -44,7 +44,9 @@ NSRange _previousSelRange; // This is the public initializer. - (instancetype)initWithClient:(NSString *)clientAppId { - BOOL legacy = ([clientAppId isEqual: @"com.github.atom"] || + BOOL legacy = ([clientAppId isEqual: @"com.apple.iWork.Pages"] || + [clientAppId isEqual: @"com.apple.iWork.Keynote"] || + [clientAppId isEqual: @"com.github.atom"] || [clientAppId isEqual: @"com.collabora.libreoffice-free"] || [clientAppId isEqual: @"com.axosoft.gitkraken"] || [clientAppId isEqual: @"org.sil.app.builder.scripture.ScriptureAppBuilder"] || -- GitLab From cabff25ae1e43c3fdb7caf05246a94fb1772772d Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Thu, 31 May 2018 16:28:31 -0400 Subject: [PATCH 179/356] [Mac] Updated history.md for PR 930 --- mac/history.md | 1 + 1 file changed, 1 insertion(+) diff --git a/mac/history.md b/mac/history.md index e8574959b9..9554578225 100644 --- a/mac/history.md +++ b/mac/history.md @@ -2,6 +2,7 @@ ## 2018-05-28 10.0.43 beta * Error-reporting improvements (settings modified to upload symbols for Engine (#884) +* Solved problem of losing font/style information in Pages and Keynote (#930) ## 2018-05-25 10.0.42 beta * Prevented crashes and performance problems with "event tap" (#883) -- GitLab From 186c1b2f652a07bd7ecc9809c12643c2e5f2fc4e Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Thu, 31 May 2018 16:40:30 -0400 Subject: [PATCH 180/356] Added explanatory comment --- mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m index 7b847a25aa..0795c37743 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m @@ -44,6 +44,10 @@ NSRange _previousSelRange; // This is the public initializer. - (instancetype)initWithClient:(NSString *)clientAppId { + // Note: Pages and Keynote (and possibly lots of other undiscovered apps that are otherwise compliant + // with Apple's IM faramework) need to be treated as "legacy" because 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. BOOL legacy = ([clientAppId isEqual: @"com.apple.iWork.Pages"] || [clientAppId isEqual: @"com.apple.iWork.Keynote"] || [clientAppId isEqual: @"com.github.atom"] || -- GitLab From 191d72a6ef58fa4d45f3450dbf087c5c8dc2bbef Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Fri, 1 Jun 2018 16:00:22 -0400 Subject: [PATCH 181/356] [Mac] #769 - Switched to using Cocoapods to get Crashlytics framework This also gets the upload-symbols script, which seems to be necessary to upload the dSYM file for the Keyman Engine. --- mac/.gitignore | 1 + mac/Cartfile | 2 - .../Keyman4MacIM.xcodeproj/project.pbxproj | 72 ++++++++++++++++++- .../contents.xcworkspacedata | 10 +++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++ .../Keyman4MacIM/KMInputMethodAppDelegate.h | 1 + mac/Keyman4MacIM/Podfile | 17 +++++ mac/Keyman4MacIM/Podfile.lock | 21 ++++++ mac/build.sh | 12 ++-- 9 files changed, 134 insertions(+), 10 deletions(-) delete mode 100644 mac/Cartfile create mode 100644 mac/Keyman4MacIM/Keyman4MacIM.xcworkspace/contents.xcworkspacedata create mode 100644 mac/Keyman4MacIM/Keyman4MacIM.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 mac/Keyman4MacIM/Podfile create mode 100644 mac/Keyman4MacIM/Podfile.lock diff --git a/mac/.gitignore b/mac/.gitignore index 1a9f734cb4..a162af22df 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/Cartfile b/mac/Cartfile deleted file mode 100644 index 88e996bd84..0000000000 --- a/mac/Cartfile +++ /dev/null @@ -1,2 +0,0 @@ -binary "https://raw.githubusercontent.com/Building42/Specs/master/Carthage/macOS/Fabric.json" ~> 1.7.6 -binary "https://raw.githubusercontent.com/Building42/Specs/master/Carthage/macOS/Crashlytics.json" ~> 3.10.1 diff --git a/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj b/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj index 2778f288cd..90fa6e26d2 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, ); }; }; @@ -67,6 +68,7 @@ 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 */; }; + E61216E78B7F03FE755687F1 /* libPods-KeymanTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9E7FB3417C46A01721AD32D0 /* libPods-KeymanTests.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -116,6 +118,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 = ""; }; @@ -180,6 +186,7 @@ 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; }; 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 = ""; }; @@ -202,6 +209,7 @@ 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 = ""; }; + 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 */ @@ -214,6 +222,7 @@ E21291A920A4DD680049790C /* Crashlytics.framework in Frameworks */, 984C2B221A79DF1B0023F89D /* KeymanEngine4Mac.framework in Frameworks */, 9803C9D81B0EFB3B0082A6F9 /* WebKit.framework in Frameworks */, + 37407275F02D5CDA553EE07E /* libPods-Keyman.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -225,12 +234,24 @@ 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 = ( @@ -315,6 +336,7 @@ E29F22F2201A59B1005EA234 /* KeymanTests */, 989C9C091A7876DE00A20425 /* Products */, E27BA9CC2020321F00D273E7 /* Frameworks */, + 2CDC487CDFFBB26D621D73BD /* Pods */, ); sourceTree = ""; }; @@ -441,6 +463,8 @@ isa = PBXGroup; children = ( E27BA9CD2020322000D273E7 /* OCMock.framework */, + 97064F9FBF9E0D09264AF6C5 /* libPods-Keyman.a */, + 9E7FB3417C46A01721AD32D0 /* libPods-KeymanTests.a */, ); name = Frameworks; sourceTree = ""; @@ -462,6 +486,7 @@ isa = PBXNativeTarget; buildConfigurationList = 989C9C251A7876DE00A20425 /* Build configuration list for PBXNativeTarget "Keyman" */; buildPhases = ( + D2FF67BB6C749BA6861F5E25 /* [CP] Check Pods Manifest.lock */, E2588F2E1F2644850061C9C4 /* ShellScript */, 989C9C041A7876DE00A20425 /* Sources */, 989C9C051A7876DE00A20425 /* Frameworks */, @@ -483,6 +508,7 @@ isa = PBXNativeTarget; buildConfigurationList = E29F22F8201A59B2005EA234 /* Build configuration list for PBXNativeTarget "KeymanTests" */; buildPhases = ( + 3263C54E5ED17882C05003D5 /* [CP] Check Pods Manifest.lock */, E29F22ED201A59B1005EA234 /* Sources */, E29F22EE201A59B1005EA234 /* Frameworks */, E29F22EF201A59B1005EA234 /* Resources */, @@ -579,6 +605,42 @@ /* 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; @@ -590,7 +652,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if [ \"${CONFIGURATION}\" = \"Release\" ]; then\n if [ \"${FABRIC_API_KEY_KEYMAN4MACIM}\" != \"\" ]; then\n ../Carthage/Build/Mac/Fabric.framework/run ${FABRIC_API_KEY_KEYMAN4MACIM} ${FABRIC_BUILD_SECRET_KEYMAN4MACIM}\n fi\nelse\n ../Carthage/Build/Mac/Fabric.framework/run 68056571ada44ad2d93864380272808ada308b24 23863472894073dc672f5027ecdd239df93ebe58830ee9c7bb383e9abaeabee7\nfi\n"; + 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 */ = { @@ -771,6 +833,7 @@ }; 989C9C261A7876DE00A20425 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 2B51C9B443060BB3B4A1AE8E /* Pods-Keyman.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "Developer ID Application"; @@ -784,7 +847,7 @@ "$(PROJECT_DIR)/Keyman4MacIM/Frameworks", "$(PROJECT_DIR)/../Carthage/Build/Mac/**", ); - HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac/**"; + HEADER_SEARCH_PATHS = ""; INFOPLIST_FILE = Keyman4MacIM/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.7; @@ -798,6 +861,7 @@ }; 989C9C271A7876DE00A20425 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 750C7C7BCA2917BAF99E6B69 /* Pods-Keyman.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "Developer ID Application"; @@ -810,7 +874,7 @@ "$(PROJECT_DIR)/Keyman4MacIM/Frameworks", "$(PROJECT_DIR)/../Carthage/Build/Mac/**", ); - HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac/**"; + HEADER_SEARCH_PATHS = ""; INFOPLIST_FILE = Keyman4MacIM/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.7; @@ -824,6 +888,7 @@ }; E29F22F9201A59B2005EA234 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 8577C0C788461AFE564DDF4F /* Pods-KeymanTests.debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -855,6 +920,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.xcworkspace/contents.xcworkspacedata b/mac/Keyman4MacIM/Keyman4MacIM.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..81894f3e4d --- /dev/null +++ b/mac/Keyman4MacIM/Keyman4MacIM.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/mac/Keyman4MacIM/Keyman4MacIM.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/mac/Keyman4MacIM/Keyman4MacIM.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/mac/Keyman4MacIM/Keyman4MacIM.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h index c43c7c8b50..702dbb52ce 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h @@ -43,6 +43,7 @@ extern NSString *const kVersion; extern NSString *const kWebSite; @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 diff --git a/mac/Keyman4MacIM/Podfile b/mac/Keyman4MacIM/Podfile new file mode 100644 index 0000000000..02cd3d59f7 --- /dev/null +++ b/mac/Keyman4MacIM/Podfile @@ -0,0 +1,17 @@ +# Uncomment the next line to define a global platform for your project +platform :osx, '10.7' + +target 'Keyman' do + # Uncomment the next line if you're using Swift or would like to use dynamic frameworks + # use_frameworks! + + # Pods for Keyman + pod 'Fabric' + pod 'Crashlytics' + + target 'KeymanTests' do + inherit! :search_paths + # Pods for testing + end + +end diff --git a/mac/Keyman4MacIM/Podfile.lock b/mac/Keyman4MacIM/Podfile.lock new file mode 100644 index 0000000000..bcdab80145 --- /dev/null +++ b/mac/Keyman4MacIM/Podfile.lock @@ -0,0 +1,21 @@ +PODS: + - Crashlytics (3.10.2): + - Fabric (~> 1.7.7) + - Fabric (1.7.7) + +DEPENDENCIES: + - Crashlytics + - Fabric + +SPEC REPOS: + https://github.com/cocoapods/specs.git: + - Crashlytics + - Fabric + +SPEC CHECKSUMS: + Crashlytics: 0360624eea1c978a743feddb2fb1ef8b37fb7a0d + Fabric: bda89e242bce1b7b8ab264248cf3407774ce0095 + +PODFILE CHECKSUM: f97fe7081827fd61ed7a61b5a0820d4e0df01dee + +COCOAPODS: 1.5.3 diff --git a/mac/build.sh b/mac/build.sh index c5e80d9b87..c1a318554f 100755 --- a/mac/build.sh +++ b/mac/build.sh @@ -79,7 +79,7 @@ KM4MIM_BASE_PATH="$KEYMAN_MAC_BASE_PATH/$IM_NAME" KME4M_PROJECT_PATH="$KME4M_BASE_PATH/$ENGINE_NAME$XCODE_PROJ_EXT" KMTESTAPP_PROJECT_PATH="$KMTESTAPP_BASE_PATH/$TESTAPP_NAME$XCODE_PROJ_EXT" -KMIM_PROJECT_PATH="$KM4MIM_BASE_PATH/$IM_NAME$XCODE_PROJ_EXT" +KMIM_WORKSPACE_PATH="$KM4MIM_BASE_PATH/$IM_NAME.xcworkspace" # KME4M_BUILD_PATH=engine/KME4M/build # APP_RESOURCES=keyman/Keyman/Keyman/libKeyman @@ -252,8 +252,10 @@ if $CLEAN ; then do_clean fi -carthage bootstrap - +if [ "$TEST_ACTION" == "test" ]; then + carthage bootstrap +fi + execBuildCommand() { typeset component="$1" shift @@ -298,10 +300,10 @@ fi if $DO_KEYMANIM ; then updatePlist "$KM4MIM_BASE_PATH" "$IM_NAME" - execBuildCommand $IM_NAME "xcodebuild -project \"$KMIM_PROJECT_PATH\" $CODESIGNING_SUPPRESSION $BUILD_OPTIONS $BUILD_ACTIONS" + execBuildCommand $IM_NAME "xcodebuild -workspace \"$KMIM_WORKSPACE_PATH\" $CODESIGNING_SUPPRESSION $BUILD_OPTIONS $BUILD_ACTIONS -scheme Keyman" if [ "$TEST_ACTION" == "test" ]; then if [ "$CONFIG" == "Debug" ]; then - execBuildCommand "$IM_NAME tests" "xcodebuild $TEST_ACTION -project \"$KMIM_PROJECT_PATH\" $CODESIGNING_SUPPRESSION $BUILD_OPTIONS -scheme Keyman" + execBuildCommand "$IM_NAME tests" "xcodebuild $TEST_ACTION -workspace \"$KMIM_WORKSPACE_PATH\" $CODESIGNING_SUPPRESSION $BUILD_OPTIONS -scheme Keyman" fi fi fi -- GitLab From c26f44f5dc1e8745dae7b6b55424df7ea4d983f7 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Mon, 4 Jun 2018 10:29:17 -0400 Subject: [PATCH 182/356] [Mac] Added pod install command to build and updated supporting files. --- mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj | 9 ++++++--- mac/README.md | 3 ++- mac/build.sh | 3 +++ mac/history.md | 5 ++++- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj b/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj index 90fa6e26d2..dd4f13d36b 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj +++ b/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj @@ -847,7 +847,7 @@ "$(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; @@ -874,7 +874,7 @@ "$(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; @@ -908,7 +908,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; diff --git a/mac/README.md b/mac/README.md index 2016895e9c..e436c565c3 100644 --- a/mac/README.md +++ b/mac/README.md @@ -3,6 +3,7 @@ ## Mac Tools Requirements/Setup Install Xcode 8.3.3 or later (it might also work to use an older version) Install [Carthage](https://github.com/Carthage/Carthage/blob/master/README.md) *see Homebrew note below +Install cocoapods (sudo gem install cocoapods) if not already installed. ## Keyman for macOS Development Keyman for macOS can be built from a command line (preferred) or Xcode. @@ -24,7 +25,7 @@ Note: If Carthage prompts you to allow it access to your github credentials, it' [Installing Keyman for Mac OS X](https://help.keyman.com/products/mac/1.0/docs/start_download-install_keyman.php). ### Compiling from Xcode -To build using Xcode, you will need to build KeymanEngine4Mac first and then build Keyman4MacIM. +To build using Xcode, you will need to build KeymanEngine4Mac first and then build Keyman4MacIM. The very _first_ time after getting the source code (and any time the Podfile is edited; e.g., to install new pods), you need to go to **keyman/mac/Keyman4MacIM and run "pod install" in Terminal. 1. Launch Xcode 2. Open **keyman/mac/KeymanEngine4Mac/KeymanEngine4Mac.xcodeproj** diff --git a/mac/build.sh b/mac/build.sh index c1a318554f..823c659e15 100755 --- a/mac/build.sh +++ b/mac/build.sh @@ -299,6 +299,9 @@ if $DO_KEYMANENGINE ; then fi if $DO_KEYMANIM ; then + cd "$KM4MIM_BASE_PATH" + pod install + cd "$KEYMAN_MAC_BASE_PATH" updatePlist "$KM4MIM_BASE_PATH" "$IM_NAME" execBuildCommand $IM_NAME "xcodebuild -workspace \"$KMIM_WORKSPACE_PATH\" $CODESIGNING_SUPPRESSION $BUILD_OPTIONS $BUILD_ACTIONS -scheme Keyman" if [ "$TEST_ACTION" == "test" ]; then diff --git a/mac/history.md b/mac/history.md index 21dfe4f1e9..711a94a99c 100644 --- a/mac/history.md +++ b/mac/history.md @@ -1,10 +1,13 @@ # Keyman for macOS Version History +## 2018-06-05 10.0.45 beta +* Error-reporting improvements (better method to ensure upload of symbols for Engine) (#935) + ## 2018-06-01 10.0.44 beta * Improved double-clicking KMP (#929) ## 2018-05-28 10.0.43 beta -* Error-reporting improvements (settings modified to upload symbols for Engine (#884) +* Error-reporting improvements (settings modified to upload symbols for Engine) (#884) * Solved problem of losing font/style information in Pages and Keynote (#930) ## 2018-05-25 10.0.42 beta -- GitLab From efbe4466f8b01eb45eadcfd37fb52dc74a27f7ea Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Mon, 4 Jun 2018 10:43:10 -0400 Subject: [PATCH 183/356] Updated carthage to remove Crashlytics & Fabric (now gotten via cocoapods) --- mac/Cartfile.resolved | 2 -- 1 file changed, 2 deletions(-) diff --git a/mac/Cartfile.resolved b/mac/Cartfile.resolved index a4570d9a91..f914031435 100644 --- a/mac/Cartfile.resolved +++ b/mac/Cartfile.resolved @@ -1,3 +1 @@ -binary "https://raw.githubusercontent.com/Building42/Specs/master/Carthage/macOS/Crashlytics.json" "3.10.1" -binary "https://raw.githubusercontent.com/Building42/Specs/master/Carthage/macOS/Fabric.json" "1.7.6" github "erikdoe/ocmock" "v3.4.1" -- GitLab From 1164cfa48f42c850010e94abc3a7e255cc14de40 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Mon, 4 Jun 2018 13:57:27 -0400 Subject: [PATCH 184/356] [Mac] #894 - Use thread synchronization to prevent crash from timer event --- .../KME/OnScreenKeyboard/KeyView.m | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyView.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyView.m index 44be4c95c7..d3cc16b8f8 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyView.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyView.m @@ -56,6 +56,10 @@ CGFloat r = 7.0; return self; } +- (void) finalize { + [self stopTimer]; +} + - (void)drawRect:(NSRect)rect { [[NSColor colorWithRed:241.0/255.0 green:242.0/255.0 blue:242.0/255.0 alpha:1.0] setFill]; NSRectFillUsingOperation(rect, NSCompositeSourceOver); @@ -221,29 +225,41 @@ CGFloat r = 7.0; } - (void)startTimerWithTimeInterval:(NSTimeInterval)interval { - if (_keyEventTimer == nil) { - TimerTarget *timerTarget = [[TimerTarget alloc] init]; - timerTarget.target = self; - _keyEventTimer = [NSTimer scheduledTimerWithTimeInterval:interval - target:timerTarget - selector:@selector(timerAction:) - userInfo:nil - repeats:YES]; + @synchronized(self) { + NSLog(@"KeyView TIMER - starting"); + if (_keyEventTimer == nil) { + // The TimerTarget class and the following two lines allow the timer to hold a *weak* + // reference to this KeyView object, so it can be disposed even if there is a timer waiting + // to fire that refers to it. + TimerTarget *timerTarget = [[TimerTarget alloc] init]; + timerTarget.target = self; + _keyEventTimer = [NSTimer scheduledTimerWithTimeInterval:interval + target:timerTarget + selector:@selector(timerAction:) + userInfo:nil + repeats:YES]; + } } } - (void)stopTimer { - if (_keyEventTimer != nil) { - [_keyEventTimer invalidate]; - _keyEventTimer = nil; + @synchronized(self) { + NSLog(@"KeyView TIMER - stopping"); + if (_keyEventTimer != nil) { + [_keyEventTimer invalidate]; + _keyEventTimer = nil; + } } } - (void)timerAction:(NSTimer *)timer { - ((void (*)(id, SEL))[self.target methodForSelector:self.action])(self.target, self.action); - if ([_keyEventTimer timeInterval] == 0.5f) { - [self stopTimer]; - [self startTimerWithTimeInterval:0.05f]; + @synchronized(self) { + NSLog(@"KeyView TIMER - Fired"); + ((void (*)(id, SEL))[self.target methodForSelector:self.action])(self.target, self.action); + if ([_keyEventTimer timeInterval] == 0.5f) { + [self stopTimer]; + [self startTimerWithTimeInterval:0.05f]; + } } } -- GitLab From c72d81d96ee819c433165c3ad5842a2ccba71c88 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 5 Jun 2018 08:14:13 +0700 Subject: [PATCH 185/356] Fixes #852. Locked files are ignored and no longer block crash report from uploading. --- windows/src/engine/tsysinfo/si_base.pas | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/windows/src/engine/tsysinfo/si_base.pas b/windows/src/engine/tsysinfo/si_base.pas index bb4af058a1..f61aff494a 100644 --- a/windows/src/engine/tsysinfo/si_base.pas +++ b/windows/src/engine/tsysinfo/si_base.pas @@ -324,7 +324,11 @@ begin Open(AFileName, TZipMode.zmWrite); Add(FTempFileName); for i := 0 to FFiles.Count - 1 do + try Add(FFiles[i]); + except + on E:EFOpenError do ; + end; Close; finally Free; -- GitLab From cd5c0adb64681e5bd5ea5b9cde88dde5385ff128 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 5 Jun 2018 08:29:00 +0700 Subject: [PATCH 186/356] Fixes #854. Remove logfile only on close of crash report dialog, not after failing to send --- windows/src/engine/tsysinfo/UfrmRemoteExceptionHandler.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/windows/src/engine/tsysinfo/UfrmRemoteExceptionHandler.pas b/windows/src/engine/tsysinfo/UfrmRemoteExceptionHandler.pas index b3133e7cca..6871e75c74 100644 --- a/windows/src/engine/tsysinfo/UfrmRemoteExceptionHandler.pas +++ b/windows/src/engine/tsysinfo/UfrmRemoteExceptionHandler.pas @@ -386,7 +386,6 @@ begin Free; end; FTempFileName := TSIFileName; - DeleteFile(FLogFile); end else FTempFileName := FLogFile; @@ -409,6 +408,9 @@ end; procedure TfrmExceptionHandler.FormDestroy(Sender: TObject); begin + if FileExists(FLogFile) then + DeleteFile(FLogFile); + Application.UnhookMainWindow(AppMessage); end; -- GitLab From db816920f9dfee21b0aeb86d0b965981a1769004 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Mon, 4 Jun 2018 22:44:20 -0400 Subject: [PATCH 187/356] [Mac] #894 Updated history file --- mac/history.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mac/history.md b/mac/history.md index 711a94a99c..e46cabb2af 100644 --- a/mac/history.md +++ b/mac/history.md @@ -1,5 +1,8 @@ # Keyman for macOS Version History +## 2018-06-05 10.0.46 beta +* Fixed crash caused by accessing disposed KeyView from timer event (#938, #941) + ## 2018-06-05 10.0.45 beta * Error-reporting improvements (better method to ensure upload of symbols for Engine) (#935) -- GitLab From f198be5d3cd4ff4bdcdcf05deeb5c6b743346d82 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Mon, 4 Jun 2018 22:44:20 -0400 Subject: [PATCH 188/356] Revert "[Mac] #894 Updated history file" This reverts commit db816920f9dfee21b0aeb86d0b965981a1769004. --- mac/history.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/mac/history.md b/mac/history.md index e46cabb2af..711a94a99c 100644 --- a/mac/history.md +++ b/mac/history.md @@ -1,8 +1,5 @@ # Keyman for macOS Version History -## 2018-06-05 10.0.46 beta -* Fixed crash caused by accessing disposed KeyView from timer event (#938, #941) - ## 2018-06-05 10.0.45 beta * Error-reporting improvements (better method to ensure upload of symbols for Engine) (#935) -- GitLab From 6b556f12804368959ce5f1d202ac4ba803a8488c Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Mon, 4 Jun 2018 22:44:20 -0400 Subject: [PATCH 189/356] Revert "Revert "[Mac] #894 Updated history file"" This reverts commit f198be5d3cd4ff4bdcdcf05deeb5c6b743346d82. --- mac/history.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mac/history.md b/mac/history.md index 711a94a99c..e46cabb2af 100644 --- a/mac/history.md +++ b/mac/history.md @@ -1,5 +1,8 @@ # Keyman for macOS Version History +## 2018-06-05 10.0.46 beta +* Fixed crash caused by accessing disposed KeyView from timer event (#938, #941) + ## 2018-06-05 10.0.45 beta * Error-reporting improvements (better method to ensure upload of symbols for Engine) (#935) -- GitLab From 9be9b0a6d003e7d5fc322c28743f3e058d06c62d Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Mon, 4 Jun 2018 22:49:38 -0400 Subject: [PATCH 190/356] Fixed date in history file --- mac/history.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mac/history.md b/mac/history.md index e46cabb2af..759e1addd8 100644 --- a/mac/history.md +++ b/mac/history.md @@ -1,6 +1,6 @@ # Keyman for macOS Version History -## 2018-06-05 10.0.46 beta +## 2018-06-06 10.0.46 beta * Fixed crash caused by accessing disposed KeyView from timer event (#938, #941) ## 2018-06-05 10.0.45 beta -- GitLab From 393ca2d336e081277b385afaf9bad90c6bc10d0c Mon Sep 17 00:00:00 2001 From: darcywong00 Date: Tue, 5 Jun 2018 13:19:47 +0700 Subject: [PATCH 191/356] Fix globe button for system keyboard Fixes #913 In #848, we used [webView.pauseTimers()](https://developer.android.com/reference/android/webkit/WebView#pauseTimers()) to disable JavaScript for transitioning between in-app and system keyboards. Unfortunately, `pauseTimers()` globally affects all the WebViews, breaking the globe button in system keyboards. (This worked going from the Keyman app to in-app browser because the browser "resumed" its keyboard) Solution is removing calls to `pauseTimers()`. --- .../app/src/main/java/com/tavultesoft/kmea/KMManager.java | 6 ------ android/history.md | 8 ++++++-- 2 files changed, 6 insertions(+), 8 deletions(-) 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 51c873f961..5099b8eabe 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 @@ -324,15 +324,9 @@ public final class KMManager { public static void onPause() { if (InAppKeyboard != null) { InAppKeyboard.onPause(); - if (InAppKeyboardLoaded) { - InAppKeyboard.pauseTimers(); - } } if (SystemKeyboard != null) { SystemKeyboard.onPause(); - if (SystemKeyboardLoaded) { - SystemKeyboard.pauseTimers(); - } } } diff --git a/android/history.md b/android/history.md index 2d70cfc09b..8394fcd03c 100644 --- a/android/history.md +++ b/android/history.md @@ -1,7 +1,11 @@ # Keyman for Android +## 2018-06-05 10.0.398 beta +* Fix globe button for system keyboard (#940) + ## 2018-05-27 10.0.397 beta -* Improve intent-filter for *.kmp extensions (902) + +* Improve intent-filter for *.kmp extensions (#902) ## 2018-05-22 10.0.396 beta * No changes to Keyman for Android. @@ -16,7 +20,7 @@ * No changes to Keyman for Android. ## 2018-05-11 10.0.392 beta -* Fix globe button when exiting in-app browser (#231) +* 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) -- GitLab From af1b08d041fc3b0c1311128025bc7e210d8e480c Mon Sep 17 00:00:00 2001 From: darcywong00 Date: Tue, 5 Jun 2018 13:22:02 +0700 Subject: [PATCH 192/356] Update PR number --- android/history.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/history.md b/android/history.md index 8394fcd03c..5d85fbec00 100644 --- a/android/history.md +++ b/android/history.md @@ -1,7 +1,7 @@ # Keyman for Android ## 2018-06-05 10.0.398 beta -* Fix globe button for system keyboard (#940) +* Fix globe button for system keyboard (#942) ## 2018-05-27 10.0.397 beta -- GitLab From 67333c95f60fd20f0c846f028354ffb88326bf19 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 5 Jun 2018 16:30:40 +0700 Subject: [PATCH 193/356] Fixes #919. Keyboards with custom BCP 47 language tags will now install on Windows 7 with a fallback language. --- .../processes/keyboard/kpinstallkeyboard.pas | 29 +++++++++++++++---- .../kpinstallkeyboardlanguageprofiles.pas | 18 ++++++++---- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas index a848643c0d..de035b6357 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas @@ -59,8 +59,8 @@ type private procedure RegisterLanguageProfile(Langs: array of Integer; const KeyboardName, KeyboardDescription, IconFileName: string); overload; - procedure RegisterLanguageProfile(const BCP47Tag, KeyboardName, - KeyboardDescription, IconFileName, LanguageName: string); overload; + function RegisterLanguageProfile(const BCP47Tag, KeyboardName, + KeyboardDescription, IconFileName, LanguageName: string): Boolean; overload; end; implementation @@ -115,8 +115,9 @@ var FLanguages: array of Integer; FExitCode: Integer; FKVKName: WideString; - FCreatedIcon: Boolean; + FLanguageInstalled, FCreatedIcon: Boolean; FLanguageID: Integer; + i: Integer; type TWSLCallback = reference to procedure(r: TRegistryErrorControlled); @@ -241,7 +242,23 @@ begin // Use language data from package to install; we only install // the first language now and add the rest to the registry for // future addition by the user - RegisterLanguageProfile(Languages[0].ID, kbdname, ki.KeyboardName, FIconFileName, Languages[0].Name); + + FLanguageInstalled := False; + for i := 0 to Languages.Count - 1 do + begin + FLanguageInstalled := RegisterLanguageProfile(Languages[i].ID, kbdname, ki.KeyboardName, FIconFileName, Languages[i].Name); + if FLanguageInstalled then + Break; + end; + + if not FLanguageInstalled then + begin + // All languages failed to install, so add to the default language. + // This is most likely to happen on Win7 where custom BCP 47 tags + // are not allowed + AddLanguage(HKLToLanguageID(FDefaultHKL)); + RegisterLanguageProfile(FLanguages, kbdname, ki.KeyboardName, FIconFileName); // I3581 // I3707 + end; // Save the list of preferred languages for the keyboard, to the registry, for future installation. WriteSuggestedLanguages( @@ -370,11 +387,11 @@ begin end; end; -procedure TKPInstallKeyboard.RegisterLanguageProfile(const BCP47Tag, KeyboardName, KeyboardDescription, IconFileName, LanguageName: string); // I3581 // I3619 // I3707 // I3768 // I4607 +function TKPInstallKeyboard.RegisterLanguageProfile(const BCP47Tag, KeyboardName, KeyboardDescription, IconFileName, LanguageName: string): Boolean; // I3581 // I3619 // I3707 // I3768 // I4607 begin with TKPInstallKeyboardLanguageProfiles.Create(Context) do try - Execute(KeyboardName, KeyboardDescription, BCP47Tag, IconFileName, LanguageName); // I3707 // I3768 // I4607 + Result := Execute(KeyboardName, KeyboardDescription, BCP47Tag, IconFileName, LanguageName); // I3707 // I3768 // I4607 finally Free; end; diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboardlanguageprofiles.pas b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboardlanguageprofiles.pas index 2fd50f24f9..c955d4dcc0 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboardlanguageprofiles.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboardlanguageprofiles.pas @@ -44,7 +44,7 @@ type TKPInstallKeyboardLanguageProfiles = class(TKPBase) // Expects LANGIDs and LocaleNames in format 'en-US en 0409'; procedure Execute(const KeyboardName, KeyboardDescription: string; LangIDs: array of Integer; IconFileName: string; InstallFirstOnly: Boolean); overload; // I3707 // I3768 // I4607 - procedure Execute(const KeyboardName, KeyboardDescription, BCP47Tag, IconFileName, LanguageName: string); overload; // I3707 // I3768 // I4607 + function Execute(const KeyboardName, KeyboardDescription, BCP47Tag, IconFileName, LanguageName: string): Boolean; overload; // I3707 // I3768 // I4607 constructor Create(AContext: TKeymanContext); destructor Destroy; override; private @@ -162,7 +162,7 @@ begin Context.Control.AutoApplyKeyman; end; -procedure TKPInstallKeyboardLanguageProfiles.Execute(const KeyboardName, KeyboardDescription, BCP47Tag, IconFileName, LanguageName: string); +function TKPInstallKeyboardLanguageProfiles.Execute(const KeyboardName, KeyboardDescription, BCP47Tag, IconFileName, LanguageName: string): Boolean; var FIsAdmin: Boolean; begin @@ -185,8 +185,9 @@ begin RootPath := GetRegistryKeyboardInstallKey_CU(KeyboardName) + SRegSubKey_LanguageProfiles; end; - if reg.OpenKey(RootPath, True) then - RegisterLocale(KeyboardDescription, BCP47Tag, 0, IconFileName, LanguageName); // I3707 // I3768 // I4607 + if reg.OpenKey(RootPath, True) + then Result := RegisterLocale(KeyboardDescription, BCP47Tag, 0, IconFileName, LanguageName) // I3707 // I3768 // I4607 + else Result := False; finally reg.Free; end; @@ -236,8 +237,15 @@ begin if not ConvertLangIDToBCP47Tag(LangID, BCP47Tag) then Exit; end - else if not ConvertBCP47TagToLangID(BCP47Tag, LangID) and FWin8Languages.IsSupported then + else if not ConvertBCP47TagToLangID(BCP47Tag, LangID) then begin + // + // Installing a custom language only supported with Win8 and later + // + + if not FWin8Languages.IsSupported then + Exit; + // // Install user language with Powershell if it isn't present // -- GitLab From d12a5531fcf3b2a18889b2bdf70162b350d7b6f3 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 5 Jun 2018 16:39:27 +0700 Subject: [PATCH 194/356] Fixes sillsdev/keyman-issues#5641. Crash in Keyman Configuration on Win7 when enumerating keyboard custom languages --- .../kmshell/install/UfrmInstallKeyboardLanguage.pas | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/windows/src/desktop/kmshell/install/UfrmInstallKeyboardLanguage.pas b/windows/src/desktop/kmshell/install/UfrmInstallKeyboardLanguage.pas index 2a405b2df6..ed9c806c8f 100644 --- a/windows/src/desktop/kmshell/install/UfrmInstallKeyboardLanguage.pas +++ b/windows/src/desktop/kmshell/install/UfrmInstallKeyboardLanguage.pas @@ -312,7 +312,17 @@ begin if Tag <> '' then begin FLanguage := TInstLanguage.Create(True, Language, Script, FKeyboard.Languages[i].Name); - FLanguage.Variants.Add(TInstLanguageVariant.Create(Language, Tag, Script, FKeyboard.Languages[i].Name)); + try + FLanguage.Variants.Add(TInstLanguageVariant.Create(Language, Tag, Script, FKeyboard.Languages[i].Name)); + except + on E:EOSError do + begin + // The language tag is not supported on this OS - probably Win7 + // Don't offer it as an option + FLanguage.Free; + Continue; + end; + end; FLanguages.Add(FLanguage); end; finally -- GitLab From 4f0010a941984a09b2e1af285d7fa4e534a6ab78 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Tue, 5 Jun 2018 14:34:48 -0400 Subject: [PATCH 195/356] [Mac] Added switches to control Keyman4MacIM build destination --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../xcshareddata/xcschemes/Keyman.xcscheme | 2 -- mac/build.sh | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 ios/keymanios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/ios/keymanios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/keymanios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/ios/keymanios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/xcshareddata/xcschemes/Keyman.xcscheme b/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/xcshareddata/xcschemes/Keyman.xcscheme index 9fd741da12..c5b862367d 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"> Date: Tue, 5 Jun 2018 15:49:18 -0400 Subject: [PATCH 196/356] Removed iOS-related file created by Xcode included in this PR by mistake --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 ios/keymanios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/ios/keymanios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/keymanios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003d..0000000000 --- a/ios/keymanios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - -- GitLab From 1f889141dc5e07816bdc420cf8bf80259ab08be4 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Tue, 5 Jun 2018 16:35:22 -0400 Subject: [PATCH 197/356] [Mac] Noted change in History file --- mac/history.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mac/history.md b/mac/history.md index 759e1addd8..0fd0afba06 100644 --- a/mac/history.md +++ b/mac/history.md @@ -1,5 +1,8 @@ # Keyman for macOS Version History +## 2018-06-07 10.0.47 beta +* Change to build script to use correct build location (#950) + ## 2018-06-06 10.0.46 beta * Fixed crash caused by accessing disposed KeyView from timer event (#938, #941) -- GitLab From ae3a0df6da88428c8a5f37d30dc243dcf0e122d3 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 6 Jun 2018 07:54:53 +0700 Subject: [PATCH 198/356] [windows] Update history.md --- windows/src/desktop/history.md | 10 ++++++++-- windows/src/developer/history.md | 7 +++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/windows/src/desktop/history.md b/windows/src/desktop/history.md index 02924f0ba1..f60243a3dc 100644 --- a/windows/src/desktop/history.md +++ b/windows/src/desktop/history.md @@ -1,5 +1,11 @@ # Keyman Desktop Version History +## 2018-06-05 10.0.1102.0 beta +* Improved crash reporting stability (#940) + +## 2018-06-03 10.0.1101.0 beta +* No changes in Keyman Desktop + ## 2018-06-01 10.0.1100.0 beta * Fixes email link in Keyman help @@ -54,10 +60,10 @@ * Adds script lookup to Add Keyboard Language dialog (#827) ## 2018-05-07 10.0.1081.0 beta -* Fixes crash in Keyman Developer when keyboard name contains an ampersand (#831) +* Fixes crash in Keyman Desktop when keyboard name contains an ampersand (#831) ## 2018-05-07 10.0.1080.0 beta -* Fixes crash starting Keyman Developer when using certain base keyboards (#832) +* Fixes crash starting Keyman Desktop when using certain base keyboards (#832) ## 2018-05-07 10.0.1079.0 beta * Fixes crash in updating active keyboard icon in On Screen Keyboard (#828) diff --git a/windows/src/developer/history.md b/windows/src/developer/history.md index cf49b5a9a9..44e0e14a5c 100644 --- a/windows/src/developer/history.md +++ b/windows/src/developer/history.md @@ -1,5 +1,12 @@ # Keyman Developer Version History +## 2018-06-05 10.0.1102.0 beta +* Improved crash reporting stability (#940) + +## 2018-06-03 10.0.1101.0 beta +* Open Packages Page now opens the browser in Package Editor (#926) +* Source editor no longer left-trims comments (#925) + ## 2018-06-01 10.0.1100.0 beta * No changes to Keyman Developer -- GitLab From dc76e53067f677b1f3b6a7e1f79e7d1609c874b3 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 6 Jun 2018 10:45:58 +0700 Subject: [PATCH 199/356] Fixes #888. Untitled keyboards will now show the filename of the keyboard in Keyman UI --- .../kmshell/xml/keyman_keyboardlist.xsl | 12 ++++-- .../kpinstallkeyboardlanguageprofiles.pas | 43 ++++++++++++------- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/windows/src/desktop/kmshell/xml/keyman_keyboardlist.xsl b/windows/src/desktop/kmshell/xml/keyman_keyboardlist.xsl index 449942fb51..f5667f66c3 100644 --- a/windows/src/desktop/kmshell/xml/keyman_keyboardlist.xsl +++ b/windows/src/desktop/kmshell/xml/keyman_keyboardlist.xsl @@ -41,7 +41,10 @@ package.gif
- + + + .kmp +

@@ -127,7 +130,10 @@
keyboard_name_ - + + + .kmx +
@@ -185,7 +191,7 @@
- + + - + @@ -239,7 +235,7 @@ help:reference/file-types/ - icon32_. + res/icon32_.
.
diff --git a/windows/src/developer/TIKE/xml/project/keyboards.xsl b/windows/src/developer/TIKE/xml/project/keyboards.xsl index 66968e3ae8..5dc620dee2 100644 --- a/windows/src/developer/TIKE/xml/project/keyboards.xsl +++ b/windows/src/developer/TIKE/xml/project/keyboards.xsl @@ -6,44 +6,56 @@
-

Keyboards - header_keyboard.png -

+

+ Keyboards +

Creating your first keyboard

- -

Click the New Keyboard button to create a keyboard for any device. This will open the Keyboard Editor, where you can - create a keyboard visually, or programatically with the Keyman Keyboard Language.

+ +

+ Click the New Keyboard button to create a keyboard for any device. This will open the Keyboard Editor, where you can + create a keyboard visually, or programatically with the Keyman Keyboard Language. +

  • - The Layout page in the Keyboard Editor lets you quickly create - a keyboard using a visual representation of a computer keyboard. You can drag and drop characters from the + The Layout page in the Keyboard Editor lets you quickly create + a keyboard using a visual representation of a computer keyboard. You can drag and drop characters from the Character Map to create Unicode keyboard layouts.
  • - The Source tab of the layout page shows the keyboard's design in the + The Source tab of the layout page shows the keyboard's design in the Keyman Keyboard Language. From here, you can enhance keyboards with input management features such as constraints, dead keys, character reordering, and more. Read the Tutorial for an introduction to these features.
- -

It's a good idea to read Developing Open Source Keyboards for guidelines - on preparing open source keyboards for sharing through the Keyman keyboard repositories. Also see the Distribution tab for more on - distributing your completed keyboards.

- + +

+ It's a good idea to read Developing Open Source Keyboards for guidelines + on preparing open source keyboards for sharing through the Keyman keyboard repositories. Also see the Distribution tab for more on + distributing your completed keyboards. +

+
.kmx diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboardlanguageprofiles.pas b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboardlanguageprofiles.pas index 2fd50f24f9..67506bb3c6 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboardlanguageprofiles.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboardlanguageprofiles.pas @@ -43,8 +43,8 @@ uses type TKPInstallKeyboardLanguageProfiles = class(TKPBase) // Expects LANGIDs and LocaleNames in format 'en-US en 0409'; - procedure Execute(const KeyboardName, KeyboardDescription: string; LangIDs: array of Integer; IconFileName: string; InstallFirstOnly: Boolean); overload; // I3707 // I3768 // I4607 - procedure Execute(const KeyboardName, KeyboardDescription, BCP47Tag, IconFileName, LanguageName: string); overload; // I3707 // I3768 // I4607 + procedure Execute(const KeyboardID, KeyboardName: string; LangIDs: array of Integer; IconFileName: string; InstallFirstOnly: Boolean); overload; // I3707 // I3768 // I4607 + procedure Execute(const KeyboardID, KeyboardName, BCP47Tag, IconFileName, LanguageName: string); overload; // I3707 // I3768 // I4607 constructor Create(AContext: TKeymanContext); destructor Destroy; override; private @@ -79,6 +79,7 @@ uses BCP47Tag, TempFileManager, utilexecute, + utilfiletypes, utilkeyman, utilstr, utiltsf; @@ -125,34 +126,39 @@ begin inherited Destroy; end; -procedure TKPInstallKeyboardLanguageProfiles.Execute(const KeyboardName, KeyboardDescription: string; LangIDs: array of Integer; IconFileName: string; InstallFirstOnly: Boolean); // I3707 // I3768 // I4607 +procedure TKPInstallKeyboardLanguageProfiles.Execute(const KeyboardID, KeyboardName: string; LangIDs: array of Integer; IconFileName: string; InstallFirstOnly: Boolean); // I3707 // I3768 // I4607 var FIsAdmin: Boolean; i: Integer; + FKeyboardName: string; begin - if not KeyboardInstalled(KeyboardName, FIsAdmin) then - ErrorFmt(KMN_E_ProfileInstall_KeyboardNotFound, VarArrayOf([KeyboardName])); // I3888 + if not KeyboardInstalled(KeyboardID, FIsAdmin) then + ErrorFmt(KMN_E_ProfileInstall_KeyboardNotFound, VarArrayOf([KeyboardID])); // I3888 if not IsAdministrator and FIsAdmin then // I3720 - ErrorFmt(KMN_E_ProfileInstall_MustBeAllUsers, VarArrayOf([KeyboardName])); // I3764 // I3888 + ErrorFmt(KMN_E_ProfileInstall_MustBeAllUsers, VarArrayOf([KeyboardID])); // I3764 // I3888 + + if KeyboardName = '' + then FKeyboardName := KeyboardID + Ext_KeymanFile + else FKeyboardName := KeyboardName; reg := TRegistry.Create; try if FIsAdmin then begin reg.RootKey := HKEY_LOCAL_MACHINE; - RootPath := GetRegistryKeyboardInstallKey_LM(KeyboardName) + SRegSubKey_LanguageProfiles; + RootPath := GetRegistryKeyboardInstallKey_LM(KeyboardID) + SRegSubKey_LanguageProfiles; end else begin reg.RootKey := HKEY_CURRENT_USER; - RootPath := GetRegistryKeyboardInstallKey_CU(KeyboardName) + SRegSubKey_LanguageProfiles; + RootPath := GetRegistryKeyboardInstallKey_CU(KeyboardID) + SRegSubKey_LanguageProfiles; end; if reg.OpenKey(RootPath, True) then begin for i := 0 to High(LangIDs) do - if RegisterLocale(KeyboardDescription, '', LangIDs[i], IconFileName, '') and InstallFirstOnly then // I3707 // I3768 // I4607 + if RegisterLocale(FKeyboardName, '', LangIDs[i], IconFileName, '') and InstallFirstOnly then // I3707 // I3768 // I4607 Break; end; finally @@ -162,31 +168,36 @@ begin Context.Control.AutoApplyKeyman; end; -procedure TKPInstallKeyboardLanguageProfiles.Execute(const KeyboardName, KeyboardDescription, BCP47Tag, IconFileName, LanguageName: string); +procedure TKPInstallKeyboardLanguageProfiles.Execute(const KeyboardID, KeyboardName, BCP47Tag, IconFileName, LanguageName: string); var FIsAdmin: Boolean; + FKeyboardName: string; begin - if not KeyboardInstalled(KeyboardName, FIsAdmin) then - ErrorFmt(KMN_E_ProfileInstall_KeyboardNotFound, VarArrayOf([KeyboardName])); // I3888 + if not KeyboardInstalled(KeyboardID, FIsAdmin) then + ErrorFmt(KMN_E_ProfileInstall_KeyboardNotFound, VarArrayOf([KeyboardID])); // I3888 if not IsAdministrator and FIsAdmin then // I3720 - ErrorFmt(KMN_E_ProfileInstall_MustBeAllUsers, VarArrayOf([KeyboardName])); // I3764 // I3888 + ErrorFmt(KMN_E_ProfileInstall_MustBeAllUsers, VarArrayOf([KeyboardID])); // I3764 // I3888 + + if KeyboardName = '' + then FKeyboardName := KeyboardID + Ext_KeymanFile + else FKeyboardName := KeyboardName; reg := TRegistry.Create; try if FIsAdmin then begin reg.RootKey := HKEY_LOCAL_MACHINE; - RootPath := GetRegistryKeyboardInstallKey_LM(KeyboardName) + SRegSubKey_LanguageProfiles; + RootPath := GetRegistryKeyboardInstallKey_LM(KeyboardID) + SRegSubKey_LanguageProfiles; end else begin reg.RootKey := HKEY_CURRENT_USER; - RootPath := GetRegistryKeyboardInstallKey_CU(KeyboardName) + SRegSubKey_LanguageProfiles; + RootPath := GetRegistryKeyboardInstallKey_CU(KeyboardID) + SRegSubKey_LanguageProfiles; end; if reg.OpenKey(RootPath, True) then - RegisterLocale(KeyboardDescription, BCP47Tag, 0, IconFileName, LanguageName); // I3707 // I3768 // I4607 + RegisterLocale(FKeyboardName, BCP47Tag, 0, IconFileName, LanguageName); // I3707 // I3768 // I4607 finally reg.Free; end; -- GitLab From a00d3f255be1fe1fa25b79d16f43eebf59601391 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Thu, 7 Jun 2018 12:24:18 -0400 Subject: [PATCH 200/356] [iOS] #735 - Allow keyboard update even if languageID not in API results --- .../KeyboardRepository/KeyboardRepository.swift | 11 ++++++----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 ios/keymanios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/ios/engine/KMEI/KeymanEngine/Classes/KeyboardRepository/KeyboardRepository.swift b/ios/engine/KMEI/KeymanEngine/Classes/KeyboardRepository/KeyboardRepository.swift index 13e24a2101..4e34bfb72c 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,12 @@ public protocol KeyboardRepository: class { public extension KeyboardRepository { public func installableKeyboard(withID keyboardID: String, languageID: String) -> InstallableKeyboard? { - guard let language = languages?[languageID] else { - return nil - } - guard let keyboard = language.keyboards?.first(where: { $0.id == keyboardID }) else { + guard let keyboard = keyboards?.first(where: { $0.key == keyboardID })?.value else { return nil } + + let language = keyboard.languages?.first(where: {$0.id == languageID}) ?? keyboard.languages?.first ?? languages?[languageID] ?? Language(name: languageID, id: languageID, keyboards: [keyboard], font: nil, oskFont: nil) + return InstallableKeyboard(keyboard: keyboard, language: language, isCustom: false) } diff --git a/ios/keymanios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/keymanios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/ios/keymanios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + -- GitLab From 55aa150d20829df386ea4936bc480f1a86ff0841 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 8 Jun 2018 10:16:33 +0700 Subject: [PATCH 201/356] Fixes #919 (again). Strip script subtag on Windows 7 before installing keyboard as script subtag not supported. --- .../keyboard/kpinstallkeyboardlanguageprofiles.pas | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboardlanguageprofiles.pas b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboardlanguageprofiles.pas index c955d4dcc0..bda97e1f18 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboardlanguageprofiles.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboardlanguageprofiles.pas @@ -208,6 +208,18 @@ begin LangID := Win8Lang.LangID; Exit(True); end; + end + else + begin + // Assuming that the tag is a Language-Script-Region triplet at most. + // If you use -Variant or -Extension then YMMV. + with TBCP47Tag.Create(Locale) do + try + Script := ''; + Locale := Tag; + finally + Free; + end; end; LangID := LocaleNameToLCID(PWideChar(Locale), 0); -- GitLab From c16e834104a2b2fe75285769791bf1e25d5ce172 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Thu, 7 Jun 2018 23:36:47 -0400 Subject: [PATCH 202/356] [Mac] #735 - Changed query to get bcp-47 language IDs Also removed kludgy and now unnecessary fall-back code to create a "language" on the fly from an id. --- .../KeyboardRepository/APIKeyboardRepository.swift | 3 ++- .../KeyboardRepository/KeyboardRepository.swift | 10 +++++++++- ios/history.md | 9 +++++++++ ios/keyman/Keyman/Keyman-Info.plist | 4 ++-- ios/keyman/Keyman/Settings.bundle/Root.plist | 2 +- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/KeyboardRepository/APIKeyboardRepository.swift b/ios/engine/KMEI/KeymanEngine/Classes/KeyboardRepository/APIKeyboardRepository.swift index f733365a07..f543484d7c 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 4e34bfb72c..97c90c8073 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/KeyboardRepository/KeyboardRepository.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/KeyboardRepository/KeyboardRepository.swift @@ -25,7 +25,15 @@ public extension KeyboardRepository { return nil } - let language = keyboard.languages?.first(where: {$0.id == languageID}) ?? keyboard.languages?.first ?? languages?[languageID] ?? Language(name: languageID, id: languageID, keyboards: [keyboard], font: nil, oskFont: 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/history.md b/ios/history.md index 6a3617a299..5a69a2d101 100644 --- a/ios/history.md +++ b/ios/history.md @@ -1,5 +1,14 @@ # Keyman for iPhone and iPad Version History +## 2018-06-7 10.0.154 beta +* Fixed API call to fetch BCP-47 language ids and make keyboard updates more robust (#961) + +## 2018-06-6 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) diff --git a/ios/keyman/Keyman/Keyman-Info.plist b/ios/keyman/Keyman/Keyman-Info.plist index 5b2a071191..487d06ecf2 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/Settings.bundle/Root.plist b/ios/keyman/Keyman/Settings.bundle/Root.plist index ab5a2c6f63..57514b9065 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 -- GitLab From 5a2e529713ab37b2da6dcdf7e322755eef90ee07 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 8 Jun 2018 13:29:12 +0700 Subject: [PATCH 203/356] Fixes #965. 'hardware' is now supported in Keyman Desktop on Windows platform test --- windows/src/engine/keyman32/kmprocess.cpp | 3 ++ .../platform-rules/Platform Results.xlsx | Bin 0 -> 15980 bytes .../platform-rules/PlatformTest.kmn | 35 ++++++++++++++ .../platform-rules/PlatformTest.kmx | Bin 0 -> 2004 bytes .../platform-rules/platformtest.js | 1 + .../platform-rules/platformtest.kmp | Bin 0 -> 2231 bytes .../platform-rules/platformtest.kps | 43 ++++++++++++++++++ 7 files changed, 82 insertions(+) create mode 100644 windows/src/test/manual-tests/platform-rules/Platform Results.xlsx create mode 100644 windows/src/test/manual-tests/platform-rules/PlatformTest.kmn create mode 100644 windows/src/test/manual-tests/platform-rules/PlatformTest.kmx create mode 100644 windows/src/test/manual-tests/platform-rules/platformtest.js create mode 100644 windows/src/test/manual-tests/platform-rules/platformtest.kmp create mode 100644 windows/src/test/manual-tests/platform-rules/platformtest.kps diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index aa507266ae..f79b44b5f8 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -584,12 +584,15 @@ BOOL IsMatchingPlatformString(PWCHAR platform) // I3432 { if(_wcsicmp(platform, L"windows") == 0 || _wcsicmp(platform, L"desktop") == 0 || + _wcsicmp(platform, L"hardware") == 0 || _wcsicmp(platform, L"native") == 0) return TRUE; PWCHAR t = wcschr(platform, 0) - 1; BOOL OrNewer = (t > platform && *t == L'+'); if(OrNewer) *t = 0; + // Note: these version number checks are not officially supported + // and won't work with recent versions of Windows anyway... WORD version; if(_wcsicmp(platform, L"xp") == 0) version = 0x0105; else if(_wcsicmp(platform, L"vista") == 0) version = 0x0006; diff --git a/windows/src/test/manual-tests/platform-rules/Platform Results.xlsx b/windows/src/test/manual-tests/platform-rules/Platform Results.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..366270c397706f8507b01a79cf1e113a1b990024 GIT binary patch literal 15980 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 eZ2#7#fBJ1%3D8dr0sz2#?xdeErsw?Q>i+}eJn literal 0 HcmV?d00001 diff --git a/windows/src/test/manual-tests/platform-rules/PlatformTest.kmn b/windows/src/test/manual-tests/platform-rules/PlatformTest.kmn new file mode 100644 index 0000000000..14d8eab5c7 --- /dev/null +++ b/windows/src/test/manual-tests/platform-rules/PlatformTest.kmn @@ -0,0 +1,35 @@ +store(&TARGETS) 'any' +store(&NAME) 'PlatformTest' +begin Unicode > use(main) + +group(main) using keys + +platform('touch') + [K_P] > 'Touch' +platform('hardware') + [K_P] > 'Hardware' ++ [K_P] > ' [UI Undefined]' + +platform('windows') + [K_O] > ' Windows' +platform('android') + [K_O] > ' Android' +platform('iOS') + [K_O] > ' iOS' +platform('macosx') + [K_O] > ' OSX' +platform('linux') + [K_O] > ' Linux' ++ [K_O] > ' [OS Undefined]' + +platform('desktop') + [K_I] > ' Desktop' +platform('tablet') + [K_I] > ' Tablet' +platform('phone') + [K_I] > ' Phone' ++ [K_I] > ' [FF Undefined]' + +platform('native') + [K_U] > ' Native' +platform('web') + [K_U] > ' Web' ++ [K_U] > ' [Nativeness Undefined]' + +platform('ie') + [K_Y] > ' IE' +platform('chrome') + [K_Y] > ' Chrome' +platform('firefox') + [K_Y] > ' Firefox' +platform('safari') + [K_Y] > ' Safari' +platform('opera') + [K_Y] > ' Opera' ++ [K_Y] > ' [Browser Undefined]' + +if(&platform != 'touch') + [SHIFT K_P] > ' !Touch' +if(&platform != 'hardware') + [SHIFT K_P] > ' !Hardware' diff --git a/windows/src/test/manual-tests/platform-rules/PlatformTest.kmx b/windows/src/test/manual-tests/platform-rules/PlatformTest.kmx new file mode 100644 index 0000000000000000000000000000000000000000..d64317c25a12149964b21932e7e5f6ddfc5106e2 GIT binary patch literal 2004 zcmaKt&r4KM6vvO#Z~Ha=9Ozx-9Z;peb)i%#6Al(dUWU)fm`w22 z>}OD8c>=4sSxXL=U8ILD&LX}hBOfrL;-W7SQ}?8?7VtEgsk_z46~<`oK2PQLdYbG~tN z54`8N^OR(ezleJ3&C@flH&T1ZJ^UJV(ka;;_4Bo*M{?cG%Wkaq()RKC`|H(qr|O-a z0(teYQ*XOC$*uODBhFKDU7&T2|JO99$FpTUbM8wKNr_z#@4EL?MqS|7uEzHh?;u7X1G7_n?lY@#7O4<;HX8A`Sqr|m5=4oJSL3P^m?f5%oRg4r|D z*wJ#!iX445L5B?wPhKxZ_}T=vlfxgDoz{sk&S=A4-m>xjo*3;Fs8F9}EZ5Hn_1$+| znKn2>gPn?T>-BHLPoxFl;I)Xyks~#-4jCVDivpWX7iF@yd0>Ab(S6wL(2Xa8H8ZL6lQ+T3nHuDg8{?W^p5S5+_FUDe50f+I= z<&C?G!u7x0(}$vIYl5iB7yA>6BY3uPdCflOvfQnfSxEd%+TNiJWvlLe6A8?E1fS=s zX5?`v*P6r%kC>xrE9!&RhBFDI&$Him7Qg1#yp3((E?W9Bf12>DN|$PUBx<&6u~-S1 zRkz^OYX>Dt=jIW|cII-PFB%h-rr!uU^qv-p(KgS|FBfr)=YTh7!(#2y+_JUIev1I29}`Cvj|!(>5Xf*%Pux5Mq041ddtHHF04GisfF9rjyj;B`R+Ya z8Nk>vbg2}(a-L-R)F52h;)%S=>ylTA+#1E8+I=ylO9MwXJQaNkZKotj9};<|gGsDYr?lZ~h5_!3Gd+_M3_a|} z%-H&7LCHU(G&A-KGs;~>$I*3r*<}1Ju9J+WAYYUibuPfRrC4W7kR46xvA}?u7XrNK zG`+Et?69+<4Fyp$@vY37>jOHjGStrj)@&6s7XMUO-N@TwJAK`>J4}7`qJGIbgV=%5 zJFMs=WOn{qVPt>Y{EPX*r<h5_PkW++t0U9e>%WauwUtpW!9IcQLaN+QMdeU48Kxd%8zVI{^9Fs+cg2>zsybsJ zUH7%4^NzQfLT~eplj(37>#^ z77@GD?Ed;9v3f`}JK-JsT&YuY0@q*N-md3&)0gA+%Dn&ph~xIqKiwX&>-Io&L4ile zm>MMYr^P3nmbu*(g?Qkm57N~108DJmhIs$Dh`+P27R4F?U#E@qN$kgIgiFv2uC2(h z7z%Q=EP{S+!NKu2nbOtQsWmZ*Wm8S^j_ML_ruQgr551}WL8dwyrql<*1;J|cl2ZVo z$D0TE8=g_OEbrR*fkvVwh1{LZL4{xP}`aXglG!wn+-;5uhlgjj5_A=zocL4vxn-)-el# zqN^`&R`zwP?c-AsL)}_R-(y*drPz9YD9!>>`chRRz)9DheN2#7tx0_-{gN`tYlop% zBgOAev-Lr#mGptqM|VSE?#5=9=aK7sheof3CtnWSFA&KR(Z!B7QmKPuSE!G$vylEn z!{4_QCVeztJw_kY?dE#jajMVk=WY31=MU4m&~fX(A1pATO-02uL+^6ubWJsE1#7n7 z-cost8790wJs3Qs=ORFMT}PjNvgl&s(`~*+_S-CJ?P<9@r(WCVr^ze)^kl5ZnfAjx zi>uZF=_^8{&1o}-{18K|t!$aD^W1Wug#RHgSDi}FxZz8I8H4GcoXU5+t`jfa9@(Cy zQgz`Nq&JmT0wNDV|3m^s{DXsxYuL;VS-=P)3C{L zsc9>CL#LFlG4TQWJ;LE(GF)cXd|m>dp6AfZA`L!Y-3=@*ZV2H2hd0NRoFn(o_uofcA_ms*+czXl0r$;ZFjz{|Ps LIkjo`Ujq0CH8$Y8 literal 0 HcmV?d00001 diff --git a/windows/src/test/manual-tests/platform-rules/platformtest.kps b/windows/src/test/manual-tests/platform-rules/platformtest.kps new file mode 100644 index 0000000000..60e493937f --- /dev/null +++ b/windows/src/test/manual-tests/platform-rules/platformtest.kps @@ -0,0 +1,43 @@ + + + + 10.0.1103.0 + 7.0 + + + + + + + + + + + + 1.0 + PlatformTest + + + + PlatformTest.kmx + Keyboard PlatformTest + 0 + .kmx + + + platformtest.js + File platformtest.js + 0 + .js + + + + + PlatformTest + platformtest + 1.0 + + + + + -- GitLab From 6291ad83fcf8d8a96d0931c148e695885680672f Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 8 Jun 2018 13:29:55 +0700 Subject: [PATCH 204/356] Fixes #968. Platform tests on Android now give correct results for hardware keyboard. Partial fix for #966 (hardware keyboard in Chrome emulator). --- android/KMEA/build.gradle | 4 ++-- android/Samples/KMSample1/build.gradle | 1 + android/Samples/KMSample2/build.gradle | 3 ++- android/Tests/KeyboardHarness/build.gradle | 3 ++- web/source/kmwcallback.ts | 6 +++--- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/android/KMEA/build.gradle b/android/KMEA/build.gradle index 2b3fa29d83..b6cb00b4fc 100644 --- a/android/KMEA/build.gradle +++ b/android/KMEA/build.gradle @@ -1,8 +1,8 @@ // 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.1.2' @@ -11,7 +11,7 @@ buildscript { allprojects { repositories { - jcenter() google() + jcenter() } } diff --git a/android/Samples/KMSample1/build.gradle b/android/Samples/KMSample1/build.gradle index b2c4770bd5..c6db9aa806 100644 --- a/android/Samples/KMSample1/build.gradle +++ b/android/Samples/KMSample1/build.gradle @@ -15,6 +15,7 @@ buildscript { allprojects { repositories { + google() jcenter() } } diff --git a/android/Samples/KMSample2/build.gradle b/android/Samples/KMSample2/build.gradle index 14d9c0e403..c6db9aa806 100644 --- a/android/Samples/KMSample2/build.gradle +++ b/android/Samples/KMSample2/build.gradle @@ -2,8 +2,8 @@ buildscript { repositories { - jcenter() google() + jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.1.2' @@ -15,6 +15,7 @@ buildscript { allprojects { repositories { + google() jcenter() } } diff --git a/android/Tests/KeyboardHarness/build.gradle b/android/Tests/KeyboardHarness/build.gradle index 14d9c0e403..c6db9aa806 100644 --- a/android/Tests/KeyboardHarness/build.gradle +++ b/android/Tests/KeyboardHarness/build.gradle @@ -2,8 +2,8 @@ buildscript { repositories { - jcenter() google() + jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.1.2' @@ -15,6 +15,7 @@ buildscript { allprojects { repositories { + google() jcenter() } } diff --git a/web/source/kmwcallback.ts b/web/source/kmwcallback.ts index a77cbfa7f6..31717df51f 100644 --- a/web/source/kmwcallback.ts +++ b/web/source/kmwcallback.ts @@ -1125,14 +1125,14 @@ namespace com.keyman { case 'tablet': case 'phone': case 'desktop': - if(this.keymanweb.util.activeDevice.formFactor != constraint) { + if(this.keymanweb.util.device.formFactor != constraint) { result=false; } } switch(constraint) { case 'web': - if(this.keymanweb.util.activeDevice.browser == 'native') { + if(this.keymanweb.util.device.browser == 'native') { result=false; // web matches anything other than 'native' } break; @@ -1142,7 +1142,7 @@ namespace com.keyman { case 'firefox': case 'safari': case 'opera': - if(this.keymanweb.util.activeDevice.browser != constraint) { + if(this.keymanweb.util.device.browser != constraint) { result=false; } } -- GitLab From ff8658edd58f4ef8834699e7681fc5398dc12fe1 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 8 Jun 2018 15:47:24 +0700 Subject: [PATCH 205/356] Fixes #966. Platform tests are now more consistent for KeymanWeb --- web/source/kmwcallback.ts | 8 ++++++-- web/source/kmwdevice.ts | 26 +++++++++++++++++--------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/web/source/kmwcallback.ts b/web/source/kmwcallback.ts index 31717df51f..bae75bffd5 100644 --- a/web/source/kmwcallback.ts +++ b/web/source/kmwcallback.ts @@ -1109,12 +1109,16 @@ namespace com.keyman { result=false; } } - + switch(constraint) { + case 'macos': + case 'mac': + constraint = 'macosx'; + // fall through + case 'macosx': case 'windows': case 'android': case 'ios': - case 'macosx': case 'linux': if(this.keymanweb.util.activeDevice.OS.toLowerCase() != constraint) { result=false; diff --git a/web/source/kmwdevice.ts b/web/source/kmwdevice.ts index ecc9ce4789..c40f363868 100644 --- a/web/source/kmwdevice.ts +++ b/web/source/kmwdevice.ts @@ -54,15 +54,11 @@ namespace com.keyman { this.OS='iOS'; this.formFactor='tablet'; this.dyPortrait=this.dyLandscape=0; - } - - if(agent.indexOf('iPhone') >= 0) { + } else if(agent.indexOf('iPhone') >= 0) { this.OS='iOS'; this.formFactor='phone'; this.dyPortrait=this.dyLandscape=25; - } - - if(agent.indexOf('Android') >= 0) { + } else if(agent.indexOf('Android') >= 0) { this.OS='Android'; this.formFactor='phone'; // form factor may be redefined on initialization this.dyPortrait=75; @@ -71,8 +67,11 @@ namespace com.keyman { var rx=new RegExp("(?:Android\\s+)(\\d+\\.\\d+\\.\\d+)"); this.version=agent.match(rx)[1]; } catch(ex) {} - } - if(agent.indexOf('Windows NT') >= 0) { + } else if(agent.indexOf('Linux') >= 0) { + this.OS='Linux'; + } else if(agent.indexOf('Macintosh') >= 0) { + this.OS='MacOSX'; + } else if(agent.indexOf('Windows NT') >= 0) { this.OS='Windows'; if(agent.indexOf('Touch') >= 0) { this.formFactor='phone'; // will be redefined as tablet if resolution high enough @@ -110,14 +109,23 @@ namespace com.keyman { this.browser='safari'; } - var bMatch=/Firefox|Chrome|OPR/; + var bMatch=/Firefox|Chrome|OPR|Safari|Edge/; if(bMatch.test(navigator.userAgent)) { if((navigator.userAgent.indexOf('Firefox') >= 0) && ('onmozorientationchange' in screen)) { this.browser='firefox'; } else if(navigator.userAgent.indexOf('OPR') >= 0) { this.browser='opera'; + } else if(navigator.userAgent.indexOf(' Edge/') >= 0) { + // Edge is too common a word, so test for Edge/ :) + // Must come before Chrome and Safari test because + // Edge pretends to be both + this.browser='edge'; } else if(navigator.userAgent.indexOf('Chrome') >= 0) { + // This test must come before Safari test because on macOS, + // Chrome also reports "Safari" this.browser='chrome'; + } else if(navigator.userAgent.indexOf('Safari') >= 0) { + this.browser='safari'; } } } -- GitLab From f8427c3f4846ee413c9d75a88670b429d39d7d42 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 8 Jun 2018 15:57:02 +0700 Subject: [PATCH 206/356] Add platformtest.js to Android test harness --- .../app/src/main/assets/cloud/platformtest.js | 138 +++++++++++++++++ .../tests/keyboardHarness/MainActivity.java | 11 ++ .../platform-rules/PlatformTest.kmx | Bin 2004 -> 2156 bytes .../platform-rules/platformtest.js | 139 +++++++++++++++++- .../platform-rules/platformtest.kmp | Bin 2231 -> 2515 bytes 5 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 android/Tests/KeyboardHarness/app/src/main/assets/cloud/platformtest.js diff --git a/android/Tests/KeyboardHarness/app/src/main/assets/cloud/platformtest.js b/android/Tests/KeyboardHarness/app/src/main/assets/cloud/platformtest.js new file mode 100644 index 0000000000..0e550d63c8 --- /dev/null +++ b/android/Tests/KeyboardHarness/app/src/main/assets/cloud/platformtest.js @@ -0,0 +1,138 @@ + +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=0x0010; + this.s7="touch"; + this.s8="hardware"; + this.s9="windows"; + this.s10="android"; + this.s11="iOS"; + this.s12="macosx"; + this.s13="linux"; + this.s14="desktop"; + this.s15="tablet"; + this.s16="phone"; + this.s17="native"; + this.s18="web"; + this.s19="ie"; + this.s20="chrome"; + this.s21="firefox"; + this.s22="safari"; + this.s23="opera"; + this.s24="touch"; + this.s25="hardware"; + this.KVER="10.0.1103.0"; + this.gs=function(t,e) { + return this.g_main(t,e); + }; + this.g_main=function(t,e) { + var k=KeymanWeb,r=0,m=0; + if(k.KKM(e, 0x4010, 0x50)&&!k.KIFS(31,this.s24,t)) { // Line 34 + r=m=1; + k.KO(0,t," !Touch"); + } + else if(k.KKM(e, 0x4010, 0x50)&&!k.KIFS(31,this.s25,t)) { // Line 35 + r=m=1; + k.KO(0,t," !Hardware"); + } + else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s14,t)) { // Line 18 + r=m=1; + k.KO(0,t," Desktop"); + } + else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s15,t)) { // Line 19 + r=m=1; + k.KO(0,t," Tablet"); + } + else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s16,t)) { // Line 20 + r=m=1; + k.KO(0,t," Phone"); + } + else if(k.KKM(e, 0x4000, 0x49)) { // Line 21 + r=m=1; + k.KO(0,t," [FF Undefined]"); + } + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s9,t)) { // Line 11 + r=m=1; + k.KO(0,t," Windows"); + } + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s10,t)) { // Line 12 + r=m=1; + k.KO(0,t," Android"); + } + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s11,t)) { // Line 13 + r=m=1; + k.KO(0,t," iOS"); + } + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s12,t)) { // Line 14 + r=m=1; + k.KO(0,t," OSX"); + } + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s13,t)) { // Line 15 + r=m=1; + k.KO(0,t," Linux"); + } + else if(k.KKM(e, 0x4000, 0x4F)) { // Line 16 + r=m=1; + k.KO(0,t," [OS Undefined]"); + } + else if(k.KKM(e, 0x4000, 0x50)&&k.KIFS(31,this.s7,t)) { // Line 7 + r=m=1; + k.KO(0,t,"Touch"); + } + else if(k.KKM(e, 0x4000, 0x50)&&k.KIFS(31,this.s8,t)) { // Line 8 + r=m=1; + k.KO(0,t,"Hardware"); + } + else if(k.KKM(e, 0x4000, 0x50)) { // Line 9 + r=m=1; + k.KO(0,t," [UI Undefined]"); + } + else if(k.KKM(e, 0x4000, 0x55)&&k.KIFS(31,this.s17,t)) { // Line 23 + r=m=1; + k.KO(0,t," Native"); + } + else if(k.KKM(e, 0x4000, 0x55)&&k.KIFS(31,this.s18,t)) { // Line 24 + r=m=1; + k.KO(0,t," Web"); + } + else if(k.KKM(e, 0x4000, 0x55)) { // Line 25 + r=m=1; + k.KO(0,t," [Nativeness Undefined]"); + } + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s19,t)) { // Line 27 + r=m=1; + k.KO(0,t," IE"); + } + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s20,t)) { // Line 28 + r=m=1; + k.KO(0,t," Chrome"); + } + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s21,t)) { // Line 29 + r=m=1; + k.KO(0,t," Firefox"); + } + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s22,t)) { // Line 30 + r=m=1; + k.KO(0,t," Safari"); + } + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s23,t)) { // Line 31 + r=m=1; + k.KO(0,t," Opera"); + } + else if(k.KKM(e, 0x4000, 0x59)) { // Line 32 + 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 37f438a1f8..95bc28e72f 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/windows/src/test/manual-tests/platform-rules/PlatformTest.kmx b/windows/src/test/manual-tests/platform-rules/PlatformTest.kmx index d64317c25a12149964b21932e7e5f6ddfc5106e2..8b2d0d567dcdfff44f19b289b65a326f170dd0db 100644 GIT binary patch literal 2156 zcmai#%WITp6vj`Ywb5#gmuigKzFG*yg(zw%uEtBXURp&HO^sbd$1oG)jAUYrE?jjL z@&~w(E=rNEq{|@UDhqLA5hc!heE$O2Z$qRp1x+XV_}+H2xo~3*6Sq z3;Pha9p8y*tiAYB;9h(;_9^-(elYMjek||}{6yee_@4q#;(rT#4}UxGANc!$pW^=v z{0jdp@B;StI`ArR8>TfRd`I9f@EZevh2IqTAbw}yQ~1MyEBMoaNAZJ!$MIv>O2+>M zKY{JBVLNC2Hp07X$u3(JTmc8KO;%849L38+P7jz3A}~W;(;3&iNjU6Rgm?7IW8puT?)!HNT90#`{&H zg;uVWTnIkEd|J8Ar0F9+saDKntduQJncv*hZ|q zWcKR^W|Nq-&qJGn|AifZFUPE8_BZ@hXe&aSzks`msh#eq+9mkr(3J1ecEV3#N1z{t zb{bv_ZEY5?G}78w56dXZ8R!YiTaRHco;uZ6ZIv~l=t?0dLsquSkpPldKFwBO-RLR%l& zbNF;`Bb(ah^y~OS7tLh_h01E zUH{4M9MyeF^ei$xtGZFiwO&wGb*GXY_IZlj&k^0MWPRRa?lr!BrmcR5<~q+-eJp+4 z9&%*vaT7IC)iYO=yej3M&ZVd>SylFFt<8OOk_~?UH^%|5!Fd$rYvOCtT&HqOd7JpR s{#~=9Ozx-9Z;peb)i%#6Al(dUWU)fm`w22 z>}OD8c>=4sSxXL=U8ILD&LX}hBOfrL;-W7SQ}?8?7VtEgsk_z46~<`oK2PQLdYbG~tN z54`8N^OR(ezleJ3&C@flH&T1ZJ^UJV(ka;;_4Bo*M{?cG%Wkaq()RKC`|H(qr|O-a z0(teYQ*XOC$*uODBhFKDU7&T2|JO99$FpTUbM8wKNr_z#@4EL@6aWAS2mlg($gvFv0Rs|#$g>v#FaduKe#lH!)WTn10{{SQ z2mk;O0000`Y+-a}Z*px^Wpi{cYi)RiRm)41Q4~LpspB*AIa%3cAmKt1EyC6KNHa|( zwM=bMjWT08BQrW`i&m|~KcGdlh=^9wQY2crkTyj`M2lz@A`#I_T4=v}?(gO}GWN-t z-{aiZcfWhC-NS!_1ClH9``yP;!IL5OIYAykyvP*U#bf+p=BK-vMgC~HK@+ZJ$@)h7y@>Sp~@(th` z`6u98@=f4p@@?Q2c{bkf4|xT+H`8)I&_{j_SVMjZSVw<;71&HZ0_-6V0msM_z)A8Y z-~yry{5fzL(Izn&mpd|x-=O$qUc%rZux>buGL2jWsvRnUn3AZ>0AuhHigEOaYMTZ* zFZCJ?${SUg$NnadXdZ)$V!qL!w8(Yol*?cPaQZQiSgs|7)J=Z@&RhIK#fTE@}Z z&S)L8aIr1b%FX`RIpY{(Lf+I^)vod17+@1OqLy}>Ej$drGNkJY)i=lzHp zQ=b8mmszNXEbE=6w+{UU(FI*%hJg1SdYfJ;y(8H;o7vVYqvwaNr&ms|8F~cK2boWA z3_3!ufZhY>WqO759z#E)S43|GdX?T$dh5_1=oQoZ3cZtU-z|rpAq6?s^V0J{*U`(R zcM*U324YC;{bamh=ny?0y;lq?=|!~y_59bLw}=pirx?C9eUOD z^03ef_8T+;brLhOzz5o^W<7oX^ZxhdazlK?zJBy zC)b9{6>F|PsZLzxm}W+$1Al(4^q^KkSlfRE<+h$uzuZizXxBeavn?sr?Xvlrb(QYi z0(Ffyoa7d&+mlrLE>pxcnjY!bcyLcWdWO>Nr$T3?-K5dynjP48f4N*G_kHg!a~U63-Ku}{ znJ;YrC#75OUr4gdfT0001RY+-a}Z*pyPWpi{c zYICKQ-%r~x5Xavu^?xvafK-Z#owPuO{4h4ERRxMDKPFWZN*ia5Xq?J%DbvLNK9i&@ zjx$V~hbYR|XMcQ`^PQWGA^jbB?16ty+rt}+(KV35H1@dvxLkN5h#;efzOQ+WE%=8C}UeCW0`bUC=XKffWc*G5J8p0L$o zQ4qe9gM;EUf(l<}=@M97;_^%yy&!}OmdP=JB3{kr1;gZoz`5N0+T*k+_XvMnhs=-H zNm0d!K#%!64t+(&1csxrA~^&`-YiaD6xAhg5wevkb_n!o@+9J=B6sC(z3GAqMLi;L zIggpLSu7o6o(P{+Rl2sOQ$><)g^H0QJ(|sV9I2{wC?qGH0K&j}Y7d8(7PSF->BvNSdv{T5e}7L74Ekfs#rDQoTeRf5 za@ye`xCj{qZYNtt?vz9XpKiY7)RBd3VMDNYo5rV=kG*Cux=84D@UDLj@0#J?H~--? ze3bG#J;^WQvFU`;L1?_-%Ho>aveCwu6l9>-6kyg)T9$kumA_!5#By zAnpC1+rau2e)jYbo44?g*Up-3nfDspF~Yy(6}m1Q>u}cyf9nHv!Hy0#my^->M{TgH zgUzMnB5i0}p-YS-b4q`Y#=E6-S~JUj9&2tMn|AQ|TKxg{MB^GO-rAU_K<1%sobvWXDKX_8`4DJH}K7gY&vv zN3Y9{x#@q+?wNJjdRcbN8Q#xtvvuKmX?D#`f1KT!>$3Ig?3ye)@hH8SZ-p)~%nf&P z#$~go{DaKS@9X^if-d#HP)h*<6aW+e00;;G5`M^&$_Fw75`M^&{|7S;4t~f?Rn)>? zUjqODYzUJ;2rwTGe#lI?|Mb1!0ssJ>4gdfT000000000003ZMW0Lqh(2qFg82mk;8 E0N1c`Bme*a delta 1528 zcmV@6aWAS2mp?I$FU6u0RxVE$Fmm!FaduTS;tKA2jXAA0ssKi z2LJ#N0000`Y+-a}Z*px^Wpi{cYi)RiRljS~K@@*YZEWkWsBIb-`C7!ONUMuD)wG7z zN*hRu5fP02CN!8PA>XuGaF9+;9UPpBgE)wPfs=?hI2Mskf{?+%!9fJa_<8SpXWsWp z>V?aFe%#%Ace#JNEEMuN8X_uv`!h%=eH4~622Z1=`iVLytS5~B<#5=J8eT=`q`|wu zW40gg1%unbW*GedK5OuySQjT09#{C1!fAzXC|pq3SGc9{mcrW#?$Q(uCj04MNl|zovW6$7Q3r^; zfv7eCo<^Ow1EDQ~-*dDo_+v+V3jW;DUV?u>T~gXd@I6Osga39kiW3dTqgoQ&bF>NY ztB#fdFUPxUV{H|@u7&p!M{7&FYs|Z61SCh9(=;lu7J-u zS{}UYXie}fN81M9akSUqpHV$JhnvwoF`dpBv_5&y*qhsTf^3hJ^q6(ddg#XJn7H}K z$+zBd@v`b3Sm%T|cPN98hkdHaT`J4n;y2{3r0>x!=Z@O(gW_IuZme~O#I^U=s>7nP zR#1QH5m9fdTWy`ACPyC8JIDQd8sp>Hb3bG9Pr>sp<31d;_QlAXVMiy-zJxD`RZp5Z z^_ZIcV!?qi=IOec<&@6aWAS2mlvZ$4taKW{G10004id2><{O0001RY+-a}Z*pyPWpi{cYIBv9 zU2obj6o&sw>Wel=QDi543i)DeMMW7<71~akrYR6-SPeF^O=(s2zt_zd6N@u)7r#D! z@*dmACm^rekUf%>8{FB99ISx6u6QV--@7DKF&A4!q_SJBVZ3K+ML9D?yr~V9ZZLnr zpfUgqv-ueYx4FFhOP)?<57&1X3|v@9518$fBp=-1tE(au!~AQMEu&}94L$UK^6*v7=$bmoJOUDFrf2AIrK2thHEZgO2x+@ zp=^H?+89JcJ}JH{rH*zJt`ee3rHg;TZo^q=25G}ARP_0%Xv+t(Du>!GEhjzgbiEOL zdsMX1mpVa~nF!0oKJb%}4*4B$8O?;yNbWO|cu5M8Ds5dcG!}0+Gqz zxBPB2#F_jpvwPK$)-}*>(>qxQt6KGQJhtvxL}JQF^s8q1pu)?*VC6Bd&1N(N4Y)6P zT{pxb1Mc%pXo&I*sQKbYQaR@y!=!9bZ~Gr(Sy1R%(jSi0W6P{$GHa zR+-oRvj)|W zW~#Vx-rO4EOjWnY8e>D6sqp4$Q>}wl9^^>q7mkRNQ_S0_(7p5h15gf20Rj{N6aWAS z2mp?I$CKs=G6Rl#$CDcgGY%J7$4v1D;$Of5007hnlUxZf9~W82OvF28iDLo)0H+B6 e01p5F000000000W0000hldB0L2D=9U0001uW6lEr -- GitLab From 4ad7ade4298dc527956ec5b0ba9e1e0574caaf14 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Fri, 8 Jun 2018 16:05:02 -0400 Subject: [PATCH 207/356] [Mac] #967 - Make platform tests case-insensitive. --- .../KeymanEngine4Mac/KME/KMEngine.m | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m index 62e1d7638e..653d2c191a 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m @@ -869,31 +869,32 @@ const NSString* kEasterEggKmxName = @"EnglishSpanish.kmx"; - (BOOL)checkPlatform:(NSString *)platform { NSArray *values = [platform componentsSeparatedByString:@" "]; for (NSString *value in values) { - if ([value isEqualToString:@"touch"]) + NSString *lcValue = [value lowercaseString]; + if ([lcValue isEqualToString:@"touch"]) return NO; - else if ([value isEqualToString:@"windows"]) + else if ([lcValue isEqualToString:@"windows"]) return NO; - else if ([value isEqualToString:@"android"]) + else if ([lcValue isEqualToString:@"android"]) return NO; - else if ([value isEqualToString:@"ios"]) + else if ([lcValue isEqualToString:@"ios"]) return NO; - else if ([value isEqualToString:@"linux"]) + else if ([lcValue isEqualToString:@"linux"]) return NO; - else if ([value isEqualToString:@"tablet"]) + else if ([lcValue isEqualToString:@"tablet"]) return NO; - else if ([value isEqualToString:@"phone"]) + else if ([lcValue isEqualToString:@"phone"]) return NO; - else if ([value isEqualToString:@"web"]) + else if ([lcValue isEqualToString:@"web"]) return NO; - else if ([value isEqualToString:@"ie"]) + else if ([lcValue isEqualToString:@"ie"]) return NO; - else if ([value isEqualToString:@"chrome"]) + else if ([lcValue isEqualToString:@"chrome"]) return NO; - else if ([value isEqualToString:@"firefox"]) + else if ([lcValue isEqualToString:@"firefox"]) return NO; - else if ([value isEqualToString:@"safari"]) + else if ([lcValue isEqualToString:@"safari"]) return NO; - else if ([value isEqualToString:@"opera"]) + else if ([lcValue isEqualToString:@"opera"]) return NO; } -- GitLab From 931bcdd5cae80f45ff479022cce23ea0eb23e3de Mon Sep 17 00:00:00 2001 From: darcywong00 Date: Sun, 10 Jun 2018 06:57:08 +0700 Subject: [PATCH 208/356] Consolidate "Info" views Fixes #960 Previously, the InfoActivity was displaying the app version in one view, and launching the help content in another Activity. --- .../com/tavultesoft/kmapro/InfoActivity.java | 46 +++++++++---------- .../src/main/res/layout/activity_info.xml | 2 +- android/history.md | 3 ++ 3 files changed, 27 insertions(+), 24 deletions(-) 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 d3b76a885d..877cd84ea7 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.infoWebView); - 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/res/layout/activity_info.xml b/android/KMAPro/kMAPro/src/main/res/layout/activity_info.xml index 00116ef67d..58fc10f5a2 100644 --- a/android/KMAPro/kMAPro/src/main/res/layout/activity_info.xml +++ b/android/KMAPro/kMAPro/src/main/res/layout/activity_info.xml @@ -3,7 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".WebBrowserActivity" > + tools:context=".InfoActivity" > Date: Sun, 10 Jun 2018 07:03:26 +0700 Subject: [PATCH 209/356] Fix PR number in history.md --- android/history.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/history.md b/android/history.md index 69f15730f8..cc96315541 100644 --- a/android/history.md +++ b/android/history.md @@ -1,7 +1,7 @@ # Keyman for Android -## 2018-06-12 10.0.399 beta -* Consolidate Info view (#967) +## 2018-06-11 10.0.399 beta +* Consolidate Info view (#972) ## 2018-06-05 10.0.398 beta * Fix globe button for system keyboard (#942) -- GitLab From 8649bd486ea96dd9f1e708a27ad8513d26c51650 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 11 Jun 2018 07:31:44 +0700 Subject: [PATCH 210/356] Renamed platformtest for Android --- .../main/assets/cloud/{platformtest.js => platformtest-1.0.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename android/Tests/KeyboardHarness/app/src/main/assets/cloud/{platformtest.js => platformtest-1.0.js} (100%) diff --git a/android/Tests/KeyboardHarness/app/src/main/assets/cloud/platformtest.js b/android/Tests/KeyboardHarness/app/src/main/assets/cloud/platformtest-1.0.js similarity index 100% rename from android/Tests/KeyboardHarness/app/src/main/assets/cloud/platformtest.js rename to android/Tests/KeyboardHarness/app/src/main/assets/cloud/platformtest-1.0.js -- GitLab From ef4c0066a98d7dc6c43a754701d5a30498fa976d Mon Sep 17 00:00:00 2001 From: glasseyes Date: Mon, 11 Jun 2018 13:27:17 +0700 Subject: [PATCH 211/356] update debian/copyright years --- linux/kmflcomp/debian/copyright | 2 +- linux/libkmfl/debian/copyright | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/linux/kmflcomp/debian/copyright b/linux/kmflcomp/debian/copyright index 98074b617f..15a4732250 100644 --- a/linux/kmflcomp/debian/copyright +++ b/linux/kmflcomp/debian/copyright @@ -3,7 +3,7 @@ Upstream-Name: kmflcomp Upstream-Contact: Doug Rintoul Files: * -Copyright: Copyright (C) 2017 SIL International +Copyright: Copyright (C) 2005-2018 SIL International License: MIT Files: src/yacc.c diff --git a/linux/libkmfl/debian/copyright b/linux/libkmfl/debian/copyright index 678a4744cd..75763836b0 100644 --- a/linux/libkmfl/debian/copyright +++ b/linux/libkmfl/debian/copyright @@ -3,7 +3,7 @@ Upstream-Name: libkmfl Upstream-Contact: Doug Rintoul Files: * -Copyright: Copyright (C) 2017 SIL International +Copyright: Copyright (C) 2005-2018 SIL International License: MIT License: MIT -- GitLab From 7ac72871b8fc5bc2778874e25eb3f74e43811a82 Mon Sep 17 00:00:00 2001 From: glasseyes Date: Mon, 11 Jun 2018 13:28:15 +0700 Subject: [PATCH 212/356] dual license kmflutil as MIT and GPL-2.0+ --- linux/ibus-kmfl/debian/copyright | 30 ++++++++++++++++++++++++++++-- linux/ibus-kmfl/src/kmflutil.c | 28 +++++++++++++++++++++++++++- linux/ibus-kmfl/src/kmflutil.h | 26 +++++++++++++++++++++++++- 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/linux/ibus-kmfl/debian/copyright b/linux/ibus-kmfl/debian/copyright index 57a17a3f76..825997310d 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/kmflutil.c b/linux/ibus-kmfl/src/kmflutil.c index 297fef7e82..415fe88198 100644 --- a/linux/ibus-kmfl/src/kmflutil.c +++ b/linux/ibus-kmfl/src/kmflutil.c @@ -3,7 +3,13 @@ /* * KMFL Input Method for IBUS (The Input Bus) * - * Copyright (C) 2009 SIL International + * Copyright (C) 2009-2018 SIL International + * + * 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 @@ -23,8 +29,28 @@ * 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 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * */ + + #include #include #include diff --git a/linux/ibus-kmfl/src/kmflutil.h b/linux/ibus-kmfl/src/kmflutil.h index b72996e5fc..1332cde33f 100644 --- a/linux/ibus-kmfl/src/kmflutil.h +++ b/linux/ibus-kmfl/src/kmflutil.h @@ -3,7 +3,13 @@ /* * KMFL Input Method for IBUS (The Input Bus) * - * Copyright (C) 2009 SIL International + * Copyright (C) 2009-2018 SIL International + * + * 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 @@ -23,6 +29,24 @@ * 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 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * */ #ifndef __KMFLUTIL_H__ -- GitLab From c24707dbbc54dfa88f8fd05c93479cc0e22e5611 Mon Sep 17 00:00:00 2001 From: glasseyes Date: Mon, 11 Jun 2018 13:35:30 +0700 Subject: [PATCH 213/356] describe dual licensing in LICENSE.md --- linux/LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/LICENSE.md b/linux/LICENSE.md index ea1f81205f..1a8c4e35aa 100644 --- a/linux/LICENSE.md +++ b/linux/LICENSE.md @@ -1,4 +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 covered by the MIT license and may be used as such in other projects. +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. -- GitLab From 27c565b0e22e5eb6446aae1c96c24f8153127242 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 11 Jun 2018 15:07:55 +0700 Subject: [PATCH 214/356] Reworked several aspects of platform constraints esp. regarding unknown constraints. Rewrote keyboard and spreadsheet to facilitate testing more reliably. --- .../src/main/assets/cloud/platformtest-1.0.js | 374 ++++++++++++++-- web/source/kmwcallback.ts | 20 +- web/testing/index.html | 1 + web/testing/platform/index.html | 95 ++++ web/testing/platform/platformtest.js | 416 ++++++++++++++++++ web/testing/platform/utilities.js | 11 + .../platform-rules/Platform Results.xlsx | Bin 15980 -> 0 bytes .../platform-rules/PlatformTest.kmn | 35 -- .../platform-rules/PlatformTest.kmx | Bin 2156 -> 0 bytes .../platform-rules/platform-results.xlsx | Bin 0 -> 22244 bytes .../platform-rules/platformtest.js | 374 ++++++++++++++-- .../platform-rules/platformtest.kmn | 135 ++++++ .../platform-rules/platformtest.kmp | Bin 2515 -> 4473 bytes .../platform-rules/platformtest.kmx | Bin 0 -> 6304 bytes .../platform-rules/platformtest.kpj | 47 ++ .../platform-rules/platformtest.kps | 4 +- 16 files changed, 1372 insertions(+), 140 deletions(-) create mode 100644 web/testing/platform/index.html create mode 100644 web/testing/platform/platformtest.js create mode 100644 web/testing/platform/utilities.js delete mode 100644 windows/src/test/manual-tests/platform-rules/Platform Results.xlsx delete mode 100644 windows/src/test/manual-tests/platform-rules/PlatformTest.kmn delete mode 100644 windows/src/test/manual-tests/platform-rules/PlatformTest.kmx create mode 100644 windows/src/test/manual-tests/platform-rules/platform-results.xlsx create mode 100644 windows/src/test/manual-tests/platform-rules/platformtest.kmn create mode 100644 windows/src/test/manual-tests/platform-rules/platformtest.kmx create mode 100644 windows/src/test/manual-tests/platform-rules/platformtest.kpj 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 index 0e550d63c8..59fd09dcf4 100644 --- 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 @@ -11,125 +11,403 @@ function Keyboard_platformtest() this.KH=''; this.KM=0; this.KBVER="1.0"; - this.KMBM=0x0010; - this.s7="touch"; - this.s8="hardware"; - this.s9="windows"; - this.s10="android"; - this.s11="iOS"; - this.s12="macosx"; - this.s13="linux"; - this.s14="desktop"; - this.s15="tablet"; - this.s16="phone"; - this.s17="native"; - this.s18="web"; - this.s19="ie"; - this.s20="chrome"; - this.s21="firefox"; - this.s22="safari"; - this.s23="opera"; - this.s24="touch"; - this.s25="hardware"; - this.KVER="10.0.1103.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="firefox"; + this.s40="safari"; + this.s41="opera"; + this.s44="touch"; + this.s45="hardware"; + this.s48="platform-x"; + this.s51="WinDOWS"; + this.s52="ANDroid"; + this.s53="iOS"; + this.s54="macOSX"; + this.s55="LINUX"; + this.s57="touch"; + this.s58="hardware"; + this.s59="windows"; + this.s60="android"; + this.s61="ios"; + this.s62="macosx"; + this.s63="linux"; + this.s64="desktop"; + this.s65="tablet"; + this.s66="phone"; + this.s67="native"; + this.s68="web"; + this.s69="ie"; + this.s70="chrome"; + this.s71="firefox"; + this.s72="safari"; + this.s73="opera"; + this.s74="touch"; + this.s75="hardware"; + this.s76="platform-x"; + this.s77="WinDOWS"; + this.s78="ANDroid"; + this.s79="iOS"; + this.s80="macOSX"; + this.s81="LINUX"; + this.KVER="10.0.1104.0"; this.gs=function(t,e) { return this.g_main(t,e); }; this.g_main=function(t,e) { var k=KeymanWeb,r=0,m=0; - if(k.KKM(e, 0x4010, 0x50)&&!k.KIFS(31,this.s24,t)) { // Line 34 + if(k.KKM(e, 0x4000, 0x41)) { // Line 7 r=m=1; - k.KO(0,t," !Touch"); + r=this.g_ui(t,e); + } + if(!m&&k.KIK(e)) { + r=1; + r=this.g_old_main(t,e); + } + return r; + }; + this.g_ui=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(k.KIFS(31,this.s17,t)) { // Line 12 + m=1; + k.KO(0,t,"touch"); + } + else if(k.KIFS(31,this.s18,t)) { // Line 13 + m=1; + k.KO(0,t,"hardware"); + } + if(m) { + + r=this.g_os(t,e); + } + if(!m) { + + k.KO(-1,t,"undefined"); + r=this.g_os(t,e); + } + return r; + }; + this.g_os=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(k.KIFS(31,this.s21,t)) { // Line 19 + m=1; + k.KO(0,t," windows"); + } + else if(k.KIFS(31,this.s22,t)) { // Line 20 + m=1; + k.KO(0,t," android"); + } + else if(k.KIFS(31,this.s23,t)) { // Line 21 + m=1; + k.KO(0,t," ios"); + } + else if(k.KIFS(31,this.s24,t)) { // Line 22 + m=1; + k.KO(0,t," macosx"); + } + else if(k.KIFS(31,this.s25,t)) { // Line 23 + m=1; + k.KO(0,t," linux"); + } + if(m) { + + r=this.g_ff(t,e); + } + if(!m) { + + k.KO(-1,t," undefined"); + r=this.g_ff(t,e); + } + return r; + }; + this.g_ff=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(k.KIFS(31,this.s28,t)) { // Line 29 + m=1; + k.KO(0,t," desktop"); + } + else if(k.KIFS(31,this.s29,t)) { // Line 30 + m=1; + k.KO(0,t," tablet"); + } + else if(k.KIFS(31,this.s30,t)) { // Line 31 + m=1; + k.KO(0,t," phone"); + } + if(m) { + + r=this.g_app(t,e); + } + if(!m) { + + k.KO(-1,t," undefined"); + r=this.g_app(t,e); + } + return r; + }; + this.g_app=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(k.KIFS(31,this.s33,t)) { // Line 37 + m=1; + k.KO(0,t," native"); + } + else if(k.KIFS(31,this.s34,t)) { // Line 38 + m=1; + k.KO(0,t," web"); + } + if(m) { + + r=this.g_browser(t,e); + } + if(!m) { + + k.KO(-1,t," undefined"); + r=this.g_browser(t,e); + } + return r; + }; + this.g_browser=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(k.KIFS(31,this.s37,t)) { // Line 44 + m=1; + k.KO(0,t," ie"); + } + else if(k.KIFS(31,this.s38,t)) { // Line 45 + m=1; + k.KO(0,t," chrome"); + } + else if(k.KIFS(31,this.s39,t)) { // Line 46 + m=1; + k.KO(0,t," firefox"); + } + else if(k.KIFS(31,this.s40,t)) { // Line 47 + m=1; + k.KO(0,t," safari"); + } + else if(k.KIFS(31,this.s41,t)) { // Line 48 + m=1; + k.KO(0,t," opera"); + } + if(m) { + + r=this.g_inverted(t,e); + } + if(!m) { + + k.KO(-1,t," undefined"); + r=this.g_inverted(t,e); + } + return r; + }; + this.g_inverted=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(!k.KIFS(31,this.s44,t)) { // Line 54 + m=1; + k.KO(0,t," !touch"); + } + else if(!k.KIFS(31,this.s45,t)) { // Line 55 + m=1; + k.KO(0,t," !hardware"); + } + if(m) { + + r=this.g_unknown(t,e); } - else if(k.KKM(e, 0x4010, 0x50)&&!k.KIFS(31,this.s25,t)) { // Line 35 + if(!m) { + + k.KO(-1,t," undefined"); + r=this.g_unknown(t,e); + } + return r; + }; + this.g_unknown=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(k.KIFS(31,this.s48,t)) { // Line 61 + m=1; + k.KO(0,t," platform-x"); + } + if(m) { + + r=this.g_case_sensitive(t,e); + } + if(!m) { + + k.KO(-1,t," undefined"); + r=this.g_case_sensitive(t,e); + } + return r; + }; + this.g_case_sensitive=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(k.KIFS(31,this.s51,t)) { // Line 67 + m=1; + k.KO(0,t," windows"); + } + else if(k.KIFS(31,this.s52,t)) { // Line 68 + m=1; + k.KO(0,t," android"); + } + else if(k.KIFS(31,this.s53,t)) { // Line 69 + m=1; + k.KO(0,t," ios"); + } + else if(k.KIFS(31,this.s54,t)) { // Line 70 + m=1; + k.KO(0,t," macosx"); + } + else if(k.KIFS(31,this.s55,t)) { // Line 71 + m=1; + k.KO(0,t," linux"); + } + if(!m) { + + k.KO(-1,t," undefined"); + } + return r; + }; + this.g_old_main=function(t,e) { + var k=KeymanWeb,r=0,m=0; + if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s77,t)) { // Line 130 r=m=1; - k.KO(0,t," !Hardware"); + k.KO(0,t," Windows"); + } + else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s78,t)) { // Line 131 + r=m=1; + k.KO(0,t," Android"); } - else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s14,t)) { // Line 18 + else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s79,t)) { // Line 132 + r=m=1; + k.KO(0,t," iOS"); + } + else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s80,t)) { // Line 133 + r=m=1; + k.KO(0,t," macOS"); + } + else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s81,t)) { // Line 134 + r=m=1; + k.KO(0,t," Linux"); + } + else if(k.KKM(e, 0x4000, 0x45)) { // Line 135 + r=m=1; + k.KO(0,t," [OS Undefined (case insensitive test)]"); + } + else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s64,t)) { // Line 97 r=m=1; k.KO(0,t," Desktop"); } - else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s15,t)) { // Line 19 + else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s65,t)) { // Line 98 r=m=1; k.KO(0,t," Tablet"); } - else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s16,t)) { // Line 20 + else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s66,t)) { // Line 99 r=m=1; k.KO(0,t," Phone"); } - else if(k.KKM(e, 0x4000, 0x49)) { // Line 21 + else if(k.KKM(e, 0x4000, 0x49)) { // Line 100 r=m=1; k.KO(0,t," [FF Undefined]"); } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s9,t)) { // Line 11 + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s59,t)) { // Line 88 r=m=1; k.KO(0,t," Windows"); } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s10,t)) { // Line 12 + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s60,t)) { // Line 89 r=m=1; k.KO(0,t," Android"); } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s11,t)) { // Line 13 + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s61,t)) { // Line 90 r=m=1; k.KO(0,t," iOS"); } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s12,t)) { // Line 14 + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s62,t)) { // Line 91 r=m=1; k.KO(0,t," OSX"); } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s13,t)) { // Line 15 + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s63,t)) { // Line 92 r=m=1; k.KO(0,t," Linux"); } - else if(k.KKM(e, 0x4000, 0x4F)) { // Line 16 + else if(k.KKM(e, 0x4000, 0x4F)) { // Line 93 r=m=1; k.KO(0,t," [OS Undefined]"); } - else if(k.KKM(e, 0x4000, 0x50)&&k.KIFS(31,this.s7,t)) { // Line 7 + else if(k.KKM(e, 0x4000, 0x50)&&k.KIFS(31,this.s57,t)) { // Line 82 r=m=1; k.KO(0,t,"Touch"); } - else if(k.KKM(e, 0x4000, 0x50)&&k.KIFS(31,this.s8,t)) { // Line 8 + else if(k.KKM(e, 0x4000, 0x50)&&k.KIFS(31,this.s58,t)) { // Line 83 r=m=1; k.KO(0,t,"Hardware"); } - else if(k.KKM(e, 0x4000, 0x50)) { // Line 9 + else if(k.KKM(e, 0x4000, 0x50)) { // Line 84 + r=m=1; + k.KO(0,t,"[UI Undefined]"); + } + else if(k.KKM(e, 0x4000, 0x52)&&k.KIFS(31,this.s76,t)) { // Line 125 + r=m=1; + k.KO(0,t," Platform-X"); + } + else if(k.KKM(e, 0x4000, 0x52)) { // Line 126 + r=m=1; + k.KO(0,t," [Platform-X Undefined]"); + } + else if(k.KKM(e, 0x4000, 0x54)&&!k.KIFS(31,this.s74,t)) { // Line 119 + r=m=1; + k.KO(0,t," !Touch"); + } + else if(k.KKM(e, 0x4000, 0x54)&&!k.KIFS(31,this.s75,t)) { // Line 120 + r=m=1; + k.KO(0,t," !Hardware"); + } + else if(k.KKM(e, 0x4000, 0x54)) { // Line 121 r=m=1; - k.KO(0,t," [UI Undefined]"); + k.KO(0,t," [Inverted OS Undefined]"); } - else if(k.KKM(e, 0x4000, 0x55)&&k.KIFS(31,this.s17,t)) { // Line 23 + else if(k.KKM(e, 0x4000, 0x55)&&k.KIFS(31,this.s67,t)) { // Line 104 r=m=1; k.KO(0,t," Native"); } - else if(k.KKM(e, 0x4000, 0x55)&&k.KIFS(31,this.s18,t)) { // Line 24 + else if(k.KKM(e, 0x4000, 0x55)&&k.KIFS(31,this.s68,t)) { // Line 105 r=m=1; k.KO(0,t," Web"); } - else if(k.KKM(e, 0x4000, 0x55)) { // Line 25 + else if(k.KKM(e, 0x4000, 0x55)) { // Line 106 r=m=1; k.KO(0,t," [Nativeness Undefined]"); } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s19,t)) { // Line 27 + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s69,t)) { // Line 110 r=m=1; k.KO(0,t," IE"); } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s20,t)) { // Line 28 + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s70,t)) { // Line 111 r=m=1; k.KO(0,t," Chrome"); } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s21,t)) { // Line 29 + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s71,t)) { // Line 112 r=m=1; k.KO(0,t," Firefox"); } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s22,t)) { // Line 30 + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s72,t)) { // Line 113 r=m=1; k.KO(0,t," Safari"); } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s23,t)) { // Line 31 + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s73,t)) { // Line 114 r=m=1; k.KO(0,t," Opera"); } - else if(k.KKM(e, 0x4000, 0x59)) { // Line 32 + else if(k.KKM(e, 0x4000, 0x59)) { // Line 115 r=m=1; k.KO(0,t," [Browser Undefined]"); } diff --git a/web/source/kmwcallback.ts b/web/source/kmwcallback.ts index bae75bffd5..07acd4a4c2 100644 --- a/web/source/kmwcallback.ts +++ b/web/source/kmwcallback.ts @@ -1108,9 +1108,8 @@ namespace com.keyman { if(this.keymanweb.util.activeDevice.touchable != (constraint == 'touch')) { result=false; } - } - - switch(constraint) { + break; + case 'macos': case 'mac': constraint = 'macosx'; @@ -1123,24 +1122,24 @@ namespace com.keyman { if(this.keymanweb.util.activeDevice.OS.toLowerCase() != constraint) { result=false; } - } - - switch(constraint) { + break; + case 'tablet': case 'phone': case 'desktop': if(this.keymanweb.util.device.formFactor != constraint) { result=false; } - } + break; - switch(constraint) { case 'web': if(this.keymanweb.util.device.browser == 'native') { result=false; // web matches anything other than 'native' } break; + case 'native': + // This will return true for embedded KeymanWeb case 'ie': case 'chrome': case 'firefox': @@ -1149,7 +1148,12 @@ namespace com.keyman { if(this.keymanweb.util.device.browser != constraint) { result=false; } + break; + + default: + result=false; } + } } return result; //Moved from previous line, now supports layer selection, Build 350 diff --git a/web/testing/index.html b/web/testing/index.html index c4f7984e9a..9fa4425405 100644 --- a/web/testing/index.html +++ b/web/testing/index.html @@ -25,6 +25,7 @@

Tests keyboard error-handling functionality

Tests the new Attachment/Enablement API functionality

Chirality testing/bootstrapping

+

Platform testing

Auto-attachment mode tests

Test desktop MutationObserver functionality

Light test for touch-based MutationObserver functionality

diff --git a/web/testing/platform/index.html b/web/testing/platform/index.html new file mode 100644 index 0000000000..1987711166 --- /dev/null +++ b/web/testing/platform/index.html @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + KeymanWeb Platform Testing + + + + + + + + + + + + + + + + + + + + + +

KeymanWeb Sample Page - Platform Testing

+

This page is designed to test the Platform statement for consistency. + Refer to PR #969. + See also /windows/src/test/manual-tests/platform-rules/platform-results.xlsx. + To run the test, just press [a]. This can be pasted into the above spreadsheet.

+

Be sure to reference the developer console for additional feedback.

+
+
+ +
+

Type in your language in this text area:

+ + +

or in this input field:

+ +
+
+
+

Return to testing home page

+ + + + diff --git a/web/testing/platform/platformtest.js b/web/testing/platform/platformtest.js new file mode 100644 index 0000000000..59fd09dcf4 --- /dev/null +++ b/web/testing/platform/platformtest.js @@ -0,0 +1,416 @@ + +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="firefox"; + this.s40="safari"; + this.s41="opera"; + this.s44="touch"; + this.s45="hardware"; + this.s48="platform-x"; + this.s51="WinDOWS"; + this.s52="ANDroid"; + this.s53="iOS"; + this.s54="macOSX"; + this.s55="LINUX"; + this.s57="touch"; + this.s58="hardware"; + this.s59="windows"; + this.s60="android"; + this.s61="ios"; + this.s62="macosx"; + this.s63="linux"; + this.s64="desktop"; + this.s65="tablet"; + this.s66="phone"; + this.s67="native"; + this.s68="web"; + this.s69="ie"; + this.s70="chrome"; + this.s71="firefox"; + this.s72="safari"; + this.s73="opera"; + this.s74="touch"; + this.s75="hardware"; + this.s76="platform-x"; + this.s77="WinDOWS"; + this.s78="ANDroid"; + this.s79="iOS"; + this.s80="macOSX"; + this.s81="LINUX"; + this.KVER="10.0.1104.0"; + this.gs=function(t,e) { + return this.g_main(t,e); + }; + this.g_main=function(t,e) { + var k=KeymanWeb,r=0,m=0; + if(k.KKM(e, 0x4000, 0x41)) { // Line 7 + r=m=1; + r=this.g_ui(t,e); + } + if(!m&&k.KIK(e)) { + r=1; + r=this.g_old_main(t,e); + } + return r; + }; + this.g_ui=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(k.KIFS(31,this.s17,t)) { // Line 12 + m=1; + k.KO(0,t,"touch"); + } + else if(k.KIFS(31,this.s18,t)) { // Line 13 + m=1; + k.KO(0,t,"hardware"); + } + if(m) { + + r=this.g_os(t,e); + } + if(!m) { + + k.KO(-1,t,"undefined"); + r=this.g_os(t,e); + } + return r; + }; + this.g_os=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(k.KIFS(31,this.s21,t)) { // Line 19 + m=1; + k.KO(0,t," windows"); + } + else if(k.KIFS(31,this.s22,t)) { // Line 20 + m=1; + k.KO(0,t," android"); + } + else if(k.KIFS(31,this.s23,t)) { // Line 21 + m=1; + k.KO(0,t," ios"); + } + else if(k.KIFS(31,this.s24,t)) { // Line 22 + m=1; + k.KO(0,t," macosx"); + } + else if(k.KIFS(31,this.s25,t)) { // Line 23 + m=1; + k.KO(0,t," linux"); + } + if(m) { + + r=this.g_ff(t,e); + } + if(!m) { + + k.KO(-1,t," undefined"); + r=this.g_ff(t,e); + } + return r; + }; + this.g_ff=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(k.KIFS(31,this.s28,t)) { // Line 29 + m=1; + k.KO(0,t," desktop"); + } + else if(k.KIFS(31,this.s29,t)) { // Line 30 + m=1; + k.KO(0,t," tablet"); + } + else if(k.KIFS(31,this.s30,t)) { // Line 31 + m=1; + k.KO(0,t," phone"); + } + if(m) { + + r=this.g_app(t,e); + } + if(!m) { + + k.KO(-1,t," undefined"); + r=this.g_app(t,e); + } + return r; + }; + this.g_app=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(k.KIFS(31,this.s33,t)) { // Line 37 + m=1; + k.KO(0,t," native"); + } + else if(k.KIFS(31,this.s34,t)) { // Line 38 + m=1; + k.KO(0,t," web"); + } + if(m) { + + r=this.g_browser(t,e); + } + if(!m) { + + k.KO(-1,t," undefined"); + r=this.g_browser(t,e); + } + return r; + }; + this.g_browser=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(k.KIFS(31,this.s37,t)) { // Line 44 + m=1; + k.KO(0,t," ie"); + } + else if(k.KIFS(31,this.s38,t)) { // Line 45 + m=1; + k.KO(0,t," chrome"); + } + else if(k.KIFS(31,this.s39,t)) { // Line 46 + m=1; + k.KO(0,t," firefox"); + } + else if(k.KIFS(31,this.s40,t)) { // Line 47 + m=1; + k.KO(0,t," safari"); + } + else if(k.KIFS(31,this.s41,t)) { // Line 48 + m=1; + k.KO(0,t," opera"); + } + if(m) { + + r=this.g_inverted(t,e); + } + if(!m) { + + k.KO(-1,t," undefined"); + r=this.g_inverted(t,e); + } + return r; + }; + this.g_inverted=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(!k.KIFS(31,this.s44,t)) { // Line 54 + m=1; + k.KO(0,t," !touch"); + } + else if(!k.KIFS(31,this.s45,t)) { // Line 55 + m=1; + k.KO(0,t," !hardware"); + } + if(m) { + + r=this.g_unknown(t,e); + } + if(!m) { + + k.KO(-1,t," undefined"); + r=this.g_unknown(t,e); + } + return r; + }; + this.g_unknown=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(k.KIFS(31,this.s48,t)) { // Line 61 + m=1; + k.KO(0,t," platform-x"); + } + if(m) { + + r=this.g_case_sensitive(t,e); + } + if(!m) { + + k.KO(-1,t," undefined"); + r=this.g_case_sensitive(t,e); + } + return r; + }; + this.g_case_sensitive=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(k.KIFS(31,this.s51,t)) { // Line 67 + m=1; + k.KO(0,t," windows"); + } + else if(k.KIFS(31,this.s52,t)) { // Line 68 + m=1; + k.KO(0,t," android"); + } + else if(k.KIFS(31,this.s53,t)) { // Line 69 + m=1; + k.KO(0,t," ios"); + } + else if(k.KIFS(31,this.s54,t)) { // Line 70 + m=1; + k.KO(0,t," macosx"); + } + else if(k.KIFS(31,this.s55,t)) { // Line 71 + m=1; + k.KO(0,t," linux"); + } + if(!m) { + + k.KO(-1,t," undefined"); + } + return r; + }; + this.g_old_main=function(t,e) { + var k=KeymanWeb,r=0,m=0; + if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s77,t)) { // Line 130 + r=m=1; + k.KO(0,t," Windows"); + } + else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s78,t)) { // Line 131 + r=m=1; + k.KO(0,t," Android"); + } + else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s79,t)) { // Line 132 + r=m=1; + k.KO(0,t," iOS"); + } + else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s80,t)) { // Line 133 + r=m=1; + k.KO(0,t," macOS"); + } + else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s81,t)) { // Line 134 + r=m=1; + k.KO(0,t," Linux"); + } + else if(k.KKM(e, 0x4000, 0x45)) { // Line 135 + r=m=1; + k.KO(0,t," [OS Undefined (case insensitive test)]"); + } + else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s64,t)) { // Line 97 + r=m=1; + k.KO(0,t," Desktop"); + } + else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s65,t)) { // Line 98 + r=m=1; + k.KO(0,t," Tablet"); + } + else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s66,t)) { // Line 99 + r=m=1; + k.KO(0,t," Phone"); + } + else if(k.KKM(e, 0x4000, 0x49)) { // Line 100 + r=m=1; + k.KO(0,t," [FF Undefined]"); + } + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s59,t)) { // Line 88 + r=m=1; + k.KO(0,t," Windows"); + } + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s60,t)) { // Line 89 + r=m=1; + k.KO(0,t," Android"); + } + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s61,t)) { // Line 90 + r=m=1; + k.KO(0,t," iOS"); + } + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s62,t)) { // Line 91 + r=m=1; + k.KO(0,t," OSX"); + } + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s63,t)) { // Line 92 + r=m=1; + k.KO(0,t," Linux"); + } + else if(k.KKM(e, 0x4000, 0x4F)) { // Line 93 + r=m=1; + k.KO(0,t," [OS Undefined]"); + } + else if(k.KKM(e, 0x4000, 0x50)&&k.KIFS(31,this.s57,t)) { // Line 82 + r=m=1; + k.KO(0,t,"Touch"); + } + else if(k.KKM(e, 0x4000, 0x50)&&k.KIFS(31,this.s58,t)) { // Line 83 + r=m=1; + k.KO(0,t,"Hardware"); + } + else if(k.KKM(e, 0x4000, 0x50)) { // Line 84 + r=m=1; + k.KO(0,t,"[UI Undefined]"); + } + else if(k.KKM(e, 0x4000, 0x52)&&k.KIFS(31,this.s76,t)) { // Line 125 + r=m=1; + k.KO(0,t," Platform-X"); + } + else if(k.KKM(e, 0x4000, 0x52)) { // Line 126 + r=m=1; + k.KO(0,t," [Platform-X Undefined]"); + } + else if(k.KKM(e, 0x4000, 0x54)&&!k.KIFS(31,this.s74,t)) { // Line 119 + r=m=1; + k.KO(0,t," !Touch"); + } + else if(k.KKM(e, 0x4000, 0x54)&&!k.KIFS(31,this.s75,t)) { // Line 120 + r=m=1; + k.KO(0,t," !Hardware"); + } + else if(k.KKM(e, 0x4000, 0x54)) { // Line 121 + r=m=1; + k.KO(0,t," [Inverted OS Undefined]"); + } + else if(k.KKM(e, 0x4000, 0x55)&&k.KIFS(31,this.s67,t)) { // Line 104 + r=m=1; + k.KO(0,t," Native"); + } + else if(k.KKM(e, 0x4000, 0x55)&&k.KIFS(31,this.s68,t)) { // Line 105 + r=m=1; + k.KO(0,t," Web"); + } + else if(k.KKM(e, 0x4000, 0x55)) { // Line 106 + r=m=1; + k.KO(0,t," [Nativeness Undefined]"); + } + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s69,t)) { // Line 110 + r=m=1; + k.KO(0,t," IE"); + } + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s70,t)) { // Line 111 + r=m=1; + k.KO(0,t," Chrome"); + } + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s71,t)) { // Line 112 + r=m=1; + k.KO(0,t," Firefox"); + } + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s72,t)) { // Line 113 + r=m=1; + k.KO(0,t," Safari"); + } + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s73,t)) { // Line 114 + r=m=1; + k.KO(0,t," Opera"); + } + else if(k.KKM(e, 0x4000, 0x59)) { // Line 115 + r=m=1; + k.KO(0,t," [Browser Undefined]"); + } + return r; + }; +} diff --git a/web/testing/platform/utilities.js b/web/testing/platform/utilities.js new file mode 100644 index 0000000000..d9f925ba9f --- /dev/null +++ b/web/testing/platform/utilities.js @@ -0,0 +1,11 @@ +function loadKeyboards() +{ + var kmw=keyman; + + kmw.addKeyboards({id:'platformtest',name:'Platform Testing', + languages:{ + id:'en',name:'English',region:'North America' + }, + filename:'platformtest.js' + }); +} \ No newline at end of file diff --git a/windows/src/test/manual-tests/platform-rules/Platform Results.xlsx b/windows/src/test/manual-tests/platform-rules/Platform Results.xlsx deleted file mode 100644 index 366270c397706f8507b01a79cf1e113a1b990024..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15980 zcmeIZgLfe7vOXN!PA0aUiLHt4Ol;ej*tTukwmq?viEV$``<(OJ=gir6eSg5c-D`EP zUfosw;;E{)x}TDj00uz;00V#k001BW;Ai!nvH}DE009L6Kn8#S(h#(^axk=V&{lM{ zF|_|q>tbnvp9=y+o(%x>`TYNF|BFYUTyeyzmmZ-*<(OBfQ#m9jsI(LUyA@l5_z*nV zC03QVaUYZX)sxIfPN@c>heXa|N`v%<3!`F%R84?y*Mjz0O@>$px+tQ;?uz^ETb8hI zez|f)U33^rHU{j)1=w5zxMcH+9<3SS2O$X>OFb0RLC>}Hkw956uOLYW<*!npr==6_ zkzO?*2?|FHJvJ9Vc^WM74VCtGIYuUB;;J-z93|TLhX@Lk8rhcmXFRdv(OH!2?=>cv z9D;a!rsaUemW+5XOo5OHH4G@%_{KlL=!n)^N1GX;`c_;#bWTJuS~GSl8y&S@IellM z!4k52@m08g*(O=@>BInuIqS99YlALwXV=6iBU_g9eP6h2u zmhQu`pUPI@)-!VX@wO7L;J&=LVud6wwZ(T2sm6GYBhY7s+_8K(&u&^GDARyt)|E-Nc(d&oU8hk@U9`Tp;E;4Kc zMJzvHQST0~*U{B=u88Adg8Loj@-QS6PNGKViom32TSst8QoBSE+w$#xM5l$jh5Hmy zaaVGujws5q=HeWQkxe3zxhtU>geh7TEJ)-6>_9Z`6d(0LDYXr~$4bBj0fn=Q!0IN} z?BlqpH1Ea4!XsGTV0OvV*%Z`adp+ajN{?X+g1aXyB?S|9(`vm;I}SouZ3Bz$8=GWZFLT02##wpPulI%Ng^?K&3u?*LKR>;1x;mZ-&3*7(*q0K4lwdv4^?p}5{MhJ z#RVs*^~B8tFofP&1+K3sC^FLN@k!YkG+e4ZatlxFFm)yh+pkA*63n2yLPDY2mf1jN zvq^eKMl<_qoY7CrjMeY`c=lH~t?;dHYQj&YFxvlU5nR0o%kp)_o4LV+6yt(*1(-RU zC!l)l5x$4GZhtkBa-B5q$$N&`$1an=EoI^M2z0;?8WzR#riiuQ&rNAly4ZFQcp0VW zTD_(oyS*^l8yQ;I{G93khRjBb1{?P$T#`Tl0N_8L_=L>AgQZ+i%6gR^rUQP-8^OW( zO|D2PVo5m7NYzIdqP4Q)F?U$9To^Btm<}@V?LqFo*72mE&xt{7#Eo#1h^1|fO04sT zWA9;XAsHk|c8jV1M*QvWTbhY@$c-ecBo-_Q_m8}!g%g#!jGEO11`S_;m4y1cPO6=y zD>M{)vO?epPIGX23uOy=Ic zvRBD_b#8OS(sMO?W{qe_xFRc%C#?^X0UE?4vFu$Y{y~NL#u%wMuZ=n{=dI{S&U0K- zNLVVo1*+;W^cPe|J!Zdjt?ETny%1ij;$fCmF-_54Vba#|B*~m&R=1?4GOh+uYtf*Jc`jlWSV^U$f@urj-1Hy6NC>C@YHN+O@VJb%77Zqm_ z3+LUv(PiJ6nj?%TB-T~vYUh}#xhGf4mLc?XOBh!8WQsO%lV-uduDwQGNw)cJZLUv; zGPFowu*`UJL9?sjp>VF_If32ytcvg}L;$-kGODQb;%||LCfFD&@QJizFaQ9Qe<01? zMAy#HK*7Pz)XLcY58vdVv}*MUH&483Z~RxD&D6rPt!9W7hcAg=0e5KE^YoZ%=ryj1 z*^|1mu#K1STcdc03;Oy5*;{yjqMpi`(hl^8y-ow8v`{xMNwqJY9?eyNuh7d?i$kTm zkj-y+K3@suHUMf+-S$&OnDT)8OiGle+#CA!iZseEj4#PFKs)3`qqYh$JEHdMvcZ`R z27tF%1f;m+k>6*dzB-4&b2D~c%?jNxGnB+wYLWVg#bpD#RU4GD(Ff3aZRJLTpY=8Z zlDKa7YQ~PI?#tt?_lJfh{s2AJ7Wrybshb8B5%#rUVG0zK$wS7y86VARoALIGdvtV)a5{Q~HF=gfQR>W>1 ztCe-Q1c?F}Y!SP7a(<*Ack9^)#3cUXobDWlp5^D(LXTvhj+6#F*J0r|7UFc^Mc|3MMnRq zp3q);6yXQpcR?5TxSs(qf(opJ%}NKrde19ht4YxhC~xj{*oNKv`!-YiU(;T=O1>Du z#Zb?;0tM{pqnlJ;y06f5@z<~&uc1KFa7F9R(RQW+OG}G~3`MJ=Le~Vy5x-&ddG#;X zL_(HC^ZZ&C3vs0%c?$b7U0!Ntd94jzPbb}QLA~dx;>W=)ul9Z#>50c>mDe@-?Rv^z zj6GV1C-)osu<+US4?X@9=le`^PdJc5%ki*=Uozma{0E75{q_=G1-q=L#PT6bj^zfx*;<-d`b2f5j51DWA;fRKiR!`8>uM(?SUUrC&+AGLh-WZgX(35ZT% z6U4pUOWI|&8Da!r!^t;QN^3}RYIgf-1%d+(<V_QBKyt+GEDTO@TnRA=n3KVADQK7^mTdx17^vF6a-$(wpt<7^S23A1lP zVdE0VNrF|hF0AbHLQb2?h0++>#RKLjIyXf_gNH)GwWiPPe(`9nIzh55R1a)zH-yS~oY1g(iP)b;VlPD;h zFGOj7yuG1sXm`C|9$&E@&68dA_IJHLjU{z`Tyfl0@2sKHb$VW3AH|_>dfpw#MB%Kg zV&f!V5`@%TR&MKGkcR2{z`a}n@@DkY3-rhGAs#vvpN|a#X=&ge_c~Ue^{!&84uZCG zb(t@>;$5{6N2XMX)PSz(hdW_7b8MBSj$K~bWJ<2b-L!z&%3m)q= z#P?shp4hOg>MJ&1;Px;e(*0})y;pF_{@|Dit=y?RyAT5lPG^|G9;2Oik0@y+9kGyG zD8{ldXhx@%q;Ru9d zoc+YmJ))L5g}4Q=WosGMnjjl{-;4;GLHEp3@b4JUDG+QU;i@X#H6tHTUexEhxl zCPJ7vIc`c4R@yKW9Kr`N+?#mpRi|~C#tvF$R0wqva8AX`sfH(&?$UJt4P#5qe^S^b zK~Nb!T*X^f8(Z7@x}cGVAa3SAVF|5^e`niIS9HsWgp=B00oupg3!9@@1U;mWZR-*{ ziGWZuPI5y#_xNr@0yS6f8TUJfgoq@%cUC#0R@A;?i-Byt|^pJ zrfzW_pSG0t6&@HxM7aYwZZBeBDx{X|)p-=x8PFaKG)m*@C7vUV-0(oirw;M~kJ{YL zBy+9XCbr!Er>l~^*23e*OR3SE7EhJoqBaS7rc8UyJ`+Lw z`55Rxn}D+?Nc&7UIDPS|Tq{|N8Q>)0V=7BB^;$d;&8{seFB#)X)HIB`py7IVdZ^@` zq6-sgwtjw)BNb}abj6GGjZ0L-oV0OEd24D3G-<3x#HcV3K&@p*r`)M#cPz*P)`b zS`rxf@*IY)q|p~SM+`Y_H~|zbV}GsX6xA6A)fw62q#Sh-+kGf{OH@>s{rfH9j{PA1 z75+dY?DzwH)S~*7_V7xm$rKT{IHr;mKv_LHCj2M|h2>UTS2IV`(hlK#8lrHAx(NDN zdSCQyYR-wo7q!9Gl%RP=nHIg4FLq4F5%7rS!h~eaKBS}y)BT)QPYq@eO_W5;=1<6n z7=4Q_U@b)R8tAzS%}$tNnO2X^x`~+RwLwDh9GY>`qhJg%$?oy}G}<)Y39!sF*twQe zDnAf-)OS<)sPNKk5ga&&T^M_aOas?3{m$7?0@FJo*fH@9W z5%X15>8QXXLwoH4HM z$VYu5p7HoRy4Jp61n%s^JcvWM*jB7Vk8!)UgerIT5JQ3E$QNQZRZ^yyEI0Idp*3s|@H z>KSaV%MKz~xRnJf*%MZ%2D>H=2s08xuROJ4@C0$r;-)We*>Ct%`a1g*o(7!&4`ywR zAAg&XOIhV^ReYva;Mf2Fu>T0Z_71KVhJUVhPt`Q4R@e}{v`s$*;~&yB@tOJkOF;;g zj+GZO>t;Js`vJ=$BarOTT30?g^*McHD+A{4zwLus4B>j)U%41@xwKIhUxkl_+MuPJ z`{`pP7jO|-prv?olPK$8CGb%T#xr53m}{n32X%dXE$&a<8Dbyo1wbkf9dAJh>$Frk z!bUH4+kzh7l9(I=f;>!QYEzHLFig-?lwGw?&-{+xD=C$uou7n2A^YUoQZ27V9gVLb z5TZ(@UMQFU_P{hK!CU~~xbGylGOe7!eGMump>?In1;Czmz%F*hGdc}tnazy7mmV_u z?I|{7_!PjjMeu`Z_oG_K3kdLMU7+7_*i|@rcyl2)c7FQxECN0zK%oc*WpySZk$53V z%$%JfLhH}IOl;ZS@&i;5)i}S#{+t;Ya0T`g@H0n~EW57}u2E<@02>x zvMWeUxEOGJXFy5RK2;*?Ug~swl`zzbW8gd)8QfGeD|fGB=!)sFlE=fSxG%-&9A$oNb1|PfH%qRA&z|c)}@vXkz zB1_*uQE2m@`8QW)gKc;|oW8<9Ki-XBCYQ8BIi9L5No+6=5r##;GCPkvF!v*GNASS% zBKHr1X(9PT)!|p04McIy?2N8);hL7ZdWaE z<+$M#eGsmCNm^;@I*Iryt?X%)Gz)#~M)RkWYNiQ=3l3}6X36Az&wbAz{#s*i5dA4w z<(J0{X#@@*WNGSz{Z(+}AvFKp9rqq7MY(OOB2G}SZw+0O_ZLp3;&iJ(L+jE?1;_R4 zYkOT6@AXRD9WM%MYZj$p5ANDSx{hM6zHGY=4fjc{50;oU0u{=gNyX16q+WrttbOe2 z@>lgw7%8jwcx*&tK#_XfC&;e91Y&~6Enob~P1-0C{Ck&zpv0#yt*IrDQa+?btb4DB zugbeIL6w{QJgII)^~Wv-^RCz+ai&5(%(*w$E?x3)Q?lg`onBA_$TDk<8o@rAal*!x zMf+5Ask^Q8;X5*KCY^Dpj@T*}&T_h;+;BF_G zrBwOf)$CV>(Y(5p9(ZNBCKT5hz(67?Ruw{2!ueG#Qbc|C{jn^#@QqWny=5fKN~WIn ztSDSVMw}DRc_f^(emY$rJQPWtnK!RiHBA-W{p!)}K;x-ugg-g>yjs3Jj&ixX3sOBaoio9~b^0PRc4yB$GrgKHQ{(BOS=AeMc6>+S5s5_7W>Xhl z{P99}lGO3@zMeAg+_dH8$(=S-BUX~%v2@f|O(wey(F7p#Ye!X{1A z^($|_w>h_l)$^vP8Nd>AVw?d6Jl4oB`A4UFx>7{4Mpb9MLvznBMi=@A#T#s#A+XHa zL7Vr37wYw|%#f_xlu&rXGIuLot7mft4T_%TUpWUqL`QehP?WTu>(}2a=I_KVqp`fy zc!C-(;?S{9Ogl8H-oAOq&YHZ~q4S6wYzLxfHXS$YQ>uHz4iVd`f7D0ho+(tnzmkON z6B3@ zNcH%VzD#Jwdp!hBER9Btj~kOcSzBJ0u~`hYtq49gd#nrf+^savw<`@dIkS15_d;nQ>td3ROd<jOTgL1E*$WH{9cM|eR!%p_c6nKl$>gXy8(vMSAR(bAk2^xiHaG}eo}g=*w=x%rDK zxl77noMd;k&fNFNm8~9?>S|!|ih~|mQy${9n>%&%soLPZ$v*K5g+Zlm?KB=;tWuux z5S=G2g&Qc8PYU%kxH#^nH#Q0jCiWhhcUrB)D2<9;3+_ zQ5>2{+c1umbp0RLy~NJL1cQu1k+jx^{@keNH^^|}dlvP*?)rNOMqNY7slCPgK5_xx zWT5K)YDJ%i@5Z3iz125BXu8Y7fMN7!L;m}0lfvR1)F1O&xkB%1H`12n zwHx2vAD9{)5I7qLPA%xn89O$gW|t| zgfvw#j9CKhd18Lsk_Hll49}O>whJe*p%VrgVGw)Ce6UC*be*08NCB?>7Q@BFLkbZX zs17~RUti_%3yMI0YmHcZNSiS?xu;T+(1q=L1uQ)94%s)W#u^aPl5pK+6b5SOVeDw( z(EdcrWTy0$(0JDTmS|rBDLswxYII3?gT4YWi;#l7P{e?}h~szDj9lWet3;EQtm^5( zTdBmDw1Gv~BM%%2d>dy&Gecdg9F}%pjd4`GH9e#r8cF%q0K@^U-BIGvtuDEB=VlV! zn%04dos&Surf+{p=vfA}1hi`O(EQr!rXfXK>m@GGz>q6fR2k1^)KGlDu@X})x3aB! zY|R;`L4sKOolfslIdYG{q>95i)8zZ`5n>eUCj=BbLI95Y$L~0dDG@MFv zMG4((=3-#Ew!R#39FrCLw7-_Kq~U;6qNzEc2R1x5S$Fhd#&w7UUe6zDRy)%dU?Oaz`LND(F?a1*}olz}u;1s6EF(%AE@c zjx+3eJ3Ue_pN0$!a8F ztj$mM;Z#y~LQ%n|t#)sdqT*P|+wSWsCUdGn^{#DKTD%;)mALPVrAP(=I}|DHYaT}i zskR+mg49mowC=X_ks#%lT2f7oe`?Vxv3Xbs&}DGOfLPS5pjS$YsB6iinsnu*Hz{~Qqt zAr+rl*d*{17N7!nEGU~w14N}O{K8{g#Xm5A$T8$fE;rg7k;GYs2}V*$qq3hqzg9IHKC??Nfpync*DJ{sL zRmGv`{_>A?D{PUp2U--cM@_C%UnsFEs7;Pr2-J~Qj`L;5L>)IR<9NFTquWJ6iw^08 z9G7$|#x+hIV}>h#7m6q!9>xN)dzrn+z`~N-a`K44_d%Ai^|;(t zCmD(;#|K4Ub%Cm4NbI!b8J&^sf<094Y+0mtR?wtJ00=q#w-p`TD0kT(a!(L~k!_H%0W-+EG zYtw`cL(KDKw?r@ZT%fACi65rkACZYV_(3i2U&%YYH$+xpM&cHha7b@j!}w*qAIg*- zd5&7fUA4_Jn4`J6>`{201Y#AaAi9Mg+$6J<5y&=&AiUM70ZP55tHX$ivV1ulN^G2^ zuOr5&?YcGs58l^u8Zf0G7}4?b4f*)TD+!|lyhaB&jN*)FQ)gzVv3gTcWdqVzz9E1&CiHmJRf zp9!;$MBq=vB-5z%96EKXHRs$^fa<4>_}*Zmrd!jHr5Lp^f2S(V>&49HqITIwO1j#c zTvWl_>}>YZ&b<>G-L>IKY*L>jxBm1j#obTk?T(zA)B-b4923(49(sD)3N9OVGvm{?G@>J*#QqzLM#W%+AscjnJL>=6z< z%xzbUYPUQ@Ko9D66mee}CJtZo!5Zl1T9ZB9C-0P~A^|Xsxms@4D`ey;h9n~j>Jyoa z&9>A{DuE8_hgsT>U>o)Pa4%~s4rOb6xS5$2yyP`8wFm}O`UKpOi6cZ@df^W zz`5NQiLth=j|-ynn5;-Wl1x306Aon$&YAfmz^?%s9?2*OT7-pSN_f?#aa!~cEeBA* z83Gm&i(rq4S>zBmhfnb7jT#xYCKU#ah|7Tg>~n(3`5Te1mI%U_vQb`ES$OgU_-xfM zWz#8vL*-WO7jca~ zCjQY;(-=AK{y?xPH*zz@x;(uv^0F_VUei2!O7vKhu5DrnM|PZw9xp{PJt~U)}EyZNl<(AmXWs1H4iJN4ux;Bfdik;sFx8#|OU?2VQFgF{%z5htAXtGgDB)OVsB#ijwBPiD) z;#0JM?4O3q-CL^JBsy+}%-w4yr`vP`_t`Yn0BRK{T4?rI6!V{9T;hHwP}-20wu5m8 z!5TMfl_~B*s8DJthxZU;Zo`Pm<36Gos9bvT45AhRTT)~tP8LkF*&tEce?*KuT-zp| zCi7pox(m^(M5?fk_N#Ui<+HZtMhVh9yS5n?Rp&oVjigw;XIW=b+NU^Ot&dS^rSl59aoML-MRu_*5vNGM+g3sSMaXow8>$Gy=cC4o&2cOFAD6UG6dz@A}8MbnDxPK^2lu_R{Fa5eB zV2V@g!@)&qQsgPbc-2N(AerXICruv9PAVP)dpL=oi*i4~nU9O2<}jO!J1w;=%v0cW zIJgYd)?kwFpzRR@qZXeTNEL1RUXm0SE^hq9a!u7>f&V3e?3Ouq;n2=%T^qGIUYY%is7!~5g4T6xnz)hf10Ui6k9 z@(t+2JT%3q&1wDC?X6Jd%giR|TZi(y87}T@6fGjBK`5Nz@iBwTx_`sr5Ol|A#;wTh zNbno;EAE0h{3hOlDC~S$sFu^oStQSfjrv9La!4o7w0HWs*1{s$ed@gvTE1xUq+xrwMD{2k*s-P4ADl z{2Y?Qj%8b83CGm?Gm)Z&Ta}Wzh=9|fwBFE2@`GGyj5cnGhxr# zce%kutUuB7+n-m44{Vy(JPY$HED!5&k0me-V!vNAL_D%C6N#9D$9lXAeq2C%(vs$v z7g(Fmn@6o$=6?tx$INm<<}D^+?Q?tj5WNG9n|?REvT7+D*@oW!C_U1%zp5>4vTTa% z*gcm!NmkFfSQj#Xc7j51>R_25YkL>GzIC~eNUQsR{@brixPEFYa-ZMTjX!B4h@X5m z18aR*J8K(zI(=(9!+$cf|BuG@IduN9auR*?C;^+GAA%$9X@&NNfsMd8?kjxNxsPbE zZ52!T1S6;S7gDQgoG2dS++^C5EyNm`1~?wRHA;DQLb({A*)Bws4O24`EpX`M)sYlE z$0GcZlR7iC%^f4nh3yQN23W9zN;<$Y@`-jCd4Be(dKOQB#C0*wa^VEF>c zZmfb>>a0!{JIeUD(mNI|bsU+!J}}>D+|9K0`1~L|s5#;vm9>nc%IqRSiAlrgGlNDv z#UMJ;=3JjQI=mda!q{Q_T)ATQDVcFjPmXKHn-E))J`0rTT4fhiV3E~0=Bp{kNn zfULYLtHiflhygA4x{YVNOj~5x{Il{m3mIo8BW5PJwj5!0{C+?Js9?K80&v;{Hlc;m zQNS2;ctnBXAZ$vdoo*jwGDRhb=a-FfmrUog5F!+$nJY7+jSEljjfc05&6*|=SW1P+ zUnP7)mzvpXZlQ^CoD!&v!({xp6Xvi1(s3xTcmzYc$R@ zFG3L%Jv*=XB3CQ>7aKQpM_lul<_|>Nu|`e^s6r_kZDy`H zIRBy$eEKt7776tl`J6;cx84K!0n;yu*|F<&l3iV?c#l5Ds)f37Xx;S(bn3-OT9Ko| zmMq%EO%B}JsulZX1vpstA%n+u`i?alE;(vEZRJxj;oDDuYhW7n7WdEC$%`nR`mjKA zH53%Im|pa(Sz{DR4qQnm&7`Oq_d0@0{FXXu*lA@IX_aGQwgj8P(P40Q4Z!LS)I(() zIQ&XOPAi^M%Lw!InwL6SNQx9kZY5%lQ~tFCL?-iTZcN%gODH)CbF5o@ul>4b{7F{$ z<cI(O7_;xRES z8evS-mQQ-kSO=~%v`l6W2-%!69mqzvkqC%x-6+Eep*nnB;h$2-&aaQYL zJaw#~6OvuAfKFmc&htIw$iz_gzo$T3(x0U^Afq^U-dVaadGlD>7HoU+k7Junj2i!D zFT8r1nu|O*;%u;>wK!n(qui3;SYzL0bU0*sR=h02BX3@FVU$kKMJUgCriHwn1RfYw z87Vvz>as;b{uhM>-5u94ad|5?JMwW@{Xxn(U2waly3D|R1Jxcr9fTLcVGW}xW#A_{D-G66(&saQ z8mtRYy4SYn$=%`Gb?}hPzMJEKkByHa=btK-xE{6l4;8#0j>vbLrzEZLwPR337E_K0 zW6v0PU|y&y;obq)Cs4GxuYtat4F>M7Yg45_kv>k`2q46 z?E3-yn&WGn;{xJtX;B62UA)!gQw22i&LgO+(etuxuIo+63)qgM>*N-*&nvd4f`RvK z<%R5o>Jh<18#r>+9LPI=Yw?H72Xl#rN0piveLPd9Fm=&|%nE1UqYuaj?qj&` zCNM4KqjmRKH#R(8ATMYo`E?bhKEmK@hCn4Os5aP7AN?20t((wS`$2e;`zZWH=RSA#cXrX;ANIkML0MEX}PjqlNj( zFhk~%Q;e^b_}NHCfnn*kSp1#b1|000t98pMPiJZuzjQcW71@fCzZ7qnxAVHG-tW4AFOYeYl`i51V8xT9>a$F0qXU=+}M1*?nI5O zv6r80TMQfrsG@bT;&WF!w~DLBG8jov|Mnf%+|eUzCLxanpCxOArr-r*!l4%Z`}ruB zjAjbpMX_azMA0(Dc-s$$y^*O~P5p`jlSL_~C5@)&B$4b==Lm)>s$H=C+sPQ znZ^CX>OIvIS}dL+RgCX*{qkU8VD(Zqyb)gZF22(e zNNI%CRJ&{aSUbbW#F}e&@KFF>-m<)0n|3psCFCE?7lRp==ZZ+QJE}zrTWO1VmoQI) zNN7!2NuEd9&H<-Ajo1^;JhA0?0+DrI82bci@a*MK+pQj~iv?{Bv}+nS{BfIr^))=s zwpVFYZfG6o_sw`3Fb^x8(G$R0QMIno6L;Z0;XZ9s03Q!%U0pasA5;ceA2MK%FUarI z!roUeT#JVK`VNxxc+kt5BZ;AZJp8X61?-U(xwBSguscI9J5;;f;`O}0%QEui^^;Hk z-+xXw_|cX_KUW!uzyJUU|GuWxwXylXCGF?p>YrPBEdL*s2LTtr_joYtU)a|jB0(8A}!F=hPAhm&cqgMm5gNo4T(=?76!<3yFQl6R@elk00?~X@_W!tr-J{i<@=Z5ALpV^qxiSVzTXA^v%cxy z1;;;&3jXJ6r{DGbUi9*prjO56{%<8PzYG6f$MBc1>1P)EDg0km4Zmynot6HVhV@U5 z*gs$YCx_yH;Hdwu@OP5;UkW$j{#5uo<@PyorvU)?ue|?v@!u1)zZ4MD|JjJ&(zCx!*M3*}pPu?Jl>h)X eZ2#7#fBJ1%3D8dr0sz2#?xdeErsw?Q>i+}eJn diff --git a/windows/src/test/manual-tests/platform-rules/PlatformTest.kmn b/windows/src/test/manual-tests/platform-rules/PlatformTest.kmn deleted file mode 100644 index 14d8eab5c7..0000000000 --- a/windows/src/test/manual-tests/platform-rules/PlatformTest.kmn +++ /dev/null @@ -1,35 +0,0 @@ -store(&TARGETS) 'any' -store(&NAME) 'PlatformTest' -begin Unicode > use(main) - -group(main) using keys - -platform('touch') + [K_P] > 'Touch' -platform('hardware') + [K_P] > 'Hardware' -+ [K_P] > ' [UI Undefined]' - -platform('windows') + [K_O] > ' Windows' -platform('android') + [K_O] > ' Android' -platform('iOS') + [K_O] > ' iOS' -platform('macosx') + [K_O] > ' OSX' -platform('linux') + [K_O] > ' Linux' -+ [K_O] > ' [OS Undefined]' - -platform('desktop') + [K_I] > ' Desktop' -platform('tablet') + [K_I] > ' Tablet' -platform('phone') + [K_I] > ' Phone' -+ [K_I] > ' [FF Undefined]' - -platform('native') + [K_U] > ' Native' -platform('web') + [K_U] > ' Web' -+ [K_U] > ' [Nativeness Undefined]' - -platform('ie') + [K_Y] > ' IE' -platform('chrome') + [K_Y] > ' Chrome' -platform('firefox') + [K_Y] > ' Firefox' -platform('safari') + [K_Y] > ' Safari' -platform('opera') + [K_Y] > ' Opera' -+ [K_Y] > ' [Browser Undefined]' - -if(&platform != 'touch') + [SHIFT K_P] > ' !Touch' -if(&platform != 'hardware') + [SHIFT K_P] > ' !Hardware' diff --git a/windows/src/test/manual-tests/platform-rules/PlatformTest.kmx b/windows/src/test/manual-tests/platform-rules/PlatformTest.kmx deleted file mode 100644 index 8b2d0d567dcdfff44f19b289b65a326f170dd0db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2156 zcmai#%WITp6vj`Ywb5#gmuigKzFG*yg(zw%uEtBXURp&HO^sbd$1oG)jAUYrE?jjL z@&~w(E=rNEq{|@UDhqLA5hc!heE$O2Z$qRp1x+XV_}+H2xo~3*6Sq z3;Pha9p8y*tiAYB;9h(;_9^-(elYMjek||}{6yee_@4q#;(rT#4}UxGANc!$pW^=v z{0jdp@B;StI`ArR8>TfRd`I9f@EZevh2IqTAbw}yQ~1MyEBMoaNAZJ!$MIv>O2+>M zKY{JBVLNC2Hp07X$u3(JTmc8KO;%849L38+P7jz3A}~W;(;3&iNjU6Rgm?7IW8puT?)!HNT90#`{&H zg;uVWTnIkEd|J8Ar0F9+saDKntduQJncv*hZ|q zWcKR^W|Nq-&qJGn|AifZFUPE8_BZ@hXe&aSzks`msh#eq+9mkr(3J1ecEV3#N1z{t zb{bv_ZEY5?G}78w56dXZ8R!YiTaRHco;uZ6ZIv~l=t?0dLsquSkpPldKFwBO-RLR%l& zbNF;`Bb(ah^y~OS7tLh_h01E zUH{4M9MyeF^ei$xtGZFiwO&wGb*GXY_IZlj&k^0MWPRRa?lr!BrmcR5<~q+-eJp+4 z9&%*vaT7IC)iYO=yej3M&ZVd>SylFFt<8OOk_~?UH^%|5!Fd$rYvOCtT&HqOd7JpR s{#~I{%)M>Ife{#5{cS!3(wiNg4T%=a1p2u}q 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 use(main) + +group(main) using keys + ++ 'a' > use(ui) +nomatch > use(old-main) + +group(ui) c Method of input (UI) + +platform('touch') > 'touch' +platform('hardware') > 'hardware' +nomatch > 'undefined' use(os) +match > use(os) + +group(os) c Operating system + +platform('windows') > ' windows' +platform('android') > ' android' +platform('ios') > ' ios' +platform('macosx') > ' macosx' +platform('linux') > ' linux' +nomatch > ' undefined' use(ff) +match > use(ff) + +group(ff) c Form factor + +platform('desktop') > ' desktop' +platform('tablet') > ' tablet' +platform('phone') > ' phone' +nomatch > ' undefined' use(app) +match > use(app) + +group(app) c App: Native vs KeymanWeb + +platform('native') > ' native' +platform('web') > ' web' +nomatch > ' undefined' use(browser) +match > use(browser) + +group(browser) c Test browser (should only return value on web) + +platform('ie') > ' ie' +platform('chrome') > ' chrome' +platform('firefox') > ' firefox' +platform('safari') > ' safari' +platform('opera') > ' opera' +nomatch > ' undefined' use(inverted) +match > use(inverted) + +group(inverted) c Test for inverted rules (touch vs hardware) + +if(&platform != 'touch') > ' !touch' +if(&platform != 'hardware') > ' !hardware' +nomatch > ' undefined' use(unknown) +match > use(unknown) + +group(unknown) c Test for unknown platform + +platform('platform-x') > ' platform-x' +nomatch > ' undefined' use(case-sensitive) +match > use(case-sensitive) + +group(case-sensitive) c Test for case sensitivity + +platform('WinDOWS') > ' windows' +platform('ANDroid') > ' android' +platform('iOS') > ' ios' +platform('macOSX') > ' macosx' +platform('LINUX') > ' linux' +nomatch > ' undefined' + +c ----------- ----------- ----------- +c Previous set of tests +c ----------- ----------- ----------- + +group(old-main) using keys + +c P: Method of input (UI) + +platform('touch') + [K_P] > 'Touch' +platform('hardware') + [K_P] > 'Hardware' ++ [K_P] > '[UI Undefined]' + +c O: Operating system + +platform('windows') + [K_O] > ' Windows' +platform('android') + [K_O] > ' Android' +platform('ios') + [K_O] > ' iOS' +platform('macosx') + [K_O] > ' OSX' +platform('linux') + [K_O] > ' Linux' ++ [K_O] > ' [OS Undefined]' + +c I: Form factor + +platform('desktop') + [K_I] > ' Desktop' +platform('tablet') + [K_I] > ' Tablet' +platform('phone') + [K_I] > ' Phone' ++ [K_I] > ' [FF Undefined]' + +c U: Native vs KeymanWeb + +platform('native') + [K_U] > ' Native' +platform('web') + [K_U] > ' Web' ++ [K_U] > ' [Nativeness Undefined]' + +c Y: Test browser (should only return value on web) + +platform('ie') + [K_Y] > ' IE' +platform('chrome') + [K_Y] > ' Chrome' +platform('firefox') + [K_Y] > ' Firefox' +platform('safari') + [K_Y] > ' Safari' +platform('opera') + [K_Y] > ' Opera' ++ [K_Y] > ' [Browser Undefined]' + +c T: Test for inverted rules (touch vs hardware) + +if(&platform != 'touch') + [K_T] > ' !Touch' +if(&platform != 'hardware') + [K_T] > ' !Hardware' ++ [K_T] > ' [Inverted OS Undefined]' + +c R: Test for unknown platform + +platform('platform-x') + [K_R] > ' Platform-X' ++ [K_R] > ' [Platform-X Undefined]' + +c E: Test for case sensitivity + +platform('WinDOWS') + [K_E] > ' Windows' +platform('ANDroid') + [K_E] > ' Android' +platform('iOS') + [K_E] > ' iOS' +platform('macOSX') + [K_E] > ' macOS' +platform('LINUX') + [K_E] > ' Linux' ++ [K_E] > ' [OS Undefined (case insensitive test)]' diff --git a/windows/src/test/manual-tests/platform-rules/platformtest.kmp b/windows/src/test/manual-tests/platform-rules/platformtest.kmp index f1b46a850210298c34a2b29a89737fd02c0a41cc..49fe1eb1fe99a050bc1185936c7daa352dd46e88 100644 GIT binary patch literal 4473 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

>7XF{&6pHy07I*pSrr5e3vM2ta` ziB+QtS+4zA-Gogw`EwD2vtKAH=n9oEvssgltK~#Y8G5d1bV0TNq3W z{WSUFR)Xr=z`_S@bxaq?x$RWl_XSyFW00Y$1ueew`T>f}B&e?(UwkK}yN>m@3JUps zmHh7=vWg1OUg94fCQHmPdyYo(W4}f{e^DBbh6a5GEB2AP<`dtF z%zXY+stXih&%U_8J!d|6=1gT>B`4+a#a)ZhhjngLw0X$t!w<2SR4{ku*~`=fW)r0# za*{SU#}1G*)|{D%Sf4XK1!svByBNyx&K7x>HkxFK$(AM6pt9+-@@`GF>hX^fS;f3ovNs~d5a794)6d0F{Wfu6f=KED7)s!B#i_4FKzIZ2|BoN8zx?aP^*`tT z4I};p{b|krxB55e*0o{(J;C^G)c-{NX-5Bp0u%nXHT@I)XJh&gI+fzT+LXQ)3GjCT O@%3K0j-kKJFW_JLHbe{n literal 2515 zcmZ{mdpOf?AIHbGlALRbaxUjYL|VwXOmiGLq#`vk|lMa>|IX)y(hy8!?J0f0not8IiH z3O^120Fw9sfbG2fDk@mZFYq$zmQGNEwpbDxwjr9Ka?3ue3P?&REs}U5n4zjE-k7~# z@4$w&-Y*Vig9D`dM%{6c6?^ET7C+^;%o}8-i=%^GiFC)To&0uk zNMf4g$>GOF(IB(VB`3ro6bfiM0M}d&-Q8X?SUc3BZl`r zB5E46?lGGEkw}k@D~*J~6eJ$;)UPs}Q6}evo5HiUFTXl1OI!!q|BXbOnPaptkAf7C z2j?#m{-HsE*_o!WCLRj*&Q&=xxF8JqQ$A8sRIv75q`2rc=(!5N%*-Zlw>37rwgg({ z!f=|ZGZ?PBR6%*ackI5XxDf5a02dDyre-Wi97lTY+z`KR-&GKwlcZ|lCV8b`1V2-T z05*jX936+YQ(oy8h*@FE)IFd_%2xy4LmnfVpooTQz@RuLKbS_dUg`?Ab=HwXm;S6(SgSC)VHWKxcpTeGnO zy=vOE!&=!}IxoPuk-hyFG7;Y8L40gDf1ZacfX7RWhs-|UV%X)N5R|iTXqeVjRAdsO z9hT*=+k{XuraNco)_+NU)J)<~L+{cl-7^QD+oBxOkN6x{(mn2vcX`rea?i3VHPz*V z;{o@YTl$t37I-8?QJik$j-*Ai*b~Q&EWFDd9{a*T)1u1;8xw(<8l2U^7Kb+^g#|-X z*^_mxyZhhzta(oq*GaaElaWgT4tyKCs*@gqhWR$kJ|;vPEtxU_d2t9?s0&p4q_NO` z3+F_YI1&?959X-U`*I*7P8`ID21j^AdRb+}gL7u&3I{bJ8KpnO7L5W|8}x*jbX&)Y zoHdW#an?E((r0VTKcgVZ*V4MH{xs*{2!DalnqjaMU0Fve2YLiQd~eCut6@Z;Jn$I) zNV+GeR7O4ikIaW10G}TcxNF>0fATiN!}HR@ZTk?pEgQ;2q--MI`!)SuRcrWER{I5D z@QM!6tp{X9xZfg=X}*7Ez^jUyd|Ppk7-jFkQ=jDUk5(3sgyK`iWii|7PTjidq1_4; zgBzc8E=@pMddZ9p(<*X{ZD6=5v#=G^y91VA1`jjV#du22-26Bc>TG&$Hii;zMRBX5 z;a$d7MEDIJL|^_!n0%ESZZhlMO#j@4l&K7<%=G)d<5EXk=SH95*j^vAVU@?9V~U`6 zHnHsdjREQ#wf@#DERon-^YYtzsdkm#fgrkBep?^b_05AS)D6j<=Bcu(A2u5`>cNHsbk0=W)i7qhbi;PDrC9cf=| zOOOl`yUIgqy|Wd|dEwctFZ|)@26vc}r2{1ARV}Bcqj|DZjL2X+BTVv#*SWTIwtguBj8ipHM(ncLcO@Npr|p_rPt&F`>47Fe*Or{3 z+Qztoy`D2iA*U;>%S6q@!v`Ao;psL)z?@O-fAs zs+S;m{>qfZ*>hhxw$fDj8#`~m(}`E~>YM;KGH=w^d|CfIR;9Wq;F;1vWSn+*n|hMC zd_p9~vKf?I_)O6dWHqD-_uAciFj%}ITRlR6>&H3pwMY>?9!Q-^5VSN>3^pX@R=8=( z_}mr9M<8ln{OM$w8JL92P%_HvjM`sP8m1~>DD3T9ObAo|$xlqdsZ(${S<$$@lGNut zPlOh#G8P0DoRk1 zYTC54!}~F5GIRYIvsh^G%?ri{NF7F2q)RQQTo>f2$Dqy5+Y;w$J*}U%6KbZgovd8m zxLZVr)X@8&%J5N)Uqt5_?47~f>5BR9GkMUTs?^*d-jO g;_vC-z5SJL1OJ!B_Av0atpN~kP4ITcR#O4|1La|ZH2?qr diff --git a/windows/src/test/manual-tests/platform-rules/platformtest.kmx b/windows/src/test/manual-tests/platform-rules/platformtest.kmx new file mode 100644 index 0000000000000000000000000000000000000000..db205d8d238aa62c4d355eb54ffca8280e9e9449 GIT binary patch literal 6304 zcmb`LZD^L)8OKjtOxM-6nRA+nwYOWBrJ=f*#Ftu|Mw>=slSh|4t}Z$;ngnCxlPpo2 zij`t*DxpY`P(+G|_(4RZY$cQ-ekf9gNI%GsehA`+Q9>DGh?C)mWxxNque0aH=T-)u zhwJ`d*Z(@N*E#n&=YHPYlJ0O%I(Iwsr++z8i5{d55nP2R z&o;2t^bEM&^bv5-^kd*b(?12r5Y>4aJZbvp-~~i=UI#CmJ_&wf`uE^1L}l-Qe>c69 zp#BG4Wf!8CBhstDNH%&6SZ#U}*nlX{7O>s)-C(Eb2f;n2kAa6wKM8(}sLnIsDbp{5 z6Nu`(1>P|I4tN_;{`=rv(<^>RtP$mJ25S)INrCH4-vf3d%JT{MzUgPd6Q*AT&zXK1 zykz<{@Cu?jZ-Cd0pTSzcXZl?9QbhGvffc5&0;^4L0#}=!2AfUa3I5jfePFlgN5KQ8 zp8!WqKMRhVei1xp`WN6O)31UPrr!j=HvK#BThs4?Q>M@0y}W1oT=Y^zV_5=LnBEB1 znBESqHGLbHHoYI*Zu&tmgUq3xaqtlGx*KvmuFLJ?+3h0tj_X6;jrJzYyKXPO3|14? z0i@pzxIu6TPWF%+ro@2Hv((kNC0>>~>Gj^CF?6Ne8fB~Icfm@Rc57U_Tj$+r30o2j#pdIs?Jz^Fv3 zAR_zl?kCS~e2!-qW9gUpN}Vy4)(b+*ep>;72{qR}`?7)mg>n#KW}JiwxmW z3U5u9x9Y9E;%h5zx0vtIbGeKarnyX7nR*x661;;2Z{1=W%W{it@%0=>xtQ-QKkH3y zqkGH0)s8ne#ZIEgW!KC`^J#7GB5#M=;$zh6TFAZGtQFRWN540Zj?v>>%m42>O679 zjrJz3AG&2IO<~_RPG1yCWpuLKI;t-Vr3Kh88K*A{rIpytNPI8JJ%2)9Ra$#?{#g{f zsz)bu+|$5TcsAZ|!Wk8OKl8ra^D21e<55&J-$_xCFTPQrxaagBeaQ%}*~oN#ha1sWeYL4>N%egi9MGu+=as6k8<5B?DzX!l_$bPkv>TLghmZUA zB$zaB@)h26q1>x_kWSEp3%(b{&z=y6rQ|KvhGQ-sc2`y#uj@fdu?O$4eYh#6TtD_< zJjYve>^+dYnm`@pzU*cXjEYTTFDUm5qIao=E18aHa(6!tyiJ~D0w z+ju+Dg570Y8oSrHoyHAeA2Dv1amTSgGp^gX^VokuHe&m`Un3F6o;2=vmTwCCzHyz# zm2m)+BPzSqxCPji#%(jM7Q4~7-y7G8-H&X-ZZ|H2ebBfL<3_Ph8kaWi9QId;%DrdY zRqRRQ4jVUxUBNM=a_<;7AG_MP5#yF)w;HE!V$J0i>@j3BrvG|_`xyH(zP& zjoV|~73_Z?ie1LIe`5dJxB=rzISl6@$~S0Sgk5XgAB=0jP8m03TqpK!^QgBa{wfG%G(+KS$@l!mds>UUE1H>zHKF_wF)X}IMXu_9 zyNX)W_jiwfX1~I9*2e!lyy*O@p{6F!WWP*9AJ_Qy(!3GbuhigM>wTM;#qh-%JleI? z%VvJXdKp?xisouxJ}H{7dT(Jg8$27nv_el_^K7w5HhNETB;!7&8C&?DA=J5wlIw{` z{yz@E`wHHz%uLHeM_%|}&|<$wggV-+Z^d#wES`&aBMbXm!ar1+jYWxlE^)2aUJENF z_g|kVah-)3Oc96dzYn4RI-&HgSd7p>CaO5$9sDTZ~S( sh&7l0zeOmy-g`UfarQrq;M1G*c3}n22JhL*|5CaCmL>Q1znjxoiU0rr literal 0 HcmV?d00001 diff --git a/windows/src/test/manual-tests/platform-rules/platformtest.kpj b/windows/src/test/manual-tests/platform-rules/platformtest.kpj new file mode 100644 index 0000000000..802678d21a --- /dev/null +++ b/windows/src/test/manual-tests/platform-rules/platformtest.kpj @@ -0,0 +1,47 @@ + + + + + False + True + + + + id_c1593d698cb624690005787147089dab + platformtest.kmn + platformtest.kmn + 1.0 + .kmn +

+ PlatformTest +
+ + + id_18e336f9ad890bf821ff56e1a7764478 + platformtest.kps + platformtest.kps + 1.0 + .kps +
+ PlatformTest + 1.0 +
+
+ + id_61f04814d427ce02953436f3ea7d7a65 + PlatformTest.kmx + PlatformTest.kmx + + .kmx + id_18e336f9ad890bf821ff56e1a7764478 + + + id_4c181ba69e04d1b060584cc3097e7e45 + platformtest.js + platformtest.js + + .js + id_18e336f9ad890bf821ff56e1a7764478 + + + diff --git a/windows/src/test/manual-tests/platform-rules/platformtest.kps b/windows/src/test/manual-tests/platform-rules/platformtest.kps index 60e493937f..bd90d84a31 100644 --- a/windows/src/test/manual-tests/platform-rules/platformtest.kps +++ b/windows/src/test/manual-tests/platform-rules/platformtest.kps @@ -36,7 +36,9 @@ PlatformTest platformtest 1.0 - + + English + -- GitLab From 62eba2012b718bed68780027792eab824e0a80a2 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 11 Jun 2018 15:19:53 +0700 Subject: [PATCH 215/356] Fixes #974. Platform statement no longer sneakily does version tests. --- windows/src/engine/keyman32/kmprocess.cpp | 40 +++-------------------- 1 file changed, 5 insertions(+), 35 deletions(-) diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index f79b44b5f8..5123fabc0e 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -579,44 +579,14 @@ BOOL IsMatchingBaseLayout(PWCHAR layoutName) // I3432 return bEqual; } -#pragma warning(disable: 4996) BOOL IsMatchingPlatformString(PWCHAR platform) // I3432 { - if(_wcsicmp(platform, L"windows") == 0 || - _wcsicmp(platform, L"desktop") == 0 || - _wcsicmp(platform, L"hardware") == 0 || - _wcsicmp(platform, L"native") == 0) return TRUE; - - PWCHAR t = wcschr(platform, 0) - 1; - BOOL OrNewer = (t > platform && *t == L'+'); - if(OrNewer) *t = 0; - - // Note: these version number checks are not officially supported - // and won't work with recent versions of Windows anyway... - WORD version; - if(_wcsicmp(platform, L"xp") == 0) version = 0x0105; - else if(_wcsicmp(platform, L"vista") == 0) version = 0x0006; - else if(_wcsicmp(platform, L"seven") == 0) version = 0x0106; - else if(_wcsicmp(platform, L"eight") == 0) version = 0x0206; - else if(_wcsicmp(platform, L"2000") == 0) version = 0x0005; - else if(_wcsicmp(platform, L"2003") == 0) version = 0x0205; - else if(_wcsicmp(platform, L"2008") == 0) version = 0x0006; - else if(_wcsicmp(platform, L"2008r2") == 0) version = 0x0106; - else if(_wcsicmp(platform, L"2012") == 0) version = 0x0206; - - else if(_wcsicmp(platform, L"5.0") == 0) version = 0x0005; - else if(_wcsicmp(platform, L"5.1") == 0) version = 0x0105; - else if(_wcsicmp(platform, L"5.2") == 0) version = 0x0205; - else if(_wcsicmp(platform, L"6.0") == 0) version = 0x0006; - else if(_wcsicmp(platform, L"6.1") == 0) version = 0x0106; - else if(_wcsicmp(platform, L"6.2") == 0) version = 0x0206; - - else return FALSE; - - return - OrNewer ? LOWORD(GetVersion()) >= version : LOWORD(GetVersion()) == version; + return + _wcsicmp(platform, L"windows") == 0 || + _wcsicmp(platform, L"desktop") == 0 || + _wcsicmp(platform, L"hardware") == 0 || + _wcsicmp(platform, L"native") == 0; } -#pragma warning(default: 4996) BOOL IsMatchingPlatform(LPSTORE s) // I3432 { -- GitLab From 19cfa165cc5f078049b4d7cf7ea170e826d48c17 Mon Sep 17 00:00:00 2001 From: glasseyes Date: Mon, 11 Jun 2018 16:30:46 +0700 Subject: [PATCH 216/356] copyright statements --- linux/kmflcomp/include/kmfl.h | 2 +- linux/kmflcomp/include/kmflcomp.h | 2 +- linux/kmflcomp/src/compiler.h | 2 +- linux/kmflcomp/src/kmflcomp.c | 2 +- linux/kmflcomp/src/memman.c | 2 +- linux/kmflcomp/src/memman.h | 2 +- linux/libkmfl/include/libkmfl.h | 2 +- linux/libkmfl/src/kmfl_interpreter.c | 2 +- linux/libkmfl/src/kmfl_load_keyboard.c | 2 +- linux/libkmfl/src/kmfl_messages.c | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/linux/kmflcomp/include/kmfl.h b/linux/kmflcomp/include/kmfl.h index 85e655819b..6846332133 100644 --- a/linux/kmflcomp/include/kmfl.h +++ b/linux/kmflcomp/include/kmfl.h @@ -1,5 +1,5 @@ /* kmfl.h - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd + * Copyright (C) 2005 SIL International * * This file is part of the KMFL compiler. * diff --git a/linux/kmflcomp/include/kmflcomp.h b/linux/kmflcomp/include/kmflcomp.h index b15d578342..8e6c4e61a8 100644 --- a/linux/kmflcomp/include/kmflcomp.h +++ b/linux/kmflcomp/include/kmflcomp.h @@ -1,5 +1,5 @@ /* kmflcomp.h - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd + * Copyright (C) 2005 SIL International * * This file is part of the KMFL compiler. * diff --git a/linux/kmflcomp/src/compiler.h b/linux/kmflcomp/src/compiler.h index c90a2d2a0e..5272b875bd 100644 --- a/linux/kmflcomp/src/compiler.h +++ b/linux/kmflcomp/src/compiler.h @@ -1,5 +1,5 @@ /* compiler.h - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd + * Copyright (C) 2005 SIL International * */ diff --git a/linux/kmflcomp/src/kmflcomp.c b/linux/kmflcomp/src/kmflcomp.c index 17c7876d67..b6ba93c160 100644 --- a/linux/kmflcomp/src/kmflcomp.c +++ b/linux/kmflcomp/src/kmflcomp.c @@ -1,5 +1,5 @@ /* kmflcomp.c - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd + * Copyright (C) 2005 SIL International * */ diff --git a/linux/kmflcomp/src/memman.c b/linux/kmflcomp/src/memman.c index 213b4f4421..c3fc9d3ab3 100644 --- a/linux/kmflcomp/src/memman.c +++ b/linux/kmflcomp/src/memman.c @@ -1,5 +1,5 @@ /* memman.c - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd + * Copyright (C) 2005 SIL International * */ diff --git a/linux/kmflcomp/src/memman.h b/linux/kmflcomp/src/memman.h index 1560b6b44a..47dc80448a 100644 --- a/linux/kmflcomp/src/memman.h +++ b/linux/kmflcomp/src/memman.h @@ -1,5 +1,5 @@ /* memman.h - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd + * Copyright (C) 2005 SIL International * */ diff --git a/linux/libkmfl/include/libkmfl.h b/linux/libkmfl/include/libkmfl.h index 4183311508..cb0a83c272 100644 --- a/linux/libkmfl/include/libkmfl.h +++ b/linux/libkmfl/include/libkmfl.h @@ -1,5 +1,5 @@ /* libkmfl.h - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd + * Copyright (C) 2005 SIL International * * This file is part of the KMFL library. * diff --git a/linux/libkmfl/src/kmfl_interpreter.c b/linux/libkmfl/src/kmfl_interpreter.c index 7236a545aa..57e8aa69f0 100644 --- a/linux/libkmfl/src/kmfl_interpreter.c +++ b/linux/libkmfl/src/kmfl_interpreter.c @@ -1,5 +1,5 @@ /* 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. * diff --git a/linux/libkmfl/src/kmfl_load_keyboard.c b/linux/libkmfl/src/kmfl_load_keyboard.c index 9cc81a4a73..d9bb670f3e 100644 --- a/linux/libkmfl/src/kmfl_load_keyboard.c +++ b/linux/libkmfl/src/kmfl_load_keyboard.c @@ -1,5 +1,5 @@ /* kmfl_load_keyboard.c - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd + * 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 6b58268e5c..033c86613c 100644 --- a/linux/libkmfl/src/kmfl_messages.c +++ b/linux/libkmfl/src/kmfl_messages.c @@ -1,5 +1,5 @@ /* kmfl_messages.c - * Copyright (C) 2005 SIL International and Tavultesoft Pty Ltd + * Copyright (C) 2005 SIL International * * This file is part of the KMFL library. * -- GitLab From 42804bf63a9560df98f2fea45422ed403c390df3 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 11 Jun 2018 21:44:12 +0700 Subject: [PATCH 217/356] Fix missing Edge browser test --- web/source/kmwcallback.ts | 1 + .../platform-rules/platformtest.js | 170 +++++++++--------- .../platform-rules/platformtest.kmn | 4 +- .../platform-rules/platformtest.kmx | Bin 6304 -> 6436 bytes 4 files changed, 94 insertions(+), 81 deletions(-) diff --git a/web/source/kmwcallback.ts b/web/source/kmwcallback.ts index 07acd4a4c2..cfa5be1775 100644 --- a/web/source/kmwcallback.ts +++ b/web/source/kmwcallback.ts @@ -1144,6 +1144,7 @@ namespace com.keyman { case 'chrome': case 'firefox': case 'safari': + case 'edge': case 'opera': if(this.keymanweb.util.device.browser != constraint) { result=false; diff --git a/windows/src/test/manual-tests/platform-rules/platformtest.js b/windows/src/test/manual-tests/platform-rules/platformtest.js index 59fd09dcf4..6089e8ceb0 100644 --- a/windows/src/test/manual-tests/platform-rules/platformtest.js +++ b/windows/src/test/manual-tests/platform-rules/platformtest.js @@ -26,43 +26,45 @@ function Keyboard_platformtest() this.s34="web"; this.s37="ie"; this.s38="chrome"; - this.s39="firefox"; - this.s40="safari"; - this.s41="opera"; - this.s44="touch"; - this.s45="hardware"; - this.s48="platform-x"; - this.s51="WinDOWS"; - this.s52="ANDroid"; - this.s53="iOS"; - this.s54="macOSX"; - this.s55="LINUX"; - this.s57="touch"; - this.s58="hardware"; - this.s59="windows"; - this.s60="android"; - this.s61="ios"; - this.s62="macosx"; - this.s63="linux"; - this.s64="desktop"; - this.s65="tablet"; - this.s66="phone"; - this.s67="native"; - this.s68="web"; - this.s69="ie"; - this.s70="chrome"; - this.s71="firefox"; - this.s72="safari"; - this.s73="opera"; - this.s74="touch"; - this.s75="hardware"; - this.s76="platform-x"; - this.s77="WinDOWS"; - this.s78="ANDroid"; - this.s79="iOS"; - this.s80="macOSX"; - this.s81="LINUX"; - this.KVER="10.0.1104.0"; + 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="edge"; + this.s63="ios"; + this.s64="macosx"; + this.s65="linux"; + this.s66="desktop"; + this.s67="tablet"; + this.s68="phone"; + this.s69="native"; + this.s70="web"; + this.s71="ie"; + this.s72="chrome"; + 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.700.0"; this.gs=function(t,e) { return this.g_main(t,e); }; @@ -190,13 +192,17 @@ function Keyboard_platformtest() } else if(k.KIFS(31,this.s39,t)) { // Line 46 m=1; - k.KO(0,t," firefox"); + k.KO(0,t," edge"); } else if(k.KIFS(31,this.s40,t)) { // Line 47 m=1; - k.KO(0,t," safari"); + k.KO(0,t," firefox"); } else if(k.KIFS(31,this.s41,t)) { // Line 48 + m=1; + k.KO(0,t," safari"); + } + else if(k.KIFS(31,this.s42,t)) { // Line 49 m=1; k.KO(0,t," opera"); } @@ -213,11 +219,11 @@ function Keyboard_platformtest() }; this.g_inverted=function(t,e) { var k=KeymanWeb,r=1,m=0; - if(!k.KIFS(31,this.s44,t)) { // Line 54 + if(!k.KIFS(31,this.s45,t)) { // Line 55 m=1; k.KO(0,t," !touch"); } - else if(!k.KIFS(31,this.s45,t)) { // Line 55 + else if(!k.KIFS(31,this.s46,t)) { // Line 56 m=1; k.KO(0,t," !hardware"); } @@ -234,7 +240,7 @@ function Keyboard_platformtest() }; this.g_unknown=function(t,e) { var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s48,t)) { // Line 61 + if(k.KIFS(31,this.s49,t)) { // Line 62 m=1; k.KO(0,t," platform-x"); } @@ -251,23 +257,23 @@ function Keyboard_platformtest() }; this.g_case_sensitive=function(t,e) { var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s51,t)) { // Line 67 + if(k.KIFS(31,this.s52,t)) { // Line 68 m=1; k.KO(0,t," windows"); } - else if(k.KIFS(31,this.s52,t)) { // Line 68 + else if(k.KIFS(31,this.s53,t)) { // Line 69 m=1; k.KO(0,t," android"); } - else if(k.KIFS(31,this.s53,t)) { // Line 69 + else if(k.KIFS(31,this.s54,t)) { // Line 70 m=1; k.KO(0,t," ios"); } - else if(k.KIFS(31,this.s54,t)) { // Line 70 + else if(k.KIFS(31,this.s55,t)) { // Line 71 m=1; k.KO(0,t," macosx"); } - else if(k.KIFS(31,this.s55,t)) { // Line 71 + else if(k.KIFS(31,this.s56,t)) { // Line 72 m=1; k.KO(0,t," linux"); } @@ -279,135 +285,139 @@ function Keyboard_platformtest() }; this.g_old_main=function(t,e) { var k=KeymanWeb,r=0,m=0; - if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s77,t)) { // Line 130 + if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s79,t)) { // Line 132 r=m=1; k.KO(0,t," Windows"); } - else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s78,t)) { // Line 131 + else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s80,t)) { // Line 133 r=m=1; k.KO(0,t," Android"); } - else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s79,t)) { // Line 132 + else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s81,t)) { // Line 134 r=m=1; k.KO(0,t," iOS"); } - else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s80,t)) { // Line 133 + else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s82,t)) { // Line 135 r=m=1; k.KO(0,t," macOS"); } - else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s81,t)) { // Line 134 + else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s83,t)) { // Line 136 r=m=1; k.KO(0,t," Linux"); } - else if(k.KKM(e, 0x4000, 0x45)) { // Line 135 + else if(k.KKM(e, 0x4000, 0x45)) { // Line 137 r=m=1; k.KO(0,t," [OS Undefined (case insensitive test)]"); } - else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s64,t)) { // Line 97 + else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s66,t)) { // Line 99 r=m=1; k.KO(0,t," Desktop"); } - else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s65,t)) { // Line 98 + else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s67,t)) { // Line 100 r=m=1; k.KO(0,t," Tablet"); } - else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s66,t)) { // Line 99 + else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s68,t)) { // Line 101 r=m=1; k.KO(0,t," Phone"); } - else if(k.KKM(e, 0x4000, 0x49)) { // Line 100 + else if(k.KKM(e, 0x4000, 0x49)) { // Line 102 r=m=1; k.KO(0,t," [FF Undefined]"); } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s59,t)) { // Line 88 + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s60,t)) { // Line 89 r=m=1; k.KO(0,t," Windows"); } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s60,t)) { // Line 89 + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s61,t)) { // Line 90 r=m=1; k.KO(0,t," Android"); } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s61,t)) { // Line 90 + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s62,t)) { // Line 91 + r=m=1; + k.KO(0,t," Edge"); + } + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s63,t)) { // Line 92 r=m=1; k.KO(0,t," iOS"); } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s62,t)) { // Line 91 + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s64,t)) { // Line 93 r=m=1; k.KO(0,t," OSX"); } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s63,t)) { // Line 92 + else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s65,t)) { // Line 94 r=m=1; k.KO(0,t," Linux"); } - else if(k.KKM(e, 0x4000, 0x4F)) { // Line 93 + else if(k.KKM(e, 0x4000, 0x4F)) { // Line 95 r=m=1; k.KO(0,t," [OS Undefined]"); } - else if(k.KKM(e, 0x4000, 0x50)&&k.KIFS(31,this.s57,t)) { // Line 82 + else if(k.KKM(e, 0x4000, 0x50)&&k.KIFS(31,this.s58,t)) { // Line 83 r=m=1; k.KO(0,t,"Touch"); } - else if(k.KKM(e, 0x4000, 0x50)&&k.KIFS(31,this.s58,t)) { // Line 83 + else if(k.KKM(e, 0x4000, 0x50)&&k.KIFS(31,this.s59,t)) { // Line 84 r=m=1; k.KO(0,t,"Hardware"); } - else if(k.KKM(e, 0x4000, 0x50)) { // Line 84 + else if(k.KKM(e, 0x4000, 0x50)) { // Line 85 r=m=1; k.KO(0,t,"[UI Undefined]"); } - else if(k.KKM(e, 0x4000, 0x52)&&k.KIFS(31,this.s76,t)) { // Line 125 + else if(k.KKM(e, 0x4000, 0x52)&&k.KIFS(31,this.s78,t)) { // Line 127 r=m=1; k.KO(0,t," Platform-X"); } - else if(k.KKM(e, 0x4000, 0x52)) { // Line 126 + else if(k.KKM(e, 0x4000, 0x52)) { // Line 128 r=m=1; k.KO(0,t," [Platform-X Undefined]"); } - else if(k.KKM(e, 0x4000, 0x54)&&!k.KIFS(31,this.s74,t)) { // Line 119 + else if(k.KKM(e, 0x4000, 0x54)&&!k.KIFS(31,this.s76,t)) { // Line 121 r=m=1; k.KO(0,t," !Touch"); } - else if(k.KKM(e, 0x4000, 0x54)&&!k.KIFS(31,this.s75,t)) { // Line 120 + else if(k.KKM(e, 0x4000, 0x54)&&!k.KIFS(31,this.s77,t)) { // Line 122 r=m=1; k.KO(0,t," !Hardware"); } - else if(k.KKM(e, 0x4000, 0x54)) { // Line 121 + else if(k.KKM(e, 0x4000, 0x54)) { // Line 123 r=m=1; k.KO(0,t," [Inverted OS Undefined]"); } - else if(k.KKM(e, 0x4000, 0x55)&&k.KIFS(31,this.s67,t)) { // Line 104 + else if(k.KKM(e, 0x4000, 0x55)&&k.KIFS(31,this.s69,t)) { // Line 106 r=m=1; k.KO(0,t," Native"); } - else if(k.KKM(e, 0x4000, 0x55)&&k.KIFS(31,this.s68,t)) { // Line 105 + else if(k.KKM(e, 0x4000, 0x55)&&k.KIFS(31,this.s70,t)) { // Line 107 r=m=1; k.KO(0,t," Web"); } - else if(k.KKM(e, 0x4000, 0x55)) { // Line 106 + else if(k.KKM(e, 0x4000, 0x55)) { // Line 108 r=m=1; k.KO(0,t," [Nativeness Undefined]"); } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s69,t)) { // Line 110 + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s71,t)) { // Line 112 r=m=1; k.KO(0,t," IE"); } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s70,t)) { // Line 111 + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s72,t)) { // Line 113 r=m=1; k.KO(0,t," Chrome"); } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s71,t)) { // Line 112 + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s73,t)) { // Line 114 r=m=1; k.KO(0,t," Firefox"); } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s72,t)) { // Line 113 + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s74,t)) { // Line 115 r=m=1; k.KO(0,t," Safari"); } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s73,t)) { // Line 114 + else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s75,t)) { // Line 116 r=m=1; k.KO(0,t," Opera"); } - else if(k.KKM(e, 0x4000, 0x59)) { // Line 115 + else if(k.KKM(e, 0x4000, 0x59)) { // Line 117 r=m=1; k.KO(0,t," [Browser Undefined]"); } diff --git a/windows/src/test/manual-tests/platform-rules/platformtest.kmn b/windows/src/test/manual-tests/platform-rules/platformtest.kmn index 21c775c35c..206a281e3b 100644 --- a/windows/src/test/manual-tests/platform-rules/platformtest.kmn +++ b/windows/src/test/manual-tests/platform-rules/platformtest.kmn @@ -42,7 +42,8 @@ match > use(browser) group(browser) c Test browser (should only return value on web) platform('ie') > ' ie' -platform('chrome') > ' chrome' +platform('chrome') > ' chrome' +platform('edge') > ' edge' platform('firefox') > ' firefox' platform('safari') > ' safari' platform('opera') > ' opera' @@ -87,6 +88,7 @@ c O: Operating system platform('windows') + [K_O] > ' Windows' platform('android') + [K_O] > ' Android' +platform('edge') + [K_O] > ' Edge' platform('ios') + [K_O] > ' iOS' platform('macosx') + [K_O] > ' OSX' platform('linux') + [K_O] > ' Linux' diff --git a/windows/src/test/manual-tests/platform-rules/platformtest.kmx b/windows/src/test/manual-tests/platform-rules/platformtest.kmx index db205d8d238aa62c4d355eb54ffca8280e9e9449..09a21353691476ec9d683b1f0017b58c24e4b72c 100644 GIT binary patch literal 6436 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 -- GitLab From 73bf690cfd9d93d5b7a466494e33060ba5ad5504 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 12 Jun 2018 09:55:46 +0700 Subject: [PATCH 218/356] Re-ran platform tests post beta release builds and documented --- .../platform-rules/platform-results.xlsx | Bin 22244 -> 20980 bytes .../platform-rules/platformtest.js | 2 +- .../platform-rules/platformtest.kmx | Bin 6436 -> 6440 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/src/test/manual-tests/platform-rules/platform-results.xlsx b/windows/src/test/manual-tests/platform-rules/platform-results.xlsx index bd0073f1daaa853e03a756db3acfffcb68f5dcee..f3e0eef1ab4ddd74ed1af955c8fcdd6041989fe4 100644 GIT binary patch delta 13620 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 CDObM$ delta 14887 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 Date: Tue, 12 Jun 2018 10:49:25 +0700 Subject: [PATCH 219/356] Update history --- android/history.md | 4 ++++ ios/history.md | 12 ++++++++++++ web/history.md | 6 ++++++ windows/src/desktop/history.md | 10 ++++++++++ windows/src/developer/history.md | 9 +++++++++ 5 files changed, 41 insertions(+) diff --git a/android/history.md b/android/history.md index 5d85fbec00..7a1c686ca9 100644 --- a/android/history.md +++ b/android/history.md @@ -1,5 +1,9 @@ # 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) diff --git a/ios/history.md b/ios/history.md index 6a3617a299..8157b4f6cc 100644 --- a/ios/history.md +++ b/ios/history.md @@ -1,5 +1,17 @@ # Keyman for iPhone and iPad Version History +## 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) diff --git a/web/history.md b/web/history.md index 4e0e5d9c33..a3b6473562 100644 --- a/web/history.md +++ b/web/history.md @@ -1,5 +1,11 @@ # KeymanWeb Version History +## 2018-06-11 10.0.93 beta +* Platform tests (in keyboards) are now consistent across all platforms (#969) + +## 2018-05-22 10.0.92 beta +* (Embedded) Fixes out-of-order key events in Keyman for iOS (does not affect web hosted keyboard) (#865) + ## 2018-05-09 10.0.91 beta * Fixes basic support for mnemonic keyboards. (#517) * At this time, all mnemonic keyboards will assume a US keyboard layout within KeymanWeb. diff --git a/windows/src/desktop/history.md b/windows/src/desktop/history.md index f60243a3dc..88e3dcfc2f 100644 --- a/windows/src/desktop/history.md +++ b/windows/src/desktop/history.md @@ -1,5 +1,15 @@ # Keyman Desktop Version History +## 2018-06-11 10.0.1105.0 beta +* Platform tests (in keyboards) are now consistent across all platforms (#969) + +## 2018-06-09 10.0.1104.0 beta +* Keyboards that have script subtags will now install on Windows 7 (#964) + +## 2018-06-07 10.0.1103.0 beta +* Keyman Configuration will now show keyboards that have no name with their filename (#955) +* Keyboard packages with BCP 47 language subtags unrecognised by Windows will now install on Windows 7 (#948) + ## 2018-06-05 10.0.1102.0 beta * Improved crash reporting stability (#940) diff --git a/windows/src/developer/history.md b/windows/src/developer/history.md index 44e0e14a5c..7180d0ae63 100644 --- a/windows/src/developer/history.md +++ b/windows/src/developer/history.md @@ -1,5 +1,14 @@ # Keyman Developer Version History +## 2018-06-11 10.0.1105.0 beta +* No changes to Keyman Developer + +## 2018-06-09 10.0.1104.0 beta +* No changes to Keyman Developer + +## 2018-06-07 10.0.1103.0 beta +* No changes to Keyman Developer + ## 2018-06-05 10.0.1102.0 beta * Improved crash reporting stability (#940) -- GitLab From 1a675063f749404d2fab65c429e7833b6fb8fdbb Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 12 Jun 2018 13:42:39 +0700 Subject: [PATCH 220/356] Build initial test case for #978 --- web/testing/test-updateLayer/index.html | 94 ++ web/testing/test-updateLayer/rac_balti.js | 1244 +++++++++++++++++++++ web/testing/test-updateLayer/utilities.js | 11 + 3 files changed, 1349 insertions(+) create mode 100644 web/testing/test-updateLayer/index.html create mode 100644 web/testing/test-updateLayer/rac_balti.js create mode 100644 web/testing/test-updateLayer/utilities.js diff --git a/web/testing/test-updateLayer/index.html b/web/testing/test-updateLayer/index.html new file mode 100644 index 0000000000..3fc530ef7a --- /dev/null +++ b/web/testing/test-updateLayer/index.html @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + KeymanWeb Shift Testing + + + + + + + + + + + + + + + + + + + + + +

KeymanWeb Sample Page - Shift Testing

+

See issue #978 for details on what this test + is all about.

+

Be sure to reference the developer console for additional feedback.

+ +
+
+ +
+

Type in your language in this text area:

+ + +

or in this input field:

+ +
+
+
+

Return to testing home page

+ + + + diff --git a/web/testing/test-updateLayer/rac_balti.js b/web/testing/test-updateLayer/rac_balti.js new file mode 100644 index 0000000000..538e1be131 --- /dev/null +++ b/web/testing/test-updateLayer/rac_balti.js @@ -0,0 +1,1244 @@ + +KeymanWeb.KR(new Keyboard_rac_balti()); + +function Keyboard_rac_balti() +{ + + this.KI="Keyboard_rac_balti"; + this.KN="Rachitrali-Balti"; + this.KMINVER="9.0"; + this.KV={F:' 1em "Scheherazade"',K102:1}; + this.KDU=0; + this.KV.KLS={ + "default": ["ڃ","۱","۲","۳","۴","۵","۶","۷","۸","۹","۰","-","=","","","","ق","و","ع","ر","ت","ے","ء","ی","ہ","پ","ڇ","ڗ","ݜ","","","","ا","س","د","ف","گ","ح","ج","ک","ل","؛","'","","","","","","\\","ز","ش","چ","ط","ب","ن","م","،","۔","/","","","","","",""], + "shift": ["ٸ","1","2","3","4","5","6","7","8","9","0","_","+","","",""," کٔ","ّ","ٰ","ڑ","ٹ","َ","ئ","ِ","ۃ","ُ","ݩ","\\","|","","","","آ","ص","ڈ","ݨ","غ","ھ","ض","خ","ٔ",":","\"","","","","","","|","ذ","ژ","ث","ظ","ً","ں","٬","<",">","؟","","","","","",""], + "ctrl-alt": ["","!","@","#","","%","","&","*","(",")","ْ","","","","","؂","ٖ","ؓ","ؔ","؁","ٔ","ؑ","","","","","","\\","","","","ﷲ","ؐ","ﷺ","","","ؒ","ﷻ","<",">","","","","","","","","","","؃","﷽","؀","","","","","|","/","","","","","",""] + }; + this.KV.BK=(function(x){ + var + empty=Array.apply(null, Array(65)).map(String.prototype.valueOf,""), + result=[], v, i, + modifiers=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt']; + for(i=modifiers.length-1;i>=0;i--) { + v = x[modifiers[i]]; + if(v || result.length > 0) { + result=(v ? v : empty).slice().concat(result); + } + } + return result; + })(this.KV.KLS); + this.KH=''; + this.KM=0; + this.KBVER="1.0"; + this.KMBM=0x0070; + this.KRTL=1; + this.KVKL={ + "tablet": { + "layer": [ + { + "id": "default", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_1", + "text": "۱" + }, + { + "id": "K_2", + "text": "۲" + }, + { + "id": "K_3", + "text": "۳" + }, + { + "id": "K_4", + "text": "۴" + }, + { + "id": "K_5", + "text": "۵" + }, + { + "id": "K_6", + "text": "۶" + }, + { + "id": "K_7", + "text": "۷" + }, + { + "id": "K_8", + "text": "۸" + }, + { + "id": "K_9", + "text": "۹" + }, + { + "id": "K_0", + "text": "۰" + }, + { + "id": "K_HYPHEN", + "text": "-" + }, + { + "id": "K_EQUAL", + "text": "=" + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "K_Q", + "text": "ق", + "pad": "" + }, + { + "id": "K_W", + "text": "و" + }, + { + "id": "K_E", + "text": "ع" + }, + { + "id": "K_R", + "text": "ر" + }, + { + "id": "K_T", + "text": "ت" + }, + { + "id": "K_Y", + "text": "ے" + }, + { + "id": "K_U", + "text": "ء" + }, + { + "id": "K_I", + "text": "ی" + }, + { + "id": "K_O", + "text": "ہ" + }, + { + "id": "K_P", + "text": "پ" + }, + { + "id": "K_LBRKT", + "text": "ڇ" + }, + { + "id": "K_RBRKT", + "text": "ڗ" + } + ] + }, + { + "id": 3, + "key": [ + { + "id": "K_BKQUOTE", + "text": "ڃ" + }, + { + "id": "K_A", + "text": "ا" + }, + { + "id": "K_S", + "text": "س" + }, + { + "id": "K_D", + "text": "د" + }, + { + "id": "K_F", + "text": "ف" + }, + { + "id": "K_G", + "text": "گ" + }, + { + "id": "K_H", + "text": "ح" + }, + { + "id": "K_J", + "text": "ج" + }, + { + "id": "K_K", + "text": "ک" + }, + { + "id": "K_L", + "text": "ل" + }, + { + "id": "K_COLON", + "text": "؛" + }, + { + "id": "K_QUOTE", + "text": "'" + } + ] + }, + { + "id": 4, + "key": [ + { + "id": "K_SHIFT", + "text": "*Shift*", + "width": "", + "sp": "1", + "nextlayer": "shift" + }, + { + "id": "K_Z", + "text": "ز" + }, + { + "id": "K_X", + "text": "ش" + }, + { + "id": "K_C", + "text": "چ" + }, + { + "id": "K_V", + "text": "ط" + }, + { + "id": "K_B", + "text": "ب" + }, + { + "id": "K_N", + "text": "ن" + }, + { + "id": "K_M", + "text": "م" + }, + { + "id": "K_COMMA", + "text": "،" + }, + { + "id": "K_PERIOD", + "text": "۔" + }, + { + "id": "K_BKSLASH", + "text": "ݜ" + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "width": "100", + "sp": "1" + } + ] + }, + { + "id": 5, + "key": [ + { + "id": "K_LCONTROL", + "text": "*Symbol*", + "width": "", + "sp": "1", + "nextlayer": "symbols" + }, + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "", + "sp": "1", + "nextlayer": "shift" + }, + { + "id": "K_SPACE", + "text": "", + "width": "930" + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "110", + "sp": "1" + } + ] + } + ] + }, + { + "id": "shift", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_1", + "text": "1" + }, + { + "id": "K_2", + "text": "2" + }, + { + "id": "K_3", + "text": "3" + }, + { + "id": "K_4", + "text": "4" + }, + { + "id": "K_5", + "text": "5" + }, + { + "id": "K_6", + "text": "6" + }, + { + "id": "K_7", + "text": "7" + }, + { + "id": "K_8", + "text": "8" + }, + { + "id": "K_9", + "text": "9" + }, + { + "id": "K_0", + "text": "0" + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "K_Q", + "text": "کٔ", + "pad": "" + }, + { + "id": "K_W", + "text": "ّ" + }, + { + "id": "K_E", + "text": "ٰ" + }, + { + "id": "K_R", + "text": "ڑ" + }, + { + "id": "K_T", + "text": "ٹ" + }, + { + "id": "K_Y", + "text": "َ" + }, + { + "id": "K_U", + "text": "ئ" + }, + { + "id": "K_I", + "text": "ِ" + }, + { + "id": "K_O", + "text": "ۃ" + }, + { + "id": "K_P", + "text": "ُ" + } + ] + }, + { + "id": 3, + "key": [ + { + "id": "K_BKQUOTE", + "text": "ٸ" + }, + { + "id": "K_A", + "text": "آ" + }, + { + "id": "K_S", + "text": "ص" + }, + { + "id": "K_D", + "text": "ڈ" + }, + { + "id": "K_F", + "text": "ݨ" + }, + { + "id": "K_G", + "text": "غ" + }, + { + "id": "K_H", + "text": "ھ" + }, + { + "id": "K_J", + "text": "ض" + }, + { + "id": "K_K", + "text": "خ" + }, + { + "id": "K_L", + "text": "ٔ" + } + ] + }, + { + "id": 4, + "key": [ + { + "id": "K_SHIFT", + "text": "*Shift*", + "width": "", + "sp": "1", + "nextlayer": "default" + }, + { + "id": "K_Z", + "text": "ذ" + }, + { + "id": "K_X", + "text": "ژ" + }, + { + "id": "K_C", + "text": "ث" + }, + { + "id": "K_V", + "text": "ظ" + }, + { + "id": "K_B", + "text": "ً" + }, + { + "id": "K_N", + "text": "ں" + }, + { + "id": "K_LBRKT", + "text": "ݩ" + }, + { + "id": "K_SLASH", + "text": "؟" + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "width": "100", + "sp": "1" + } + ] + }, + { + "id": 5, + "key": [ + { + "id": "K_LCONTROL", + "text": "*Symbol*", + "width": "", + "sp": "1", + "nextlayer": "symbols" + }, + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "", + "sp": "1" + }, + { + "id": "K_SPACE", + "text": "", + "width": "705" + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "125", + "sp": "1" + } + ] + } + ] + }, + { + "id": "symbols", + "row": [ + { + "id": 1, + "key": [ + { + "id": "U_0021", + "text": "!" + }, + { + "id": "U_0040", + "text": "@" + }, + { + "id": "U_0023", + "text": "#" + }, + { + "id": "U_0025", + "text": "%" + }, + { + "id": "U_0026", + "text": "&" + }, + { + "id": "U_002A", + "text": "*" + }, + { + "id": "U_0028", + "text": "(" + }, + { + "id": "U_0029", + "text": ")" + }, + { + "id": "U_005F", + "text": "_" + }, + { + "id": "U_002B", + "text": "+" + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "U_0602", + "text": "؂", + "pad": "" + }, + { + "id": "U_0656", + "text": "ٖ" + }, + { + "id": "U_0613", + "text": "ؓ" + }, + { + "id": "U_0614", + "text": "ؔ" + }, + { + "id": "U_0601", + "text": "؁" + }, + { + "id": "U_0654", + "text": "ٔ" + }, + { + "id": "U_0611", + "text": "ؑ" + }, + { + "id": "U_0652", + "text": "ْ" + }, + { + "id": "U_007B", + "text": "{" + }, + { + "id": "U_007D", + "text": "}" + } + ] + }, + { + "id": 3, + "key": [ + { + "id": "U_FDF2", + "text": "ﷲ" + }, + { + "id": "U_0610", + "text": "ؐ" + }, + { + "id": "U_0612", + "text": "ؒ" + }, + { + "id": "U_FDFB", + "text": "ﷻ" + }, + { + "id": "U_0603", + "text": "؃" + }, + { + "id": "U_FDFD", + "text": "﷽" + }, + { + "id": "U_FDFA", + "text": "ﷺ" + }, + { + "id": "U_0600", + "text": "؀" + }, + { + "id": "U_003C", + "text": "<" + }, + { + "id": "U_003E", + "text": ">" + } + ] + }, + { + "id": 4, + "key": [ + { + "id": "K_SHIFT", + "text": "*Shift*", + "width": "", + "sp": "1", + "nextlayer": "shift" + }, + { + "id": "U_003A", + "text": ":" + }, + { + "id": "U_0022", + "text": "\"" + }, + { + "id": "U_002F", + "text": "/" + }, + { + "id": "U_007C", + "text": "|" + }, + { + "id": "U_005C", + "text": "\\" + }, + { + "id": "U_002C", + "text": "," + }, + { + "id": "U_005B", + "text": "[" + }, + { + "id": "U_005D", + "text": "]" + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "width": "", + "sp": "1" + } + ] + }, + { + "id": 5, + "key": [ + { + "id": "K_LCONTROL", + "text": "*abc*", + "width": "", + "sp": "1", + "nextlayer": "default" + }, + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "", + "sp": "1" + }, + { + "id": "K_SPACE", + "text": "", + "pad": "", + "width": "705" + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "125", + "sp": "1" + } + ] + } + ] + } + ] + } +} +; + this.KVER="10.0.1105.0"; + this.gs=function(t,e) { + return this.g_main(t,e); + }; + this.g_main=function(t,e) { + var k=KeymanWeb,r=0,m=0; + if(k.KKM(e, 0x4000, 0xE2)) { // Line 32 + r=m=1; + k.KO(0,t,"\\"); + } + else if(k.KKM(e, 0x4010, 0xE2)) { // Line 99 + r=m=1; + k.KO(0,t,"|"); + } + else if(k.KKM(e, 0x4010, 0x31)) { // Line 126 + r=m=1; + k.KO(0,t,"1"); + } + else if(k.KKM(e, 0x4010, 0xDE)) { // Line 100 + r=m=1; + k.KO(0,t,"\""); + } + else if(k.KKM(e, 0x4010, 0x33)) { // Line 124 + r=m=1; + k.KO(0,t,"3"); + } + else if(k.KKM(e, 0x4010, 0x34)) { // Line 123 + r=m=1; + k.KO(0,t,"4"); + } + else if(k.KKM(e, 0x4010, 0x35)) { // Line 122 + r=m=1; + k.KO(0,t,"5"); + } + else if(k.KKM(e, 0x4010, 0x37)) { // Line 120 + r=m=1; + k.KO(0,t,"7"); + } + else if(k.KKM(e, 0x4000, 0xDE)) { // Line 51 + r=m=1; + k.KO(0,t,"'"); + } + else if(k.KKM(e, 0x4010, 0x39)) { // Line 118 + r=m=1; + k.KO(0,t,"9"); + } + else if(k.KKM(e, 0x4010, 0x30)) { // Line 117 + r=m=1; + k.KO(0,t,"0"); + } + else if(k.KKM(e, 0x4010, 0x38)) { // Line 119 + r=m=1; + k.KO(0,t,"8"); + } + else if(k.KKM(e, 0x4010, 0xBB)) { // Line 115 + r=m=1; + k.KO(0,t,"+"); + } + else if(k.KKM(e, 0x4000, 0xBC)) { // Line 43 + r=m=1; + k.KO(0,t,"،"); + } + else if(k.KKM(e, 0x4060, 0xBD)) { // Line 36 + r=m=1; + k.KO(0,t,"ْ"); + } + else if(k.KKM(e, 0x4000, 0xBD)) { // Line 74 + r=m=1; + k.KO(0,t,"-"); + } + else if(k.KKM(e, 0x4060, 0xBE)) { // Line 24 + r=m=1; + k.KO(0,t,"|"); + } + else if(k.KKM(e, 0x4000, 0xBE)) { // Line 42 + r=m=1; + k.KO(0,t,"۔"); + } + else if(k.KKM(e, 0x4060, 0xBF)) { // Line 25 + r=m=1; + k.KO(0,t,"/"); + } + else if(k.KKM(e, 0x4000, 0xBF)) { // Line 40 + r=m=1; + k.KO(0,t,"/"); + } + else if(k.KKM(e, 0x4000, 0x30)) { // Line 75 + r=m=1; + k.KO(0,t,"۰"); + } + else if(k.KKM(e, 0x4060, 0x30)) { // Line 143 + r=m=1; + k.KO(0,t,")"); + } + else if(k.KKM(e, 0x4000, 0x31)) { // Line 84 + r=m=1; + k.KO(0,t,"۱"); + } + else if(k.KKM(e, 0x4060, 0x31)) { // Line 150 + r=m=1; + k.KO(0,t,"!"); + } + else if(k.KKM(e, 0x4000, 0x32)) { // Line 83 + r=m=1; + k.KO(0,t,"۲"); + } + else if(k.KKM(e, 0x4060, 0x32)) { // Line 149 + r=m=1; + k.KO(0,t,"@"); + } + else if(k.KKM(e, 0x4000, 0x33)) { // Line 82 + r=m=1; + k.KO(0,t,"۳"); + } + else if(k.KKM(e, 0x4060, 0x33)) { // Line 148 + r=m=1; + k.KO(0,t,"#"); + } + else if(k.KKM(e, 0x4000, 0x34)) { // Line 81 + r=m=1; + k.KO(0,t,"۴"); + } + else if(k.KKM(e, 0x4000, 0x35)) { // Line 80 + r=m=1; + k.KO(0,t,"۵"); + } + else if(k.KKM(e, 0x4060, 0x35)) { // Line 147 + r=m=1; + k.KO(0,t,"%"); + } + else if(k.KKM(e, 0x4000, 0x36)) { // Line 79 + r=m=1; + k.KO(0,t,"۶"); + } + else if(k.KKM(e, 0x4000, 0x37)) { // Line 78 + r=m=1; + k.KO(0,t,"۷"); + } + else if(k.KKM(e, 0x4060, 0x37)) { // Line 146 + r=m=1; + k.KO(0,t,"&"); + } + else if(k.KKM(e, 0x4000, 0x38)) { // Line 77 + r=m=1; + k.KO(0,t,"۸"); + } + else if(k.KKM(e, 0x4060, 0x38)) { // Line 145 + r=m=1; + k.KO(0,t,"*"); + } + else if(k.KKM(e, 0x4000, 0x39)) { // Line 76 + r=m=1; + k.KO(0,t,"۹"); + } + else if(k.KKM(e, 0x4060, 0x39)) { // Line 144 + r=m=1; + k.KO(0,t,"("); + } + else if(k.KKM(e, 0x4010, 0xBA)) { // Line 101 + r=m=1; + k.KO(0,t,":"); + } + else if(k.KKM(e, 0x4000, 0xBA)) { // Line 52 + r=m=1; + k.KO(0,t,"؛"); + } + else if(k.KKM(e, 0x4010, 0xBC)) { // Line 91 + r=m=1; + k.KO(0,t,"<"); + } + else if(k.KKM(e, 0x4000, 0xBB)) { // Line 73 + r=m=1; + k.KO(0,t,"="); + } + else if(k.KKM(e, 0x4010, 0xBE)) { // Line 37 + r=m=1; + k.KO(0,t,">"); + } + else if(k.KKM(e, 0x4010, 0xBF)) { // Line 88 + r=m=1; + k.KO(0,t,"؟"); + } + else if(k.KKM(e, 0x4010, 0x32)) { // Line 125 + r=m=1; + k.KO(0,t,"2"); + } + else if(k.KKM(e, 0x4010, 0x41)) { // Line 107 + r=m=1; + k.KO(0,t,"آ"); + } + else if(k.KKM(e, 0x4010, 0x42)) { // Line 94 + r=m=1; + k.KO(0,t,"ً"); + } + else if(k.KKM(e, 0x4010, 0x43)) { // Line 96 + r=m=1; + k.KO(0,t,"ث"); + } + else if(k.KKM(e, 0x4010, 0x44)) { // Line 105 + r=m=1; + k.KO(0,t,"ڈ"); + } + else if(k.KKM(e, 0x4010, 0x45)) { // Line 114 + r=m=1; + k.KO(0,t,"ٰ"); + } + else if(k.KKM(e, 0x4010, 0x46)) { // Line 30 + r=m=1; + k.KO(0,t,"ݨ"); + } + else if(k.KKM(e, 0x4010, 0x47)) { // Line 89 + r=m=1; + k.KO(0,t,"غ"); + } + else if(k.KKM(e, 0x4010, 0x48)) { // Line 104 + r=m=1; + k.KO(0,t,"ھ"); + } + else if(k.KKM(e, 0x4010, 0x49)) { // Line 111 + r=m=1; + k.KO(0,t,"ِ"); + } + else if(k.KKM(e, 0x4010, 0x4A)) { // Line 103 + r=m=1; + k.KO(0,t,"ض"); + } + else if(k.KKM(e, 0x4010, 0x4B)) { // Line 102 + r=m=1; + k.KO(0,t,"خ"); + } + else if(k.KKM(e, 0x4010, 0x4C)) { // Line 22 + r=m=1; + k.KO(0,t,"ٔ"); + } + else if(k.KKM(e, 0x4010, 0x4D)) { // Line 92 + r=m=1; + k.KO(0,t,"٬"); + } + else if(k.KKM(e, 0x4010, 0x4E)) { // Line 93 + r=m=1; + k.KO(0,t,"ں"); + } + else if(k.KKM(e, 0x4010, 0x4F)) { // Line 110 + r=m=1; + k.KO(0,t,"ۃ"); + } + else if(k.KKM(e, 0x4010, 0x50)) { // Line 109 + r=m=1; + k.KO(0,t,"ُ"); + } + else if(k.KKM(e, 0x4010, 0x51)) { // Line 23 + r=m=1; + k.KO(0,t,"کٔ"); + } + else if(k.KKM(e, 0x4010, 0x52)) { // Line 39 + r=m=1; + k.KO(0,t,"ڑ"); + } + else if(k.KKM(e, 0x4010, 0x53)) { // Line 106 + r=m=1; + k.KO(0,t,"ص"); + } + else if(k.KKM(e, 0x4010, 0x54)) { // Line 113 + r=m=1; + k.KO(0,t,"ٹ"); + } + else if(k.KKM(e, 0x4010, 0x55)) { // Line 112 + r=m=1; + k.KO(0,t,"ئ"); + } + else if(k.KKM(e, 0x4010, 0x56)) { // Line 95 + r=m=1; + k.KO(0,t,"ظ"); + } + else if(k.KKM(e, 0x4010, 0x57)) { // Line 26 + r=m=1; + k.KO(0,t,"ّ"); + } + else if(k.KKM(e, 0x4010, 0x58)) { // Line 97 + r=m=1; + k.KO(0,t,"ژ"); + } + else if(k.KKM(e, 0x4010, 0x59)) { // Line 38 + r=m=1; + k.KO(0,t,"َ"); + } + else if(k.KKM(e, 0x4010, 0x5A)) { // Line 98 + r=m=1; + k.KO(0,t,"ذ"); + } + else if(k.KKM(e, 0x4000, 0xDB)) { // Line 63 + r=m=1; + k.KO(0,t,"ڇ"); + } + else if(k.KKM(e, 0x4060, 0xDC)) { // Line 35 + r=m=1; + k.KO(0,t,"\\"); + } + else if(k.KKM(e, 0x4000, 0xDC)) { // Line 41 + r=m=1; + k.KO(0,t,"ݜ"); + } + else if(k.KKM(e, 0x4000, 0xDD)) { // Line 62 + r=m=1; + k.KO(0,t,"ڗ"); + } + else if(k.KKM(e, 0x4010, 0x36)) { // Line 121 + r=m=1; + k.KO(0,t,"6"); + } + else if(k.KKM(e, 0x4010, 0xBD)) { // Line 116 + r=m=1; + k.KO(0,t,"_"); + } + else if(k.KKM(e, 0x4000, 0xC0)) { // Line 85 + r=m=1; + k.KO(0,t,"ڃ"); + } + else if(k.KKM(e, 0x4000, 0x41)) { // Line 61 + r=m=1; + k.KO(0,t,"ا"); + } + else if(k.KKM(e, 0x4060, 0x41)) { // Line 136 + r=m=1; + k.KO(0,t,"ﷲ"); + } + else if(k.KKM(e, 0x4000, 0x42)) { // Line 46 + r=m=1; + k.KO(0,t,"ب"); + } + else if(k.KKM(e, 0x4000, 0x43)) { // Line 48 + r=m=1; + k.KO(0,t,"چ"); + } + else if(k.KKM(e, 0x4060, 0x43)) { // Line 131 + r=m=1; + k.KO(0,t,"﷽"); + } + else if(k.KKM(e, 0x4060, 0x44)) { // Line 34 + r=m=1; + k.KO(0,t,"ﷺ"); + } + else if(k.KKM(e, 0x4000, 0x44)) { // Line 59 + r=m=1; + k.KO(0,t,"د"); + } + else if(k.KKM(e, 0x4000, 0x45)) { // Line 70 + r=m=1; + k.KO(0,t,"ع"); + } + else if(k.KKM(e, 0x4060, 0x45)) { // Line 141 + r=m=1; + k.KO(0,t,"ؓ"); + } + else if(k.KKM(e, 0x4000, 0x46)) { // Line 58 + r=m=1; + k.KO(0,t,"ف"); + } + else if(k.KKM(e, 0x4000, 0x47)) { // Line 57 + r=m=1; + k.KO(0,t,"گ"); + } + else if(k.KKM(e, 0x4000, 0x48)) { // Line 56 + r=m=1; + k.KO(0,t,"ح"); + } + else if(k.KKM(e, 0x4060, 0x48)) { // Line 134 + r=m=1; + k.KO(0,t,"ؒ"); + } + else if(k.KKM(e, 0x4000, 0x49)) { // Line 66 + r=m=1; + k.KO(0,t,"ی"); + } + else if(k.KKM(e, 0x4000, 0x4A)) { // Line 55 + r=m=1; + k.KO(0,t,"ج"); + } + else if(k.KKM(e, 0x4060, 0x4A)) { // Line 133 + r=m=1; + k.KO(0,t,"ﷻ"); + } + else if(k.KKM(e, 0x4060, 0x4B)) { // Line 28 + r=m=1; + k.KO(0,t,"<"); + } + else if(k.KKM(e, 0x4000, 0x4B)) { // Line 54 + r=m=1; + k.KO(0,t,"ک"); + } + else if(k.KKM(e, 0x4060, 0x4C)) { // Line 27 + r=m=1; + k.KO(0,t,">"); + } + else if(k.KKM(e, 0x4000, 0x4C)) { // Line 53 + r=m=1; + k.KO(0,t,"ل"); + } + else if(k.KKM(e, 0x4000, 0x4D)) { // Line 44 + r=m=1; + k.KO(0,t,"م"); + } + else if(k.KKM(e, 0x4000, 0x4E)) { // Line 45 + r=m=1; + k.KO(0,t,"ن"); + } + else if(k.KKM(e, 0x4000, 0x4F)) { // Line 65 + r=m=1; + k.KO(0,t,"ہ"); + } + else if(k.KKM(e, 0x4000, 0x50)) { // Line 64 + r=m=1; + k.KO(0,t,"پ"); + } + else if(k.KKM(e, 0x4000, 0x51)) { // Line 72 + r=m=1; + k.KO(0,t,"ق"); + } + else if(k.KKM(e, 0x4060, 0x51)) { // Line 142 + r=m=1; + k.KO(0,t,"؂"); + } + else if(k.KKM(e, 0x4000, 0x52)) { // Line 69 + r=m=1; + k.KO(0,t,"ر"); + } + else if(k.KKM(e, 0x4060, 0x52)) { // Line 140 + r=m=1; + k.KO(0,t,"ؔ"); + } + else if(k.KKM(e, 0x4000, 0x53)) { // Line 60 + r=m=1; + k.KO(0,t,"س"); + } + else if(k.KKM(e, 0x4060, 0x53)) { // Line 135 + r=m=1; + k.KO(0,t,"ؐ"); + } + else if(k.KKM(e, 0x4000, 0x54)) { // Line 68 + r=m=1; + k.KO(0,t,"ت"); + } + else if(k.KKM(e, 0x4060, 0x54)) { // Line 139 + r=m=1; + k.KO(0,t,"؁"); + } + else if(k.KKM(e, 0x4000, 0x55)) { // Line 33 + r=m=1; + k.KO(0,t,"ء"); + } + else if(k.KKM(e, 0x4060, 0x55)) { // Line 137 + r=m=1; + k.KO(0,t,"ؑ"); + } + else if(k.KKM(e, 0x4000, 0x56)) { // Line 47 + r=m=1; + k.KO(0,t,"ط"); + } + else if(k.KKM(e, 0x4060, 0x56)) { // Line 130 + r=m=1; + k.KO(0,t,"؀"); + } + else if(k.KKM(e, 0x4000, 0x57)) { // Line 71 + r=m=1; + k.KO(0,t,"و"); + } + else if(k.KKM(e, 0x4060, 0x57)) { // Line 129 + r=m=1; + k.KO(0,t,"ٖ"); + } + else if(k.KKM(e, 0x4000, 0x58)) { // Line 49 + r=m=1; + k.KO(0,t,"ش"); + } + else if(k.KKM(e, 0x4060, 0x58)) { // Line 132 + r=m=1; + k.KO(0,t,"؃"); + } + else if(k.KKM(e, 0x4000, 0x59)) { // Line 67 + r=m=1; + k.KO(0,t,"ے"); + } + else if(k.KKM(e, 0x4060, 0x59)) { // Line 138 + r=m=1; + k.KO(0,t,"ٔ"); + } + else if(k.KKM(e, 0x4000, 0x5A)) { // Line 50 + r=m=1; + k.KO(0,t,"ز"); + } + else if(k.KKM(e, 0x4010, 0xDB)) { // Line 31 + r=m=1; + k.KO(0,t,"ݩ"); + } + else if(k.KKM(e, 0x4010, 0xDC)) { // Line 29 + r=m=1; + k.KO(0,t,"|"); + } + else if(k.KKM(e, 0x4010, 0xDD)) { // Line 108 + r=m=1; + k.KO(0,t,"\\"); + } + else if(k.KKM(e, 0x4010, 0xC0)) { // Line 90 + r=m=1; + k.KO(0,t,"ٸ"); + } + return r; + }; +} diff --git a/web/testing/test-updateLayer/utilities.js b/web/testing/test-updateLayer/utilities.js new file mode 100644 index 0000000000..41704fa0da --- /dev/null +++ b/web/testing/test-updateLayer/utilities.js @@ -0,0 +1,11 @@ +function loadKeyboards() +{ + var kmw=keyman; + + kmw.addKeyboards({id:'rac_balti',name:'RAC Balti', + languages:{ + id:'en',name:'English',region:'North America' + }, + filename:'rac_balti.js' + }); +} \ No newline at end of file -- GitLab From 3d4697dea205b04cb51e9bb8c907e5554fe56995 Mon Sep 17 00:00:00 2001 From: darcywong00 Date: Tue, 12 Jun 2018 15:14:27 +0700 Subject: [PATCH 221/356] Update to Unicode 11.0 Fixes #976 Update to Unicode 11.0 characters from ftp://ftp.unicode.org/Public/11.0.0/ucd --- .../unicode-character-database/Blocks.txt | 15 +- .../UnicodeData.txt | 778 ++++++++++++++++-- 2 files changed, 739 insertions(+), 54 deletions(-) diff --git a/resources/standards-data/unicode-character-database/Blocks.txt b/resources/standards-data/unicode-character-database/Blocks.txt index a4f851b14a..357982078a 100644 --- a/resources/standards-data/unicode-character-database/Blocks.txt +++ b/resources/standards-data/unicode-character-database/Blocks.txt @@ -1,5 +1,5 @@ -# Blocks-10.0.0.txt -# Date: 2017-04-12, 17:30:00 GMT [KW] +# Blocks-11.0.0.txt +# Date: 2017-10-16, 24:39:00 GMT [KW] # © 2017 Unicode®, Inc. # For terms of use, see http://www.unicode.org/terms_of_use.html # @@ -95,6 +95,7 @@ 1C00..1C4F; Lepcha 1C50..1C7F; Ol Chiki 1C80..1C8F; Cyrillic Extended-C +1C90..1CBF; Georgian Extended 1CC0..1CCF; Sundanese Supplement 1CD0..1CFF; Vedic Extensions 1D00..1D7F; Phonetic Extensions @@ -234,7 +235,10 @@ FFF0..FFFF; Specials 10B80..10BAF; Psalter Pahlavi 10C00..10C4F; Old Turkic 10C80..10CFF; Old Hungarian +10D00..10D3F; Hanifi Rohingya 10E60..10E7F; Rumi Numeral Symbols +10F00..10F2F; Old Sogdian +10F30..10F6F; Sogdian 11000..1107F; Brahmi 11080..110CF; Kaithi 110D0..110FF; Sora Sompeng @@ -253,6 +257,7 @@ FFF0..FFFF; Specials 11660..1167F; Mongolian Supplement 11680..116CF; Takri 11700..1173F; Ahom +11800..1184F; Dogra 118A0..118FF; Warang Citi 11A00..11A4F; Zanabazar Square 11A50..11AAF; Soyombo @@ -260,6 +265,8 @@ FFF0..FFFF; Specials 11C00..11C6F; Bhaiksuki 11C70..11CBF; Marchen 11D00..11D5F; Masaram Gondi +11D60..11DAF; Gunjala Gondi +11EE0..11EFF; Makasar 12000..123FF; Cuneiform 12400..1247F; Cuneiform Numbers and Punctuation 12480..1254F; Early Dynastic Cuneiform @@ -269,6 +276,7 @@ FFF0..FFFF; Specials 16A40..16A6F; Mro 16AD0..16AFF; Bassa Vah 16B00..16B8F; Pahawh Hmong +16E40..16E9F; Medefaidrin 16F00..16F9F; Miao 16FE0..16FFF; Ideographic Symbols and Punctuation 17000..187FF; Tangut @@ -281,6 +289,7 @@ FFF0..FFFF; Specials 1D000..1D0FF; Byzantine Musical Symbols 1D100..1D1FF; Musical Symbols 1D200..1D24F; Ancient Greek Musical Notation +1D2E0..1D2FF; Mayan Numerals 1D300..1D35F; Tai Xuan Jing Symbols 1D360..1D37F; Counting Rod Numerals 1D400..1D7FF; Mathematical Alphanumeric Symbols @@ -288,6 +297,7 @@ FFF0..FFFF; Specials 1E000..1E02F; Glagolitic Supplement 1E800..1E8DF; Mende Kikakui 1E900..1E95F; Adlam +1EC70..1ECBF; Indic Siyaq Numbers 1EE00..1EEFF; Arabic Mathematical Alphabetic Symbols 1F000..1F02F; Mahjong Tiles 1F030..1F09F; Domino Tiles @@ -302,6 +312,7 @@ FFF0..FFFF; Specials 1F780..1F7FF; Geometric Shapes Extended 1F800..1F8FF; Supplemental Arrows-C 1F900..1F9FF; Supplemental Symbols and Pictographs +1FA00..1FA6F; Chess Symbols 20000..2A6DF; CJK Unified Ideographs Extension B 2A700..2B73F; CJK Unified Ideographs Extension C 2B740..2B81F; CJK Unified Ideographs Extension D diff --git a/resources/standards-data/unicode-character-database/UnicodeData.txt b/resources/standards-data/unicode-character-database/UnicodeData.txt index d89c64f526..ec32fafbce 100644 --- a/resources/standards-data/unicode-character-database/UnicodeData.txt +++ b/resources/standards-data/unicode-character-database/UnicodeData.txt @@ -1362,6 +1362,7 @@ 055D;ARMENIAN COMMA;Po;0;L;;;;;N;;;;; 055E;ARMENIAN QUESTION MARK;Po;0;L;;;;;N;;;;; 055F;ARMENIAN ABBREVIATION MARK;Po;0;L;;;;;N;;;;; +0560;ARMENIAN SMALL LETTER TURNED AYB;Ll;0;L;;;;;N;;;;; 0561;ARMENIAN SMALL LETTER AYB;Ll;0;L;;;;;N;;;0531;;0531 0562;ARMENIAN SMALL LETTER BEN;Ll;0;L;;;;;N;;;0532;;0532 0563;ARMENIAN SMALL LETTER GIM;Ll;0;L;;;;;N;;;0533;;0533 @@ -1401,6 +1402,7 @@ 0585;ARMENIAN SMALL LETTER OH;Ll;0;L;;;;;N;;;0555;;0555 0586;ARMENIAN SMALL LETTER FEH;Ll;0;L;;;;;N;;;0556;;0556 0587;ARMENIAN SMALL LIGATURE ECH YIWN;Ll;0;L; 0565 0582;;;;N;;;;; +0588;ARMENIAN SMALL LETTER YI WITH STROKE;Ll;0;L;;;;;N;;;;; 0589;ARMENIAN FULL STOP;Po;0;L;;;;;N;ARMENIAN PERIOD;;;; 058A;ARMENIAN HYPHEN;Pd;0;ON;;;;;N;;;;; 058D;RIGHT-FACING ARMENIAN ETERNITY SIGN;So;0;ON;;;;;N;;;;; @@ -1488,6 +1490,7 @@ 05E8;HEBREW LETTER RESH;Lo;0;R;;;;;N;;;;; 05E9;HEBREW LETTER SHIN;Lo;0;R;;;;;N;;;;; 05EA;HEBREW LETTER TAV;Lo;0;R;;;;;N;;;;; +05EF;HEBREW YOD TRIANGLE;Lo;0;R;;;;;N;;;;; 05F0;HEBREW LIGATURE YIDDISH DOUBLE VAV;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE VAV;;;; 05F1;HEBREW LIGATURE YIDDISH VAV YOD;Lo;0;R;;;;;N;HEBREW LETTER VAV YOD;;;; 05F2;HEBREW LIGATURE YIDDISH DOUBLE YOD;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE YOD;;;; @@ -1982,6 +1985,9 @@ 07F8;NKO COMMA;Po;0;ON;;;;;N;;;;; 07F9;NKO EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; 07FA;NKO LAJANYALAN;Lm;0;R;;;;;N;;;;; +07FD;NKO DANTAYALAN;Mn;220;NSM;;;;;N;;;;; +07FE;NKO DOROME SIGN;Sc;0;R;;;;;N;;;;; +07FF;NKO TAMAN SIGN;Sc;0;R;;;;;N;;;;; 0800;SAMARITAN LETTER ALAF;Lo;0;R;;;;;N;;;;; 0801;SAMARITAN LETTER BIT;Lo;0;R;;;;;N;;;;; 0802;SAMARITAN LETTER GAMAN;Lo;0;R;;;;;N;;;;; @@ -2112,6 +2118,7 @@ 08BB;ARABIC LETTER AFRICAN FEH;Lo;0;AL;;;;;N;;;;; 08BC;ARABIC LETTER AFRICAN QAF;Lo;0;AL;;;;;N;;;;; 08BD;ARABIC LETTER AFRICAN NOON;Lo;0;AL;;;;;N;;;;; +08D3;ARABIC SMALL LOW WAW;Mn;220;NSM;;;;;N;;;;; 08D4;ARABIC SMALL HIGH WORD AR-RUB;Mn;230;NSM;;;;;N;;;;; 08D5;ARABIC SMALL HIGH SAD;Mn;230;NSM;;;;;N;;;;; 08D6;ARABIC SMALL HIGH AIN;Mn;230;NSM;;;;;N;;;;; @@ -2379,6 +2386,7 @@ 09FB;BENGALI GANDA MARK;Sc;0;ET;;;;;N;;;;; 09FC;BENGALI LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;; 09FD;BENGALI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +09FE;BENGALI SANDHI MARK;Mn;230;NSM;;;;;N;;;;; 0A01;GURMUKHI SIGN ADAK BINDI;Mn;0;NSM;;;;;N;;;;; 0A02;GURMUKHI SIGN BINDI;Mn;0;NSM;;;;;N;;;;; 0A03;GURMUKHI SIGN VISARGA;Mc;0;L;;;;;N;;;;; @@ -2458,6 +2466,7 @@ 0A73;GURMUKHI URA;Lo;0;L;;;;;N;;;;; 0A74;GURMUKHI EK ONKAR;Lo;0;L;;;;;N;;;;; 0A75;GURMUKHI SIGN YAKASH;Mn;0;NSM;;;;;N;;;;; +0A76;GURMUKHI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; 0A81;GUJARATI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0A82;GUJARATI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; 0A83;GUJARATI SIGN VISARGA;Mc;0;L;;;;;N;;;;; @@ -2715,6 +2724,7 @@ 0C01;TELUGU SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;; 0C02;TELUGU SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0C03;TELUGU SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0C04;TELUGU SIGN COMBINING ANUSVARA ABOVE;Mn;0;NSM;;;;;N;;;;; 0C05;TELUGU LETTER A;Lo;0;L;;;;;N;;;;; 0C06;TELUGU LETTER AA;Lo;0;L;;;;;N;;;;; 0C07;TELUGU LETTER I;Lo;0;L;;;;;N;;;;; @@ -2811,6 +2821,7 @@ 0C81;KANNADA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0C82;KANNADA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0C83;KANNADA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0C84;KANNADA SIGN SIDDHAM;Po;0;L;;;;;N;;;;; 0C85;KANNADA LETTER A;Lo;0;L;;;;;N;;;;; 0C86;KANNADA LETTER AA;Lo;0;L;;;;;N;;;;; 0C87;KANNADA LETTER I;Lo;0;L;;;;;N;;;;; @@ -3667,54 +3678,54 @@ 10C5;GEORGIAN CAPITAL LETTER HOE;Lu;0;L;;;;;N;;;;2D25; 10C7;GEORGIAN CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;2D27; 10CD;GEORGIAN CAPITAL LETTER AEN;Lu;0;L;;;;;N;;;;2D2D; -10D0;GEORGIAN LETTER AN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER AN;;;; -10D1;GEORGIAN LETTER BAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER BAN;;;; -10D2;GEORGIAN LETTER GAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GAN;;;; -10D3;GEORGIAN LETTER DON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER DON;;;; -10D4;GEORGIAN LETTER EN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER EN;;;; -10D5;GEORGIAN LETTER VIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER VIN;;;; -10D6;GEORGIAN LETTER ZEN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZEN;;;; -10D7;GEORGIAN LETTER TAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAN;;;; -10D8;GEORGIAN LETTER IN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER IN;;;; -10D9;GEORGIAN LETTER KAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KAN;;;; -10DA;GEORGIAN LETTER LAS;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER LAS;;;; -10DB;GEORGIAN LETTER MAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER MAN;;;; -10DC;GEORGIAN LETTER NAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER NAR;;;; -10DD;GEORGIAN LETTER ON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ON;;;; -10DE;GEORGIAN LETTER PAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PAR;;;; -10DF;GEORGIAN LETTER ZHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZHAR;;;; -10E0;GEORGIAN LETTER RAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER RAE;;;; -10E1;GEORGIAN LETTER SAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SAN;;;; -10E2;GEORGIAN LETTER TAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAR;;;; -10E3;GEORGIAN LETTER UN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER UN;;;; -10E4;GEORGIAN LETTER PHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PHAR;;;; -10E5;GEORGIAN LETTER KHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KHAR;;;; -10E6;GEORGIAN LETTER GHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GHAN;;;; -10E7;GEORGIAN LETTER QAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER QAR;;;; -10E8;GEORGIAN LETTER SHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SHIN;;;; -10E9;GEORGIAN LETTER CHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHIN;;;; -10EA;GEORGIAN LETTER CAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CAN;;;; -10EB;GEORGIAN LETTER JIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JIL;;;; -10EC;GEORGIAN LETTER CIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CIL;;;; -10ED;GEORGIAN LETTER CHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHAR;;;; -10EE;GEORGIAN LETTER XAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER XAN;;;; -10EF;GEORGIAN LETTER JHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JHAN;;;; -10F0;GEORGIAN LETTER HAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAE;;;; -10F1;GEORGIAN LETTER HE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HE;;;; -10F2;GEORGIAN LETTER HIE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HIE;;;; -10F3;GEORGIAN LETTER WE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER WE;;;; -10F4;GEORGIAN LETTER HAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAR;;;; -10F5;GEORGIAN LETTER HOE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HOE;;;; -10F6;GEORGIAN LETTER FI;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER FI;;;; -10F7;GEORGIAN LETTER YN;Lo;0;L;;;;;N;;;;; -10F8;GEORGIAN LETTER ELIFI;Lo;0;L;;;;;N;;;;; -10F9;GEORGIAN LETTER TURNED GAN;Lo;0;L;;;;;N;;;;; -10FA;GEORGIAN LETTER AIN;Lo;0;L;;;;;N;;;;; +10D0;GEORGIAN LETTER AN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER AN;;1C90;;10D0 +10D1;GEORGIAN LETTER BAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER BAN;;1C91;;10D1 +10D2;GEORGIAN LETTER GAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER GAN;;1C92;;10D2 +10D3;GEORGIAN LETTER DON;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER DON;;1C93;;10D3 +10D4;GEORGIAN LETTER EN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER EN;;1C94;;10D4 +10D5;GEORGIAN LETTER VIN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER VIN;;1C95;;10D5 +10D6;GEORGIAN LETTER ZEN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER ZEN;;1C96;;10D6 +10D7;GEORGIAN LETTER TAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER TAN;;1C97;;10D7 +10D8;GEORGIAN LETTER IN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER IN;;1C98;;10D8 +10D9;GEORGIAN LETTER KAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER KAN;;1C99;;10D9 +10DA;GEORGIAN LETTER LAS;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER LAS;;1C9A;;10DA +10DB;GEORGIAN LETTER MAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER MAN;;1C9B;;10DB +10DC;GEORGIAN LETTER NAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER NAR;;1C9C;;10DC +10DD;GEORGIAN LETTER ON;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER ON;;1C9D;;10DD +10DE;GEORGIAN LETTER PAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER PAR;;1C9E;;10DE +10DF;GEORGIAN LETTER ZHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER ZHAR;;1C9F;;10DF +10E0;GEORGIAN LETTER RAE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER RAE;;1CA0;;10E0 +10E1;GEORGIAN LETTER SAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER SAN;;1CA1;;10E1 +10E2;GEORGIAN LETTER TAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER TAR;;1CA2;;10E2 +10E3;GEORGIAN LETTER UN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER UN;;1CA3;;10E3 +10E4;GEORGIAN LETTER PHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER PHAR;;1CA4;;10E4 +10E5;GEORGIAN LETTER KHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER KHAR;;1CA5;;10E5 +10E6;GEORGIAN LETTER GHAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER GHAN;;1CA6;;10E6 +10E7;GEORGIAN LETTER QAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER QAR;;1CA7;;10E7 +10E8;GEORGIAN LETTER SHIN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER SHIN;;1CA8;;10E8 +10E9;GEORGIAN LETTER CHIN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CHIN;;1CA9;;10E9 +10EA;GEORGIAN LETTER CAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CAN;;1CAA;;10EA +10EB;GEORGIAN LETTER JIL;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER JIL;;1CAB;;10EB +10EC;GEORGIAN LETTER CIL;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CIL;;1CAC;;10EC +10ED;GEORGIAN LETTER CHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CHAR;;1CAD;;10ED +10EE;GEORGIAN LETTER XAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER XAN;;1CAE;;10EE +10EF;GEORGIAN LETTER JHAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER JHAN;;1CAF;;10EF +10F0;GEORGIAN LETTER HAE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HAE;;1CB0;;10F0 +10F1;GEORGIAN LETTER HE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HE;;1CB1;;10F1 +10F2;GEORGIAN LETTER HIE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HIE;;1CB2;;10F2 +10F3;GEORGIAN LETTER WE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER WE;;1CB3;;10F3 +10F4;GEORGIAN LETTER HAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HAR;;1CB4;;10F4 +10F5;GEORGIAN LETTER HOE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HOE;;1CB5;;10F5 +10F6;GEORGIAN LETTER FI;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER FI;;1CB6;;10F6 +10F7;GEORGIAN LETTER YN;Ll;0;L;;;;;N;;;1CB7;;10F7 +10F8;GEORGIAN LETTER ELIFI;Ll;0;L;;;;;N;;;1CB8;;10F8 +10F9;GEORGIAN LETTER TURNED GAN;Ll;0;L;;;;;N;;;1CB9;;10F9 +10FA;GEORGIAN LETTER AIN;Ll;0;L;;;;;N;;;1CBA;;10FA 10FB;GEORGIAN PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;; 10FC;MODIFIER LETTER GEORGIAN NAR;Lm;0;L; 10DC;;;;N;;;;; -10FD;GEORGIAN LETTER AEN;Lo;0;L;;;;;N;;;;; -10FE;GEORGIAN LETTER HARD SIGN;Lo;0;L;;;;;N;;;;; -10FF;GEORGIAN LETTER LABIAL SIGN;Lo;0;L;;;;;N;;;;; +10FD;GEORGIAN LETTER AEN;Ll;0;L;;;;;N;;;1CBD;;10FD +10FE;GEORGIAN LETTER HARD SIGN;Ll;0;L;;;;;N;;;1CBE;;10FE +10FF;GEORGIAN LETTER LABIAL SIGN;Ll;0;L;;;;;N;;;1CBF;;10FF 1100;HANGUL CHOSEONG KIYEOK;Lo;0;L;;;;;N;;;;; 1101;HANGUL CHOSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;;;; 1102;HANGUL CHOSEONG NIEUN;Lo;0;L;;;;;N;;;;; @@ -5513,6 +5524,7 @@ 1875;MONGOLIAN LETTER MANCHU RA;Lo;0;L;;;;;N;;;;; 1876;MONGOLIAN LETTER MANCHU FA;Lo;0;L;;;;;N;;;;; 1877;MONGOLIAN LETTER MANCHU ZHA;Lo;0;L;;;;;N;;;;; +1878;MONGOLIAN LETTER CHA WITH TWO DOTS;Lo;0;L;;;;;N;;;;; 1880;MONGOLIAN LETTER ALI GALI ANUSVARA ONE;Lo;0;L;;;;;N;;;;; 1881;MONGOLIAN LETTER ALI GALI VISARGA ONE;Lo;0;L;;;;;N;;;;; 1882;MONGOLIAN LETTER ALI GALI DAMARU;Lo;0;L;;;;;N;;;;; @@ -6388,6 +6400,52 @@ 1C86;CYRILLIC SMALL LETTER TALL HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A 1C87;CYRILLIC SMALL LETTER TALL YAT;Ll;0;L;;;;;N;;;0462;;0462 1C88;CYRILLIC SMALL LETTER UNBLENDED UK;Ll;0;L;;;;;N;;;A64A;;A64A +1C90;GEORGIAN MTAVRULI CAPITAL LETTER AN;Lu;0;L;;;;;N;;;;10D0; +1C91;GEORGIAN MTAVRULI CAPITAL LETTER BAN;Lu;0;L;;;;;N;;;;10D1; +1C92;GEORGIAN MTAVRULI CAPITAL LETTER GAN;Lu;0;L;;;;;N;;;;10D2; +1C93;GEORGIAN MTAVRULI CAPITAL LETTER DON;Lu;0;L;;;;;N;;;;10D3; +1C94;GEORGIAN MTAVRULI CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;10D4; +1C95;GEORGIAN MTAVRULI CAPITAL LETTER VIN;Lu;0;L;;;;;N;;;;10D5; +1C96;GEORGIAN MTAVRULI CAPITAL LETTER ZEN;Lu;0;L;;;;;N;;;;10D6; +1C97;GEORGIAN MTAVRULI CAPITAL LETTER TAN;Lu;0;L;;;;;N;;;;10D7; +1C98;GEORGIAN MTAVRULI CAPITAL LETTER IN;Lu;0;L;;;;;N;;;;10D8; +1C99;GEORGIAN MTAVRULI CAPITAL LETTER KAN;Lu;0;L;;;;;N;;;;10D9; +1C9A;GEORGIAN MTAVRULI CAPITAL LETTER LAS;Lu;0;L;;;;;N;;;;10DA; +1C9B;GEORGIAN MTAVRULI CAPITAL LETTER MAN;Lu;0;L;;;;;N;;;;10DB; +1C9C;GEORGIAN MTAVRULI CAPITAL LETTER NAR;Lu;0;L;;;;;N;;;;10DC; +1C9D;GEORGIAN MTAVRULI CAPITAL LETTER ON;Lu;0;L;;;;;N;;;;10DD; +1C9E;GEORGIAN MTAVRULI CAPITAL LETTER PAR;Lu;0;L;;;;;N;;;;10DE; +1C9F;GEORGIAN MTAVRULI CAPITAL LETTER ZHAR;Lu;0;L;;;;;N;;;;10DF; +1CA0;GEORGIAN MTAVRULI CAPITAL LETTER RAE;Lu;0;L;;;;;N;;;;10E0; +1CA1;GEORGIAN MTAVRULI CAPITAL LETTER SAN;Lu;0;L;;;;;N;;;;10E1; +1CA2;GEORGIAN MTAVRULI CAPITAL LETTER TAR;Lu;0;L;;;;;N;;;;10E2; +1CA3;GEORGIAN MTAVRULI CAPITAL LETTER UN;Lu;0;L;;;;;N;;;;10E3; +1CA4;GEORGIAN MTAVRULI CAPITAL LETTER PHAR;Lu;0;L;;;;;N;;;;10E4; +1CA5;GEORGIAN MTAVRULI CAPITAL LETTER KHAR;Lu;0;L;;;;;N;;;;10E5; +1CA6;GEORGIAN MTAVRULI CAPITAL LETTER GHAN;Lu;0;L;;;;;N;;;;10E6; +1CA7;GEORGIAN MTAVRULI CAPITAL LETTER QAR;Lu;0;L;;;;;N;;;;10E7; +1CA8;GEORGIAN MTAVRULI CAPITAL LETTER SHIN;Lu;0;L;;;;;N;;;;10E8; +1CA9;GEORGIAN MTAVRULI CAPITAL LETTER CHIN;Lu;0;L;;;;;N;;;;10E9; +1CAA;GEORGIAN MTAVRULI CAPITAL LETTER CAN;Lu;0;L;;;;;N;;;;10EA; +1CAB;GEORGIAN MTAVRULI CAPITAL LETTER JIL;Lu;0;L;;;;;N;;;;10EB; +1CAC;GEORGIAN MTAVRULI CAPITAL LETTER CIL;Lu;0;L;;;;;N;;;;10EC; +1CAD;GEORGIAN MTAVRULI CAPITAL LETTER CHAR;Lu;0;L;;;;;N;;;;10ED; +1CAE;GEORGIAN MTAVRULI CAPITAL LETTER XAN;Lu;0;L;;;;;N;;;;10EE; +1CAF;GEORGIAN MTAVRULI CAPITAL LETTER JHAN;Lu;0;L;;;;;N;;;;10EF; +1CB0;GEORGIAN MTAVRULI CAPITAL LETTER HAE;Lu;0;L;;;;;N;;;;10F0; +1CB1;GEORGIAN MTAVRULI CAPITAL LETTER HE;Lu;0;L;;;;;N;;;;10F1; +1CB2;GEORGIAN MTAVRULI CAPITAL LETTER HIE;Lu;0;L;;;;;N;;;;10F2; +1CB3;GEORGIAN MTAVRULI CAPITAL LETTER WE;Lu;0;L;;;;;N;;;;10F3; +1CB4;GEORGIAN MTAVRULI CAPITAL LETTER HAR;Lu;0;L;;;;;N;;;;10F4; +1CB5;GEORGIAN MTAVRULI CAPITAL LETTER HOE;Lu;0;L;;;;;N;;;;10F5; +1CB6;GEORGIAN MTAVRULI CAPITAL LETTER FI;Lu;0;L;;;;;N;;;;10F6; +1CB7;GEORGIAN MTAVRULI CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;10F7; +1CB8;GEORGIAN MTAVRULI CAPITAL LETTER ELIFI;Lu;0;L;;;;;N;;;;10F8; +1CB9;GEORGIAN MTAVRULI CAPITAL LETTER TURNED GAN;Lu;0;L;;;;;N;;;;10F9; +1CBA;GEORGIAN MTAVRULI CAPITAL LETTER AIN;Lu;0;L;;;;;N;;;;10FA; +1CBD;GEORGIAN MTAVRULI CAPITAL LETTER AEN;Lu;0;L;;;;;N;;;;10FD; +1CBE;GEORGIAN MTAVRULI CAPITAL LETTER HARD SIGN;Lu;0;L;;;;;N;;;;10FE; +1CBF;GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN;Lu;0;L;;;;;N;;;;10FF; 1CC0;SUNDANESE PUNCTUATION BINDU SURYA;Po;0;L;;;;;N;;;;; 1CC1;SUNDANESE PUNCTUATION BINDU PANGLONG;Po;0;L;;;;;N;;;;; 1CC2;SUNDANESE PUNCTUATION BINDU PURNAMA;Po;0;L;;;;;N;;;;; @@ -9559,7 +9617,7 @@ 299E;ANGLE WITH S INSIDE;Sm;0;ON;;;;;Y;;;;; 299F;ACUTE ANGLE;Sm;0;ON;;;;;Y;;;;; 29A0;SPHERICAL ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;; -29A1;SPHERICAL ANGLE OPENING UP;Sm;0;ON;;;;;Y;;;;; +29A1;SPHERICAL ANGLE OPENING UP;Sm;0;ON;;;;;N;;;;; 29A2;TURNED ANGLE;Sm;0;ON;;;;;Y;;;;; 29A3;REVERSED ANGLE;Sm;0;ON;;;;;Y;;;;; 29A4;ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; @@ -10092,6 +10150,9 @@ 2BB7;RIBBON ARROW RIGHT DOWN;So;0;ON;;;;;N;;;;; 2BB8;UPWARDS WHITE ARROW FROM BAR WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;; 2BB9;UP ARROWHEAD IN A RECTANGLE BOX;So;0;ON;;;;;N;;;;; +2BBA;OVERLAPPING WHITE SQUARES;So;0;ON;;;;;N;;;;; +2BBB;OVERLAPPING WHITE AND BLACK SQUARES;So;0;ON;;;;;N;;;;; +2BBC;OVERLAPPING BLACK SQUARES;So;0;ON;;;;;N;;;;; 2BBD;BALLOT BOX WITH LIGHT X;So;0;ON;;;;;N;;;;; 2BBE;CIRCLED X;So;0;ON;;;;;N;;;;; 2BBF;CIRCLED BOLD X;So;0;ON;;;;;N;;;;; @@ -10113,10 +10174,50 @@ 2BD0;SQUARE POSITION INDICATOR;So;0;ON;;;;;N;;;;; 2BD1;UNCERTAINTY SIGN;So;0;ON;;;;;N;;;;; 2BD2;GROUP MARK;So;0;ON;;;;;N;;;;; +2BD3;PLUTO FORM TWO;So;0;ON;;;;;N;;;;; +2BD4;PLUTO FORM THREE;So;0;ON;;;;;N;;;;; +2BD5;PLUTO FORM FOUR;So;0;ON;;;;;N;;;;; +2BD6;PLUTO FORM FIVE;So;0;ON;;;;;N;;;;; +2BD7;TRANSPLUTO;So;0;ON;;;;;N;;;;; +2BD8;PROSERPINA;So;0;ON;;;;;N;;;;; +2BD9;ASTRAEA;So;0;ON;;;;;N;;;;; +2BDA;HYGIEA;So;0;ON;;;;;N;;;;; +2BDB;PHOLUS;So;0;ON;;;;;N;;;;; +2BDC;NESSUS;So;0;ON;;;;;N;;;;; +2BDD;WHITE MOON SELENA;So;0;ON;;;;;N;;;;; +2BDE;BLACK DIAMOND ON CROSS;So;0;ON;;;;;N;;;;; +2BDF;TRUE LIGHT MOON ARTA;So;0;ON;;;;;N;;;;; +2BE0;CUPIDO;So;0;ON;;;;;N;;;;; +2BE1;HADES;So;0;ON;;;;;N;;;;; +2BE2;ZEUS;So;0;ON;;;;;N;;;;; +2BE3;KRONOS;So;0;ON;;;;;N;;;;; +2BE4;APOLLON;So;0;ON;;;;;N;;;;; +2BE5;ADMETOS;So;0;ON;;;;;N;;;;; +2BE6;VULCANUS;So;0;ON;;;;;N;;;;; +2BE7;POSEIDON;So;0;ON;;;;;N;;;;; +2BE8;LEFT HALF BLACK STAR;So;0;ON;;;;;N;;;;; +2BE9;RIGHT HALF BLACK STAR;So;0;ON;;;;;N;;;;; +2BEA;STAR WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;; +2BEB;STAR WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;; 2BEC;LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; 2BED;UPWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; 2BEE;RIGHTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; 2BEF;DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; +2BF0;ERIS FORM ONE;So;0;ON;;;;;N;;;;; +2BF1;ERIS FORM TWO;So;0;ON;;;;;N;;;;; +2BF2;SEDNA;So;0;ON;;;;;N;;;;; +2BF3;RUSSIAN ASTROLOGICAL SYMBOL VIGINTILE;So;0;ON;;;;;N;;;;; +2BF4;RUSSIAN ASTROLOGICAL SYMBOL NOVILE;So;0;ON;;;;;N;;;;; +2BF5;RUSSIAN ASTROLOGICAL SYMBOL QUINTILE;So;0;ON;;;;;N;;;;; +2BF6;RUSSIAN ASTROLOGICAL SYMBOL BINOVILE;So;0;ON;;;;;N;;;;; +2BF7;RUSSIAN ASTROLOGICAL SYMBOL SENTAGON;So;0;ON;;;;;N;;;;; +2BF8;RUSSIAN ASTROLOGICAL SYMBOL TREDECILE;So;0;ON;;;;;N;;;;; +2BF9;EQUALS SIGN WITH INFINITY BELOW;So;0;ON;;;;;N;;;;; +2BFA;UNITED SYMBOL;So;0;ON;;;;;N;;;;; +2BFB;SEPARATED SYMBOL;So;0;ON;;;;;N;;;;; +2BFC;DOUBLED SYMBOL;So;0;ON;;;;;N;;;;; +2BFD;PASSED SYMBOL;So;0;ON;;;;;N;;;;; +2BFE;REVERSED RIGHT ANGLE;So;0;ON;;;;;Y;;;;; 2C00;GLAGOLITIC CAPITAL LETTER AZU;Lu;0;L;;;;;N;;;;2C30; 2C01;GLAGOLITIC CAPITAL LETTER BUKY;Lu;0;L;;;;;N;;;;2C31; 2C02;GLAGOLITIC CAPITAL LETTER VEDE;Lu;0;L;;;;;N;;;;2C32; @@ -10650,6 +10751,11 @@ 2E47;LOW KAVYKA;Po;0;ON;;;;;N;;;;; 2E48;LOW KAVYKA WITH DOT;Po;0;ON;;;;;N;;;;; 2E49;DOUBLE STACKED COMMA;Po;0;ON;;;;;N;;;;; +2E4A;DOTTED SOLIDUS;Po;0;ON;;;;;N;;;;; +2E4B;TRIPLE DAGGER;Po;0;ON;;;;;N;;;;; +2E4C;MEDIEVAL COMMA;Po;0;ON;;;;;N;;;;; +2E4D;PARAGRAPHUS MARK;Po;0;ON;;;;;N;;;;; +2E4E;PUNCTUS ELEVATUS MARK;Po;0;ON;;;;;N;;;;; 2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;; 2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;; 2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;; @@ -11286,6 +11392,7 @@ 312C;BOPOMOFO LETTER GN;Lo;0;L;;;;;N;;;;; 312D;BOPOMOFO LETTER IH;Lo;0;L;;;;;N;;;;; 312E;BOPOMOFO LETTER O WITH DOT ABOVE;Lo;0;L;;;;;N;;;;; +312F;BOPOMOFO LETTER NN;Lo;0;L;;;;;N;;;;; 3131;HANGUL LETTER KIYEOK;Lo;0;L; 1100;;;;N;HANGUL LETTER GIYEOG;;;; 3132;HANGUL LETTER SSANGKIYEOK;Lo;0;L; 1101;;;;N;HANGUL LETTER SSANG GIYEOG;;;; 3133;HANGUL LETTER KIYEOK-SIOS;Lo;0;L; 11AA;;;;N;HANGUL LETTER GIYEOG SIOS;;;; @@ -12052,7 +12159,7 @@ 4DFE;HEXAGRAM FOR AFTER COMPLETION;So;0;ON;;;;;N;;;;; 4DFF;HEXAGRAM FOR BEFORE COMPLETION;So;0;ON;;;;;N;;;;; 4E00;;Lo;0;L;;;;;N;;;;; -9FEA;;Lo;0;L;;;;;N;;;;; +9FEF;;Lo;0;L;;;;;N;;;;; A000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;; A001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;; A002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;; @@ -13980,6 +14087,7 @@ A7AB;LATIN CAPITAL LETTER REVERSED OPEN E;Lu;0;L;;;;;N;;;;025C; A7AC;LATIN CAPITAL LETTER SCRIPT G;Lu;0;L;;;;;N;;;;0261; A7AD;LATIN CAPITAL LETTER L WITH BELT;Lu;0;L;;;;;N;;;;026C; A7AE;LATIN CAPITAL LETTER SMALL CAPITAL I;Lu;0;L;;;;;N;;;;026A; +A7AF;LATIN LETTER SMALL CAPITAL Q;Ll;0;L;;;;;N;;;;; A7B0;LATIN CAPITAL LETTER TURNED K;Lu;0;L;;;;;N;;;;029E; A7B1;LATIN CAPITAL LETTER TURNED T;Lu;0;L;;;;;N;;;;0287; A7B2;LATIN CAPITAL LETTER J WITH CROSSED-TAIL;Lu;0;L;;;;;N;;;;029D; @@ -13988,6 +14096,8 @@ A7B4;LATIN CAPITAL LETTER BETA;Lu;0;L;;;;;N;;;;A7B5; A7B5;LATIN SMALL LETTER BETA;Ll;0;L;;;;;N;;;A7B4;;A7B4 A7B6;LATIN CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;A7B7; A7B7;LATIN SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;A7B6;;A7B6 +A7B8;LATIN CAPITAL LETTER U WITH STROKE;Lu;0;L;;;;;N;;;;A7B9; +A7B9;LATIN SMALL LETTER U WITH STROKE;Ll;0;L;;;;;N;;;A7B8;;A7B8 A7F7;LATIN EPIGRAPHIC LETTER SIDEWAYS I;Lo;0;L;;;;;N;;;;; A7F8;MODIFIER LETTER CAPITAL H WITH STROKE;Lm;0;L; 0126;;;;N;;;;; A7F9;MODIFIER LETTER SMALL LIGATURE OE;Lm;0;L; 0153;;;;N;;;;; @@ -14219,6 +14329,8 @@ A8FA;DEVANAGARI CARET;Po;0;L;;;;;N;;;;; A8FB;DEVANAGARI HEADSTROKE;Lo;0;L;;;;;N;;;;; A8FC;DEVANAGARI SIGN SIDDHAM;Po;0;L;;;;;N;;;;; A8FD;DEVANAGARI JAIN OM;Lo;0;L;;;;;N;;;;; +A8FE;DEVANAGARI LETTER AY;Lo;0;L;;;;;N;;;;; +A8FF;DEVANAGARI VOWEL SIGN AY;Mn;0;NSM;;;;;N;;;;; A900;KAYAH LI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; A901;KAYAH LI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; A902;KAYAH LI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; @@ -18363,6 +18475,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10A31;KHAROSHTHI LETTER HA;Lo;0;R;;;;;N;;;;; 10A32;KHAROSHTHI LETTER KKA;Lo;0;R;;;;;N;;;;; 10A33;KHAROSHTHI LETTER TTTHA;Lo;0;R;;;;;N;;;;; +10A34;KHAROSHTHI LETTER TTTA;Lo;0;R;;;;;N;;;;; +10A35;KHAROSHTHI LETTER VHA;Lo;0;R;;;;;N;;;;; 10A38;KHAROSHTHI SIGN BAR ABOVE;Mn;230;NSM;;;;;N;;;;; 10A39;KHAROSHTHI SIGN CAUDA;Mn;1;NSM;;;;;N;;;;; 10A3A;KHAROSHTHI SIGN DOT BELOW;Mn;220;NSM;;;;;N;;;;; @@ -18375,6 +18489,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10A45;KHAROSHTHI NUMBER TWENTY;No;0;R;;;;20;N;;;;; 10A46;KHAROSHTHI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; 10A47;KHAROSHTHI NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; +10A48;KHAROSHTHI FRACTION ONE HALF;No;0;R;;;;1/2;N;;;;; 10A50;KHAROSHTHI PUNCTUATION DOT;Po;0;R;;;;;N;;;;; 10A51;KHAROSHTHI PUNCTUATION SMALL CIRCLE;Po;0;R;;;;;N;;;;; 10A52;KHAROSHTHI PUNCTUATION CIRCLE;Po;0;R;;;;;N;;;;; @@ -18827,6 +18942,56 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10CFD;OLD HUNGARIAN NUMBER FIFTY;No;0;R;;;;50;N;;;;; 10CFE;OLD HUNGARIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; 10CFF;OLD HUNGARIAN NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; +10D00;HANIFI ROHINGYA LETTER A;Lo;0;AL;;;;;N;;;;; +10D01;HANIFI ROHINGYA LETTER BA;Lo;0;AL;;;;;N;;;;; +10D02;HANIFI ROHINGYA LETTER PA;Lo;0;AL;;;;;N;;;;; +10D03;HANIFI ROHINGYA LETTER TA;Lo;0;AL;;;;;N;;;;; +10D04;HANIFI ROHINGYA LETTER TTA;Lo;0;AL;;;;;N;;;;; +10D05;HANIFI ROHINGYA LETTER JA;Lo;0;AL;;;;;N;;;;; +10D06;HANIFI ROHINGYA LETTER CA;Lo;0;AL;;;;;N;;;;; +10D07;HANIFI ROHINGYA LETTER HA;Lo;0;AL;;;;;N;;;;; +10D08;HANIFI ROHINGYA LETTER KHA;Lo;0;AL;;;;;N;;;;; +10D09;HANIFI ROHINGYA LETTER FA;Lo;0;AL;;;;;N;;;;; +10D0A;HANIFI ROHINGYA LETTER DA;Lo;0;AL;;;;;N;;;;; +10D0B;HANIFI ROHINGYA LETTER DDA;Lo;0;AL;;;;;N;;;;; +10D0C;HANIFI ROHINGYA LETTER RA;Lo;0;AL;;;;;N;;;;; +10D0D;HANIFI ROHINGYA LETTER RRA;Lo;0;AL;;;;;N;;;;; +10D0E;HANIFI ROHINGYA LETTER ZA;Lo;0;AL;;;;;N;;;;; +10D0F;HANIFI ROHINGYA LETTER SA;Lo;0;AL;;;;;N;;;;; +10D10;HANIFI ROHINGYA LETTER SHA;Lo;0;AL;;;;;N;;;;; +10D11;HANIFI ROHINGYA LETTER KA;Lo;0;AL;;;;;N;;;;; +10D12;HANIFI ROHINGYA LETTER GA;Lo;0;AL;;;;;N;;;;; +10D13;HANIFI ROHINGYA LETTER LA;Lo;0;AL;;;;;N;;;;; +10D14;HANIFI ROHINGYA LETTER MA;Lo;0;AL;;;;;N;;;;; +10D15;HANIFI ROHINGYA LETTER NA;Lo;0;AL;;;;;N;;;;; +10D16;HANIFI ROHINGYA LETTER WA;Lo;0;AL;;;;;N;;;;; +10D17;HANIFI ROHINGYA LETTER KINNA WA;Lo;0;AL;;;;;N;;;;; +10D18;HANIFI ROHINGYA LETTER YA;Lo;0;AL;;;;;N;;;;; +10D19;HANIFI ROHINGYA LETTER KINNA YA;Lo;0;AL;;;;;N;;;;; +10D1A;HANIFI ROHINGYA LETTER NGA;Lo;0;AL;;;;;N;;;;; +10D1B;HANIFI ROHINGYA LETTER NYA;Lo;0;AL;;;;;N;;;;; +10D1C;HANIFI ROHINGYA LETTER VA;Lo;0;AL;;;;;N;;;;; +10D1D;HANIFI ROHINGYA VOWEL A;Lo;0;AL;;;;;N;;;;; +10D1E;HANIFI ROHINGYA VOWEL I;Lo;0;AL;;;;;N;;;;; +10D1F;HANIFI ROHINGYA VOWEL U;Lo;0;AL;;;;;N;;;;; +10D20;HANIFI ROHINGYA VOWEL E;Lo;0;AL;;;;;N;;;;; +10D21;HANIFI ROHINGYA VOWEL O;Lo;0;AL;;;;;N;;;;; +10D22;HANIFI ROHINGYA MARK SAKIN;Lo;0;AL;;;;;N;;;;; +10D23;HANIFI ROHINGYA MARK NA KHONNA;Lo;0;AL;;;;;N;;;;; +10D24;HANIFI ROHINGYA SIGN HARBAHAY;Mn;230;NSM;;;;;N;;;;; +10D25;HANIFI ROHINGYA SIGN TAHALA;Mn;230;NSM;;;;;N;;;;; +10D26;HANIFI ROHINGYA SIGN TANA;Mn;230;NSM;;;;;N;;;;; +10D27;HANIFI ROHINGYA SIGN TASSI;Mn;230;NSM;;;;;N;;;;; +10D30;HANIFI ROHINGYA DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;; +10D31;HANIFI ROHINGYA DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;; +10D32;HANIFI ROHINGYA DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;; +10D33;HANIFI ROHINGYA DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;; +10D34;HANIFI ROHINGYA DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;; +10D35;HANIFI ROHINGYA DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;; +10D36;HANIFI ROHINGYA DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;; +10D37;HANIFI ROHINGYA DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;; +10D38;HANIFI ROHINGYA DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;; +10D39;HANIFI ROHINGYA DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;; 10E60;RUMI DIGIT ONE;No;0;AN;;;1;1;N;;;;; 10E61;RUMI DIGIT TWO;No;0;AN;;;2;2;N;;;;; 10E62;RUMI DIGIT THREE;No;0;AN;;;3;3;N;;;;; @@ -18858,6 +19023,88 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10E7C;RUMI FRACTION ONE QUARTER;No;0;AN;;;;1/4;N;;;;; 10E7D;RUMI FRACTION ONE THIRD;No;0;AN;;;;1/3;N;;;;; 10E7E;RUMI FRACTION TWO THIRDS;No;0;AN;;;;2/3;N;;;;; +10F00;OLD SOGDIAN LETTER ALEPH;Lo;0;R;;;;;N;;;;; +10F01;OLD SOGDIAN LETTER FINAL ALEPH;Lo;0;R;;;;;N;;;;; +10F02;OLD SOGDIAN LETTER BETH;Lo;0;R;;;;;N;;;;; +10F03;OLD SOGDIAN LETTER FINAL BETH;Lo;0;R;;;;;N;;;;; +10F04;OLD SOGDIAN LETTER GIMEL;Lo;0;R;;;;;N;;;;; +10F05;OLD SOGDIAN LETTER HE;Lo;0;R;;;;;N;;;;; +10F06;OLD SOGDIAN LETTER FINAL HE;Lo;0;R;;;;;N;;;;; +10F07;OLD SOGDIAN LETTER WAW;Lo;0;R;;;;;N;;;;; +10F08;OLD SOGDIAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +10F09;OLD SOGDIAN LETTER HETH;Lo;0;R;;;;;N;;;;; +10F0A;OLD SOGDIAN LETTER YODH;Lo;0;R;;;;;N;;;;; +10F0B;OLD SOGDIAN LETTER KAPH;Lo;0;R;;;;;N;;;;; +10F0C;OLD SOGDIAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +10F0D;OLD SOGDIAN LETTER MEM;Lo;0;R;;;;;N;;;;; +10F0E;OLD SOGDIAN LETTER NUN;Lo;0;R;;;;;N;;;;; +10F0F;OLD SOGDIAN LETTER FINAL NUN;Lo;0;R;;;;;N;;;;; +10F10;OLD SOGDIAN LETTER FINAL NUN WITH VERTICAL TAIL;Lo;0;R;;;;;N;;;;; +10F11;OLD SOGDIAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +10F12;OLD SOGDIAN LETTER AYIN;Lo;0;R;;;;;N;;;;; +10F13;OLD SOGDIAN LETTER ALTERNATE AYIN;Lo;0;R;;;;;N;;;;; +10F14;OLD SOGDIAN LETTER PE;Lo;0;R;;;;;N;;;;; +10F15;OLD SOGDIAN LETTER SADHE;Lo;0;R;;;;;N;;;;; +10F16;OLD SOGDIAN LETTER FINAL SADHE;Lo;0;R;;;;;N;;;;; +10F17;OLD SOGDIAN LETTER FINAL SADHE WITH VERTICAL TAIL;Lo;0;R;;;;;N;;;;; +10F18;OLD SOGDIAN LETTER RESH-AYIN-DALETH;Lo;0;R;;;;;N;;;;; +10F19;OLD SOGDIAN LETTER SHIN;Lo;0;R;;;;;N;;;;; +10F1A;OLD SOGDIAN LETTER TAW;Lo;0;R;;;;;N;;;;; +10F1B;OLD SOGDIAN LETTER FINAL TAW;Lo;0;R;;;;;N;;;;; +10F1C;OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL;Lo;0;R;;;;;N;;;;; +10F1D;OLD SOGDIAN NUMBER ONE;No;0;R;;;;1;N;;;;; +10F1E;OLD SOGDIAN NUMBER TWO;No;0;R;;;;2;N;;;;; +10F1F;OLD SOGDIAN NUMBER THREE;No;0;R;;;;3;N;;;;; +10F20;OLD SOGDIAN NUMBER FOUR;No;0;R;;;;4;N;;;;; +10F21;OLD SOGDIAN NUMBER FIVE;No;0;R;;;;5;N;;;;; +10F22;OLD SOGDIAN NUMBER TEN;No;0;R;;;;10;N;;;;; +10F23;OLD SOGDIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; +10F24;OLD SOGDIAN NUMBER THIRTY;No;0;R;;;;30;N;;;;; +10F25;OLD SOGDIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +10F26;OLD SOGDIAN FRACTION ONE HALF;No;0;R;;;;1/2;N;;;;; +10F27;OLD SOGDIAN LIGATURE AYIN-DALETH;Lo;0;R;;;;;N;;;;; +10F30;SOGDIAN LETTER ALEPH;Lo;0;AL;;;;;N;;;;; +10F31;SOGDIAN LETTER BETH;Lo;0;AL;;;;;N;;;;; +10F32;SOGDIAN LETTER GIMEL;Lo;0;AL;;;;;N;;;;; +10F33;SOGDIAN LETTER HE;Lo;0;AL;;;;;N;;;;; +10F34;SOGDIAN LETTER WAW;Lo;0;AL;;;;;N;;;;; +10F35;SOGDIAN LETTER ZAYIN;Lo;0;AL;;;;;N;;;;; +10F36;SOGDIAN LETTER HETH;Lo;0;AL;;;;;N;;;;; +10F37;SOGDIAN LETTER YODH;Lo;0;AL;;;;;N;;;;; +10F38;SOGDIAN LETTER KAPH;Lo;0;AL;;;;;N;;;;; +10F39;SOGDIAN LETTER LAMEDH;Lo;0;AL;;;;;N;;;;; +10F3A;SOGDIAN LETTER MEM;Lo;0;AL;;;;;N;;;;; +10F3B;SOGDIAN LETTER NUN;Lo;0;AL;;;;;N;;;;; +10F3C;SOGDIAN LETTER SAMEKH;Lo;0;AL;;;;;N;;;;; +10F3D;SOGDIAN LETTER AYIN;Lo;0;AL;;;;;N;;;;; +10F3E;SOGDIAN LETTER PE;Lo;0;AL;;;;;N;;;;; +10F3F;SOGDIAN LETTER SADHE;Lo;0;AL;;;;;N;;;;; +10F40;SOGDIAN LETTER RESH-AYIN;Lo;0;AL;;;;;N;;;;; +10F41;SOGDIAN LETTER SHIN;Lo;0;AL;;;;;N;;;;; +10F42;SOGDIAN LETTER TAW;Lo;0;AL;;;;;N;;;;; +10F43;SOGDIAN LETTER FETH;Lo;0;AL;;;;;N;;;;; +10F44;SOGDIAN LETTER LESH;Lo;0;AL;;;;;N;;;;; +10F45;SOGDIAN INDEPENDENT SHIN;Lo;0;AL;;;;;N;;;;; +10F46;SOGDIAN COMBINING DOT BELOW;Mn;220;NSM;;;;;N;;;;; +10F47;SOGDIAN COMBINING TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;; +10F48;SOGDIAN COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;;;;; +10F49;SOGDIAN COMBINING TWO DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; +10F4A;SOGDIAN COMBINING CURVE ABOVE;Mn;230;NSM;;;;;N;;;;; +10F4B;SOGDIAN COMBINING CURVE BELOW;Mn;220;NSM;;;;;N;;;;; +10F4C;SOGDIAN COMBINING HOOK ABOVE;Mn;230;NSM;;;;;N;;;;; +10F4D;SOGDIAN COMBINING HOOK BELOW;Mn;220;NSM;;;;;N;;;;; +10F4E;SOGDIAN COMBINING LONG HOOK BELOW;Mn;220;NSM;;;;;N;;;;; +10F4F;SOGDIAN COMBINING RESH BELOW;Mn;220;NSM;;;;;N;;;;; +10F50;SOGDIAN COMBINING STROKE BELOW;Mn;220;NSM;;;;;N;;;;; +10F51;SOGDIAN NUMBER ONE;No;0;AL;;;;1;N;;;;; +10F52;SOGDIAN NUMBER TEN;No;0;AL;;;;10;N;;;;; +10F53;SOGDIAN NUMBER TWENTY;No;0;AL;;;;20;N;;;;; +10F54;SOGDIAN NUMBER ONE HUNDRED;No;0;AL;;;;100;N;;;;; +10F55;SOGDIAN PUNCTUATION TWO VERTICAL BARS;Po;0;AL;;;;;N;;;;; +10F56;SOGDIAN PUNCTUATION TWO VERTICAL BARS WITH DOTS;Po;0;AL;;;;;N;;;;; +10F57;SOGDIAN PUNCTUATION CIRCLE WITH DOT;Po;0;AL;;;;;N;;;;; +10F58;SOGDIAN PUNCTUATION TWO CIRCLES WITH DOTS;Po;0;AL;;;;;N;;;;; +10F59;SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT;Po;0;AL;;;;;N;;;;; 11000;BRAHMI SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;; 11001;BRAHMI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; 11002;BRAHMI SIGN VISARGA;Mc;0;L;;;;;N;;;;; @@ -19033,6 +19280,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 110BF;KAITHI DOUBLE SECTION MARK;Po;0;L;;;;;N;;;;; 110C0;KAITHI DANDA;Po;0;L;;;;;N;;;;; 110C1;KAITHI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +110CD;KAITHI NUMBER SIGN ABOVE;Cf;0;L;;;;;N;;;;; 110D0;SORA SOMPENG LETTER SAH;Lo;0;L;;;;;N;;;;; 110D1;SORA SOMPENG LETTER TAH;Lo;0;L;;;;;N;;;;; 110D2;SORA SOMPENG LETTER BAH;Lo;0;L;;;;;N;;;;; @@ -19135,6 +19383,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11141;CHAKMA DANDA;Po;0;L;;;;;N;;;;; 11142;CHAKMA DOUBLE DANDA;Po;0;L;;;;;N;;;;; 11143;CHAKMA QUESTION MARK;Po;0;L;;;;;N;;;;; +11144;CHAKMA LETTER LHAA;Lo;0;L;;;;;N;;;;; +11145;CHAKMA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +11146;CHAKMA VOWEL SIGN EI;Mc;0;L;;;;;N;;;;; 11150;MAHAJANI LETTER A;Lo;0;L;;;;;N;;;;; 11151;MAHAJANI LETTER I;Lo;0;L;;;;;N;;;;; 11152;MAHAJANI LETTER U;Lo;0;L;;;;;N;;;;; @@ -19247,7 +19498,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 111C6;SHARADA DOUBLE DANDA;Po;0;L;;;;;N;;;;; 111C7;SHARADA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; 111C8;SHARADA SEPARATOR;Po;0;L;;;;;N;;;;; -111C9;SHARADA SANDHI MARK;Po;0;L;;;;;N;;;;; +111C9;SHARADA SANDHI MARK;Mn;0;NSM;;;;;N;;;;; 111CA;SHARADA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; 111CB;SHARADA VOWEL MODIFIER MARK;Mn;0;NSM;;;;;N;;;;; 111CC;SHARADA EXTRA SHORT VOWEL MARK;Mn;0;NSM;;;;;N;;;;; @@ -19507,6 +19758,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11337;GRANTHA LETTER SSA;Lo;0;L;;;;;N;;;;; 11338;GRANTHA LETTER SA;Lo;0;L;;;;;N;;;;; 11339;GRANTHA LETTER HA;Lo;0;L;;;;;N;;;;; +1133B;COMBINING BINDU BELOW;Mn;7;NSM;;;;;N;;;;; 1133C;GRANTHA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; 1133D;GRANTHA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; 1133E;GRANTHA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; @@ -19634,6 +19886,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11459;NEWA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 1145B;NEWA PLACEHOLDER MARK;Po;0;L;;;;;N;;;;; 1145D;NEWA INSERTION SIGN;Po;0;L;;;;;N;;;;; +1145E;NEWA SANDHI MARK;Mn;230;NSM;;;;;N;;;;; 11480;TIRHUTA ANJI;Lo;0;L;;;;;N;;;;; 11481;TIRHUTA LETTER A;Lo;0;L;;;;;N;;;;; 11482;TIRHUTA LETTER AA;Lo;0;L;;;;;N;;;;; @@ -19992,6 +20245,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11717;AHOM LETTER GHA;Lo;0;L;;;;;N;;;;; 11718;AHOM LETTER BHA;Lo;0;L;;;;;N;;;;; 11719;AHOM LETTER JHA;Lo;0;L;;;;;N;;;;; +1171A;AHOM LETTER ALTERNATE BA;Lo;0;L;;;;;N;;;;; 1171D;AHOM CONSONANT SIGN MEDIAL LA;Mn;0;NSM;;;;;N;;;;; 1171E;AHOM CONSONANT SIGN MEDIAL RA;Mn;0;NSM;;;;;N;;;;; 1171F;AHOM CONSONANT SIGN MEDIAL LIGATING RA;Mn;0;NSM;;;;;N;;;;; @@ -20023,6 +20277,66 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1173D;AHOM SIGN SECTION;Po;0;L;;;;;N;;;;; 1173E;AHOM SIGN RULAI;Po;0;L;;;;;N;;;;; 1173F;AHOM SYMBOL VI;So;0;L;;;;;N;;;;; +11800;DOGRA LETTER A;Lo;0;L;;;;;N;;;;; +11801;DOGRA LETTER AA;Lo;0;L;;;;;N;;;;; +11802;DOGRA LETTER I;Lo;0;L;;;;;N;;;;; +11803;DOGRA LETTER II;Lo;0;L;;;;;N;;;;; +11804;DOGRA LETTER U;Lo;0;L;;;;;N;;;;; +11805;DOGRA LETTER UU;Lo;0;L;;;;;N;;;;; +11806;DOGRA LETTER E;Lo;0;L;;;;;N;;;;; +11807;DOGRA LETTER AI;Lo;0;L;;;;;N;;;;; +11808;DOGRA LETTER O;Lo;0;L;;;;;N;;;;; +11809;DOGRA LETTER AU;Lo;0;L;;;;;N;;;;; +1180A;DOGRA LETTER KA;Lo;0;L;;;;;N;;;;; +1180B;DOGRA LETTER KHA;Lo;0;L;;;;;N;;;;; +1180C;DOGRA LETTER GA;Lo;0;L;;;;;N;;;;; +1180D;DOGRA LETTER GHA;Lo;0;L;;;;;N;;;;; +1180E;DOGRA LETTER NGA;Lo;0;L;;;;;N;;;;; +1180F;DOGRA LETTER CA;Lo;0;L;;;;;N;;;;; +11810;DOGRA LETTER CHA;Lo;0;L;;;;;N;;;;; +11811;DOGRA LETTER JA;Lo;0;L;;;;;N;;;;; +11812;DOGRA LETTER JHA;Lo;0;L;;;;;N;;;;; +11813;DOGRA LETTER NYA;Lo;0;L;;;;;N;;;;; +11814;DOGRA LETTER TTA;Lo;0;L;;;;;N;;;;; +11815;DOGRA LETTER TTHA;Lo;0;L;;;;;N;;;;; +11816;DOGRA LETTER DDA;Lo;0;L;;;;;N;;;;; +11817;DOGRA LETTER DDHA;Lo;0;L;;;;;N;;;;; +11818;DOGRA LETTER NNA;Lo;0;L;;;;;N;;;;; +11819;DOGRA LETTER TA;Lo;0;L;;;;;N;;;;; +1181A;DOGRA LETTER THA;Lo;0;L;;;;;N;;;;; +1181B;DOGRA LETTER DA;Lo;0;L;;;;;N;;;;; +1181C;DOGRA LETTER DHA;Lo;0;L;;;;;N;;;;; +1181D;DOGRA LETTER NA;Lo;0;L;;;;;N;;;;; +1181E;DOGRA LETTER PA;Lo;0;L;;;;;N;;;;; +1181F;DOGRA LETTER PHA;Lo;0;L;;;;;N;;;;; +11820;DOGRA LETTER BA;Lo;0;L;;;;;N;;;;; +11821;DOGRA LETTER BHA;Lo;0;L;;;;;N;;;;; +11822;DOGRA LETTER MA;Lo;0;L;;;;;N;;;;; +11823;DOGRA LETTER YA;Lo;0;L;;;;;N;;;;; +11824;DOGRA LETTER RA;Lo;0;L;;;;;N;;;;; +11825;DOGRA LETTER LA;Lo;0;L;;;;;N;;;;; +11826;DOGRA LETTER VA;Lo;0;L;;;;;N;;;;; +11827;DOGRA LETTER SHA;Lo;0;L;;;;;N;;;;; +11828;DOGRA LETTER SSA;Lo;0;L;;;;;N;;;;; +11829;DOGRA LETTER SA;Lo;0;L;;;;;N;;;;; +1182A;DOGRA LETTER HA;Lo;0;L;;;;;N;;;;; +1182B;DOGRA LETTER RRA;Lo;0;L;;;;;N;;;;; +1182C;DOGRA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +1182D;DOGRA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +1182E;DOGRA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +1182F;DOGRA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11830;DOGRA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +11831;DOGRA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +11832;DOGRA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +11833;DOGRA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +11834;DOGRA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +11835;DOGRA VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +11836;DOGRA VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +11837;DOGRA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11838;DOGRA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11839;DOGRA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +1183A;DOGRA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +1183B;DOGRA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; 118A0;WARANG CITI CAPITAL LETTER NGAA;Lu;0;L;;;;;N;;;;118C0; 118A1;WARANG CITI CAPITAL LETTER A;Lu;0;L;;;;;N;;;;118C1; 118A2;WARANG CITI CAPITAL LETTER WI;Lu;0;L;;;;;N;;;;118C2; @@ -20114,8 +20428,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11A04;ZANABAZAR SQUARE VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; 11A05;ZANABAZAR SQUARE VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;; 11A06;ZANABAZAR SQUARE VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; -11A07;ZANABAZAR SQUARE VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; -11A08;ZANABAZAR SQUARE VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +11A07;ZANABAZAR SQUARE VOWEL SIGN AI;Mn;0;L;;;;;N;;;;; +11A08;ZANABAZAR SQUARE VOWEL SIGN AU;Mn;0;L;;;;;N;;;;; 11A09;ZANABAZAR SQUARE VOWEL SIGN REVERSED I;Mn;0;NSM;;;;;N;;;;; 11A0A;ZANABAZAR SQUARE VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;; 11A0B;ZANABAZAR SQUARE LETTER KA;Lo;0;L;;;;;N;;;;; @@ -20254,6 +20568,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11A9A;SOYOMBO MARK TSHEG;Po;0;L;;;;;N;;;;; 11A9B;SOYOMBO MARK SHAD;Po;0;L;;;;;N;;;;; 11A9C;SOYOMBO MARK DOUBLE SHAD;Po;0;L;;;;;N;;;;; +11A9D;SOYOMBO MARK PLUTA;Lo;0;L;;;;;N;;;;; 11A9E;SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME;Po;0;L;;;;;N;;;;; 11A9F;SOYOMBO HEAD MARK WITH MOON AND SUN AND FLAME;Po;0;L;;;;;N;;;;; 11AA0;SOYOMBO HEAD MARK WITH MOON AND SUN;Po;0;L;;;;;N;;;;; @@ -20556,6 +20871,94 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11D57;MASARAM GONDI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 11D58;MASARAM GONDI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 11D59;MASARAM GONDI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11D60;GUNJALA GONDI LETTER A;Lo;0;L;;;;;N;;;;; +11D61;GUNJALA GONDI LETTER AA;Lo;0;L;;;;;N;;;;; +11D62;GUNJALA GONDI LETTER I;Lo;0;L;;;;;N;;;;; +11D63;GUNJALA GONDI LETTER II;Lo;0;L;;;;;N;;;;; +11D64;GUNJALA GONDI LETTER U;Lo;0;L;;;;;N;;;;; +11D65;GUNJALA GONDI LETTER UU;Lo;0;L;;;;;N;;;;; +11D67;GUNJALA GONDI LETTER EE;Lo;0;L;;;;;N;;;;; +11D68;GUNJALA GONDI LETTER AI;Lo;0;L;;;;;N;;;;; +11D6A;GUNJALA GONDI LETTER OO;Lo;0;L;;;;;N;;;;; +11D6B;GUNJALA GONDI LETTER AU;Lo;0;L;;;;;N;;;;; +11D6C;GUNJALA GONDI LETTER YA;Lo;0;L;;;;;N;;;;; +11D6D;GUNJALA GONDI LETTER VA;Lo;0;L;;;;;N;;;;; +11D6E;GUNJALA GONDI LETTER BA;Lo;0;L;;;;;N;;;;; +11D6F;GUNJALA GONDI LETTER BHA;Lo;0;L;;;;;N;;;;; +11D70;GUNJALA GONDI LETTER MA;Lo;0;L;;;;;N;;;;; +11D71;GUNJALA GONDI LETTER KA;Lo;0;L;;;;;N;;;;; +11D72;GUNJALA GONDI LETTER KHA;Lo;0;L;;;;;N;;;;; +11D73;GUNJALA GONDI LETTER TA;Lo;0;L;;;;;N;;;;; +11D74;GUNJALA GONDI LETTER THA;Lo;0;L;;;;;N;;;;; +11D75;GUNJALA GONDI LETTER LA;Lo;0;L;;;;;N;;;;; +11D76;GUNJALA GONDI LETTER GA;Lo;0;L;;;;;N;;;;; +11D77;GUNJALA GONDI LETTER GHA;Lo;0;L;;;;;N;;;;; +11D78;GUNJALA GONDI LETTER DA;Lo;0;L;;;;;N;;;;; +11D79;GUNJALA GONDI LETTER DHA;Lo;0;L;;;;;N;;;;; +11D7A;GUNJALA GONDI LETTER NA;Lo;0;L;;;;;N;;;;; +11D7B;GUNJALA GONDI LETTER CA;Lo;0;L;;;;;N;;;;; +11D7C;GUNJALA GONDI LETTER CHA;Lo;0;L;;;;;N;;;;; +11D7D;GUNJALA GONDI LETTER TTA;Lo;0;L;;;;;N;;;;; +11D7E;GUNJALA GONDI LETTER TTHA;Lo;0;L;;;;;N;;;;; +11D7F;GUNJALA GONDI LETTER LLA;Lo;0;L;;;;;N;;;;; +11D80;GUNJALA GONDI LETTER JA;Lo;0;L;;;;;N;;;;; +11D81;GUNJALA GONDI LETTER JHA;Lo;0;L;;;;;N;;;;; +11D82;GUNJALA GONDI LETTER DDA;Lo;0;L;;;;;N;;;;; +11D83;GUNJALA GONDI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11D84;GUNJALA GONDI LETTER NGA;Lo;0;L;;;;;N;;;;; +11D85;GUNJALA GONDI LETTER PA;Lo;0;L;;;;;N;;;;; +11D86;GUNJALA GONDI LETTER PHA;Lo;0;L;;;;;N;;;;; +11D87;GUNJALA GONDI LETTER HA;Lo;0;L;;;;;N;;;;; +11D88;GUNJALA GONDI LETTER RA;Lo;0;L;;;;;N;;;;; +11D89;GUNJALA GONDI LETTER SA;Lo;0;L;;;;;N;;;;; +11D8A;GUNJALA GONDI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +11D8B;GUNJALA GONDI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +11D8C;GUNJALA GONDI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +11D8D;GUNJALA GONDI VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +11D8E;GUNJALA GONDI VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +11D90;GUNJALA GONDI VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;; +11D91;GUNJALA GONDI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +11D93;GUNJALA GONDI VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; +11D94;GUNJALA GONDI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +11D95;GUNJALA GONDI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11D96;GUNJALA GONDI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11D97;GUNJALA GONDI VIRAMA;Mn;9;NSM;;;;;N;;;;; +11D98;GUNJALA GONDI OM;Lo;0;L;;;;;N;;;;; +11DA0;GUNJALA GONDI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11DA1;GUNJALA GONDI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11DA2;GUNJALA GONDI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11DA3;GUNJALA GONDI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11DA4;GUNJALA GONDI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11DA5;GUNJALA GONDI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11DA6;GUNJALA GONDI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11DA7;GUNJALA GONDI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11DA8;GUNJALA GONDI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11DA9;GUNJALA GONDI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11EE0;MAKASAR LETTER KA;Lo;0;L;;;;;N;;;;; +11EE1;MAKASAR LETTER GA;Lo;0;L;;;;;N;;;;; +11EE2;MAKASAR LETTER NGA;Lo;0;L;;;;;N;;;;; +11EE3;MAKASAR LETTER PA;Lo;0;L;;;;;N;;;;; +11EE4;MAKASAR LETTER BA;Lo;0;L;;;;;N;;;;; +11EE5;MAKASAR LETTER MA;Lo;0;L;;;;;N;;;;; +11EE6;MAKASAR LETTER TA;Lo;0;L;;;;;N;;;;; +11EE7;MAKASAR LETTER DA;Lo;0;L;;;;;N;;;;; +11EE8;MAKASAR LETTER NA;Lo;0;L;;;;;N;;;;; +11EE9;MAKASAR LETTER CA;Lo;0;L;;;;;N;;;;; +11EEA;MAKASAR LETTER JA;Lo;0;L;;;;;N;;;;; +11EEB;MAKASAR LETTER NYA;Lo;0;L;;;;;N;;;;; +11EEC;MAKASAR LETTER YA;Lo;0;L;;;;;N;;;;; +11EED;MAKASAR LETTER RA;Lo;0;L;;;;;N;;;;; +11EEE;MAKASAR LETTER LA;Lo;0;L;;;;;N;;;;; +11EEF;MAKASAR LETTER VA;Lo;0;L;;;;;N;;;;; +11EF0;MAKASAR LETTER SA;Lo;0;L;;;;;N;;;;; +11EF1;MAKASAR LETTER A;Lo;0;L;;;;;N;;;;; +11EF2;MAKASAR ANGKA;Lo;0;L;;;;;N;;;;; +11EF3;MAKASAR VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +11EF4;MAKASAR VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11EF5;MAKASAR VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +11EF6;MAKASAR VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +11EF7;MAKASAR PASSIMBANG;Po;0;L;;;;;N;;;;; +11EF8;MAKASAR END OF SECTION;Po;0;L;;;;;N;;;;; 12000;CUNEIFORM SIGN A;Lo;0;L;;;;;N;;;;; 12001;CUNEIFORM SIGN A TIMES A;Lo;0;L;;;;;N;;;;; 12002;CUNEIFORM SIGN A TIMES BAD;Lo;0;L;;;;;N;;;;; @@ -24219,6 +24622,97 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 16B8D;PAHAWH HMONG CLAN SIGN TSWB;Lo;0;L;;;;;N;;;;; 16B8E;PAHAWH HMONG CLAN SIGN KWM;Lo;0;L;;;;;N;;;;; 16B8F;PAHAWH HMONG CLAN SIGN VWJ;Lo;0;L;;;;;N;;;;; +16E40;MEDEFAIDRIN CAPITAL LETTER M;Lu;0;L;;;;;N;;;;16E60; +16E41;MEDEFAIDRIN CAPITAL LETTER S;Lu;0;L;;;;;N;;;;16E61; +16E42;MEDEFAIDRIN CAPITAL LETTER V;Lu;0;L;;;;;N;;;;16E62; +16E43;MEDEFAIDRIN CAPITAL LETTER W;Lu;0;L;;;;;N;;;;16E63; +16E44;MEDEFAIDRIN CAPITAL LETTER ATIU;Lu;0;L;;;;;N;;;;16E64; +16E45;MEDEFAIDRIN CAPITAL LETTER Z;Lu;0;L;;;;;N;;;;16E65; +16E46;MEDEFAIDRIN CAPITAL LETTER KP;Lu;0;L;;;;;N;;;;16E66; +16E47;MEDEFAIDRIN CAPITAL LETTER P;Lu;0;L;;;;;N;;;;16E67; +16E48;MEDEFAIDRIN CAPITAL LETTER T;Lu;0;L;;;;;N;;;;16E68; +16E49;MEDEFAIDRIN CAPITAL LETTER G;Lu;0;L;;;;;N;;;;16E69; +16E4A;MEDEFAIDRIN CAPITAL LETTER F;Lu;0;L;;;;;N;;;;16E6A; +16E4B;MEDEFAIDRIN CAPITAL LETTER I;Lu;0;L;;;;;N;;;;16E6B; +16E4C;MEDEFAIDRIN CAPITAL LETTER K;Lu;0;L;;;;;N;;;;16E6C; +16E4D;MEDEFAIDRIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;16E6D; +16E4E;MEDEFAIDRIN CAPITAL LETTER J;Lu;0;L;;;;;N;;;;16E6E; +16E4F;MEDEFAIDRIN CAPITAL LETTER E;Lu;0;L;;;;;N;;;;16E6F; +16E50;MEDEFAIDRIN CAPITAL LETTER B;Lu;0;L;;;;;N;;;;16E70; +16E51;MEDEFAIDRIN CAPITAL LETTER C;Lu;0;L;;;;;N;;;;16E71; +16E52;MEDEFAIDRIN CAPITAL LETTER U;Lu;0;L;;;;;N;;;;16E72; +16E53;MEDEFAIDRIN CAPITAL LETTER YU;Lu;0;L;;;;;N;;;;16E73; +16E54;MEDEFAIDRIN CAPITAL LETTER L;Lu;0;L;;;;;N;;;;16E74; +16E55;MEDEFAIDRIN CAPITAL LETTER Q;Lu;0;L;;;;;N;;;;16E75; +16E56;MEDEFAIDRIN CAPITAL LETTER HP;Lu;0;L;;;;;N;;;;16E76; +16E57;MEDEFAIDRIN CAPITAL LETTER NY;Lu;0;L;;;;;N;;;;16E77; +16E58;MEDEFAIDRIN CAPITAL LETTER X;Lu;0;L;;;;;N;;;;16E78; +16E59;MEDEFAIDRIN CAPITAL LETTER D;Lu;0;L;;;;;N;;;;16E79; +16E5A;MEDEFAIDRIN CAPITAL LETTER OE;Lu;0;L;;;;;N;;;;16E7A; +16E5B;MEDEFAIDRIN CAPITAL LETTER N;Lu;0;L;;;;;N;;;;16E7B; +16E5C;MEDEFAIDRIN CAPITAL LETTER R;Lu;0;L;;;;;N;;;;16E7C; +16E5D;MEDEFAIDRIN CAPITAL LETTER O;Lu;0;L;;;;;N;;;;16E7D; +16E5E;MEDEFAIDRIN CAPITAL LETTER AI;Lu;0;L;;;;;N;;;;16E7E; +16E5F;MEDEFAIDRIN CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;16E7F; +16E60;MEDEFAIDRIN SMALL LETTER M;Ll;0;L;;;;;N;;;16E40;;16E40 +16E61;MEDEFAIDRIN SMALL LETTER S;Ll;0;L;;;;;N;;;16E41;;16E41 +16E62;MEDEFAIDRIN SMALL LETTER V;Ll;0;L;;;;;N;;;16E42;;16E42 +16E63;MEDEFAIDRIN SMALL LETTER W;Ll;0;L;;;;;N;;;16E43;;16E43 +16E64;MEDEFAIDRIN SMALL LETTER ATIU;Ll;0;L;;;;;N;;;16E44;;16E44 +16E65;MEDEFAIDRIN SMALL LETTER Z;Ll;0;L;;;;;N;;;16E45;;16E45 +16E66;MEDEFAIDRIN SMALL LETTER KP;Ll;0;L;;;;;N;;;16E46;;16E46 +16E67;MEDEFAIDRIN SMALL LETTER P;Ll;0;L;;;;;N;;;16E47;;16E47 +16E68;MEDEFAIDRIN SMALL LETTER T;Ll;0;L;;;;;N;;;16E48;;16E48 +16E69;MEDEFAIDRIN SMALL LETTER G;Ll;0;L;;;;;N;;;16E49;;16E49 +16E6A;MEDEFAIDRIN SMALL LETTER F;Ll;0;L;;;;;N;;;16E4A;;16E4A +16E6B;MEDEFAIDRIN SMALL LETTER I;Ll;0;L;;;;;N;;;16E4B;;16E4B +16E6C;MEDEFAIDRIN SMALL LETTER K;Ll;0;L;;;;;N;;;16E4C;;16E4C +16E6D;MEDEFAIDRIN SMALL LETTER A;Ll;0;L;;;;;N;;;16E4D;;16E4D +16E6E;MEDEFAIDRIN SMALL LETTER J;Ll;0;L;;;;;N;;;16E4E;;16E4E +16E6F;MEDEFAIDRIN SMALL LETTER E;Ll;0;L;;;;;N;;;16E4F;;16E4F +16E70;MEDEFAIDRIN SMALL LETTER B;Ll;0;L;;;;;N;;;16E50;;16E50 +16E71;MEDEFAIDRIN SMALL LETTER C;Ll;0;L;;;;;N;;;16E51;;16E51 +16E72;MEDEFAIDRIN SMALL LETTER U;Ll;0;L;;;;;N;;;16E52;;16E52 +16E73;MEDEFAIDRIN SMALL LETTER YU;Ll;0;L;;;;;N;;;16E53;;16E53 +16E74;MEDEFAIDRIN SMALL LETTER L;Ll;0;L;;;;;N;;;16E54;;16E54 +16E75;MEDEFAIDRIN SMALL LETTER Q;Ll;0;L;;;;;N;;;16E55;;16E55 +16E76;MEDEFAIDRIN SMALL LETTER HP;Ll;0;L;;;;;N;;;16E56;;16E56 +16E77;MEDEFAIDRIN SMALL LETTER NY;Ll;0;L;;;;;N;;;16E57;;16E57 +16E78;MEDEFAIDRIN SMALL LETTER X;Ll;0;L;;;;;N;;;16E58;;16E58 +16E79;MEDEFAIDRIN SMALL LETTER D;Ll;0;L;;;;;N;;;16E59;;16E59 +16E7A;MEDEFAIDRIN SMALL LETTER OE;Ll;0;L;;;;;N;;;16E5A;;16E5A +16E7B;MEDEFAIDRIN SMALL LETTER N;Ll;0;L;;;;;N;;;16E5B;;16E5B +16E7C;MEDEFAIDRIN SMALL LETTER R;Ll;0;L;;;;;N;;;16E5C;;16E5C +16E7D;MEDEFAIDRIN SMALL LETTER O;Ll;0;L;;;;;N;;;16E5D;;16E5D +16E7E;MEDEFAIDRIN SMALL LETTER AI;Ll;0;L;;;;;N;;;16E5E;;16E5E +16E7F;MEDEFAIDRIN SMALL LETTER Y;Ll;0;L;;;;;N;;;16E5F;;16E5F +16E80;MEDEFAIDRIN DIGIT ZERO;No;0;L;;;;0;N;;;;; +16E81;MEDEFAIDRIN DIGIT ONE;No;0;L;;;;1;N;;;;; +16E82;MEDEFAIDRIN DIGIT TWO;No;0;L;;;;2;N;;;;; +16E83;MEDEFAIDRIN DIGIT THREE;No;0;L;;;;3;N;;;;; +16E84;MEDEFAIDRIN DIGIT FOUR;No;0;L;;;;4;N;;;;; +16E85;MEDEFAIDRIN DIGIT FIVE;No;0;L;;;;5;N;;;;; +16E86;MEDEFAIDRIN DIGIT SIX;No;0;L;;;;6;N;;;;; +16E87;MEDEFAIDRIN DIGIT SEVEN;No;0;L;;;;7;N;;;;; +16E88;MEDEFAIDRIN DIGIT EIGHT;No;0;L;;;;8;N;;;;; +16E89;MEDEFAIDRIN DIGIT NINE;No;0;L;;;;9;N;;;;; +16E8A;MEDEFAIDRIN NUMBER TEN;No;0;L;;;;10;N;;;;; +16E8B;MEDEFAIDRIN NUMBER ELEVEN;No;0;L;;;;11;N;;;;; +16E8C;MEDEFAIDRIN NUMBER TWELVE;No;0;L;;;;12;N;;;;; +16E8D;MEDEFAIDRIN NUMBER THIRTEEN;No;0;L;;;;13;N;;;;; +16E8E;MEDEFAIDRIN NUMBER FOURTEEN;No;0;L;;;;14;N;;;;; +16E8F;MEDEFAIDRIN NUMBER FIFTEEN;No;0;L;;;;15;N;;;;; +16E90;MEDEFAIDRIN NUMBER SIXTEEN;No;0;L;;;;16;N;;;;; +16E91;MEDEFAIDRIN NUMBER SEVENTEEN;No;0;L;;;;17;N;;;;; +16E92;MEDEFAIDRIN NUMBER EIGHTEEN;No;0;L;;;;18;N;;;;; +16E93;MEDEFAIDRIN NUMBER NINETEEN;No;0;L;;;;19;N;;;;; +16E94;MEDEFAIDRIN DIGIT ONE ALTERNATE FORM;No;0;L;;;;1;N;;;;; +16E95;MEDEFAIDRIN DIGIT TWO ALTERNATE FORM;No;0;L;;;;2;N;;;;; +16E96;MEDEFAIDRIN DIGIT THREE ALTERNATE FORM;No;0;L;;;;3;N;;;;; +16E97;MEDEFAIDRIN COMMA;Po;0;L;;;;;N;;;;; +16E98;MEDEFAIDRIN FULL STOP;Po;0;L;;;;;N;;;;; +16E99;MEDEFAIDRIN SYMBOL AIVA;Po;0;L;;;;;N;;;;; +16E9A;MEDEFAIDRIN EXCLAMATION OH;Po;0;L;;;;;N;;;;; 16F00;MIAO LETTER PA;Lo;0;L;;;;;N;;;;; 16F01;MIAO LETTER BA;Lo;0;L;;;;;N;;;;; 16F02;MIAO LETTER YI PA;Lo;0;L;;;;;N;;;;; @@ -24355,7 +24849,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 16FE0;TANGUT ITERATION MARK;Lm;0;L;;;;;N;;;;; 16FE1;NUSHU ITERATION MARK;Lm;0;L;;;;;N;;;;; 17000;;Lo;0;L;;;;;N;;;;; -187EC;;Lo;0;L;;;;;N;;;;; +187F1;;Lo;0;L;;;;;N;;;;; 18800;TANGUT COMPONENT-001;Lo;0;L;;;;;N;;;;; 18801;TANGUT COMPONENT-002;Lo;0;L;;;;;N;;;;; 18802;TANGUT COMPONENT-003;Lo;0;L;;;;;N;;;;; @@ -26488,6 +26982,26 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1D243;COMBINING GREEK MUSICAL TETRASEME;Mn;230;NSM;;;;;N;;;;; 1D244;COMBINING GREEK MUSICAL PENTASEME;Mn;230;NSM;;;;;N;;;;; 1D245;GREEK MUSICAL LEIMMA;So;0;ON;;;;;N;;;;; +1D2E0;MAYAN NUMERAL ZERO;No;0;L;;;;0;N;;;;; +1D2E1;MAYAN NUMERAL ONE;No;0;L;;;;1;N;;;;; +1D2E2;MAYAN NUMERAL TWO;No;0;L;;;;2;N;;;;; +1D2E3;MAYAN NUMERAL THREE;No;0;L;;;;3;N;;;;; +1D2E4;MAYAN NUMERAL FOUR;No;0;L;;;;4;N;;;;; +1D2E5;MAYAN NUMERAL FIVE;No;0;L;;;;5;N;;;;; +1D2E6;MAYAN NUMERAL SIX;No;0;L;;;;6;N;;;;; +1D2E7;MAYAN NUMERAL SEVEN;No;0;L;;;;7;N;;;;; +1D2E8;MAYAN NUMERAL EIGHT;No;0;L;;;;8;N;;;;; +1D2E9;MAYAN NUMERAL NINE;No;0;L;;;;9;N;;;;; +1D2EA;MAYAN NUMERAL TEN;No;0;L;;;;10;N;;;;; +1D2EB;MAYAN NUMERAL ELEVEN;No;0;L;;;;11;N;;;;; +1D2EC;MAYAN NUMERAL TWELVE;No;0;L;;;;12;N;;;;; +1D2ED;MAYAN NUMERAL THIRTEEN;No;0;L;;;;13;N;;;;; +1D2EE;MAYAN NUMERAL FOURTEEN;No;0;L;;;;14;N;;;;; +1D2EF;MAYAN NUMERAL FIFTEEN;No;0;L;;;;15;N;;;;; +1D2F0;MAYAN NUMERAL SIXTEEN;No;0;L;;;;16;N;;;;; +1D2F1;MAYAN NUMERAL SEVENTEEN;No;0;L;;;;17;N;;;;; +1D2F2;MAYAN NUMERAL EIGHTEEN;No;0;L;;;;18;N;;;;; +1D2F3;MAYAN NUMERAL NINETEEN;No;0;L;;;;19;N;;;;; 1D300;MONOGRAM FOR EARTH;So;0;ON;;;;;N;;;;; 1D301;DIGRAM FOR HEAVENLY EARTH;So;0;ON;;;;;N;;;;; 1D302;DIGRAM FOR HUMAN EARTH;So;0;ON;;;;;N;;;;; @@ -26593,6 +27107,13 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1D36F;COUNTING ROD TENS DIGIT SEVEN;No;0;L;;;;70;N;;;;; 1D370;COUNTING ROD TENS DIGIT EIGHT;No;0;L;;;;80;N;;;;; 1D371;COUNTING ROD TENS DIGIT NINE;No;0;L;;;;90;N;;;;; +1D372;IDEOGRAPHIC TALLY MARK ONE;No;0;L;;;;1;N;;;;; +1D373;IDEOGRAPHIC TALLY MARK TWO;No;0;L;;;;2;N;;;;; +1D374;IDEOGRAPHIC TALLY MARK THREE;No;0;L;;;;3;N;;;;; +1D375;IDEOGRAPHIC TALLY MARK FOUR;No;0;L;;;;4;N;;;;; +1D376;IDEOGRAPHIC TALLY MARK FIVE;No;0;L;;;;5;N;;;;; +1D377;TALLY MARK ONE;No;0;L;;;;1;N;;;;; +1D378;TALLY MARK FIVE;No;0;L;;;;5;N;;;;; 1D400;MATHEMATICAL BOLD CAPITAL A;Lu;0;L; 0041;;;;N;;;;; 1D401;MATHEMATICAL BOLD CAPITAL B;Lu;0;L; 0042;;;;N;;;;; 1D402;MATHEMATICAL BOLD CAPITAL C;Lu;0;L; 0043;;;;N;;;;; @@ -28599,6 +29120,74 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1E959;ADLAM DIGIT NINE;Nd;0;R;;9;9;9;N;;;;; 1E95E;ADLAM INITIAL EXCLAMATION MARK;Po;0;R;;;;;N;;;;; 1E95F;ADLAM INITIAL QUESTION MARK;Po;0;R;;;;;N;;;;; +1EC71;INDIC SIYAQ NUMBER ONE;No;0;AL;;;;1;N;;;;; +1EC72;INDIC SIYAQ NUMBER TWO;No;0;AL;;;;2;N;;;;; +1EC73;INDIC SIYAQ NUMBER THREE;No;0;AL;;;;3;N;;;;; +1EC74;INDIC SIYAQ NUMBER FOUR;No;0;AL;;;;4;N;;;;; +1EC75;INDIC SIYAQ NUMBER FIVE;No;0;AL;;;;5;N;;;;; +1EC76;INDIC SIYAQ NUMBER SIX;No;0;AL;;;;6;N;;;;; +1EC77;INDIC SIYAQ NUMBER SEVEN;No;0;AL;;;;7;N;;;;; +1EC78;INDIC SIYAQ NUMBER EIGHT;No;0;AL;;;;8;N;;;;; +1EC79;INDIC SIYAQ NUMBER NINE;No;0;AL;;;;9;N;;;;; +1EC7A;INDIC SIYAQ NUMBER TEN;No;0;AL;;;;10;N;;;;; +1EC7B;INDIC SIYAQ NUMBER TWENTY;No;0;AL;;;;20;N;;;;; +1EC7C;INDIC SIYAQ NUMBER THIRTY;No;0;AL;;;;30;N;;;;; +1EC7D;INDIC SIYAQ NUMBER FORTY;No;0;AL;;;;40;N;;;;; +1EC7E;INDIC SIYAQ NUMBER FIFTY;No;0;AL;;;;50;N;;;;; +1EC7F;INDIC SIYAQ NUMBER SIXTY;No;0;AL;;;;60;N;;;;; +1EC80;INDIC SIYAQ NUMBER SEVENTY;No;0;AL;;;;70;N;;;;; +1EC81;INDIC SIYAQ NUMBER EIGHTY;No;0;AL;;;;80;N;;;;; +1EC82;INDIC SIYAQ NUMBER NINETY;No;0;AL;;;;90;N;;;;; +1EC83;INDIC SIYAQ NUMBER ONE HUNDRED;No;0;AL;;;;100;N;;;;; +1EC84;INDIC SIYAQ NUMBER TWO HUNDRED;No;0;AL;;;;200;N;;;;; +1EC85;INDIC SIYAQ NUMBER THREE HUNDRED;No;0;AL;;;;300;N;;;;; +1EC86;INDIC SIYAQ NUMBER FOUR HUNDRED;No;0;AL;;;;400;N;;;;; +1EC87;INDIC SIYAQ NUMBER FIVE HUNDRED;No;0;AL;;;;500;N;;;;; +1EC88;INDIC SIYAQ NUMBER SIX HUNDRED;No;0;AL;;;;600;N;;;;; +1EC89;INDIC SIYAQ NUMBER SEVEN HUNDRED;No;0;AL;;;;700;N;;;;; +1EC8A;INDIC SIYAQ NUMBER EIGHT HUNDRED;No;0;AL;;;;800;N;;;;; +1EC8B;INDIC SIYAQ NUMBER NINE HUNDRED;No;0;AL;;;;900;N;;;;; +1EC8C;INDIC SIYAQ NUMBER ONE THOUSAND;No;0;AL;;;;1000;N;;;;; +1EC8D;INDIC SIYAQ NUMBER TWO THOUSAND;No;0;AL;;;;2000;N;;;;; +1EC8E;INDIC SIYAQ NUMBER THREE THOUSAND;No;0;AL;;;;3000;N;;;;; +1EC8F;INDIC SIYAQ NUMBER FOUR THOUSAND;No;0;AL;;;;4000;N;;;;; +1EC90;INDIC SIYAQ NUMBER FIVE THOUSAND;No;0;AL;;;;5000;N;;;;; +1EC91;INDIC SIYAQ NUMBER SIX THOUSAND;No;0;AL;;;;6000;N;;;;; +1EC92;INDIC SIYAQ NUMBER SEVEN THOUSAND;No;0;AL;;;;7000;N;;;;; +1EC93;INDIC SIYAQ NUMBER EIGHT THOUSAND;No;0;AL;;;;8000;N;;;;; +1EC94;INDIC SIYAQ NUMBER NINE THOUSAND;No;0;AL;;;;9000;N;;;;; +1EC95;INDIC SIYAQ NUMBER TEN THOUSAND;No;0;AL;;;;10000;N;;;;; +1EC96;INDIC SIYAQ NUMBER TWENTY THOUSAND;No;0;AL;;;;20000;N;;;;; +1EC97;INDIC SIYAQ NUMBER THIRTY THOUSAND;No;0;AL;;;;30000;N;;;;; +1EC98;INDIC SIYAQ NUMBER FORTY THOUSAND;No;0;AL;;;;40000;N;;;;; +1EC99;INDIC SIYAQ NUMBER FIFTY THOUSAND;No;0;AL;;;;50000;N;;;;; +1EC9A;INDIC SIYAQ NUMBER SIXTY THOUSAND;No;0;AL;;;;60000;N;;;;; +1EC9B;INDIC SIYAQ NUMBER SEVENTY THOUSAND;No;0;AL;;;;70000;N;;;;; +1EC9C;INDIC SIYAQ NUMBER EIGHTY THOUSAND;No;0;AL;;;;80000;N;;;;; +1EC9D;INDIC SIYAQ NUMBER NINETY THOUSAND;No;0;AL;;;;90000;N;;;;; +1EC9E;INDIC SIYAQ NUMBER LAKH;No;0;AL;;;;100000;N;;;;; +1EC9F;INDIC SIYAQ NUMBER LAKHAN;No;0;AL;;;;200000;N;;;;; +1ECA0;INDIC SIYAQ LAKH MARK;No;0;AL;;;;100000;N;;;;; +1ECA1;INDIC SIYAQ NUMBER KAROR;No;0;AL;;;;10000000;N;;;;; +1ECA2;INDIC SIYAQ NUMBER KARORAN;No;0;AL;;;;20000000;N;;;;; +1ECA3;INDIC SIYAQ NUMBER PREFIXED ONE;No;0;AL;;;;1;N;;;;; +1ECA4;INDIC SIYAQ NUMBER PREFIXED TWO;No;0;AL;;;;2;N;;;;; +1ECA5;INDIC SIYAQ NUMBER PREFIXED THREE;No;0;AL;;;;3;N;;;;; +1ECA6;INDIC SIYAQ NUMBER PREFIXED FOUR;No;0;AL;;;;4;N;;;;; +1ECA7;INDIC SIYAQ NUMBER PREFIXED FIVE;No;0;AL;;;;5;N;;;;; +1ECA8;INDIC SIYAQ NUMBER PREFIXED SIX;No;0;AL;;;;6;N;;;;; +1ECA9;INDIC SIYAQ NUMBER PREFIXED SEVEN;No;0;AL;;;;7;N;;;;; +1ECAA;INDIC SIYAQ NUMBER PREFIXED EIGHT;No;0;AL;;;;8;N;;;;; +1ECAB;INDIC SIYAQ NUMBER PREFIXED NINE;No;0;AL;;;;9;N;;;;; +1ECAC;INDIC SIYAQ PLACEHOLDER;So;0;AL;;;;;N;;;;; +1ECAD;INDIC SIYAQ FRACTION ONE QUARTER;No;0;AL;;;;1/4;N;;;;; +1ECAE;INDIC SIYAQ FRACTION ONE HALF;No;0;AL;;;;1/2;N;;;;; +1ECAF;INDIC SIYAQ FRACTION THREE QUARTERS;No;0;AL;;;;3/4;N;;;;; +1ECB0;INDIC SIYAQ RUPEE MARK;Sc;0;AL;;;;;N;;;;; +1ECB1;INDIC SIYAQ NUMBER ALTERNATE ONE;No;0;AL;;;;1;N;;;;; +1ECB2;INDIC SIYAQ NUMBER ALTERNATE TWO;No;0;AL;;;;2;N;;;;; +1ECB3;INDIC SIYAQ NUMBER ALTERNATE TEN THOUSAND;No;0;AL;;;;10000;N;;;;; +1ECB4;INDIC SIYAQ ALTERNATE LAKH MARK;No;0;AL;;;;100000;N;;;;; 1EE00;ARABIC MATHEMATICAL ALEF;Lo;0;AL; 0627;;;;N;;;;; 1EE01;ARABIC MATHEMATICAL BEH;Lo;0;AL; 0628;;;;N;;;;; 1EE02;ARABIC MATHEMATICAL JEEM;Lo;0;AL; 062C;;;;N;;;;; @@ -29012,6 +29601,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F12C;CIRCLED ITALIC LATIN CAPITAL LETTER R;So;0;L; 0052;;;;N;;;;; 1F12D;CIRCLED CD;So;0;L; 0043 0044;;;;N;;;;; 1F12E;CIRCLED WZ;So;0;L; 0057 005A;;;;N;;;;; +1F12F;COPYLEFT SYMBOL;So;0;ON;;;;;N;;;;; 1F130;SQUARED LATIN CAPITAL LETTER A;So;0;L; 0041;;;;N;;;;; 1F131;SQUARED LATIN CAPITAL LETTER B;So;0;L; 0042;;;;N;;;;; 1F132;SQUARED LATIN CAPITAL LETTER C;So;0;L; 0043;;;;N;;;;; @@ -30226,6 +30816,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F6F6;CANOE;So;0;ON;;;;;N;;;;; 1F6F7;SLED;So;0;ON;;;;;N;;;;; 1F6F8;FLYING SAUCER;So;0;ON;;;;;N;;;;; +1F6F9;SKATEBOARD;So;0;ON;;;;;N;;;;; 1F700;ALCHEMICAL SYMBOL FOR QUINTESSENCE;So;0;ON;;;;;N;;;;; 1F701;ALCHEMICAL SYMBOL FOR AIR;So;0;ON;;;;;N;;;;; 1F702;ALCHEMICAL SYMBOL FOR FIRE;So;0;ON;;;;;N;;;;; @@ -30427,6 +31018,10 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F7D2;LIGHT TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; 1F7D3;HEAVY TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; 1F7D4;HEAVY TWELVE POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; +1F7D5;CIRCLED TRIANGLE;So;0;ON;;;;;N;;;;; +1F7D6;NEGATIVE CIRCLED TRIANGLE;So;0;ON;;;;;N;;;;; +1F7D7;CIRCLED SQUARE;So;0;ON;;;;;N;;;;; +1F7D8;NEGATIVE CIRCLED SQUARE;So;0;ON;;;;;N;;;;; 1F800;LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; 1F801;UPWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; 1F802;RIGHTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; @@ -30647,6 +31242,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F94A;BOXING GLOVE;So;0;ON;;;;;N;;;;; 1F94B;MARTIAL ARTS UNIFORM;So;0;ON;;;;;N;;;;; 1F94C;CURLING STONE;So;0;ON;;;;;N;;;;; +1F94D;LACROSSE STICK AND BALL;So;0;ON;;;;;N;;;;; +1F94E;SOFTBALL;So;0;ON;;;;;N;;;;; +1F94F;FLYING DISC;So;0;ON;;;;;N;;;;; 1F950;CROISSANT;So;0;ON;;;;;N;;;;; 1F951;AVOCADO;So;0;ON;;;;;N;;;;; 1F952;CUCUMBER;So;0;ON;;;;;N;;;;; @@ -30675,6 +31273,20 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F969;CUT OF MEAT;So;0;ON;;;;;N;;;;; 1F96A;SANDWICH;So;0;ON;;;;;N;;;;; 1F96B;CANNED FOOD;So;0;ON;;;;;N;;;;; +1F96C;LEAFY GREEN;So;0;ON;;;;;N;;;;; +1F96D;MANGO;So;0;ON;;;;;N;;;;; +1F96E;MOON CAKE;So;0;ON;;;;;N;;;;; +1F96F;BAGEL;So;0;ON;;;;;N;;;;; +1F970;SMILING FACE WITH SMILING EYES AND THREE HEARTS;So;0;ON;;;;;N;;;;; +1F973;FACE WITH PARTY HORN AND PARTY HAT;So;0;ON;;;;;N;;;;; +1F974;FACE WITH UNEVEN EYES AND WAVY MOUTH;So;0;ON;;;;;N;;;;; +1F975;OVERHEATED FACE;So;0;ON;;;;;N;;;;; +1F976;FREEZING FACE;So;0;ON;;;;;N;;;;; +1F97A;FACE WITH PLEADING EYES;So;0;ON;;;;;N;;;;; +1F97C;LAB COAT;So;0;ON;;;;;N;;;;; +1F97D;GOGGLES;So;0;ON;;;;;N;;;;; +1F97E;HIKING BOOT;So;0;ON;;;;;N;;;;; +1F97F;FLAT SHOE;So;0;ON;;;;;N;;;;; 1F980;CRAB;So;0;ON;;;;;N;;;;; 1F981;LION FACE;So;0;ON;;;;;N;;;;; 1F982;SCORPION;So;0;ON;;;;;N;;;;; @@ -30699,7 +31311,30 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F995;SAUROPOD;So;0;ON;;;;;N;;;;; 1F996;T-REX;So;0;ON;;;;;N;;;;; 1F997;CRICKET;So;0;ON;;;;;N;;;;; +1F998;KANGAROO;So;0;ON;;;;;N;;;;; +1F999;LLAMA;So;0;ON;;;;;N;;;;; +1F99A;PEACOCK;So;0;ON;;;;;N;;;;; +1F99B;HIPPOPOTAMUS;So;0;ON;;;;;N;;;;; +1F99C;PARROT;So;0;ON;;;;;N;;;;; +1F99D;RACCOON;So;0;ON;;;;;N;;;;; +1F99E;LOBSTER;So;0;ON;;;;;N;;;;; +1F99F;MOSQUITO;So;0;ON;;;;;N;;;;; +1F9A0;MICROBE;So;0;ON;;;;;N;;;;; +1F9A1;BADGER;So;0;ON;;;;;N;;;;; +1F9A2;SWAN;So;0;ON;;;;;N;;;;; +1F9B0;EMOJI COMPONENT RED HAIR;So;0;ON;;;;;N;;;;; +1F9B1;EMOJI COMPONENT CURLY HAIR;So;0;ON;;;;;N;;;;; +1F9B2;EMOJI COMPONENT BALD;So;0;ON;;;;;N;;;;; +1F9B3;EMOJI COMPONENT WHITE HAIR;So;0;ON;;;;;N;;;;; +1F9B4;BONE;So;0;ON;;;;;N;;;;; +1F9B5;LEG;So;0;ON;;;;;N;;;;; +1F9B6;FOOT;So;0;ON;;;;;N;;;;; +1F9B7;TOOTH;So;0;ON;;;;;N;;;;; +1F9B8;SUPERHERO;So;0;ON;;;;;N;;;;; +1F9B9;SUPERVILLAIN;So;0;ON;;;;;N;;;;; 1F9C0;CHEESE WEDGE;So;0;ON;;;;;N;;;;; +1F9C1;CUPCAKE;So;0;ON;;;;;N;;;;; +1F9C2;SALT SHAKER;So;0;ON;;;;;N;;;;; 1F9D0;FACE WITH MONOCLE;So;0;ON;;;;;N;;;;; 1F9D1;ADULT;So;0;ON;;;;;N;;;;; 1F9D2;CHILD;So;0;ON;;;;;N;;;;; @@ -30723,6 +31358,45 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F9E4;GLOVES;So;0;ON;;;;;N;;;;; 1F9E5;COAT;So;0;ON;;;;;N;;;;; 1F9E6;SOCKS;So;0;ON;;;;;N;;;;; +1F9E7;RED GIFT ENVELOPE;So;0;ON;;;;;N;;;;; +1F9E8;FIRECRACKER;So;0;ON;;;;;N;;;;; +1F9E9;JIGSAW PUZZLE PIECE;So;0;ON;;;;;N;;;;; +1F9EA;TEST TUBE;So;0;ON;;;;;N;;;;; +1F9EB;PETRI DISH;So;0;ON;;;;;N;;;;; +1F9EC;DNA DOUBLE HELIX;So;0;ON;;;;;N;;;;; +1F9ED;COMPASS;So;0;ON;;;;;N;;;;; +1F9EE;ABACUS;So;0;ON;;;;;N;;;;; +1F9EF;FIRE EXTINGUISHER;So;0;ON;;;;;N;;;;; +1F9F0;TOOLBOX;So;0;ON;;;;;N;;;;; +1F9F1;BRICK;So;0;ON;;;;;N;;;;; +1F9F2;MAGNET;So;0;ON;;;;;N;;;;; +1F9F3;LUGGAGE;So;0;ON;;;;;N;;;;; +1F9F4;LOTION BOTTLE;So;0;ON;;;;;N;;;;; +1F9F5;SPOOL OF THREAD;So;0;ON;;;;;N;;;;; +1F9F6;BALL OF YARN;So;0;ON;;;;;N;;;;; +1F9F7;SAFETY PIN;So;0;ON;;;;;N;;;;; +1F9F8;TEDDY BEAR;So;0;ON;;;;;N;;;;; +1F9F9;BROOM;So;0;ON;;;;;N;;;;; +1F9FA;BASKET;So;0;ON;;;;;N;;;;; +1F9FB;ROLL OF PAPER;So;0;ON;;;;;N;;;;; +1F9FC;BAR OF SOAP;So;0;ON;;;;;N;;;;; +1F9FD;SPONGE;So;0;ON;;;;;N;;;;; +1F9FE;RECEIPT;So;0;ON;;;;;N;;;;; +1F9FF;NAZAR AMULET;So;0;ON;;;;;N;;;;; +1FA60;XIANGQI RED GENERAL;So;0;ON;;;;;N;;;;; +1FA61;XIANGQI RED MANDARIN;So;0;ON;;;;;N;;;;; +1FA62;XIANGQI RED ELEPHANT;So;0;ON;;;;;N;;;;; +1FA63;XIANGQI RED HORSE;So;0;ON;;;;;N;;;;; +1FA64;XIANGQI RED CHARIOT;So;0;ON;;;;;N;;;;; +1FA65;XIANGQI RED CANNON;So;0;ON;;;;;N;;;;; +1FA66;XIANGQI RED SOLDIER;So;0;ON;;;;;N;;;;; +1FA67;XIANGQI BLACK GENERAL;So;0;ON;;;;;N;;;;; +1FA68;XIANGQI BLACK MANDARIN;So;0;ON;;;;;N;;;;; +1FA69;XIANGQI BLACK ELEPHANT;So;0;ON;;;;;N;;;;; +1FA6A;XIANGQI BLACK HORSE;So;0;ON;;;;;N;;;;; +1FA6B;XIANGQI BLACK CHARIOT;So;0;ON;;;;;N;;;;; +1FA6C;XIANGQI BLACK CANNON;So;0;ON;;;;;N;;;;; +1FA6D;XIANGQI BLACK SOLDIER;So;0;ON;;;;;N;;;;; 20000;;Lo;0;L;;;;;N;;;;; 2A6D6;;Lo;0;L;;;;;N;;;;; 2A700;;Lo;0;L;;;;;N;;;;; -- GitLab From ad9d6bae8c34689a1bffa367543e1e37392369bc Mon Sep 17 00:00:00 2001 From: darcywong00 Date: Tue, 12 Jun 2018 15:18:31 +0700 Subject: [PATCH 222/356] Update history.md --- windows/src/desktop/history.md | 3 +++ windows/src/developer/history.md | 3 +++ 2 files changed, 6 insertions(+) diff --git a/windows/src/desktop/history.md b/windows/src/desktop/history.md index 88e3dcfc2f..bde2acce08 100644 --- a/windows/src/desktop/history.md +++ b/windows/src/desktop/history.md @@ -1,5 +1,8 @@ # Keyman Desktop Version History +## 2018-06-12 10.0.1106.0 beta +* No changes in Keyman Desktop + ## 2018-06-11 10.0.1105.0 beta * Platform tests (in keyboards) are now consistent across all platforms (#969) diff --git a/windows/src/developer/history.md b/windows/src/developer/history.md index 7180d0ae63..db13e57798 100644 --- a/windows/src/developer/history.md +++ b/windows/src/developer/history.md @@ -1,5 +1,8 @@ # Keyman Developer Version History +## 2018-06-12 10.0.1106.0 beta +* Add Unicode 11.0 characters +* ## 2018-06-11 10.0.1105.0 beta * No changes to Keyman Developer -- GitLab From 6392ac8f15f78a8f9acf37ce535dc1d77246b96c Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 12 Jun 2018 22:37:41 +0700 Subject: [PATCH 223/356] Fixes #500. Cleaning up constraint violations and confused keyboard resizing code, first pass. --- .../KMEI/KeymanEngine/Classes/Constants.swift | 7 +- .../Classes/InputViewController.swift | 71 +++++++++------ .../KeymanEngine/Classes/KeyPreviewView.swift | 4 +- .../Classes/KeyboardMenuView.swift | 2 +- .../Classes/KeymanWebViewController.swift | 1 + .../KMEI/KeymanEngine/Classes/Manager.swift | 89 +++++++++---------- .../KeymanEngine/Classes/SubKeysView.swift | 2 +- 7 files changed, 101 insertions(+), 75 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Constants.swift b/ios/engine/KMEI/KeymanEngine/Classes/Constants.swift index 161e3bbf7e..f590810d18 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/InputViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift index 33f1861665..ed6716c1b1 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,8 @@ 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 + view.translatesAutoresizingMaskIntoConstraints = false + Manager.shared.inputViewDidLoad() Manager.shared.keymanWebDelegate = self @@ -130,6 +137,7 @@ open class InputViewController: UIInputViewController, KeymanWebDelegate { } open override func viewDidAppear(_ animated: Bool) { + Manager.shared.isSystemKeyboard = true super.viewDidAppear(animated) setConstraints() inputView?.setNeedsUpdateConstraints() @@ -143,10 +151,22 @@ open class InputViewController: UIInputViewController, KeymanWebDelegate { } } + open override func viewWillDisappear(_ animated: Bool) { + Manager.shared.isSystemKeyboard = false + } + open override func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) { Manager.shared.inputViewWillRotate(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?) { let contextBeforeInput = textDocumentProxy.documentContextBeforeInput ?? "" let contextAfterInput = textDocumentProxy.documentContextAfterInput ?? "" @@ -236,12 +256,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( @@ -254,11 +275,11 @@ open class InputViewController: UIInputViewController, KeymanWebDelegate { // 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 c2090a7082..8dcfb73047 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 8e51c0f74a..01f98979a6 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/KeymanWebViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift index 736b32d692..1dee45104d 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 diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift index da3f542801..814e1c6e5f 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift @@ -31,10 +31,18 @@ private let keyboardChangeHelpText = "Tap here to change keyboard" private let keymanHostName = "api.keyman.com" // UI In-App Keyboard Constants -private let phonePortraitInAppKeyboardHeight: CGFloat = 183.0 +/* +These values are currently determined by the default keyboard size + provided by iOS. TODO: In the future, we may want to allow a custom size +to cater for larger keyboard layouts. This can be achieved by +implementing allowsSelfSizing: +https://stackoverflow.com/questions/33261686/how-can-i-set-height-of-custom-inputview + +private let phonePortraitInAppKeyboardHeight: CGFloat = 253.0 private let phoneLandscapeInAppKeyboardHeight: CGFloat = 183.0 private let padPortraitInAppKeyboardHeight: CGFloat = 385.0 private let padLandscapeInAppKeyboardHeight: CGFloat = 385.0 +*/ // UI System Keyboard Constants private let phonePortraitSystemKeyboardHeight: CGFloat = 216.0 @@ -42,6 +50,7 @@ private let phoneLandscapeSystemKeyboardHeight: CGFloat = 162.0 private let padPortraitSystemKeyboardHeight: CGFloat = 264.0 private let padLandscapeSystemKeyboardHeight: CGFloat = 352.0 + public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegate, KeymanWebDelegate { /// Application group identifier for shared container. Set this before accessing the shared manager. public static var applicationGroupIdentifier: String? @@ -51,6 +60,8 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat /// Display the help bubble on first use. public var isKeymanHelpOn = true + public var isSystemKeyboard = false + // TODO: Change API to not disable removing as well /// Allow users to add new keyboards in the keyboard picker. /// - Default value is true. @@ -100,7 +111,6 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat private var reachability: Reachability! private var didSynchronize = false private var didResizeToOrientation = false - private var lastKeyboardSize: CGSize = .zero private var useSpecialFontForSubkeys = false private let subKeyColor = #colorLiteral(red: 244.0 / 255.0, green: 244.0 / 255.0, blue: 244.0 / 255.0, alpha: 1.0) @@ -399,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)) } } @@ -855,7 +874,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) @@ -867,17 +886,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 } } } @@ -890,30 +910,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 } @@ -1016,7 +1012,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat @objc func showHelpBubble() { // Help bubble is always disabled for system-wide keyboard - if Util.isSystemKeyboard || keyboardMenuView != nil { + if Manager.shared.isSystemKeyboard || keyboardMenuView != nil { return } @@ -1077,12 +1073,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) { @@ -1092,11 +1094,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 @@ -1148,7 +1147,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 @@ -1178,7 +1177,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 } @@ -1239,7 +1238,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 b4dc96bc5b..02d541a188 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 -- GitLab From 11ae1d02aa48d841a2322cd13db188c3b1160550 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 13 Jun 2018 10:41:48 +0700 Subject: [PATCH 224/356] Add super calls --- ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift index ed6716c1b1..9848716c96 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift @@ -153,10 +153,12 @@ 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) { -- GitLab From 4230ad660a4108177aa803a8f229cedc073eb52c Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 13 Jun 2018 10:44:32 +0700 Subject: [PATCH 225/356] Address review comments --- ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift index 9848716c96..d3e414586a 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift @@ -275,7 +275,6 @@ 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(\(Manager.shared.keyboardHeight))]", metrics: nil, views: viewsDict) -- GitLab From 46efbbc5c8c9666e86b00aee2b540e2aff7ddf71 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 13 Jun 2018 13:12:43 +0700 Subject: [PATCH 226/356] Fixes #510. If a keyboard.json has no timezone in the last modified date string, then it will still install --- ...der.DateDecodingStrategy+ISO8601Fallback.swift | 6 ++++++ .../KMEI/KeymanEngine/Classes/Manager.swift | 15 ++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) 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 5d4274bf07..ed187adfbb 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 diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift index da3f542801..a8bf290877 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift @@ -595,12 +595,17 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat 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) + decoder.dateDecodingStrategy = .iso8601WithoutTimezone + if let keyboard = try? decoder.decode(KeyboardAPICall.self, from: data) { downloadKeyboard(keyboard) - } catch { - downloadFailed(forKeyboards: [], error: error) + } else { + decoder.dateDecodingStrategy = .ios8601WithMilliseconds + do { + let keyboard = try decoder.decode(KeyboardAPICall.self, from: data) + downloadKeyboard(keyboard) + } catch { + downloadFailed(forKeyboards: [], error: error) + } } } } -- GitLab From cab25abb4d2d8c99b5201c7d6430a6927905ba8e Mon Sep 17 00:00:00 2001 From: darcywong00 Date: Wed, 13 Jun 2018 13:42:41 +0700 Subject: [PATCH 227/356] Update history.md files --- windows/src/desktop/history.md | 3 +++ windows/src/developer/history.md | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/windows/src/desktop/history.md b/windows/src/desktop/history.md index bde2acce08..43da2d0c40 100644 --- a/windows/src/desktop/history.md +++ b/windows/src/desktop/history.md @@ -1,5 +1,8 @@ # Keyman Desktop Version History +## 2018-06-13 10.0.1107.0 beta +* Add Unicode 11.0 characters + ## 2018-06-12 10.0.1106.0 beta * No changes in Keyman Desktop diff --git a/windows/src/developer/history.md b/windows/src/developer/history.md index db13e57798..a632b71e34 100644 --- a/windows/src/developer/history.md +++ b/windows/src/developer/history.md @@ -1,8 +1,11 @@ # Keyman Developer Version History -## 2018-06-12 10.0.1106.0 beta +## 2018-06-13 10.0.1107.0 beta * Add Unicode 11.0 characters -* + +## 2018-06-12 10.0.1106.0 beta +* No changes to Keyman Developer + ## 2018-06-11 10.0.1105.0 beta * No changes to Keyman Developer -- GitLab From 8d4232374539fe52b3ef8fc4897d7e732ced25b1 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 14 Jun 2018 10:35:44 +0700 Subject: [PATCH 228/356] Tweak history.md --- android/history.md | 4 +++- ios/history.md | 6 ++++++ web/history.md | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/android/history.md b/android/history.md index 7a1c686ca9..5c312411d7 100644 --- a/android/history.md +++ b/android/history.md @@ -1,5 +1,8 @@ # 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) @@ -8,7 +11,6 @@ * 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 diff --git a/ios/history.md b/ios/history.md index 8157b4f6cc..f459466002 100644 --- a/ios/history.md +++ b/ios/history.md @@ -1,5 +1,11 @@ # Keyman for iPhone and iPad Version History +## 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) diff --git a/web/history.md b/web/history.md index a3b6473562..5cca6f6ba4 100644 --- a/web/history.md +++ b/web/history.md @@ -1,5 +1,8 @@ # KeymanWeb Version History +## 2018-06-13 10.0.94 beta +* No substantial changes. + ## 2018-06-11 10.0.93 beta * Platform tests (in keyboards) are now consistent across all platforms (#969) -- GitLab From 68e35ed7ae8f4f5df605581ce6676a130a69d524 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 14 Jun 2018 21:07:36 +0700 Subject: [PATCH 229/356] Fixes broken keyboard -- not responding to touch -- regression in #981 --- .../KMEI/KeymanEngine/Classes/InputViewController.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift index d3e414586a..e4346ab29c 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift @@ -116,7 +116,9 @@ 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 - view.translatesAutoresizingMaskIntoConstraints = false + // 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 -- GitLab From 8f8170cbfbfb1262bc0501fa4e2ff5b7057aa4bb Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Thu, 14 Jun 2018 23:35:07 -0400 Subject: [PATCH 230/356] [Mac] #967 - Changed platform implementation to make spec change Any unrecognized platform tokens will cause it to return false (not a match). --- .../KeymanEngine4Mac/KME/KMEngine.m | 41 +++++++------------ 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m index 653d2c191a..a64c94356c 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m @@ -867,34 +867,21 @@ const NSString* kEasterEggKmxName = @"EnglishSpanish.kmx"; } - (BOOL)checkPlatform:(NSString *)platform { - NSArray *values = [platform componentsSeparatedByString:@" "]; + NSArray *values = [[platform lowercaseString] componentsSeparatedByString:@" "]; for (NSString *value in values) { - NSString *lcValue = [value lowercaseString]; - if ([lcValue isEqualToString:@"touch"]) - return NO; - else if ([lcValue isEqualToString:@"windows"]) - return NO; - else if ([lcValue isEqualToString:@"android"]) - return NO; - else if ([lcValue isEqualToString:@"ios"]) - return NO; - else if ([lcValue isEqualToString:@"linux"]) - return NO; - else if ([lcValue isEqualToString:@"tablet"]) - return NO; - else if ([lcValue isEqualToString:@"phone"]) - return NO; - else if ([lcValue isEqualToString:@"web"]) - return NO; - else if ([lcValue isEqualToString:@"ie"]) - return NO; - else if ([lcValue isEqualToString:@"chrome"]) - return NO; - else if ([lcValue isEqualToString:@"firefox"]) - return NO; - else if ([lcValue isEqualToString:@"safari"]) - return NO; - else if ([lcValue isEqualToString:@"opera"]) + if ([value isEqualToString:@"hardware"]) + continue; + else if ([value isEqualToString:@"macosx"]) + continue; + else if ([value isEqualToString:@"mac"]) + continue; + else if ([value isEqualToString:@"macos"]) + continue; + else if ([value isEqualToString:@"desktop"]) + continue; + else if ([value isEqualToString:@"native"]) + continue; + else return NO; } -- GitLab From 7857e346760f27045c25a6845bd9d250bd470ea9 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Fri, 15 Jun 2018 00:53:22 -0400 Subject: [PATCH 231/356] [Mac] Changed checkPlatform implementation to be regex-based --- .../KeymanEngine4Mac/KME/KMEngine.m | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m index a64c94356c..3afc919241 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m @@ -27,12 +27,21 @@ NSString *const Q_RETURN = @"Q_RETURN"; DWORD VKMap[0x80]; @interface KMEngine () ++ (NSRegularExpression *)regexPlatform; @property (strong, nonatomic) NSMutableString *tmpCtxBuf; @property (strong, nonatomic) NSMutableArray *indexStack; @end @implementation KMEngine ++ (NSRegularExpression *)regexPlatform { + static NSRegularExpression *regex = nil; + if (regex == nil) { + regex = [NSRegularExpression regularExpressionWithPattern:@"(\\b(((mac(os)?)x?)|(native)|(hardware)|(desktop)) *)*" options:NSRegularExpressionCaseInsensitive error:nil]; + } + return regex; +} + NSMutableString* _easterEggForCrashlytics = nil; const NSString* kEasterEggText = @"Cr@shlyt!cs crash#KME"; const NSString* kEasterEggKmxName = @"EnglishSpanish.kmx"; @@ -867,25 +876,9 @@ const NSString* kEasterEggKmxName = @"EnglishSpanish.kmx"; } - (BOOL)checkPlatform:(NSString *)platform { - NSArray *values = [[platform lowercaseString] componentsSeparatedByString:@" "]; - for (NSString *value in values) { - if ([value isEqualToString:@"hardware"]) - continue; - else if ([value isEqualToString:@"macosx"]) - continue; - else if ([value isEqualToString:@"mac"]) - continue; - else if ([value isEqualToString:@"macos"]) - continue; - else if ([value isEqualToString:@"desktop"]) - continue; - else if ([value isEqualToString:@"native"]) - continue; - else - return NO; - } - - return YES; + NSRange wholeString = NSMakeRange(0, [platform length]); + NSRange firstMatchRange = [[KMEngine regexPlatform] rangeOfFirstMatchInString:platform options:NSMatchingAnchored range:wholeString]; + return (firstMatchRange.length == wholeString.length); } // Creates a VK map to convert Mac VK codes to Windows VK codes -- GitLab From 3bb54d49435fd69a48bb589f21d55b24d462dca6 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Fri, 15 Jun 2018 02:34:03 -0400 Subject: [PATCH 232/356] [Mac] Added unit tests for checkPlatform --- .../project.pbxproj | 4 + .../KeymanEngine4MacTests/KMEngineTests.m | 75 ++++++++++++++++ .../KeymanEngineTestsStaticHelperMethods.h | 1 + .../KeymanEngineTestsStaticHelperMethods.m | 6 ++ .../KeymanEngine4MacTests/PlatformTest.kmn | 80 ++++++++++++++++++ .../KeymanEngine4MacTests/PlatformTest.kmx | Bin 0 -> 4962 bytes 6 files changed, 166 insertions(+) create mode 100755 mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmn create mode 100644 mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmx diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac.xcodeproj/project.pbxproj b/mac/KeymanEngine4Mac/KeymanEngine4Mac.xcodeproj/project.pbxproj index 22ae755b62..2aa2eef6c4 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac.xcodeproj/project.pbxproj +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac.xcodeproj/project.pbxproj @@ -45,6 +45,7 @@ 984C2B161A79CA4F0023F89D /* KVKFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 984C2B021A79CA4F0023F89D /* KVKFile.h */; settings = {ATTRIBUTES = (Public, ); }; }; 984C2B171A79CA4F0023F89D /* KVKFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 984C2B031A79CA4F0023F89D /* KVKFile.m */; }; 984C2B191A79CB020023F89D /* WindowsVKCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 984C2B181A79CB020023F89D /* WindowsVKCodes.h */; }; + E224323F20D37E97006940A1 /* PlatformTest.kmx in Resources */ = {isa = PBXBuildFile; fileRef = E224323E20D37E97006940A1 /* PlatformTest.kmx */; }; E22A5A1120113DC100233965 /* KMEngineTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E22A5A1020113DC100233965 /* KMEngineTests.m */; }; E22A5A142011402E00233965 /* KeymanEngineTestsStaticHelperMethods.m in Sources */ = {isa = PBXBuildFile; fileRef = E22A5A132011402E00233965 /* KeymanEngineTestsStaticHelperMethods.m */; }; E2537D9A201641DA0069FEA6 /* TestMacEngine.kmx in Resources */ = {isa = PBXBuildFile; fileRef = E2537D99201641DA0069FEA6 /* TestMacEngine.kmx */; }; @@ -102,6 +103,7 @@ 984C2B021A79CA4F0023F89D /* KVKFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KVKFile.h; sourceTree = ""; }; 984C2B031A79CA4F0023F89D /* KVKFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KVKFile.m; sourceTree = ""; }; 984C2B181A79CB020023F89D /* WindowsVKCodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WindowsVKCodes.h; sourceTree = ""; }; + E224323E20D37E97006940A1 /* PlatformTest.kmx */ = {isa = PBXFileReference; lastKnownFileType = file; path = PlatformTest.kmx; sourceTree = ""; }; E22A5A1020113DC100233965 /* KMEngineTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KMEngineTests.m; sourceTree = ""; }; E22A5A1220113F8100233965 /* KeymanEngineTestsStaticHelperMethods.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeymanEngineTestsStaticHelperMethods.h; sourceTree = ""; }; E22A5A132011402E00233965 /* KeymanEngineTestsStaticHelperMethods.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KeymanEngineTestsStaticHelperMethods.m; sourceTree = ""; }; @@ -197,6 +199,7 @@ 984C2AE21A79C98D0023F89D /* Supporting Files */ = { isa = PBXGroup; children = ( + E224323E20D37E97006940A1 /* PlatformTest.kmx */, E2537D99201641DA0069FEA6 /* TestMacEngine.kmx */, 984C2AE31A79C98D0023F89D /* Info.plist */, ); @@ -361,6 +364,7 @@ buildActionMask = 2147483647; files = ( E2537D9A201641DA0069FEA6 /* TestMacEngine.kmx in Resources */, + E224323F20D37E97006940A1 /* PlatformTest.kmx in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m index 6678cad933..2570371631 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m @@ -269,4 +269,79 @@ NSString * names[nCombinations]; } } } + +// The following checkPlatform tests all use the PlatformTest KMX file based on PlatformTest.kmn +// (not included in the project itself, but available in the source repo for reference. This +// keyboard has been craefully crafted to check for all the "wrong" values first, for which checkPlatform +// should return NO, so while these tests are ostensibly testing for YES for the platform components that +// should match on a Mac, they are also testing for NO for all the other non-matching values. + +- (NSString *)checkPlatform_getOutputForKeystroke: (NSString*) character modifierFlags: (NSEventModifierFlags) flag keyCode:(unsigned short)code { + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForPlatformTest]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile contextBuffer:@""]; + NSString *lcChar = [character lowercaseString]; + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:flag timestamp:0 windowNumber:0 context:nil characters:character charactersIgnoringModifiers:lcChar isARepeat:NO keyCode:code]; + NSArray *actions = [engine processEvent:event]; + XCTAssert(actions.count == 1, @"Expected 1 action"); + NSDictionary *action = actions[0]; + NSString *actionType = [[action allKeys] objectAtIndex:0]; + XCTAssert([actionType isEqualToString:Q_STR], @"Expected Q_STR action"); + NSString *output = [action objectForKey:actionType]; + return output; +} + +- (void)testCheckPlatform_native_ReturnsYes { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"u" modifierFlags:0 keyCode:kVK_ANSI_U]; + XCTAssert([output isEqualToString:@" Native"], @"Expected checkPlatform to return YES for native."); +} + +- (void)testCheckPlatform_NATIVE_ReturnsYes { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"U" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_U]; + XCTAssert([output isEqualToString:@" Native"], @"Expected checkPlatform to return YES for NATIVE."); +} + +- (void)testCheckPlatform_hardware_ReturnsYes { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"p" modifierFlags:0 keyCode:kVK_ANSI_P]; + XCTAssert([output isEqualToString:@" Hardware"], @"Expected checkPlatform to return YES for hardware."); +} + +- (void)testCheckPlatform_HARDWARE_ReturnsYes { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"P" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_P]; + XCTAssert([output isEqualToString:@" Hardware"], @"Expected checkPlatform to return YES for HARDWARE."); +} + +- (void)testCheckPlatform_desktop_ReturnsYes { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"I" modifierFlags:0 keyCode:kVK_ANSI_I]; + XCTAssert([output isEqualToString:@" Desktop"], @"Expected checkPlatform to return YES for desktop."); +} + +- (void)testCheckPlatform_Desktop_ReturnsYes { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"I" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_I]; + XCTAssert([output isEqualToString:@" Desktop"], @"Expected checkPlatform to return YES for Desktop."); +} + +- (void)testCheckPlatform_macosx_ReturnsYes { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"o" modifierFlags:0 keyCode:kVK_ANSI_O]; + XCTAssert([output isEqualToString:@" macOS"], @"Expected checkPlatform to return YES for macosx."); +} + +- (void)testCheckPlatform_MacOS_ReturnsYes { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"K" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_K]; + XCTAssert([output isEqualToString:@" macOS"], @"Expected checkPlatform to return YES for MacOS."); +} + +- (void)testCheckPlatform_MAC_ReturnsYes { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"L" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_L]; + XCTAssert([output isEqualToString:@" mac"], @"Expected checkPlatform to return YES for MAC."); +} + +- (void)testCheckPlatform_Browsers_ReturnsNo { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"y" modifierFlags:0 keyCode:kVK_ANSI_Y]; + XCTAssert([output isEqualToString:@" [Browser Undefined]"], @"Expected checkPlatform to return NO for all browsers (ie, chrome, firefox, safari, opera)."); +} + +- (void)testCheckPlatform_multipleTokens_MatchesCorrectOneForMac { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"m" modifierFlags:0 keyCode:kVK_ANSI_M]; + XCTAssert([output isEqualToString:@" macOS native desktop hardware"], @"Expected checkPlatform to return YES for macOS native desktop hardware."); +} @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.h b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.h index 3e4c6fe7f6..a58f1f5953 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.h +++ b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.h @@ -21,6 +21,7 @@ @interface KeymanEngineTestsStaticHelperMethods : NSObject + (KMXFile *)getKmxFileTestMacEngine; ++ (KMXFile *)getKmxFileForPlatformTest; @end #endif /* KeymanEngineTestsStaticHelperMethods_h */ diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.m b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.m index 6806fb63f5..f2b32bc2b2 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.m @@ -16,4 +16,10 @@ KMXFile *kmxFile = [[KMXFile alloc] initWithFilePath:path]; return kmxFile; } + ++ (KMXFile *)getKmxFileForPlatformTest { + NSString *path = [[NSBundle bundleForClass:[KeymanEngineTestsStaticHelperMethods class]] pathForResource:@"PlatformTest.kmx" ofType:nil]; + KMXFile *kmxFile = [[KMXFile alloc] initWithFilePath:path]; + return kmxFile; +} @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmn b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmn new file mode 100755 index 0000000000..265df6d634 --- /dev/null +++ b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmn @@ -0,0 +1,80 @@ +store(&TARGETS) 'any' +store(&NAME) 'PlatformTest' +begin Unicode > use(main) + +group(main) using keys + +platform('touch') + [K_P] > ' Touch' +platform('hardware') + [K_P] > ' Hardware' ++ [K_P] > ' [UI Undefined]' + +platform('TOUCH') + [SHIFT K_P] > ' Touch' +platform('HARDWARE') + [SHIFT K_P] > ' Hardware' ++ [SHIFT K_P] > ' [UI Undefined]' + +platform('windows') + [K_O] > ' Windows' +platform('android') + [K_O] > ' Android' +platform('iOS') + [K_O] > ' iOS' +platform('linux') + [K_O] > ' Linux' +platform('macosx') + [K_O] > ' macOS' ++ [K_O] > ' [OS Undefined]' + +platform('WINDOWS') + [SHIFT K_O] > ' Windows' +platform('ANDROID') + [SHIFT K_O] > ' Android' +platform('IOS') + [SHIFT K_O] > ' iOS' +platform('LINUX') + [SHIFT K_O] > ' Linux' +platform('MacOSX') + [SHIFT K_O] > ' macOS' ++ [SHIFT K_O] > ' [OS Undefined]' + +platform('mac') + [K_L] > ' mac' ++ [K_L] > ' [Not a mac]' +platform('MAC') + [SHIFT K_L] > ' mac' ++ [SHIFT K_L] > ' [Not a mac]' +platform('macos') + [K_K] > ' macOS' ++ [K_K] > ' [Not macos]' +platform('MacOS') + [SHIFT K_K] > ' macOS' ++ [SHIFT K_K] > ' [Not macos]' + +platform('tablet') + [K_I] > ' Tablet' +platform('phone') + [K_I] > ' Phone' +platform('desktop') + [K_I] > ' Desktop' ++ [K_I] > ' [FF Undefined]' + +platform('TABLET') + [SHIFT K_I] > ' Tablet' +platform('Phone') + [SHIFT K_I] > ' Phone' +platform('DeskTop') + [SHIFT K_I] > ' Desktop' ++ [SHIFT K_I] > ' [FF Undefined]' + +platform('web') + [K_U] > ' Web' +platform('native') + [K_U] > ' Native' ++ [K_U] > ' [Nativeness Undefined]' + +platform('Web') + [SHIFT K_U] > ' Web' +platform('NATIVE') + [SHIFT K_U] > ' Native' ++ [SHIFT K_U] > ' [Nativeness Undefined]' + +platform('ie') + [K_Y] > ' IE' +platform('chrome') + [K_Y] > ' Chrome' +platform('firefox') + [K_Y] > ' Firefox' +platform('safari') + [K_Y] > ' Safari' +platform('opera') + [K_Y] > ' Opera' ++ [K_Y] > ' [Browser Undefined]' + +platform('IE') + [SHIFT K_Y] > ' IE' +platform('Chrome') + [SHIFT K_Y] > ' Chrome' +platform('FireFox') + [SHIFT K_Y] > ' Firefox' +platform('Safari') + [SHIFT K_Y] > ' Safari' +platform('OPERA') + [SHIFT K_Y] > ' Opera' ++ [SHIFT K_Y] > ' [Browser Undefined]' + +platform('tablet') + [K_T] > ' Mobile' +platform('phone') + [K_T] > ' Mobile' ++ [K_T] > ' [Mobile Undefined]' + +platform('tablet ie web') + [K_M] > ' tablet ie web' +platform('touch phone safari web') + [K_M] > ' phone safari web' +platform('Windows desktop native hardware') + [K_M] > ' Windows desktop native hardware' +platform('Linux desktop native') + [K_M] > ' Linux desktop native' +platform('macOS native desktop hardware Safari') + [K_M] > ' macOS native hardware Safari' +platform('macOS native desktop hardware') + [K_M] > ' macOS native desktop hardware' ++ [K_M] > ' [No match]' diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmx b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmx new file mode 100644 index 0000000000000000000000000000000000000000..0a06ba4784958752f1f3eaa4ff37e8f782505330 GIT binary patch literal 4962 zcmbW5Pi$316vht~5wv0jl&V#)T5GLX0qdU-LRz6sOaBr2YLRMU%WDGyZPQm2j4@p_ z#)Tm)j4{NpAS?`F(GVrX1q(yEFoqy8UAZtUh%tl(VPOaXe`oF;?zz*~SLHV6z3=I7GUYZ6=oejvg1;AaxtYH-frVS~pFo-+7rgHITI%HXpG&lo&w@D+ov8GO^= zrHj)(R~TGraJ9i}4c=t%R)cpMyxZUjgQpDs%HX30A2)c~;4=oFH~4phFB^Q#;2Q>) z-Jgzqg~5@*YYg6CaErl%1|Ko_qQN%}-on~jm8_FV@Mam8AsLVfKJyaEC$a~;8`O?+ zNcQ6!fo*|(jO~+A8RL5#P5HPKh!}Nk*2!9_cc$nKdCM^YOD3DRoQF`ikx%bEOonmp zl_O&TF4(9XkX`gdumQYz`ljDQC^_ktUi#h&Zj~n4PXGGccQcBPVTAUhpaNV+kSB5! zJrCbQbPwPAT)P8u5Uk_eMT>%CebOdf25_>41jxOTm=1Fh3#P+eJ^ zPt_*+>AB{&Ep?m&GDuH`+^EMGtInm4G4JMLubYW6c#cf(NQX3obmr2Q`fLia7hRu? zj(>=pLLQylJ?=RPBZ<{6^5p3EyJXV2(0l1T>-_9@Y#3GNS)Yo|O@Tba*f_eld+2i? z0Jpgun={cZNpwpR-IIy#rsvH(uO_1BAG`HLu8+Dhrlh_N#qubq3zBr@MS$aKpz@4LS?0TyBI zkm9?dQRK^qIGZr5oq(SXv~%!_f%XUd7S>KKy)@r#czJnNtAww|I$W!`T?2emplyZc zv2N3D7=AF&rr_TM+Hv@)KsyVc3A9V_KLhP5y!>H(zv4^Bu^e6%XtnT-fz}G&jrE$? zkKhx5HVHoxXy3tq#ojZq7vQsjb{T#>&~C#kmS5W#5zs8_u-!g+86MX zfp!M|PoOQX;5@=?zK!sMfi?yIInXY^uVCG#FMq*r2HKKGMJh4dt{Pq+XdB?IftG_0 z2HFVxFt*Ly_Xzx0pq+%D3$$P0e`9)PxT{g*D*RTUEnPvMG25;h-huh`tk0+mz9Z1` z@QFa1gim9BJ!|Y~_)md01D_4F%kUe4CM#Lvn9WxOuM4y{;U8iVBe5szoja@1%H$~~ zAz~)|xuKPK?5T1df0pVgGlt^5PdjhFwD1=(BYLLj38|-xR!$$_*UahOoyKbI9!Wnn z#3*N;Z=o_^N2o_F)lht?#%j`OigU2N-|v)22UCAoXql}hFI6^)OJTwE7<)2he& zo=b9CuRgf~f2HmbS2#Y)OD;>c-toR#=kwK%ubsU2W#`SF^WInIeBDW1Jpl8bSDdGx zx=){_Rc^0Zg z(;mImLRLk%15tFLrn8pzg3<<0Ixne*qQb4Od)a}s z5RUle7*_j!7WKa>x^@@ZfjW6B2N{k2eoK3{#zhzRy_#gU-ctKdxX0=Lcp^@cVtd@P oNp9=?|9jl?E=%z}?gi(YZ;z{X-r{@Qi_TYUkE?N>|Gvll3k9@`SO5S3 literal 0 HcmV?d00001 -- GitLab From dd6ec9ea5dbe281c1c3ba674797671e8e828a7ce Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Fri, 15 Jun 2018 16:49:24 -0400 Subject: [PATCH 233/356] [Mac] #931 - Made anything that appears to be "lLibreOffice" use legacy --- mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m index 0795c37743..d69426a857 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m @@ -51,7 +51,7 @@ NSRange _previousSelRange; BOOL legacy = ([clientAppId isEqual: @"com.apple.iWork.Pages"] || [clientAppId isEqual: @"com.apple.iWork.Keynote"] || [clientAppId isEqual: @"com.github.atom"] || - [clientAppId isEqual: @"com.collabora.libreoffice-free"] || + [clientAppId containsString: @"libreoffice"] || [clientAppId isEqual: @"com.axosoft.gitkraken"] || [clientAppId isEqual: @"org.sil.app.builder.scripture.ScriptureAppBuilder"] || [clientAppId isEqual: @"org.sil.app.builder.reading.ReadingAppBuilder"] || -- GitLab From fe55bbf9d0e907fa1e44663bffb69b7b4fd48d54 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Sun, 17 Jun 2018 21:46:22 -0400 Subject: [PATCH 234/356] [Mac] Updated history for this fix (for issue #967) and for PR 990. --- mac/history.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mac/history.md b/mac/history.md index 0fd0afba06..5e9e7b9e6a 100644 --- a/mac/history.md +++ b/mac/history.md @@ -1,5 +1,9 @@ # Keyman for macOS Version History +## 2018-06-18 10.0.48 beta +* Made other version(s) of LibreOffice use "legacy" mode for character replacements (#990) +* Corrected the way Keyman responds evaluates tokens in **platform** statement (#971) + ## 2018-06-07 10.0.47 beta * Change to build script to use correct build location (#950) -- GitLab From e89b0d5a6a44195b141f9425186b0707b1934fe0 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Sun, 17 Jun 2018 23:23:41 -0400 Subject: [PATCH 235/356] [Mac] Fixed logic to handle inverted (NOT_EQUAL) platform check --- .../KeymanEngine4Mac/KME/KMEngine.m | 13 +++++++++---- .../platform-rules/platform-results.xlsx | Bin 20980 -> 21247 bytes 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m index 3afc919241..38aba15da1 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m @@ -797,14 +797,19 @@ const NSString* kEasterEggKmxName = @"EnglishSpanish.kmx"; DWORD x2 = [keyCtx characterAtIndex:i+3]-1; DWORD x3 = [keyCtx characterAtIndex:i+4]-1; KMCompStore *store = [self.kmx.store objectAtIndex:x3]; - if (x1 == TSS_PLATFORM && x2 == EQUAL) { - if ([self checkPlatform:store.string]) + if (x1 == TSS_PLATFORM) { + BOOL platformMatches = [self checkPlatform:store.string]; + if ((platformMatches && (x2 == EQUAL)) || + (!platformMatches && (x2 == NOT_EQUAL))) { checkPlatform = YES; - else + } + else { return 0; + } } - else + else { return 0; // CODE_IFSYSTEMSTORE is not supported except TSS_PLATFORM + } i+=5; break; diff --git a/windows/src/test/manual-tests/platform-rules/platform-results.xlsx b/windows/src/test/manual-tests/platform-rules/platform-results.xlsx index f3e0eef1ab4ddd74ed1af955c8fcdd6041989fe4..6eb0927ce92e5669c53c19b6a58d3a5452d9d37b 100644 GIT binary patch delta 13890 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 BE!_YB delta 13680 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 Date: Sun, 17 Jun 2018 23:56:54 -0400 Subject: [PATCH 236/356] [Mac] Added unit tests for inverted platform logic --- .../KeymanEngine4MacTests/KMEngineTests.m | 20 ++++++++++++++++++ .../KeymanEngine4MacTests/PlatformTest.kmn | 4 ++++ .../KeymanEngine4MacTests/PlatformTest.kmx | Bin 4962 -> 5188 bytes 3 files changed, 24 insertions(+) diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m index 2570371631..290aaf3741 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m @@ -344,4 +344,24 @@ NSString * names[nCombinations]; NSString *output = [self checkPlatform_getOutputForKeystroke:@"m" modifierFlags:0 keyCode:kVK_ANSI_M]; XCTAssert([output isEqualToString:@" macOS native desktop hardware"], @"Expected checkPlatform to return YES for macOS native desktop hardware."); } + +- (void)testContextMatch_InvertedPlatformLogic_NotTouch { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"x" modifierFlags:0 keyCode:kVK_ANSI_X]; + XCTAssert([output isEqualToString:@" !Touch"], @"Expected !touch to be true."); +} + +// This allows for easy debugging of the "manual" platformtest keyboard developed for filling in the test spreadsheet. +//- (void)testCheckPlatform_temp_UnknownPlatformX { +// KMXFile *kmxFile = [[KMXFile alloc] initWithFilePath:@"/Users/tom/Documents/keymanapp/keyman/windows/src/test/manual-tests/platform-rules/platformtest.kmx"]; +// +// KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile contextBuffer:@""]; +// NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"a" charactersIgnoringModifiers:@"a" isARepeat:NO keyCode:kVK_ANSI_A]; +// NSArray *actions = [engine processEvent:event]; +// XCTAssert(actions.count == 1, @"Expected 1 action"); +// NSDictionary *action = actions[0]; +// NSString *actionType = [[action allKeys] objectAtIndex:0]; +// XCTAssert([actionType isEqualToString:Q_STR], @"Expected Q_STR action"); +// NSString *output = [action objectForKey:actionType]; +// XCTAssert([output isEqualToString:@"hardware macosx desktop native undefined !touch undefined macosx"], @"Expected !touch."); +//} @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmn b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmn index 265df6d634..8ffe47fba4 100755 --- a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmn +++ b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmn @@ -71,6 +71,10 @@ platform('tablet') + [K_T] > ' Mobile' platform('phone') + [K_T] > ' Mobile' + [K_T] > ' [Mobile Undefined]' +if(&platform != 'hardware') + [K_X] > ' !Hardware' +if(&platform != 'touch') + [K_X] > ' !Touch' ++ [K_X] > ' [Inverted rule Failed]' + platform('tablet ie web') + [K_M] > ' tablet ie web' platform('touch phone safari web') + [K_M] > ' phone safari web' platform('Windows desktop native hardware') + [K_M] > ' Windows desktop native hardware' diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmx b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmx index 0a06ba4784958752f1f3eaa4ff37e8f782505330..909154f325bcc1e87bab23e141aec7748a5770c8 100644 GIT binary patch literal 5188 zcmbW5Uue~37{{NjT4u|ZnVOmXG&3`^V_A$4*>sML%}wT})=E0_Y-G;uaE_Wvh;%u^ ziwFrB5g`&G5?+*uL>D3wAzg%oNJJN2h)8%L;f3~j-rw)__x#?Sor!0>JKyj3d7tO~ z`+MK#cRIHAZj#4DuKaX)h487-e|+AiC~l%$tP{D*2Ph5tk59|2`1_goOD@!k%uev~ zheYNiI0s&m;5Fb!6Wj`3kl+su9ya)(!D9xG8+^jxvj(3t_;-W88I-*2=6^vV`9yYr zKLT~2?3Z2GMqn+ly_8`Yl_K9IH032J<1y;$tdyLraAl<^ZgfmQl8GiR=6=+T#M8Ei zh)|-fULuy^LK&4kvYnm?C6Bd0-}HMBrB}M8kG{8o+oV}~=-(Fiy&gr!Fhc!NP#LZx zDBwAYUV!hwdlTQouHGKm2i9?Jr$*VaEz&Ms#Ox-j)@*jH2i}e<{Es7ax_W)G6>Woy zpt`a+o~q6C({qh)Yw9@jGC)rT-KdLyArl348`PA~o5OeCEPZA<4_=VzB=L#R5>x+*$1W#SA`O6cO+ z&~?v)+g*%x8SmD_yEXCNl=1GS=j&OoX1pgK`@|Ku`@#A}ZUnk-z}cTja-zy7*A!l>DGp4du+kDdQ`XFW(HaZhEXCzQpI ztDFY@qpMRxX-|ZPCXw5Zi%hT2YO~>s11$$%8)#kd5lV-NSA-u7v@!TGN~fuJ9R5R~ zorPbbbenpA!mkC|E%>x2vh`-c7X;cecw?Zoz&<|#p}cE+o8WDM)(bBLS`q$PpdE&P9cbUfPY2pL_zjBR2b$LW z3zsLeT0MMTpe=zn23iZeK=J!P;|;-g2ihU{QA%erUadC{KOShO;J;Ben0goC*8}Z8 z`22=!y`}Jv18pz-+dw-BzZPh>;H#d>#%qFarF5IVyayi+w0-cgKsy5eCeTj6&ji|e z_#c7xH(X|>ds64B7TyqO^WnKbTMd7oqBn~BG>L43j|AEQ_*kGFf&WbL`&rxl1^#QG zU4mZ?w43lnPcvU}t1ew$41XukTH%`mZ2H4UI?&F+F9q5^@SA~l z2VPH_WZRevUrULYEqiC*y*mf3R-R)lQRZIumif-&Z)v@uiYVUtytDR8D}NEQsrQlI zy?QfgPWAzIjhvqQsjt2*MAA=oGRkf0>u8pd^-4YTy~BFs?|FHT?46i;@(5A4+4V2Y zrTi#(Ah7z(%B#9HBc5U%OPptU3mf2G%W*E{ElfR@ewSfYn-9%)e1__Ci|unI?-x10F5;&7l(#KRVp^-NT$#UWZN#~gkMgpMlFg*NZK<>Qyvk=~ z-ujBOW^)8@Tjp%tNyeUsdCRNL(oaUIYpHp1oYPOf|0?hLxh{^)Mtuv@MoJXOyVCuV=?ioM~YrO#6J zNU7hO&M!SZ!u&JLYQucfk7m^rai+>+(;mI$BE_dxd}i%-Zy-~hK+~PyWG4{mDQg^_ zKqP>u>8z!_AkD&(&P!_11m{6dAWfnp-buqZ1wV`WJC4Sl>IB-rQ#rtB^vy8s*>dMy z+4foz*;=ceKj9gtzZOK?B$dv%7n0c4dOv5}!bxYMhTjIXy@lMS;W=I-uP5!bb8p1I zGWg#oN}TyRClR-0KAE5Nj?A8^i(Hh-XX=a2HrbiF*jX!|sV_NOr89Mjv)uog`adko Bs-yq_ literal 4962 zcmbW5Pi$316vht~5wv0jl&V#)T5GLX0qdU-LRz6sOaBr2YLRMU%WDGyZPQm2j4@p_ z#)Tm)j4{NpAS?`F(GVrX1q(yEFoqy8UAZtUh%tl(VPOaXe`oF;?zz*~SLHV6z3=I7GUYZ6=oejvg1;AaxtYH-frVS~pFo-+7rgHITI%HXpG&lo&w@D+ov8GO^= zrHj)(R~TGraJ9i}4c=t%R)cpMyxZUjgQpDs%HX30A2)c~;4=oFH~4phFB^Q#;2Q>) z-Jgzqg~5@*YYg6CaErl%1|Ko_qQN%}-on~jm8_FV@Mam8AsLVfKJyaEC$a~;8`O?+ zNcQ6!fo*|(jO~+A8RL5#P5HPKh!}Nk*2!9_cc$nKdCM^YOD3DRoQF`ikx%bEOonmp zl_O&TF4(9XkX`gdumQYz`ljDQC^_ktUi#h&Zj~n4PXGGccQcBPVTAUhpaNV+kSB5! zJrCbQbPwPAT)P8u5Uk_eMT>%CebOdf25_>41jxOTm=1Fh3#P+eJ^ zPt_*+>AB{&Ep?m&GDuH`+^EMGtInm4G4JMLubYW6c#cf(NQX3obmr2Q`fLia7hRu? zj(>=pLLQylJ?=RPBZ<{6^5p3EyJXV2(0l1T>-_9@Y#3GNS)Yo|O@Tba*f_eld+2i? z0Jpgun={cZNpwpR-IIy#rsvH(uO_1BAG`HLu8+Dhrlh_N#qubq3zBr@MS$aKpz@4LS?0TyBI zkm9?dQRK^qIGZr5oq(SXv~%!_f%XUd7S>KKy)@r#czJnNtAww|I$W!`T?2emplyZc zv2N3D7=AF&rr_TM+Hv@)KsyVc3A9V_KLhP5y!>H(zv4^Bu^e6%XtnT-fz}G&jrE$? zkKhx5HVHoxXy3tq#ojZq7vQsjb{T#>&~C#kmS5W#5zs8_u-!g+86MX zfp!M|PoOQX;5@=?zK!sMfi?yIInXY^uVCG#FMq*r2HKKGMJh4dt{Pq+XdB?IftG_0 z2HFVxFt*Ly_Xzx0pq+%D3$$P0e`9)PxT{g*D*RTUEnPvMG25;h-huh`tk0+mz9Z1` z@QFa1gim9BJ!|Y~_)md01D_4F%kUe4CM#Lvn9WxOuM4y{;U8iVBe5szoja@1%H$~~ zAz~)|xuKPK?5T1df0pVgGlt^5PdjhFwD1=(BYLLj38|-xR!$$_*UahOoyKbI9!Wnn z#3*N;Z=o_^N2o_F)lht?#%j`OigU2N-|v)22UCAoXql}hFI6^)OJTwE7<)2he& zo=b9CuRgf~f2HmbS2#Y)OD;>c-toR#=kwK%ubsU2W#`SF^WInIeBDW1Jpl8bSDdGx zx=){_Rc^0Zg z(;mImLRLk%15tFLrn8pzg3<<0Ixne*qQb4Od)a}s z5RUle7*_j!7WKa>x^@@ZfjW6B2N{k2eoK3{#zhzRy_#gU-ctKdxX0=Lcp^@cVtd@P oNp9=?|9jl?E=%z}?gi(YZ;z{X-r{@Qi_TYUkE?N>|Gvll3k9@`SO5S3 -- GitLab From cdeb36977a922bf4c9974fbb25f2cd138da31090 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 18 Jun 2018 14:24:44 +0700 Subject: [PATCH 237/356] Fixes IKeymanControl::OpenConfiguration giving noop --- windows/src/engine/kmcomapi/com/system/keymancontrol.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/src/engine/kmcomapi/com/system/keymancontrol.pas b/windows/src/engine/kmcomapi/com/system/keymancontrol.pas index 43530c9e76..a9112e76ed 100644 --- a/windows/src/engine/kmcomapi/com/system/keymancontrol.pas +++ b/windows/src/engine/kmcomapi/com/system/keymancontrol.pas @@ -388,7 +388,7 @@ end; procedure TKeymanControl.OpenConfiguration; begin - RunKeymanConfiguration(''); + RunKeymanConfiguration('-c'); end; procedure TKeymanControl.OpenDiagnostics; -- GitLab From c5e553782e0f02f69b3a6fd3c13af400c014896e Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 18 Jun 2018 16:08:35 +0700 Subject: [PATCH 238/356] Fixes #975. Fixes #996. Installation of keyboards in Windows avoids some side effects with refresh and additional system keyboards. --- windows/src/engine/keyman/UfrmKeyman7Main.pas | 7 +++++ .../kpinstallkeyboardlanguageprofiles.pas | 30 ++++++++++--------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/windows/src/engine/keyman/UfrmKeyman7Main.pas b/windows/src/engine/keyman/UfrmKeyman7Main.pas index 473002cee7..0d1383ccaa 100644 --- a/windows/src/engine/keyman/UfrmKeyman7Main.pas +++ b/windows/src/engine/keyman/UfrmKeyman7Main.pas @@ -890,6 +890,13 @@ procedure TfrmKeyman7Main.ShowLanguageSwitchForm; var Keyboard: TLangSwitchKeyboard; begin + FLangSwitchManager.Refresh; // ?? is this really needed. It seems in some situations that the refresh + // occurs too soon after keyboard installation and background processing + // has not completed, so this makes sure it's all okay. Long term, if we + // keep this pattern, we should not have a global FLangSwitchManager but + // instead always build an instance of the lang switch manager when the + // form is shown. Performance may be a concern. + if not Assigned(frmLanguageSwitch) then begin frmLanguageSwitch := TfrmLanguageSwitch.Create(Self); diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboardlanguageprofiles.pas b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboardlanguageprofiles.pas index a2835ed5a5..1c5b16a476 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboardlanguageprofiles.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboardlanguageprofiles.pas @@ -322,20 +322,6 @@ begin PIconFileName := PWideChar(IconFileName); - OleCheck(pInputProcessorProfileMgr.RegisterProfile( // I3743 - c_clsidKMTipTextService, - LangID, - guid, - PWideChar(KeyboardName), - Length(KeyboardName), - PWideChar(IconFileName), - Length(IconFileName), - IconIndex, - 0, - 0, - 1, - 0)); - FLayoutInstallString := Format('%04.4x:%s%s', [LangID, GuidToString(c_clsidKMTipTextService), // I4244 GuidToString(guid)]); @@ -359,6 +345,22 @@ begin end; end; + { Register the keyboard profile } + + OleCheck(pInputProcessorProfileMgr.RegisterProfile( // I3743 + c_clsidKMTipTextService, + LangID, + guid, + PWideChar(KeyboardName), + Length(KeyboardName), + PWideChar(IconFileName), + Length(IconFileName), + IconIndex, + 0, + 0, + 1, + 0)); + if UserLanguageInstalled then begin RemoveDefaultKeyboardForLanguage(BCP47Tag); -- GitLab From 75824f14aafbbb4bb1d6c302c35b313b23fff1f5 Mon Sep 17 00:00:00 2001 From: Vitrum Date: Mon, 18 Jun 2018 13:58:49 +0300 Subject: [PATCH 239/356] packaging path variables --- linux/kmflcomp/Makefile.am | 2 +- linux/libkmfl/Makefile.am | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/linux/kmflcomp/Makefile.am b/linux/kmflcomp/Makefile.am index c833351d7d..dfdd4d0b2c 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/libkmfl/Makefile.am b/linux/libkmfl/Makefile.am index 5e6683605a..6d55dfcb33 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\ -- GitLab From 3caf37e45c6d55f58829f4187068fd75e8593a63 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Mon, 18 Jun 2018 15:00:35 -0400 Subject: [PATCH 240/356] [Mac] #994 - Use keyboard names w/ native script from KMX instead of inf It seems the *.inf files are not UTF-8, so any non-Roman characters used in keyboard names turn into question marks. The native script name is stored in the kmx file, so getting it from there seems to work. --- .../KMInfoWindow/KMInfoWindowController.m | 19 +++++++++++++++---- .../Keyman4MacIM/KMInputMethodAppDelegate.h | 1 + .../Keyman4MacIM/KMInputMethodAppDelegate.m | 16 ++++++++++++++++ mac/history.md | 3 +++ 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m index 22e5a78832..bc7200bdce 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/KMInputMethodAppDelegate.h b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h index 702dbb52ce..e1e01c5ec8 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h @@ -104,6 +104,7 @@ extern NSString *const kWebSite; - (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; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m index 34d9c56d29..4b8b3b150d 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m @@ -474,6 +474,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]; diff --git a/mac/history.md b/mac/history.md index 5e9e7b9e6a..f8665d7e1e 100644 --- a/mac/history.md +++ b/mac/history.md @@ -1,5 +1,8 @@ # Keyman for macOS Version History +## 2018-06-19 10.0.49 beta +* Added suport for displaying keyboard names in native script in information window (#999) + ## 2018-06-18 10.0.48 beta * Made other version(s) of LibreOffice use "legacy" mode for character replacements (#990) * Corrected the way Keyman responds evaluates tokens in **platform** statement (#971) -- GitLab From a9c88da956ff6799c6f646772dd86f81fc51c2e3 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Mon, 18 Jun 2018 15:03:35 -0400 Subject: [PATCH 241/356] [Mac] Edited history.md to correct PR # --- mac/history.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mac/history.md b/mac/history.md index f8665d7e1e..d16c4d405b 100644 --- a/mac/history.md +++ b/mac/history.md @@ -1,7 +1,7 @@ # Keyman for macOS Version History ## 2018-06-19 10.0.49 beta -* Added suport for displaying keyboard names in native script in information window (#999) +* Enabled displaying keyboard names in native script in information window (#1001) ## 2018-06-18 10.0.48 beta * Made other version(s) of LibreOffice use "legacy" mode for character replacements (#990) -- GitLab From 007b420e9ede15740c6778afdebe09249dad07d8 Mon Sep 17 00:00:00 2001 From: darcywong00 Date: Tue, 19 Jun 2018 07:12:56 +0700 Subject: [PATCH 242/356] Move "edge" platform test with other browsers Follow-on to #969 This updates the platformtest.kmn keyboard and moves `edge` from `[K_O]` (OS) to `[K_Y]` (browsers) --- .../src/main/assets/cloud/platformtest-1.0.js | 786 +++++++++--------- web/testing/platform/platformtest.js | 786 +++++++++--------- .../platform-rules/platformtest.js | 427 +--------- .../platform-rules/platformtest.kmn | 2 +- .../platform-rules/platformtest.kmp | Bin 4473 -> 3564 bytes .../platform-rules/platformtest.kmx | Bin 6440 -> 5184 bytes .../platform-rules/platformtest.kpj | 3 +- .../platform-rules/platformtest.kps | 5 +- 8 files changed, 756 insertions(+), 1253 deletions(-) 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 index 59fd09dcf4..e62165ce22 100644 --- 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 @@ -1,416 +1,380 @@ KeymanWeb.KR(new Keyboard_platformtest()); -function 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="firefox"; - this.s40="safari"; - this.s41="opera"; - this.s44="touch"; - this.s45="hardware"; - this.s48="platform-x"; - this.s51="WinDOWS"; - this.s52="ANDroid"; - this.s53="iOS"; - this.s54="macOSX"; - this.s55="LINUX"; - this.s57="touch"; - this.s58="hardware"; - this.s59="windows"; - this.s60="android"; - this.s61="ios"; - this.s62="macosx"; - this.s63="linux"; - this.s64="desktop"; - this.s65="tablet"; - this.s66="phone"; - this.s67="native"; - this.s68="web"; - this.s69="ie"; - this.s70="chrome"; - this.s71="firefox"; - this.s72="safari"; - this.s73="opera"; - this.s74="touch"; - this.s75="hardware"; - this.s76="platform-x"; - this.s77="WinDOWS"; - this.s78="ANDroid"; - this.s79="iOS"; - this.s80="macOSX"; - this.s81="LINUX"; - this.KVER="10.0.1104.0"; - this.gs=function(t,e) { - return this.g_main(t,e); - }; - this.g_main=function(t,e) { - var k=KeymanWeb,r=0,m=0; - if(k.KKM(e, 0x4000, 0x41)) { // Line 7 - r=m=1; - r=this.g_ui(t,e); - } - if(!m&&k.KIK(e)) { - r=1; - r=this.g_old_main(t,e); - } - return r; - }; - this.g_ui=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s17,t)) { // Line 12 - m=1; - k.KO(0,t,"touch"); - } - else if(k.KIFS(31,this.s18,t)) { // Line 13 - m=1; - k.KO(0,t,"hardware"); - } - if(m) { - - r=this.g_os(t,e); - } - if(!m) { - - k.KO(-1,t,"undefined"); - r=this.g_os(t,e); - } - return r; - }; - this.g_os=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s21,t)) { // Line 19 - m=1; - k.KO(0,t," windows"); - } - else if(k.KIFS(31,this.s22,t)) { // Line 20 - m=1; - k.KO(0,t," android"); - } - else if(k.KIFS(31,this.s23,t)) { // Line 21 - m=1; - k.KO(0,t," ios"); - } - else if(k.KIFS(31,this.s24,t)) { // Line 22 - m=1; - k.KO(0,t," macosx"); - } - else if(k.KIFS(31,this.s25,t)) { // Line 23 - m=1; - k.KO(0,t," linux"); - } - if(m) { - - r=this.g_ff(t,e); - } - if(!m) { - - k.KO(-1,t," undefined"); - r=this.g_ff(t,e); - } - return r; - }; - this.g_ff=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s28,t)) { // Line 29 - m=1; - k.KO(0,t," desktop"); - } - else if(k.KIFS(31,this.s29,t)) { // Line 30 - m=1; - k.KO(0,t," tablet"); - } - else if(k.KIFS(31,this.s30,t)) { // Line 31 - m=1; - k.KO(0,t," phone"); - } - if(m) { - - r=this.g_app(t,e); - } - if(!m) { - - k.KO(-1,t," undefined"); - r=this.g_app(t,e); - } - return r; - }; - this.g_app=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s33,t)) { // Line 37 - m=1; - k.KO(0,t," native"); - } - else if(k.KIFS(31,this.s34,t)) { // Line 38 - m=1; - k.KO(0,t," web"); - } - if(m) { - - r=this.g_browser(t,e); - } - if(!m) { - - k.KO(-1,t," undefined"); - r=this.g_browser(t,e); - } - return r; - }; - this.g_browser=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s37,t)) { // Line 44 - m=1; - k.KO(0,t," ie"); - } - else if(k.KIFS(31,this.s38,t)) { // Line 45 - m=1; - k.KO(0,t," chrome"); - } - else if(k.KIFS(31,this.s39,t)) { // Line 46 - m=1; - k.KO(0,t," firefox"); - } - else if(k.KIFS(31,this.s40,t)) { // Line 47 - m=1; - k.KO(0,t," safari"); - } - else if(k.KIFS(31,this.s41,t)) { // Line 48 - m=1; - k.KO(0,t," opera"); - } - if(m) { - - r=this.g_inverted(t,e); - } - if(!m) { - - k.KO(-1,t," undefined"); - r=this.g_inverted(t,e); - } - return r; - }; - this.g_inverted=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(!k.KIFS(31,this.s44,t)) { // Line 54 - m=1; - k.KO(0,t," !touch"); - } - else if(!k.KIFS(31,this.s45,t)) { // Line 55 - m=1; - k.KO(0,t," !hardware"); - } - if(m) { - - r=this.g_unknown(t,e); - } - if(!m) { - - k.KO(-1,t," undefined"); - r=this.g_unknown(t,e); - } - return r; - }; - this.g_unknown=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s48,t)) { // Line 61 - m=1; - k.KO(0,t," platform-x"); - } - if(m) { - - r=this.g_case_sensitive(t,e); - } - if(!m) { - - k.KO(-1,t," undefined"); - r=this.g_case_sensitive(t,e); - } - return r; - }; - this.g_case_sensitive=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s51,t)) { // Line 67 - m=1; - k.KO(0,t," windows"); - } - else if(k.KIFS(31,this.s52,t)) { // Line 68 - m=1; - k.KO(0,t," android"); - } - else if(k.KIFS(31,this.s53,t)) { // Line 69 - m=1; - k.KO(0,t," ios"); - } - else if(k.KIFS(31,this.s54,t)) { // Line 70 - m=1; - k.KO(0,t," macosx"); - } - else if(k.KIFS(31,this.s55,t)) { // Line 71 - m=1; - k.KO(0,t," linux"); - } - if(!m) { - - k.KO(-1,t," undefined"); - } - return r; - }; - this.g_old_main=function(t,e) { - var k=KeymanWeb,r=0,m=0; - if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s77,t)) { // Line 130 - r=m=1; - k.KO(0,t," Windows"); - } - else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s78,t)) { // Line 131 - r=m=1; - k.KO(0,t," Android"); - } - else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s79,t)) { // Line 132 - r=m=1; - k.KO(0,t," iOS"); - } - else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s80,t)) { // Line 133 - r=m=1; - k.KO(0,t," macOS"); - } - else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s81,t)) { // Line 134 - r=m=1; - k.KO(0,t," Linux"); - } - else if(k.KKM(e, 0x4000, 0x45)) { // Line 135 - r=m=1; - k.KO(0,t," [OS Undefined (case insensitive test)]"); - } - else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s64,t)) { // Line 97 - r=m=1; - k.KO(0,t," Desktop"); - } - else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s65,t)) { // Line 98 - r=m=1; - k.KO(0,t," Tablet"); - } - else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s66,t)) { // Line 99 - r=m=1; - k.KO(0,t," Phone"); - } - else if(k.KKM(e, 0x4000, 0x49)) { // Line 100 - r=m=1; - k.KO(0,t," [FF Undefined]"); - } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s59,t)) { // Line 88 - r=m=1; - k.KO(0,t," Windows"); - } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s60,t)) { // Line 89 - r=m=1; - k.KO(0,t," Android"); - } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s61,t)) { // Line 90 - r=m=1; - k.KO(0,t," iOS"); - } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s62,t)) { // Line 91 - r=m=1; - k.KO(0,t," OSX"); - } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s63,t)) { // Line 92 - r=m=1; - k.KO(0,t," Linux"); - } - else if(k.KKM(e, 0x4000, 0x4F)) { // Line 93 - r=m=1; - k.KO(0,t," [OS Undefined]"); - } - else if(k.KKM(e, 0x4000, 0x50)&&k.KIFS(31,this.s57,t)) { // Line 82 - r=m=1; - k.KO(0,t,"Touch"); - } - else if(k.KKM(e, 0x4000, 0x50)&&k.KIFS(31,this.s58,t)) { // Line 83 - r=m=1; - k.KO(0,t,"Hardware"); - } - else if(k.KKM(e, 0x4000, 0x50)) { // Line 84 - r=m=1; - k.KO(0,t,"[UI Undefined]"); - } - else if(k.KKM(e, 0x4000, 0x52)&&k.KIFS(31,this.s76,t)) { // Line 125 - r=m=1; - k.KO(0,t," Platform-X"); - } - else if(k.KKM(e, 0x4000, 0x52)) { // Line 126 - r=m=1; - k.KO(0,t," [Platform-X Undefined]"); - } - else if(k.KKM(e, 0x4000, 0x54)&&!k.KIFS(31,this.s74,t)) { // Line 119 - r=m=1; - k.KO(0,t," !Touch"); - } - else if(k.KKM(e, 0x4000, 0x54)&&!k.KIFS(31,this.s75,t)) { // Line 120 - r=m=1; - k.KO(0,t," !Hardware"); - } - else if(k.KKM(e, 0x4000, 0x54)) { // Line 121 - r=m=1; - k.KO(0,t," [Inverted OS Undefined]"); - } - else if(k.KKM(e, 0x4000, 0x55)&&k.KIFS(31,this.s67,t)) { // Line 104 - r=m=1; - k.KO(0,t," Native"); - } - else if(k.KKM(e, 0x4000, 0x55)&&k.KIFS(31,this.s68,t)) { // Line 105 - r=m=1; - k.KO(0,t," Web"); - } - else if(k.KKM(e, 0x4000, 0x55)) { // Line 106 - r=m=1; - k.KO(0,t," [Nativeness Undefined]"); - } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s69,t)) { // Line 110 - r=m=1; - k.KO(0,t," IE"); - } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s70,t)) { // Line 111 - r=m=1; - k.KO(0,t," Chrome"); - } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s71,t)) { // Line 112 - r=m=1; - k.KO(0,t," Firefox"); - } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s72,t)) { // Line 113 - r=m=1; - k.KO(0,t," Safari"); - } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s73,t)) { // Line 114 - r=m=1; - k.KO(0,t," Opera"); - } - else if(k.KKM(e, 0x4000, 0x59)) { // Line 115 - r=m=1; - k.KO(0,t," [Browser Undefined]"); - } - return r; - }; + + 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/web/testing/platform/platformtest.js b/web/testing/platform/platformtest.js index 59fd09dcf4..e62165ce22 100644 --- a/web/testing/platform/platformtest.js +++ b/web/testing/platform/platformtest.js @@ -1,416 +1,380 @@ KeymanWeb.KR(new Keyboard_platformtest()); -function 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="firefox"; - this.s40="safari"; - this.s41="opera"; - this.s44="touch"; - this.s45="hardware"; - this.s48="platform-x"; - this.s51="WinDOWS"; - this.s52="ANDroid"; - this.s53="iOS"; - this.s54="macOSX"; - this.s55="LINUX"; - this.s57="touch"; - this.s58="hardware"; - this.s59="windows"; - this.s60="android"; - this.s61="ios"; - this.s62="macosx"; - this.s63="linux"; - this.s64="desktop"; - this.s65="tablet"; - this.s66="phone"; - this.s67="native"; - this.s68="web"; - this.s69="ie"; - this.s70="chrome"; - this.s71="firefox"; - this.s72="safari"; - this.s73="opera"; - this.s74="touch"; - this.s75="hardware"; - this.s76="platform-x"; - this.s77="WinDOWS"; - this.s78="ANDroid"; - this.s79="iOS"; - this.s80="macOSX"; - this.s81="LINUX"; - this.KVER="10.0.1104.0"; - this.gs=function(t,e) { - return this.g_main(t,e); - }; - this.g_main=function(t,e) { - var k=KeymanWeb,r=0,m=0; - if(k.KKM(e, 0x4000, 0x41)) { // Line 7 - r=m=1; - r=this.g_ui(t,e); - } - if(!m&&k.KIK(e)) { - r=1; - r=this.g_old_main(t,e); - } - return r; - }; - this.g_ui=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s17,t)) { // Line 12 - m=1; - k.KO(0,t,"touch"); - } - else if(k.KIFS(31,this.s18,t)) { // Line 13 - m=1; - k.KO(0,t,"hardware"); - } - if(m) { - - r=this.g_os(t,e); - } - if(!m) { - - k.KO(-1,t,"undefined"); - r=this.g_os(t,e); - } - return r; - }; - this.g_os=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s21,t)) { // Line 19 - m=1; - k.KO(0,t," windows"); - } - else if(k.KIFS(31,this.s22,t)) { // Line 20 - m=1; - k.KO(0,t," android"); - } - else if(k.KIFS(31,this.s23,t)) { // Line 21 - m=1; - k.KO(0,t," ios"); - } - else if(k.KIFS(31,this.s24,t)) { // Line 22 - m=1; - k.KO(0,t," macosx"); - } - else if(k.KIFS(31,this.s25,t)) { // Line 23 - m=1; - k.KO(0,t," linux"); - } - if(m) { - - r=this.g_ff(t,e); - } - if(!m) { - - k.KO(-1,t," undefined"); - r=this.g_ff(t,e); - } - return r; - }; - this.g_ff=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s28,t)) { // Line 29 - m=1; - k.KO(0,t," desktop"); - } - else if(k.KIFS(31,this.s29,t)) { // Line 30 - m=1; - k.KO(0,t," tablet"); - } - else if(k.KIFS(31,this.s30,t)) { // Line 31 - m=1; - k.KO(0,t," phone"); - } - if(m) { - - r=this.g_app(t,e); - } - if(!m) { - - k.KO(-1,t," undefined"); - r=this.g_app(t,e); - } - return r; - }; - this.g_app=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s33,t)) { // Line 37 - m=1; - k.KO(0,t," native"); - } - else if(k.KIFS(31,this.s34,t)) { // Line 38 - m=1; - k.KO(0,t," web"); - } - if(m) { - - r=this.g_browser(t,e); - } - if(!m) { - - k.KO(-1,t," undefined"); - r=this.g_browser(t,e); - } - return r; - }; - this.g_browser=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s37,t)) { // Line 44 - m=1; - k.KO(0,t," ie"); - } - else if(k.KIFS(31,this.s38,t)) { // Line 45 - m=1; - k.KO(0,t," chrome"); - } - else if(k.KIFS(31,this.s39,t)) { // Line 46 - m=1; - k.KO(0,t," firefox"); - } - else if(k.KIFS(31,this.s40,t)) { // Line 47 - m=1; - k.KO(0,t," safari"); - } - else if(k.KIFS(31,this.s41,t)) { // Line 48 - m=1; - k.KO(0,t," opera"); - } - if(m) { - - r=this.g_inverted(t,e); - } - if(!m) { - - k.KO(-1,t," undefined"); - r=this.g_inverted(t,e); - } - return r; - }; - this.g_inverted=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(!k.KIFS(31,this.s44,t)) { // Line 54 - m=1; - k.KO(0,t," !touch"); - } - else if(!k.KIFS(31,this.s45,t)) { // Line 55 - m=1; - k.KO(0,t," !hardware"); - } - if(m) { - - r=this.g_unknown(t,e); - } - if(!m) { - - k.KO(-1,t," undefined"); - r=this.g_unknown(t,e); - } - return r; - }; - this.g_unknown=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s48,t)) { // Line 61 - m=1; - k.KO(0,t," platform-x"); - } - if(m) { - - r=this.g_case_sensitive(t,e); - } - if(!m) { - - k.KO(-1,t," undefined"); - r=this.g_case_sensitive(t,e); - } - return r; - }; - this.g_case_sensitive=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s51,t)) { // Line 67 - m=1; - k.KO(0,t," windows"); - } - else if(k.KIFS(31,this.s52,t)) { // Line 68 - m=1; - k.KO(0,t," android"); - } - else if(k.KIFS(31,this.s53,t)) { // Line 69 - m=1; - k.KO(0,t," ios"); - } - else if(k.KIFS(31,this.s54,t)) { // Line 70 - m=1; - k.KO(0,t," macosx"); - } - else if(k.KIFS(31,this.s55,t)) { // Line 71 - m=1; - k.KO(0,t," linux"); - } - if(!m) { - - k.KO(-1,t," undefined"); - } - return r; - }; - this.g_old_main=function(t,e) { - var k=KeymanWeb,r=0,m=0; - if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s77,t)) { // Line 130 - r=m=1; - k.KO(0,t," Windows"); - } - else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s78,t)) { // Line 131 - r=m=1; - k.KO(0,t," Android"); - } - else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s79,t)) { // Line 132 - r=m=1; - k.KO(0,t," iOS"); - } - else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s80,t)) { // Line 133 - r=m=1; - k.KO(0,t," macOS"); - } - else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s81,t)) { // Line 134 - r=m=1; - k.KO(0,t," Linux"); - } - else if(k.KKM(e, 0x4000, 0x45)) { // Line 135 - r=m=1; - k.KO(0,t," [OS Undefined (case insensitive test)]"); - } - else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s64,t)) { // Line 97 - r=m=1; - k.KO(0,t," Desktop"); - } - else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s65,t)) { // Line 98 - r=m=1; - k.KO(0,t," Tablet"); - } - else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s66,t)) { // Line 99 - r=m=1; - k.KO(0,t," Phone"); - } - else if(k.KKM(e, 0x4000, 0x49)) { // Line 100 - r=m=1; - k.KO(0,t," [FF Undefined]"); - } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s59,t)) { // Line 88 - r=m=1; - k.KO(0,t," Windows"); - } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s60,t)) { // Line 89 - r=m=1; - k.KO(0,t," Android"); - } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s61,t)) { // Line 90 - r=m=1; - k.KO(0,t," iOS"); - } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s62,t)) { // Line 91 - r=m=1; - k.KO(0,t," OSX"); - } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s63,t)) { // Line 92 - r=m=1; - k.KO(0,t," Linux"); - } - else if(k.KKM(e, 0x4000, 0x4F)) { // Line 93 - r=m=1; - k.KO(0,t," [OS Undefined]"); - } - else if(k.KKM(e, 0x4000, 0x50)&&k.KIFS(31,this.s57,t)) { // Line 82 - r=m=1; - k.KO(0,t,"Touch"); - } - else if(k.KKM(e, 0x4000, 0x50)&&k.KIFS(31,this.s58,t)) { // Line 83 - r=m=1; - k.KO(0,t,"Hardware"); - } - else if(k.KKM(e, 0x4000, 0x50)) { // Line 84 - r=m=1; - k.KO(0,t,"[UI Undefined]"); - } - else if(k.KKM(e, 0x4000, 0x52)&&k.KIFS(31,this.s76,t)) { // Line 125 - r=m=1; - k.KO(0,t," Platform-X"); - } - else if(k.KKM(e, 0x4000, 0x52)) { // Line 126 - r=m=1; - k.KO(0,t," [Platform-X Undefined]"); - } - else if(k.KKM(e, 0x4000, 0x54)&&!k.KIFS(31,this.s74,t)) { // Line 119 - r=m=1; - k.KO(0,t," !Touch"); - } - else if(k.KKM(e, 0x4000, 0x54)&&!k.KIFS(31,this.s75,t)) { // Line 120 - r=m=1; - k.KO(0,t," !Hardware"); - } - else if(k.KKM(e, 0x4000, 0x54)) { // Line 121 - r=m=1; - k.KO(0,t," [Inverted OS Undefined]"); - } - else if(k.KKM(e, 0x4000, 0x55)&&k.KIFS(31,this.s67,t)) { // Line 104 - r=m=1; - k.KO(0,t," Native"); - } - else if(k.KKM(e, 0x4000, 0x55)&&k.KIFS(31,this.s68,t)) { // Line 105 - r=m=1; - k.KO(0,t," Web"); - } - else if(k.KKM(e, 0x4000, 0x55)) { // Line 106 - r=m=1; - k.KO(0,t," [Nativeness Undefined]"); - } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s69,t)) { // Line 110 - r=m=1; - k.KO(0,t," IE"); - } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s70,t)) { // Line 111 - r=m=1; - k.KO(0,t," Chrome"); - } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s71,t)) { // Line 112 - r=m=1; - k.KO(0,t," Firefox"); - } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s72,t)) { // Line 113 - r=m=1; - k.KO(0,t," Safari"); - } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s73,t)) { // Line 114 - r=m=1; - k.KO(0,t," Opera"); - } - else if(k.KKM(e, 0x4000, 0x59)) { // Line 115 - r=m=1; - k.KO(0,t," [Browser Undefined]"); - } - return r; - }; + + 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/windows/src/test/manual-tests/platform-rules/platformtest.js b/windows/src/test/manual-tests/platform-rules/platformtest.js index 4c8e3083bc..b7c614c2a5 100644 --- a/windows/src/test/manual-tests/platform-rules/platformtest.js +++ b/windows/src/test/manual-tests/platform-rules/platformtest.js @@ -1,426 +1 @@ - -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="edge"; - this.s63="ios"; - this.s64="macosx"; - this.s65="linux"; - this.s66="desktop"; - this.s67="tablet"; - this.s68="phone"; - this.s69="native"; - this.s70="web"; - this.s71="ie"; - this.s72="chrome"; - 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.1105.0"; - this.gs=function(t,e) { - return this.g_main(t,e); - }; - this.g_main=function(t,e) { - var k=KeymanWeb,r=0,m=0; - if(k.KKM(e, 0x4000, 0x41)) { // Line 7 - r=m=1; - r=this.g_ui(t,e); - } - if(!m&&k.KIK(e)) { - r=1; - r=this.g_old_main(t,e); - } - return r; - }; - this.g_ui=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s17,t)) { // Line 12 - m=1; - k.KO(0,t,"touch"); - } - else if(k.KIFS(31,this.s18,t)) { // Line 13 - m=1; - k.KO(0,t,"hardware"); - } - if(m) { - - r=this.g_os(t,e); - } - if(!m) { - - k.KO(-1,t,"undefined"); - r=this.g_os(t,e); - } - return r; - }; - this.g_os=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s21,t)) { // Line 19 - m=1; - k.KO(0,t," windows"); - } - else if(k.KIFS(31,this.s22,t)) { // Line 20 - m=1; - k.KO(0,t," android"); - } - else if(k.KIFS(31,this.s23,t)) { // Line 21 - m=1; - k.KO(0,t," ios"); - } - else if(k.KIFS(31,this.s24,t)) { // Line 22 - m=1; - k.KO(0,t," macosx"); - } - else if(k.KIFS(31,this.s25,t)) { // Line 23 - m=1; - k.KO(0,t," linux"); - } - if(m) { - - r=this.g_ff(t,e); - } - if(!m) { - - k.KO(-1,t," undefined"); - r=this.g_ff(t,e); - } - return r; - }; - this.g_ff=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s28,t)) { // Line 29 - m=1; - k.KO(0,t," desktop"); - } - else if(k.KIFS(31,this.s29,t)) { // Line 30 - m=1; - k.KO(0,t," tablet"); - } - else if(k.KIFS(31,this.s30,t)) { // Line 31 - m=1; - k.KO(0,t," phone"); - } - if(m) { - - r=this.g_app(t,e); - } - if(!m) { - - k.KO(-1,t," undefined"); - r=this.g_app(t,e); - } - return r; - }; - this.g_app=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s33,t)) { // Line 37 - m=1; - k.KO(0,t," native"); - } - else if(k.KIFS(31,this.s34,t)) { // Line 38 - m=1; - k.KO(0,t," web"); - } - if(m) { - - r=this.g_browser(t,e); - } - if(!m) { - - k.KO(-1,t," undefined"); - r=this.g_browser(t,e); - } - return r; - }; - this.g_browser=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s37,t)) { // Line 44 - m=1; - k.KO(0,t," ie"); - } - else if(k.KIFS(31,this.s38,t)) { // Line 45 - m=1; - k.KO(0,t," chrome"); - } - else if(k.KIFS(31,this.s39,t)) { // Line 46 - m=1; - k.KO(0,t," edge"); - } - else if(k.KIFS(31,this.s40,t)) { // Line 47 - m=1; - k.KO(0,t," firefox"); - } - else if(k.KIFS(31,this.s41,t)) { // Line 48 - m=1; - k.KO(0,t," safari"); - } - else if(k.KIFS(31,this.s42,t)) { // Line 49 - m=1; - k.KO(0,t," opera"); - } - if(m) { - - r=this.g_inverted(t,e); - } - if(!m) { - - k.KO(-1,t," undefined"); - r=this.g_inverted(t,e); - } - return r; - }; - this.g_inverted=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(!k.KIFS(31,this.s45,t)) { // Line 55 - m=1; - k.KO(0,t," !touch"); - } - else if(!k.KIFS(31,this.s46,t)) { // Line 56 - m=1; - k.KO(0,t," !hardware"); - } - if(m) { - - r=this.g_unknown(t,e); - } - if(!m) { - - k.KO(-1,t," undefined"); - r=this.g_unknown(t,e); - } - return r; - }; - this.g_unknown=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s49,t)) { // Line 62 - m=1; - k.KO(0,t," platform-x"); - } - if(m) { - - r=this.g_case_sensitive(t,e); - } - if(!m) { - - k.KO(-1,t," undefined"); - r=this.g_case_sensitive(t,e); - } - return r; - }; - this.g_case_sensitive=function(t,e) { - var k=KeymanWeb,r=1,m=0; - if(k.KIFS(31,this.s52,t)) { // Line 68 - m=1; - k.KO(0,t," windows"); - } - else if(k.KIFS(31,this.s53,t)) { // Line 69 - m=1; - k.KO(0,t," android"); - } - else if(k.KIFS(31,this.s54,t)) { // Line 70 - m=1; - k.KO(0,t," ios"); - } - else if(k.KIFS(31,this.s55,t)) { // Line 71 - m=1; - k.KO(0,t," macosx"); - } - else if(k.KIFS(31,this.s56,t)) { // Line 72 - m=1; - k.KO(0,t," linux"); - } - if(!m) { - - k.KO(-1,t," undefined"); - } - return r; - }; - this.g_old_main=function(t,e) { - var k=KeymanWeb,r=0,m=0; - if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s79,t)) { // Line 132 - r=m=1; - k.KO(0,t," Windows"); - } - else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s80,t)) { // Line 133 - r=m=1; - k.KO(0,t," Android"); - } - else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s81,t)) { // Line 134 - r=m=1; - k.KO(0,t," iOS"); - } - else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s82,t)) { // Line 135 - r=m=1; - k.KO(0,t," macOS"); - } - else if(k.KKM(e, 0x4000, 0x45)&&k.KIFS(31,this.s83,t)) { // Line 136 - r=m=1; - k.KO(0,t," Linux"); - } - else if(k.KKM(e, 0x4000, 0x45)) { // Line 137 - r=m=1; - k.KO(0,t," [OS Undefined (case insensitive test)]"); - } - else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s66,t)) { // Line 99 - r=m=1; - k.KO(0,t," Desktop"); - } - else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s67,t)) { // Line 100 - r=m=1; - k.KO(0,t," Tablet"); - } - else if(k.KKM(e, 0x4000, 0x49)&&k.KIFS(31,this.s68,t)) { // Line 101 - r=m=1; - k.KO(0,t," Phone"); - } - else if(k.KKM(e, 0x4000, 0x49)) { // Line 102 - r=m=1; - k.KO(0,t," [FF Undefined]"); - } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s60,t)) { // Line 89 - r=m=1; - k.KO(0,t," Windows"); - } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s61,t)) { // Line 90 - r=m=1; - k.KO(0,t," Android"); - } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s62,t)) { // Line 91 - r=m=1; - k.KO(0,t," Edge"); - } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s63,t)) { // Line 92 - r=m=1; - k.KO(0,t," iOS"); - } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s64,t)) { // Line 93 - r=m=1; - k.KO(0,t," OSX"); - } - else if(k.KKM(e, 0x4000, 0x4F)&&k.KIFS(31,this.s65,t)) { // Line 94 - r=m=1; - k.KO(0,t," Linux"); - } - else if(k.KKM(e, 0x4000, 0x4F)) { // Line 95 - r=m=1; - k.KO(0,t," [OS Undefined]"); - } - else if(k.KKM(e, 0x4000, 0x50)&&k.KIFS(31,this.s58,t)) { // Line 83 - r=m=1; - k.KO(0,t,"Touch"); - } - else if(k.KKM(e, 0x4000, 0x50)&&k.KIFS(31,this.s59,t)) { // Line 84 - r=m=1; - k.KO(0,t,"Hardware"); - } - else if(k.KKM(e, 0x4000, 0x50)) { // Line 85 - r=m=1; - k.KO(0,t,"[UI Undefined]"); - } - else if(k.KKM(e, 0x4000, 0x52)&&k.KIFS(31,this.s78,t)) { // Line 127 - r=m=1; - k.KO(0,t," Platform-X"); - } - else if(k.KKM(e, 0x4000, 0x52)) { // Line 128 - r=m=1; - k.KO(0,t," [Platform-X Undefined]"); - } - else if(k.KKM(e, 0x4000, 0x54)&&!k.KIFS(31,this.s76,t)) { // Line 121 - r=m=1; - k.KO(0,t," !Touch"); - } - else if(k.KKM(e, 0x4000, 0x54)&&!k.KIFS(31,this.s77,t)) { // Line 122 - r=m=1; - k.KO(0,t," !Hardware"); - } - else if(k.KKM(e, 0x4000, 0x54)) { // Line 123 - r=m=1; - k.KO(0,t," [Inverted OS Undefined]"); - } - else if(k.KKM(e, 0x4000, 0x55)&&k.KIFS(31,this.s69,t)) { // Line 106 - r=m=1; - k.KO(0,t," Native"); - } - else if(k.KKM(e, 0x4000, 0x55)&&k.KIFS(31,this.s70,t)) { // Line 107 - r=m=1; - k.KO(0,t," Web"); - } - else if(k.KKM(e, 0x4000, 0x55)) { // Line 108 - r=m=1; - k.KO(0,t," [Nativeness Undefined]"); - } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s71,t)) { // Line 112 - r=m=1; - k.KO(0,t," IE"); - } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s72,t)) { // Line 113 - r=m=1; - k.KO(0,t," Chrome"); - } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s73,t)) { // Line 114 - r=m=1; - k.KO(0,t," Firefox"); - } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s74,t)) { // Line 115 - r=m=1; - k.KO(0,t," Safari"); - } - else if(k.KKM(e, 0x4000, 0x59)&&k.KIFS(31,this.s75,t)) { // Line 116 - r=m=1; - k.KO(0,t," Opera"); - } - else if(k.KKM(e, 0x4000, 0x59)) { // Line 117 - r=m=1; - k.KO(0,t," [Browser Undefined]"); - } - return r; - }; -} +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;};} \ No newline at end of file diff --git a/windows/src/test/manual-tests/platform-rules/platformtest.kmn b/windows/src/test/manual-tests/platform-rules/platformtest.kmn index 206a281e3b..b33fe0e763 100644 --- a/windows/src/test/manual-tests/platform-rules/platformtest.kmn +++ b/windows/src/test/manual-tests/platform-rules/platformtest.kmn @@ -88,7 +88,6 @@ c O: Operating system platform('windows') + [K_O] > ' Windows' platform('android') + [K_O] > ' Android' -platform('edge') + [K_O] > ' Edge' platform('ios') + [K_O] > ' iOS' platform('macosx') + [K_O] > ' OSX' platform('linux') + [K_O] > ' Linux' @@ -111,6 +110,7 @@ c Y: Test browser (should only return value on web) platform('ie') + [K_Y] > ' IE' platform('chrome') + [K_Y] > ' Chrome' +platform('edge') + [K_Y] > ' Edge' platform('firefox') + [K_Y] > ' Firefox' platform('safari') + [K_Y] > ' Safari' platform('opera') + [K_Y] > ' Opera' diff --git a/windows/src/test/manual-tests/platform-rules/platformtest.kmp b/windows/src/test/manual-tests/platform-rules/platformtest.kmp index 49fe1eb1fe99a050bc1185936c7daa352dd46e88..08be2631c2ef60d5554a81e4dd6271398a4a8df7 100644 GIT binary patch delta 3159 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 No}4cyx_#!??LSn|3E2Pu delta 4047 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ξ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 z;W+jVX0hid_18e336f9ad890bf821ff56e1a7764478 platformtest.kps platformtest.kps - 1.0 + .kps
PlatformTest - 1.0
diff --git a/windows/src/test/manual-tests/platform-rules/platformtest.kps b/windows/src/test/manual-tests/platform-rules/platformtest.kps index bd90d84a31..825b0d5607 100644 --- a/windows/src/test/manual-tests/platform-rules/platformtest.kps +++ b/windows/src/test/manual-tests/platform-rules/platformtest.kps @@ -1,20 +1,21 @@ - 10.0.1103.0 + 10.0.1107.0 7.0 + - 1.0 + PlatformTest -- GitLab From 6a84096fde3334b9f4badb8c4ca13203f9fa7a2b Mon Sep 17 00:00:00 2001 From: darcywong00 Date: Tue, 19 Jun 2018 07:21:26 +0700 Subject: [PATCH 243/356] beautify windows platformtest.js --- .../platform-rules/platformtest.js | 381 +++++++++++++++++- .../platform-rules/platformtest.kmp | Bin 3564 -> 3699 bytes 2 files changed, 380 insertions(+), 1 deletion(-) diff --git a/windows/src/test/manual-tests/platform-rules/platformtest.js b/windows/src/test/manual-tests/platform-rules/platformtest.js index b7c614c2a5..0a1c8bfa78 100644 --- a/windows/src/test/manual-tests/platform-rules/platformtest.js +++ b/windows/src/test/manual-tests/platform-rules/platformtest.js @@ -1 +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;};} \ No newline at end of file + +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; + }; +} \ No newline at end of file diff --git a/windows/src/test/manual-tests/platform-rules/platformtest.kmp b/windows/src/test/manual-tests/platform-rules/platformtest.kmp index 08be2631c2ef60d5554a81e4dd6271398a4a8df7..c6a939f9aed7ee0a711ff44af2ba9a84bc609a93 100644 GIT binary patch delta 1460 zcmV;l1xxzu8}l3tP)h>@6aWAS2mqlvu?!ah0--vyB>_SK0#Z7&X#&Irf0a7ZOl=Hp zDJKO00I4hh01p5F0B~$!bY^dIZFFUGbS`Rh#aiD_+d33}N8*1lJZ!C0s{BqWbRWhA zw5o$nD~u~mS688RM?{;TB&D0C{qHw+6CkebILA|)C*@%I_6G3K7Bjyn#}uLns2tuSHtVC7hlMnLEosGz80hLYO$ydek=yxzpsCy7&2-j zXXPhN_LEma&QQOi4{2(qze6C?`Do&Wt;h(L74=JYiPoP!DI}JWM0T zLLHnu;WT6nt{{?*eNar&MhlD;pFq#ww{f9Vf|;tUL-I0KU_&cG6h zGqCyM995~-=o@|0G}tWuJu9r$;nK-_2zSx1jh#Fx&R1z%PBk|6^7Y@f&lu9rJclWI zEM~l%dA(N~g&|p=8C$+NHpmmrQRlHg8eMg851F1FI6dUK-5O5yE%L5;x;?((YSz|4 z*HVW$TB3LFe^3E79Ca`sLHzZB?CYgJQ?3t9Z6BIyJ{(?7I=0z+Ia`arwpYpXVe#&` zV-(YS)h?;66X8XM1t0+k{T3O{6H& zZDQ|fo4|4ws){P*m=9n$Wrd~+V;eA-O}Ph@ma`LSNl~QIa`q!F8yJbvm@VtC%z zQcZ;0u%rg000OG0HHdQ{tPn$p*oW@4KxB$I+JM)JPwsQ(@bp)Z7C-O005~h Old}yo26qhr0001#-?6U% delta 1324 zcmV+{1=ITT9PAqmP)h>@6aWAS2mn(!u?!ah0#i7%B>_SK0#G=!X#&Ire^5BnOw52k zkDvqq00|iY01p5F0B~$!bY^dIZFFUGbS`RhrC4om+At9QDTQYE2mn)cu4kXPb!LdHIgi=W4L_nhzSPT23Q>p!xm;pB7QXM1JB zem@0nxcu?5apP4GZete3fBnJWa<%gpu^0HV6@TKj7Y!$4s)7sD%k=w{s-H6ReZ_n? zo_@LcOx4j)&rM&bzuRoGA0O!3xA{`4XaBo8K#US{cf~*c()qvC5E+E3aj;vg)!g7v zbc;bTrGf9Y zWYKdRycDJp_s4zOusra{(y98g4*bF!i|^yRvG-b9_*Q%NRQ%*IdF4mG$zmM_+tR}K zV9TGyZ=3J1@3eRjFapbPt&?_uF;NXRYZec*R%-LAXoXxk&MZPH55$AgJ{Oj4{ zyfE>g-c7Ho`9wS_e{WWOl$~ZV)IB$Y}LiY zc1=u-1TitLi-}21OzhOf#G@lIiCz_x7L%601BJ;D| zgtS0p(gK=LHi*hPMH3K#z_g)=s#tPW6i60JCX02BEMP4udCzN#b_61`*4O~FbP$+! zP%%w*$28fpG}&jQ$$~2>Yw}IO!o`%#0x?w7F;pZAe-)h*D%g}1uQ^P(jIycL1ca;T zF#H-|He5sbjBG-}eJC5HO+dH}r4v`w5_i-R%e2HDwCo8^!!4;N%oq`gVPwOYAss^| zvXIFc Date: Tue, 19 Jun 2018 07:53:12 +0700 Subject: [PATCH 244/356] Fixes #945. Getting Started links are no longer relevant. --- windows/src/desktop/kmshell/xml/help.xsl | 5 ----- windows/src/desktop/kmshell/xml/keyman.xsl | 6 ------ windows/src/desktop/kmshell/xml/locale.xml | 3 --- 3 files changed, 14 deletions(-) diff --git a/windows/src/desktop/kmshell/xml/help.xsl b/windows/src/desktop/kmshell/xml/help.xsl index 04b38c1192..9d41ddde59 100644 --- a/windows/src/desktop/kmshell/xml/help.xsl +++ b/windows/src/desktop/kmshell/xml/help.xsl @@ -158,11 +158,6 @@
-
- - - -
diff --git a/windows/src/desktop/kmshell/xml/keyman.xsl b/windows/src/desktop/kmshell/xml/keyman.xsl index 9bb6d125ea..9521d4a0b5 100644 --- a/windows/src/desktop/kmshell/xml/keyman.xsl +++ b/windows/src/desktop/kmshell/xml/keyman.xsl @@ -57,12 +57,6 @@
- icon32_arrow.gif - - icon32_plus.gif -
- + + + + + @@ -107,7 +119,11 @@ - () + + + () + + true @@ -117,68 +133,96 @@ - + - +
Source Files Outputs
Source Files Outputs
- + + - + + - + + - + +
Full path:Full path: + +
Copyright:Copyright: + +
Version:Version: + +
Message:Message: + +
- + @@ -186,16 +230,22 @@ - + - - kbdbitmap + + + + kbdbitmap + - keyman:editfile?id= + + keyman:editfile?id= + -
+
+
diff --git a/windows/src/developer/TIKE/xml/project/packages.xsl b/windows/src/developer/TIKE/xml/project/packages.xsl index f280857cf4..3420a42437 100644 --- a/windows/src/developer/TIKE/xml/project/packages.xsl +++ b/windows/src/developer/TIKE/xml/project/packages.xsl @@ -6,9 +6,7 @@
-

- header_package.png -

+

diff --git a/windows/src/developer/TIKE/xml/project/welcome.xsl b/windows/src/developer/TIKE/xml/project/welcome.xsl index 9b008355d4..5333d0f092 100644 --- a/windows/src/developer/TIKE/xml/project/welcome.xsl +++ b/windows/src/developer/TIKE/xml/project/welcome.xsl @@ -6,9 +6,7 @@
-

Welcome - header_welcome.gif -

+

Welcome