mirror of
https://github.com/keymanapp/keyman.git
synced 2026-10-09 23:47:27 +00:00
Merge branch 'beta' into fix/android/selectively-disable-autocorrect
Some checks failed
Keyman Build Summary / Summarize build status checks (push) Has been cancelled
Some checks failed
Keyman Build Summary / Summarize build status checks (push) Has been cancelled
This commit is contained in:
commit
2abfcdf3cc
556 changed files with 36157 additions and 14689 deletions
89
HISTORY.md
89
HISTORY.md
|
|
@ -1,5 +1,87 @@
|
|||
# Keyman Version History
|
||||
|
||||
## 19.0.303 beta 2026-10-07
|
||||
|
||||
* fix(resources): export KEYMAN_TIER so we get beta tagging on release build (#16751)
|
||||
|
||||
## 19.0.302 beta 2026-10-07
|
||||
|
||||
* fix(mac): lower case 'k' for .pkg.download_info (#16743)
|
||||
* docs: update v19 whats-new (#16748)
|
||||
|
||||
## 19.0.300 beta 2026-10-06
|
||||
|
||||
* chore: move to beta
|
||||
|
||||
## 19.0.299 alpha 2026-10-05
|
||||
|
||||
* chore(deps): bump ip-address from 10.5.0 to 10.7.2 in /developer/src/server/src/win32/trayicon/addon-src (#16698)
|
||||
* chore(deps): bump ip-address from 10.4.0 to 10.7.2 (#16696)
|
||||
* chore(deps-dev): bump brace-expansion from 2.0.2 to 2.1.7 in /resources/build/pr-build-status (#16721)
|
||||
* chore(deps): bump multer from 2.3.0 to 2.4.0 (#16692)
|
||||
* chore(deps): bump brace-expansion (#16728)
|
||||
* fix(mac): show or hide the OSK from the Keyman menu (#16708)
|
||||
* chore(deps-dev): bump brace-expansion from 2.1.1 to 2.1.7 in /core/tests/unit/wasm (#16730)
|
||||
|
||||
## 19.0.298 alpha 2026-10-03
|
||||
|
||||
* chore(linux): update Debian standards version (#16714)
|
||||
|
||||
## 19.0.297 alpha 2026-10-02
|
||||
|
||||
* fix(windows): add warning when system startup disabled (#16603)
|
||||
* docs(windows): add startup app disabled warning help (#16695)
|
||||
|
||||
## 19.0.296 alpha 2026-09-30
|
||||
|
||||
* fix(developer): handle missing `&name` store in package compiler (#16697)
|
||||
* fix(developer): handle out-of-range return values from `GetExitCodeProcess` (#16702)
|
||||
* fix(developer): handle .gitignore in npm-based installations of kmc-generate (#16686)
|
||||
* fix(developer): transform unpaired surrogates in editor to U+FFFD (#16694)
|
||||
* chore(web): allow to open guide example from TC artifacts (#16689)
|
||||
|
||||
## 19.0.295 alpha 2026-09-29
|
||||
|
||||
* fix(mac): open config app from input method (#16676)
|
||||
* maint(web): improve build perf and test params (#16582)
|
||||
* fix(developer): support Rich Edit in Charmap drag + drop (#16685)
|
||||
|
||||
## 19.0.294 alpha 2026-09-28
|
||||
|
||||
* fix(mac): disable the help button entirely in the title bar of OSK (#16679)
|
||||
|
||||
## 19.0.293 alpha 2026-09-25
|
||||
|
||||
* fix(mac): change .pkg name to lower case (#16659)
|
||||
* chore(deps-dev): bump grunt from 1.4.1 to 1.5.3 in /developer/src/tike/xml/layoutbuilder/src/ext/jquery-ui (#16648)
|
||||
* chore(deps): bump multer from 2.2.0 to 2.3.0 (#16543)
|
||||
* chore(web): clarify `LanguageProcessorSpec` usage (#16662)
|
||||
* docs(web): deprecate `keyman.moveToElement(elem)` API (#16661)
|
||||
* chore(developer): cleanup tike build.sh for touch-layout-editor (#16665)
|
||||
* change(mac): remove unused minizip code (#16639)
|
||||
|
||||
## 19.0.292 alpha 2026-09-24
|
||||
|
||||
* chore(windows): use ✕ U+2715 consistently in localizations (#16566)
|
||||
* docs(windows): replace 'keep in touch' tab with 'update' tab to help … (#16544)
|
||||
* chore(web): improve reporting on dictionary load errors (#16647)
|
||||
* maint(mac): use build/upload as upload path for downloads.keyman.com (#16654)
|
||||
|
||||
## 19.0.291 alpha 2026-09-24
|
||||
|
||||
* epic: mac-config (#15328)
|
||||
* chore(common): fix TC reporter reporting failures (#16643)
|
||||
* chore(android): remove unused map-polyfill.js and es6-shim.min.js polyfills (#16637)
|
||||
* fix(developer): address crashes in touch layout editor (#16572)
|
||||
* feat(mac): remove obsolete configuration UI (#16570)
|
||||
* change(developer): reorganize touch layout editor files (#16517)
|
||||
* change(developer): move touch layout editor to typescript (#16520)
|
||||
|
||||
## 19.0.290 alpha 2026-09-23
|
||||
|
||||
* fix(windows): set basekeyboard as current user not the admin user on an elevated process (#16162)
|
||||
* fix(windows): add non-admin user install with different base keyboard (#16528)
|
||||
|
||||
## 19.0.289 alpha 2026-09-21
|
||||
|
||||
* fix(android): suppress autocorrection of hardware keystroke input (#16606)
|
||||
|
|
@ -643,6 +725,7 @@
|
|||
|
||||
## 19.0.182 alpha 2025-12-22
|
||||
|
||||
* epic: ARM support for Windows
|
||||
* maint(common): Fix crowdin sync version to v2.7.0 (#15373)
|
||||
* chore(linux): Update keyman-config.pot strings (#15366)
|
||||
* chore(windows): show architecture in support texteditor (#15378)
|
||||
|
|
@ -1744,6 +1827,10 @@
|
|||
* refactor(windows): rename `TKeymanMutex.MutexOwned` to `TakeOwnership` and add `ReleaseOwnership` (#13168)
|
||||
* chore: increment to alpha 19.0 (#13187)
|
||||
|
||||
## 18.0.253 stable 2026-10-02
|
||||
|
||||
* fix(mac): disable the help button entirely in the title bar of OSK (#16680)
|
||||
|
||||
## 18.0.252 stable 2026-09-22
|
||||
|
||||
* change(android): use webview asset loader (#16628)
|
||||
|
|
@ -1752,7 +1839,7 @@
|
|||
## 18.0.251 stable 2026-09-21
|
||||
|
||||
* maint(android): update Android Target API to 36 (#16620)
|
||||
*
|
||||
|
||||
## 18.0.250 stable 2026-09-21
|
||||
|
||||
* fix(linux): fix memory problem (#15828)
|
||||
|
|
|
|||
2
TIER.md
2
TIER.md
|
|
@ -1 +1 @@
|
|||
alpha
|
||||
beta
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
19.0.290
|
||||
19.0.304
|
||||
2
android/.gitignore
vendored
2
android/.gitignore
vendored
|
|
@ -37,10 +37,8 @@ KMEA/**/assets/keymanandroid.js
|
|||
KMEA/**/assets/keyman.js.map
|
||||
KMEA/**/assets/keymanweb-webview.js
|
||||
KMEA/**/assets/keymanweb-webview.js.map
|
||||
KMEA/**/assets/map-polyfill.js
|
||||
KMEA/**/assets/sentry.min.js
|
||||
KMEA/**/assets/keyman-sentry.js
|
||||
KMEA/**/assets/es6-shim.min.js
|
||||
KMEA/**/assets/kmwosk.css
|
||||
KMEA/**/assets/globe-hint.css
|
||||
KMEA/**/assets/resources
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ plugins {
|
|||
ext.rootPath = '../../'
|
||||
apply from: "$rootPath/version.gradle"
|
||||
String tier = System.getenv("KEYMAN_TIER");
|
||||
println "Using tier $tier"
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
|
|
|
|||
|
|
@ -437,12 +437,6 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
if (navigationView != null) {
|
||||
updateCurrentKeyboardDrawerItemTitle(navigationView);
|
||||
updateInstalledLanguagesDrawerTitle(navigationView);
|
||||
initializeDrawerItemSubtitles(navigationView);
|
||||
}
|
||||
|
||||
if (textView != null) {
|
||||
KMManager.setSuggestionType(KeyboardType.KEYBOARD_TYPE_INAPP, KMManager.defaultSuggestionModeForInputType(textView.getInputType()));
|
||||
}
|
||||
|
|
@ -464,12 +458,35 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
}
|
||||
resizeTextView(textView.isKeyboardVisible());
|
||||
|
||||
// The keyboard may have been changed while we were paused, for example if
|
||||
// the keyboard picker activity is started.
|
||||
com.keyman.engine.data.Keyboard currentKeyboard = KMManager.getCurrentKeyboardInfo(context);
|
||||
if(currentKeyboard != null) {
|
||||
// TODO(v20): eliminate `lastKnownKeyboardId` and always use `currentKeyboard.getKeyboardID()`
|
||||
// TODO(v20): this lines up with onKeyboardChanged(), refactor accordingly
|
||||
lastKnownKeyboardId = currentKeyboard.getKeyboardID();
|
||||
}
|
||||
|
||||
if (navigationView != null) {
|
||||
// TODO(v20): these three calls are repeated in various places and should be cleaned up
|
||||
updateCurrentKeyboardDrawerItemTitle(navigationView);
|
||||
updateInstalledLanguagesDrawerTitle(navigationView);
|
||||
initializeDrawerItemSubtitles(navigationView);
|
||||
}
|
||||
|
||||
if (textView != null) {
|
||||
// Reset inAppPredictionsSuspendedForSensitiveInput flag
|
||||
KMManager.setPredictionsSuspended(textView.getInputType(), KeyboardType.KEYBOARD_TYPE_INAPP);
|
||||
textView.setTypeface(KMManager.getKeyboardTextFontTypeface(this));
|
||||
}
|
||||
|
||||
KMManager.addKeyboardEventListener(this);
|
||||
KMKeyboardDownloaderActivity.addKeyboardDownloadEventListener(this);
|
||||
PackageActivity.addKeyboardDownloadEventListener(this);
|
||||
|
||||
CheckInstallReferrer.checkGooglePlayInstallReferrer(this, context);
|
||||
|
||||
// TODO(v20): move loadingIntentUri logic into a separate function
|
||||
Intent intent = getIntent();
|
||||
Uri loadingIntentUri = intent.getData();
|
||||
|
||||
|
|
@ -662,6 +679,9 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
if (drawerLayout.isDrawerOpen(GravityCompat.END)) {
|
||||
drawerLayout.closeDrawer(GravityCompat.END);
|
||||
} else {
|
||||
updateCurrentKeyboardDrawerItemTitle(navigationView);
|
||||
updateInstalledLanguagesDrawerTitle(navigationView);
|
||||
initializeDrawerItemSubtitles(navigationView);
|
||||
drawerLayout.openDrawer(GravityCompat.END);
|
||||
}
|
||||
return true;
|
||||
|
|
@ -865,8 +885,9 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
* If URL is valid, download the kmp.
|
||||
* @param packageUri URI to download the package.
|
||||
* @param installMode KMP installation mode (silent, welcome only, or full)
|
||||
* TODO: only ever pass packageId and bcp47 from callers, as KMPLink should be responsible for
|
||||
* TODO(v20): only ever pass packageId and bcp47 from callers, as KMPLink should be responsible for
|
||||
* URL parsing, not this function.
|
||||
* TODO(v20): move this into a separate module
|
||||
*/
|
||||
public void downloadKMP(Uri packageUri, KmpInstallMode installMode) {
|
||||
if (packageUri == null) {
|
||||
|
|
@ -982,6 +1003,7 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
overridePendingTransition(android.R.anim.fade_in, com.keyman.engine.R.anim.hold);
|
||||
}
|
||||
|
||||
// TODO(v20): remove remaining tendrils
|
||||
private void showWebBrowser() {
|
||||
// Telemetry for in-app browser usage.
|
||||
// Logging here because WebBrowserActivity is launched in a separate process.
|
||||
|
|
@ -1266,7 +1288,7 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Move this to KMEA during Keyman 13.0 refactoring
|
||||
// TODO(v20): Move this to KMEA during Keyman 13.0 refactoring
|
||||
public static void useLocalKMP(Context context, Uri data) {
|
||||
if (data != null) {
|
||||
useLocalKMP(context, data, false);
|
||||
|
|
@ -1409,6 +1431,7 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
});
|
||||
}
|
||||
|
||||
// TODO(v20): cleanup setting draw item [sub]titles; lots of repetition and unnecessary conditions
|
||||
private void initializeDrawerItemSubtitles(NavigationView navigationView) {
|
||||
setDrawerItemSubtitle(navigationView, R.id.nav_spacebar_caption,
|
||||
getString(R.string.drawer_subtitle_spacebar_caption));
|
||||
|
|
@ -1416,8 +1439,6 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
getString(R.string.drawer_subtitle_show_osk));
|
||||
setDrawerItemSubtitle(navigationView, R.id.nav_toggle_send_crash_report,
|
||||
getString(R.string.drawer_subtitle_send_crash_report));
|
||||
setDrawerItemSubtitle(navigationView, R.id.nav_about_current_keyboard,
|
||||
getString(R.string.drawer_subtitle_about_current_keyboard));
|
||||
updateThemeDrawerSubtitle(navigationView);
|
||||
updateCurrentKeyboardDrawerSubtitle(navigationView);
|
||||
}
|
||||
|
|
@ -1631,6 +1652,7 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
}
|
||||
}
|
||||
|
||||
// TODO(v20): remove
|
||||
private void bindDrawerCheckboxAction(NavigationView navigationView, int menuItemId,
|
||||
final Runnable onActivate) {
|
||||
MenuItem menuItem = navigationView.getMenu().findItem(menuItemId);
|
||||
|
|
@ -1670,6 +1692,7 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
});
|
||||
}
|
||||
|
||||
// TODO(v20): remove
|
||||
private void setDrawerCheckboxState(NavigationView navigationView, int menuItemId, boolean isChecked) {
|
||||
MenuItem menuItem = navigationView.getMenu().findItem(menuItemId);
|
||||
if (menuItem == null) {
|
||||
|
|
|
|||
|
|
@ -380,9 +380,7 @@ public final class KMManager {
|
|||
protected static final String KMFilename_KmwCss = "kmwosk.css";
|
||||
protected static final String KMFilename_KmwGlobeHintCss = "globe-hint.css";
|
||||
protected static final String KMFilename_Osk_Ttf_Font = "keymanweb-osk.ttf";
|
||||
protected static final String KMFilename_JSPolyfill = "es6-shim.min.js";
|
||||
protected static final String KMFilename_JSPolyfill2 = "other-polyfills.js";
|
||||
protected static final String KMFilename_JSPolyfill3 = "map-polyfill.js";
|
||||
|
||||
// Deprecated by KeyboardController.KMFilename_Installed_KeyboardsList
|
||||
public static final String KMFilename_KeyboardsList = "keyboards_list.dat";
|
||||
|
|
@ -3026,6 +3024,9 @@ public final class KMManager {
|
|||
|
||||
public static int getCurrentKeyboardIndex(Context context) {
|
||||
String key = KMKeyboard.currentKeyboard();
|
||||
if(key == null) {
|
||||
return KeyboardController.INDEX_NOT_FOUND;
|
||||
}
|
||||
return KeyboardController.getInstance().getKeyboardIndex(key);
|
||||
}
|
||||
|
||||
|
|
@ -3034,11 +3035,6 @@ public final class KMManager {
|
|||
if(index < 0) {
|
||||
// index can be undefined if user installs Keyman (without launching it)
|
||||
// and then enables Keyaman as a system keyboard from the Android settings menus.
|
||||
// We'll only log if key isn't for fallback keyboard
|
||||
String key = KMKeyboard.currentKeyboard();
|
||||
if (!isDefaultKey(key)) {
|
||||
KMLog.LogError(TAG, "Failed getCurrentKeyboardIndex check for keyboard: " + key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return KeyboardController.getInstance().getKeyboardInfo(index);
|
||||
|
|
|
|||
|
|
@ -188,16 +188,15 @@ public class KeyboardController {
|
|||
* If no match, returns INDEX_NOT_FOUND
|
||||
* @param key - String of the key to find
|
||||
* @return int - Index of the matching keyboard
|
||||
*
|
||||
* Note: do not perform logging here because KMLog.tagDebugInfo can call this, causing recursion
|
||||
*/
|
||||
public int getKeyboardIndex(String key) {
|
||||
int index = INDEX_NOT_FOUND;
|
||||
if (!isInitialized || list == null) {
|
||||
KMLog.LogError(TAG, "getKeyboardIndex while KeyboardController() not initialized");
|
||||
return index;
|
||||
return INDEX_NOT_FOUND;
|
||||
}
|
||||
if (key == null || key.isEmpty()) {
|
||||
KMLog.LogError(TAG, "getKeyboardIndex while key is null");
|
||||
return index;
|
||||
return INDEX_NOT_FOUND;
|
||||
}
|
||||
|
||||
synchronized (list) {
|
||||
|
|
@ -209,11 +208,7 @@ public class KeyboardController {
|
|||
}
|
||||
}
|
||||
|
||||
// We'll only log if key isn't for fallback keyboard
|
||||
if (!KMManager.isDefaultKey(key)) {
|
||||
KMLog.LogError(TAG, "getKeyboardIndex failed for key " + key);
|
||||
}
|
||||
return index;
|
||||
return INDEX_NOT_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import io.sentry.Breadcrumb;
|
|||
import io.sentry.Sentry;
|
||||
import io.sentry.SentryLevel;
|
||||
|
||||
// TODO(v20): make KMLog more resilient to re-entrancy by preventing nested calls with a sentinel flag
|
||||
public final class KMLog {
|
||||
private static final String TAG = "KMLog";
|
||||
|
||||
|
|
|
|||
|
|
@ -55,16 +55,12 @@ do_build() {
|
|||
builder_echo "Copying Keyman Web artifacts"
|
||||
cp "$KEYMAN_ROOT/web/build/app/webview/$BUILDER_CONFIGURATION/keymanweb-webview.js" "$ENGINE_ASSETS/"
|
||||
cp "$KEYMAN_ROOT/web/build/app/webview/$BUILDER_CONFIGURATION/keymanweb-webview.js.map" "$ENGINE_ASSETS/"
|
||||
cp "$KEYMAN_ROOT/web/build/app/webview/$BUILDER_CONFIGURATION/map-polyfill.js" "$ENGINE_ASSETS/"
|
||||
cp "$KEYMAN_ROOT/web/build/app/resources/osk/ajax-loader.gif" "$ENGINE_ASSETS/"
|
||||
cp "$KEYMAN_ROOT/web/build/app/resources/osk/kmwosk.css" "$ENGINE_ASSETS/"
|
||||
cp "$KEYMAN_ROOT/web/build/app/resources/osk/globe-hint.css" "$ENGINE_ASSETS/"
|
||||
cp "$KEYMAN_ROOT/web/build/app/resources/osk/keymanweb-osk.ttf" "$ENGINE_ASSETS/"
|
||||
cp "$KEYMAN_ROOT/common/web/sentry-manager/build/lib/index.js" "$ENGINE_ASSETS/keyman-sentry.js"
|
||||
|
||||
builder_echo "Copying es6-shim polyfill"
|
||||
cp "$KEYMAN_ROOT/node_modules/es6-shim/es6-shim.min.js" "$ENGINE_ASSETS/"
|
||||
|
||||
builder_echo "BUILD_FLAGS $BUILD_FLAGS"
|
||||
|
||||
# Build without test
|
||||
|
|
|
|||
|
|
@ -2,9 +2,14 @@
|
|||
title: What's New in Keyman Engine 19.0 for Android
|
||||
---
|
||||
|
||||
* Added API for broadcasting when Keyman system keyboard font changes (#15193)
|
||||
* Added API for selecting and controlling what types of suggestions are offered
|
||||
for different `Editable` input types (#16644)
|
||||
* **BREAKING** Apps that use the functionality of Keyman Engine for Android will have to add `androidx.webkit:webkit:1.14.0` as a dependency (#16146)
|
||||
* **KNOWN ISSUE** `sil_euro_latin` keyboard must be included in an app if `setDefaultKeyboard()` is not called during initialization (#16215)
|
||||
* Added [Intent `com.tavultesoft.kmapro.keyboard_changed`](KMAPro/) which is broadcast when Keyman system keyboard changes and includes font name (#15193)
|
||||
* Added [`KMManager.getKeyboardHeightMax()`](KMManager/getKeyboardHeightMax) API (#13663)
|
||||
* Added [`KMManager.getKeyboardHeightMin()`](KMManager/getKeyboardHeightMin) API (#13663)
|
||||
* Clarified font filename vs facename in various APIs (#16211)
|
||||
|
||||
## See Also
|
||||
* [Keyman Engine for Android Documentation](index)
|
||||
|
|
@ -4,3 +4,9 @@ title: What's New in Keyman 19.0 for Android
|
|||
|
||||
Here are some of the new features we have added to Keyman 19.0 for Android:
|
||||
|
||||
- Keyboard search is now localized for several languages (#15510)
|
||||
- Support for dark mode (#15827)
|
||||
- Refreshed and modernized settings user interface (#15827)
|
||||
- Automatic acceptance of corrections (#12893)
|
||||
- Improvements to interface for keyboard resizing (#15267)
|
||||
- About [220 other fixes and changes](https://keyman.com/go/app/whatsnew/android/19.0)
|
||||
|
|
|
|||
63
common/cpp/kmx_file.cpp
Normal file
63
common/cpp/kmx_file.cpp
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*
|
||||
* Created by mcdurdin on 2026-10-03
|
||||
*
|
||||
* Number of parameters for xstring codes
|
||||
*/
|
||||
#include "kmx_file.h"
|
||||
|
||||
#ifdef KM_CORE_LIBRARY
|
||||
// TODO: move this to a common namespace keyman::common::kmx_file or similar in the future
|
||||
namespace km {
|
||||
namespace core {
|
||||
namespace kmx {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Define the number of parameters for each of the extended string codes:
|
||||
* * -1 means the code should not (or cannot) occur; treated as if the code is
|
||||
* not present.
|
||||
*
|
||||
* * 0, 1, 2, 3 parameters otherwise, each one 16 bits (i.e. one u16 char) wide.
|
||||
* Each parameter must be a non-zero value (0x0001-0xFFFF).
|
||||
*
|
||||
* * If a UC_SENTINEL is followed by any other code, the code is returned as a
|
||||
* character.
|
||||
*/
|
||||
const int CODE__SIZE[] = {
|
||||
-1, // undefined 0x00
|
||||
1, // CODE_ANY 0x01
|
||||
2, // CODE_INDEX 0x02
|
||||
0, // CODE_CONTEXT 0x03
|
||||
0, // CODE_NUL 0x04
|
||||
1, // CODE_USE 0x05
|
||||
0, // CODE_RETURN 0x06
|
||||
0, // CODE_BEEP 0x07
|
||||
1, // CODE_DEADKEY 0x08
|
||||
-1, // unused 0x09
|
||||
2, // CODE_EXTENDED 0x0A
|
||||
-1, // CODE_EXTENDEDEND 0x0B (unused)
|
||||
1, // CODE_SWITCH 0x0C (unused, removed in 19.0)
|
||||
-1, // CODE_KEY 0x0D (unused, removed in 19.0)
|
||||
0, // CODE_CLEARCONTEXT 0x0E (unused, removed in 19.0)
|
||||
1, // CODE_CALL 0x0F
|
||||
-1, // UC_SENTINEL_EXTENDEDEND 0x10 (not valid with UC_SENTINEL)
|
||||
1, // CODE_CONTEXTEX 0x11
|
||||
1, // CODE_NOTANY 0x12
|
||||
2, // CODE_SETOPT 0x13
|
||||
3, // CODE_IFOPT 0x14
|
||||
1, // CODE_SAVEOPT 0x15
|
||||
1, // CODE_RESETOPT 0x16
|
||||
3, // CODE_IFSYSTEMSTORE 0x17
|
||||
2 // CODE_SETSYSTEMSTORE 0x18
|
||||
};
|
||||
|
||||
// Ensure that all CODE_### sizes are defined
|
||||
static_assert(sizeof(CODE__SIZE) / sizeof(CODE__SIZE[0]) == (CODE_LASTCODE + 1), "Size of array CODE__SIZE not correct");
|
||||
|
||||
#ifdef KM_CORE_LIBRARY
|
||||
} // namespace kmx
|
||||
} // namespace core
|
||||
} // namespace km
|
||||
#endif
|
||||
|
|
@ -200,9 +200,9 @@ namespace kmx {
|
|||
// 0x09 = bkspace.-- we don't need to keep this separate though with UC_SENTINEL
|
||||
#define CODE_EXTENDED 0x0A
|
||||
//#define CODE_EXTENDEDEND 0x0B deprecated
|
||||
#define CODE_SWITCH 0x0C
|
||||
#define CODE_KEY 0x0D
|
||||
#define CODE_CLEARCONTEXT 0x0E // deprecated in 19.0
|
||||
//#define CODE_SWITCH 0x0C // unused, removed in 19.0
|
||||
//#define CODE_KEY 0x0D // unused, removed in 19.0
|
||||
//#define CODE_CLEARCONTEXT 0x0E // unused, removed in 19.0
|
||||
#define CODE_CALL 0x0F
|
||||
// UC_SENTINEL_EXTENDEDEND 0x10
|
||||
#define CODE_CONTEXTEX 0x11
|
||||
|
|
@ -234,8 +234,8 @@ namespace kmx {
|
|||
#define U_CODE_BEEP u"\u0007"
|
||||
#define U_CODE_DEADKEY u"\u0008"
|
||||
#define U_CODE_EXTENDED u"\u000A"
|
||||
#define U_CODE_SWITCH u"\u000C"
|
||||
#define U_CODE_CLEARCONTEXT u"\u000E" // deprecated in 19.0
|
||||
#define U_CODE_SWITCH u"\u000C" // unused, removed in 19.0; this macro kept for security tests
|
||||
#define U_CODE_CLEARCONTEXT u"\u000E" // unused, removed in 19.0; this macro kept for security tests
|
||||
#define U_CODE_CALL u"\u000F"
|
||||
#define U_CODE_EXTENDEDEND u"\u0010"
|
||||
#define U_CODE_CONTEXTEX u"\u0011"
|
||||
|
|
@ -256,8 +256,8 @@ namespace kmx {
|
|||
#define C_CODE_BEEP() U_UC_SENTINEL U_CODE_BEEP
|
||||
#define C_CODE_DEADKEY(deadkey) U_UC_SENTINEL U_CODE_DEADKEY deadkey
|
||||
#define C_CODE_EXTENDED(varargs) U_UC_SENTINEL U_CODE_EXTENDED varargs
|
||||
#define C_CODE_SWITCH(val) U_UC_SENTINEL U_CODE_SWITCH val
|
||||
#define C_CODE_CLEARCONTEXT() U_UC_SENTINEL U_CODE_CLEARCONTEXT // deprecated in 19.0
|
||||
#define C_CODE_SWITCH(val) U_UC_SENTINEL U_CODE_SWITCH val // unused, removed in 19.0; this macro kept for security tests
|
||||
#define C_CODE_CLEARCONTEXT() U_UC_SENTINEL U_CODE_CLEARCONTEXT // unused, removed in 19.0; this macro kept for security tests
|
||||
#define C_CODE_CALL(val) U_UC_SENTINEL U_CODE_CALL val
|
||||
#define C_CODE_CONTEXTEX(val) U_UC_SENTINEL U_CODE_CONTEXTEX val
|
||||
#define C_CODE_NOTANY(val) U_UC_SENTINEL U_CODE_NOTANY val
|
||||
|
|
|
|||
|
|
@ -63,12 +63,12 @@ export default function teamcityReporter({ name="Web Test Runner JavaScript test
|
|||
} else {
|
||||
summary.failed++;
|
||||
const message = test.error ? `message='${e(test.error.message)}'` : '';
|
||||
const details = test.error ? `\ndetails='${e(test.error.stack)}\n`: '';
|
||||
const details = test.error ? `details='${e(test.error.stack)}'`: '';
|
||||
|
||||
if(test.error?.actual !== undefined && test.error?.expected !== undefined) {
|
||||
logger.log(`##teamcity[testFailed type='comparisonFailure' name='${e(test.name)}' ${e(message)}] ${e(details)} expected='${e(test.error?.expected)}' actual='${e(test.error?.actual)}']`);
|
||||
logger.log(`##teamcity[testFailed type='comparisonFailure' name='${e(test.name)}' ${message} ${details} expected='${e(test.error?.expected)}' actual='${e(test.error?.actual)}']`);
|
||||
}
|
||||
logger.log(`##teamcity[testFailed name='${e(test.name)}' ${e(message)}] ${e(details)}']`);
|
||||
logger.log(`##teamcity[testFailed name='${e(test.name)}' ${message} ${details}]`);
|
||||
}
|
||||
|
||||
logger.log(`##teamcity[testFinished name='${e(test.name)}' duration='${e(test.duration ?? 0)}']`);
|
||||
|
|
|
|||
|
|
@ -308,9 +308,9 @@ export class KMXFile {
|
|||
// 0x09 = bkspace.-- we don't need to keep this separate though with UC_SENTINEL
|
||||
public static readonly CODE_EXTENDED = 0x0A;
|
||||
//public static readonly CODE_EXTENDEDEND = 0x0B; deprecated
|
||||
public static readonly CODE_SWITCH = 0x0C;
|
||||
public static readonly CODE_KEY = 0x0D;
|
||||
public static readonly CODE_CLEARCONTEXT = 0x0E; // deprecated in 19.0
|
||||
//public static readonly CODE_SWITCH = 0x0C; // unused, removed in 19.0
|
||||
//public static readonly CODE_KEY = 0x0D; // unused, removed in 19.0
|
||||
//public static readonly CODE_CLEARCONTEXT = 0x0E; // unused, removed in 19.0
|
||||
public static readonly CODE_CALL = 0x0F;
|
||||
// UC_SENTINEL_EXTENDEDEND 0x10
|
||||
public static readonly CODE_CONTEXTEX = 0x11;
|
||||
|
|
|
|||
|
|
@ -256,9 +256,9 @@
|
|||
// 0x09 = bkspace.-- we don't need to keep this separate though with UC_SENTINEL
|
||||
#define CODE_EXTENDED 0x0A
|
||||
//#define CODE_EXTENDEDEND 0x0B deprecated
|
||||
#define CODE_SWITCH 0x0C
|
||||
#define CODE_KEY 0x0D
|
||||
#define CODE_CLEARCONTEXT 0x0E // deprecated in 19.0
|
||||
//#define CODE_SWITCH 0x0C // unused, removed in 19.0
|
||||
//#define CODE_KEY 0x0D // unused, removed in 19.0
|
||||
//#define CODE_CLEARCONTEXT 0x0E // unused, removed in 19.0
|
||||
#define CODE_CALL 0x0F
|
||||
// UC_SENTINEL_EXTENDEDEND 0x10
|
||||
#define CODE_CONTEXTEX 0x11
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ PWSTR incxstr(PWSTR p)
|
|||
case CODE_USE: return p+1;
|
||||
case CODE_DEADKEY: return p+1;
|
||||
case CODE_EXTENDED: p += 2; while(*p && *p != UC_SENTINEL_EXTENDEDEND) p++; return p+1;
|
||||
case CODE_CLEARCONTEXT: return p+1;
|
||||
case CODE_CALL: return p+1;
|
||||
case CODE_CONTEXTEX: return p+1;
|
||||
case CODE_IFOPT: return p+3;
|
||||
|
|
@ -98,7 +97,6 @@ PWSTR decxstr(PWSTR p, PWSTR pStart)
|
|||
case CODE_NOTANY:
|
||||
case CODE_USE:
|
||||
case CODE_DEADKEY:
|
||||
case CODE_CLEARCONTEXT:
|
||||
case CODE_CALL:
|
||||
case CODE_CONTEXTEX:
|
||||
case CODE_RESETOPT:
|
||||
|
|
|
|||
|
|
@ -283,6 +283,8 @@ const
|
|||
|
||||
SRegValue_WindowsRun_Keyman = 'Keyman';
|
||||
|
||||
SRegKey_StartupApproved_Run = 'Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run'; // CU
|
||||
|
||||
SRegValue_LanguageCheckDisabledItems = 'language check disabled items'; // CU
|
||||
|
||||
{-------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ begin
|
|||
end;
|
||||
until b = 0;
|
||||
|
||||
ExitCode := ec; // I3631
|
||||
ExitCode := Integer(ec); // I3631
|
||||
|
||||
Result := True;
|
||||
finally
|
||||
|
|
|
|||
|
|
@ -54,9 +54,9 @@ const
|
|||
// = $09 = bkspace.-- we don't need to keep this separate though with UC_SENTINEL
|
||||
CODE_EXTENDED = $0A;
|
||||
//#define CODE_EXTENDEDEND = $0B deprecated
|
||||
CODE_SWITCH = $0C;
|
||||
CODE_KEY = $0D;
|
||||
CODE_CLEARCONTEXT = $0E; // deprecated in 19.0
|
||||
//CODE_SWITCH = $0C; // unused, removed in 19.0
|
||||
//CODE_KEY = $0D; // unused, removed in 19.0
|
||||
//CODE_CLEARCONTEXT = $0E; // unused, removed in 19.0
|
||||
CODE_CALL = $0F;
|
||||
// UC_SENTINEL_EXTENDEDEND 0x10
|
||||
CODE_CONTEXTEX = $11;
|
||||
|
|
@ -74,15 +74,6 @@ const
|
|||
CODE_SETSYSTEMSTORE = $18; // I3437
|
||||
CODE_LASTCODE = $18;
|
||||
|
||||
const
|
||||
KMXCodeNames: array[CODE_FIRSTCODE..CODE_LASTCODE] of string = (
|
||||
'any', 'index', 'context', 'nul', 'use', 'return', 'beep', 'deadkey',
|
||||
'',
|
||||
'extended', '', 'switch', 'key', 'clearcontext', 'call',
|
||||
'', 'contextex', 'notany',
|
||||
'set', 'if', 'save', 'reset', // I3429
|
||||
'if(&system)', 'set(&system)'); // I3430 // I3437
|
||||
|
||||
const
|
||||
VERSION_30 = $00000300;
|
||||
VERSION_31 = $00000301;
|
||||
|
|
|
|||
|
|
@ -163,7 +163,6 @@ begin
|
|||
CODE_CONTEXTEX: Inc(Result, 2);
|
||||
CODE_NOTANY: Inc(Result, 2);
|
||||
|
||||
CODE_CLEARCONTEXT: Inc(Result, 2); // I3442 // deprecated in 19.0
|
||||
CODE_IFOPT: Inc(Result, 4); // I3442
|
||||
CODE_IFSYSTEMSTORE: Inc(Result, 4); // I3442
|
||||
CODE_SETOPT: Inc(Result, 3); // I3442
|
||||
|
|
|
|||
|
|
@ -20,37 +20,6 @@ KMX_BOOL KMX_ProcessEvent::Load(PKMX_BYTE buf, size_t sz) {
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
const int km::core::kmx::CODE__SIZE[] = {
|
||||
-1, // undefined 0x00
|
||||
1, // CODE_ANY 0x01
|
||||
2, // CODE_INDEX 0x02
|
||||
0, // CODE_CONTEXT 0x03
|
||||
0, // CODE_NUL 0x04
|
||||
1, // CODE_USE 0x05
|
||||
0, // CODE_RETURN 0x06
|
||||
0, // CODE_BEEP 0x07
|
||||
1, // CODE_DEADKEY 0x08
|
||||
-1, // unused 0x09
|
||||
2, // CODE_EXTENDED 0x0A
|
||||
-1, // CODE_EXTENDEDEND 0x0B (unused)
|
||||
1, // CODE_SWITCH 0x0C
|
||||
-1, // CODE_KEY 0x0D (never used)
|
||||
0, // CODE_CLEARCONTEXT 0x0E (deprecated in 19.0)
|
||||
1, // CODE_CALL 0x0F
|
||||
-1, // UC_SENTINEL_EXTENDEDEND 0x10 (not valid with UC_SENTINEL)
|
||||
1, // CODE_CONTEXTEX 0x11
|
||||
1, // CODE_NOTANY 0x12
|
||||
2, // CODE_SETOPT 0x13
|
||||
3, // CODE_IFOPT 0x14
|
||||
1, // CODE_SAVEOPT 0x15
|
||||
1, // CODE_RESETOPT 0x16
|
||||
3, // CODE_IFSYSTEMSTORE 0x17
|
||||
2 // CODE_SETSYSTEMSTORE 0x18
|
||||
};
|
||||
|
||||
// Ensure that all CODE_### sizes are defined
|
||||
static_assert(sizeof(CODE__SIZE) / sizeof(CODE__SIZE[0]) == (CODE_LASTCODE + 1), "Size of array CODE__SIZE not correct");
|
||||
|
||||
KMX_BOOL KMX_ProcessEvent::LoadKeyboardFromBlob(
|
||||
PKMX_BYTE original_buf,
|
||||
size_t sz,
|
||||
|
|
|
|||
|
|
@ -494,10 +494,6 @@ int KMX_ProcessEvent::PostString(PKMX_WCHAR str, LPKEYBOARD lpkb, PKMX_WCHAR end
|
|||
if(m_state.StopOutput) return psrPostMessages;
|
||||
FoundUse = TRUE;
|
||||
break;
|
||||
case CODE_CLEARCONTEXT:
|
||||
// statement deprecated in 19.0
|
||||
// no longer supported, no-op
|
||||
break;
|
||||
case CODE_INDEX:
|
||||
p++;
|
||||
s = &m_keyboard.Keyboard->dpStoreArray[*p - 1];
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ core_files = files(
|
|||
'state.cpp',
|
||||
'jsonpp.cpp',
|
||||
'../../common/cpp/utfcodec.cpp',
|
||||
'../../common/cpp/kmx_file.cpp',
|
||||
)
|
||||
|
||||
mock_files = files(
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ void test_decxstr() {
|
|||
test_assert(q == (p - 4) );
|
||||
|
||||
//runs OK with NEW version of decxstr (with CODE_SWITCH pointer moves 2 ( 3 altogether)
|
||||
p_start = (PKMX_WCHAR)u"abc" C_CODE_SWITCH(u"\u0001") u"d";
|
||||
p_start = (PKMX_WCHAR)u"abc" C_CODE_SWITCH(u"\u0001") u"d"; // unused, marked as such in 19.0
|
||||
p = find_ptr_to_last_character(p_start);
|
||||
q = decxstr(p, p_start);
|
||||
test_assert(q == (p - 3) );
|
||||
|
|
@ -625,7 +625,7 @@ void test_decxstr() {
|
|||
test_assert(q == p + 2 );
|
||||
|
||||
// --- Test for FFFF + CODE_SWITCH -----------------------------------------------------------------------------------------------------------
|
||||
p = (PKMX_WCHAR) C_CODE_SWITCH(u"\u0001");
|
||||
p = (PKMX_WCHAR) C_CODE_SWITCH(u"\u0001"); // unused, marked as such in 19.0
|
||||
q = incxstr(p);
|
||||
test_assert(q == p + 3 );
|
||||
|
||||
|
|
@ -860,8 +860,8 @@ void test_decxstr() {
|
|||
q = incxstr(p);
|
||||
test_assert(q == p + 2 );
|
||||
|
||||
// --- Test for FFFF + CODE_SWITCH -----------------------------------------------------------------------------------------------------------
|
||||
p = (PKMX_WCHAR) C_CODE_SWITCH(u"\u0001") u"\u1234\u2468";
|
||||
// --- Test for FFFF + CODE_SWITCH ----------------------------------- ------------------------------------------------------------------------
|
||||
p = (PKMX_WCHAR) C_CODE_SWITCH(u"\u0001") u"\u1234\u2468"; // unused, marked as such in 19.0
|
||||
q = incxstr(p);
|
||||
test_assert(q == p + 3 );
|
||||
|
||||
|
|
@ -1112,7 +1112,7 @@ void test_decxstr() {
|
|||
test_assert(q == p + 2 );
|
||||
|
||||
// --- Test for FFFF + CODE_SWITCH -----------------------------------------------------------------------------------------------------------
|
||||
p = (PKMX_WCHAR) C_CODE_SWITCH(u"\u0001") U_1F609_WINKING_FACE;
|
||||
p = (PKMX_WCHAR) C_CODE_SWITCH(u"\u0001") U_1F609_WINKING_FACE; // unused, marked as such in 19.0
|
||||
q = incxstr(p);
|
||||
test_assert(q == p + 3 );
|
||||
|
||||
|
|
|
|||
6
core/tests/unit/wasm/package-lock.json
generated
6
core/tests/unit/wasm/package-lock.json
generated
|
|
@ -133,9 +133,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz",
|
||||
"integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==",
|
||||
"version": "2.1.7",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz",
|
||||
"integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
|
|
|||
|
|
@ -3,3 +3,13 @@ title: What's new in Keyman Developer 19.0
|
|||
---
|
||||
|
||||
Keyman Developer 19 has the following significant changes:
|
||||
|
||||
- Updated to Unicode 17.0 (#14728)
|
||||
- Updated langtags.json, ISO639-3, language-subtag-registry (#16371)
|
||||
- Validate a keyboard or lexical model project frmo within Keyman Developer (#16076)
|
||||
- Support for line numbers in LDML keyboard compiler messages (#13375)
|
||||
- Convert from .keylayout (macOS keyboards, Ukelele) into .kmn (#12191)
|
||||
- Compiler improvements - prevent illegal constructs (#16723, #16726, #36710, #16717)
|
||||
- Various improvements to touch layout editor (#16572, #16520, #16517, #16516, #16509, #16456, #16370, #16347, #16129, #15371, #15338, #15243, #15060, #14228)
|
||||
- Support output folder and `--continue-on-error` in kmc (#16453)
|
||||
- About [400 other fixes and changes](https://keyman.com/go/app/whatsnew/developer/19.0)
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ namespace KmnCompilerMessages {
|
|||
|
||||
WARN_TooManyWarnings = SevWarn | 0x080,
|
||||
WARN_OldVersion = SevWarn | 0x081,
|
||||
WARN_BitmapNotUsed = SevWarn | 0x082,
|
||||
// WARN_BitmapNotUsed = SevWarn | 0x082, removed in 19.0.295-alpha
|
||||
WARN_CustomLanguagesNotSupported = SevWarn | 0x083,
|
||||
WARN_KeyBadLength = SevWarn | 0x084,
|
||||
WARN_IndexStoreShort = SevWarn | 0x085,
|
||||
|
|
@ -285,7 +285,11 @@ namespace KmnCompilerMessages {
|
|||
ERROR_NameMustNotContainParentheses = SevError | 0x0B9,
|
||||
ERROR_NameMustNotContainSquareBrackets = SevError | 0x0BA,
|
||||
|
||||
WARN_DeprecatedStatement = SevWarn | 0x0BB,
|
||||
// 0x0BB unused
|
||||
WARN_DeprecatedValueFormat = SevWarn | 0x0BC,
|
||||
WARN_DeprecatedCompileTarget = SevWarn | 0x0BD,
|
||||
|
||||
ERROR_StoreContainsUnsupportedStatement = SevError | 0x0BE,
|
||||
|
||||
FATAL_BufferOverflow = SevFatal | 0x0C0
|
||||
// FATAL_Break = SevFatal | 0x0C1, unused
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ function make-kmc-install-zip() {
|
|||
add_zip_files "${KMCOMP_ZIP}" -q -r \
|
||||
kmconvert.exe \
|
||||
keyboard_info.schema.json \
|
||||
xml/layoutbuilder/*.keyman-touch-layout \
|
||||
xml/layoutbuilder/templates/*.keyman-touch-layout \
|
||||
projects/ \
|
||||
server/
|
||||
)
|
||||
|
|
|
|||
|
|
@ -249,7 +249,7 @@
|
|||
</Component>
|
||||
|
||||
<Component Directory="FontsFolder">
|
||||
<File Name='keymanweb-osk.ttf' TrueType='yes' Source='..\tike\xml\layoutbuilder\keymanweb-osk.ttf' KeyPath="yes" />
|
||||
<File Name='keymanweb-osk.ttf' TrueType='yes' Source='..\tike\xml\layoutbuilder\src\assets\fonts\keymanweb-osk.ttf' KeyPath="yes" />
|
||||
</Component>
|
||||
|
||||
</ComponentGroup>
|
||||
|
|
|
|||
|
|
@ -543,43 +543,6 @@ DWORD NextUTF32(PWCHAR pc) {
|
|||
}
|
||||
return *pc;
|
||||
}
|
||||
/*
|
||||
void PrintRule(LPKEYBOARD kbd, LPKEY kp) {
|
||||
LPSTORE sp;
|
||||
std::vector<DWORD> context, output;
|
||||
|
||||
// Always take first char in each referenced store
|
||||
for (PWCHAR pc = kp->dpContext; pc && *pc; pc = incxstr(pc)) {
|
||||
if (*pc == UC_SENTINEL) {
|
||||
switch (*(pc + 1)) {
|
||||
case CODE_ANY:
|
||||
sp = &kbd->dpStoreArray[*(pc + 2) - 1];
|
||||
context.push_back(NextUTF32(sp->dpString));
|
||||
break;
|
||||
case CODE_NOTANY:
|
||||
assert(FALSE); //TODO
|
||||
case CODE_INDEX:
|
||||
assert(FALSE); //TODO
|
||||
case CODE_DEADKEY:
|
||||
|
||||
case CODE_EXTENDED: p += 2; while (*p != UC_SENTINEL_EXTENDEDEND) p++; return p + 1;
|
||||
case CODE_CLEARCONTEXT: return p + 1;
|
||||
case CODE_CALL: return p + 1;
|
||||
case CODE_CONTEXTEX: return p + 1;
|
||||
case CODE_IFOPT: return p + 3;
|
||||
case CODE_IFSYSTEMSTORE: return p + 3;
|
||||
case CODE_SETOPT: return p + 2;
|
||||
case CODE_SETSYSTEMSTORE: return p + 2;
|
||||
case CODE_RESETOPT: return p + 1;
|
||||
case CODE_SAVEOPT: return p + 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Character (either 1 or 2 word)
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
int groupindex(LPKEYBOARD kbd, LPGROUP gp) {
|
||||
return gp - kbd->dpGroupArray;
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ export class AbstractGenerator {
|
|||
protected static readonly SFile_LicenseMD = 'LICENSE.md';
|
||||
protected static readonly SFile_ReadmeMD = 'README.md';
|
||||
protected static readonly SFile_GitIgnore = '.gitignore';
|
||||
protected static readonly SFile_GitIgnore_NoDot = 'gitignore'; // #16683
|
||||
|
||||
protected get callbacks(): CompilerCallbacks { return this._callbacks; }
|
||||
private _callbacks: CompilerCallbacks;
|
||||
|
|
|
|||
|
|
@ -106,6 +106,13 @@ export class BasicGenerator extends AbstractGenerator {
|
|||
|
||||
private transform(sourceFile: string, destFile: string, artifacts: GeneratorArtifacts) {
|
||||
destFile = this.callbacks.path.join(this.options.outPath, this.options.id, destFile == '' ? sourceFile : destFile);
|
||||
|
||||
if(sourceFile == AbstractGenerator.SFile_GitIgnore) {
|
||||
// #16683: npm does not package .gitignore, so we renamed it in our
|
||||
// template distribution. The source file will have the name 'gitignore',
|
||||
// but the output file will be '.gitignore'
|
||||
sourceFile = AbstractGenerator.SFile_GitIgnore_NoDot;
|
||||
}
|
||||
sourceFile = this.callbacks.path.join(this.templateBasePath, this.templatePath, sourceFile);
|
||||
|
||||
const sourceData = this.callbacks.loadFile(sourceFile);
|
||||
|
|
|
|||
|
|
@ -650,8 +650,6 @@ export class KmnCompilerMessages {
|
|||
static WARN_OldVersion = SevWarn | 0x081;
|
||||
static Warn_OldVersion = () => mc(this.WARN_OldVersion, `The keyboard file is an old version`);
|
||||
|
||||
static WARN_BitmapNotUsed = SevWarn | 0x082;
|
||||
static Warn_BitmapNotUsed = () => mc(this.WARN_BitmapNotUsed, `The 'bitmaps' statement is obsolete and only the first bitmap referred to will be used, you should use 'bitmap'.`);
|
||||
|
||||
static WARN_CustomLanguagesNotSupported = SevWarn | 0x083;
|
||||
static Warn_CustomLanguagesNotSupported = () => mc(this.WARN_CustomLanguagesNotSupported, `Languages over 0x1FF, 0x1F are not supported correctly by Windows. You should use no LANGUAGE line instead.`);
|
||||
|
|
@ -756,7 +754,7 @@ export class KmnCompilerMessages {
|
|||
static Warn_PlatformNotInTargets = () => mc(this.WARN_PlatformNotInTargets, `The specified platform is not a target platform`);
|
||||
|
||||
static WARN_HeaderStatementIsDeprecated = SevWarn | 0x09D;
|
||||
static Warn_HeaderStatementIsDeprecated = () => mc(this.WARN_HeaderStatementIsDeprecated, `Header statements are deprecated; use instead the equivalent system store`);
|
||||
static Warn_HeaderStatementIsDeprecated = () => mc(this.WARN_HeaderStatementIsDeprecated, `Header statements are deprecated; use instead the equivalent system store. Header statements are scheduled to be removed in Keyman 20.`);
|
||||
|
||||
static WARN_UseNotLastStatementInRule = SevWarn | 0x09E;
|
||||
static Warn_UseNotLastStatementInRule = () => mc(this.WARN_UseNotLastStatementInRule, `A rule with use() statements in the output should not have other content following the use() statements`);
|
||||
|
|
@ -784,7 +782,7 @@ export class KmnCompilerMessages {
|
|||
static Warn_MixingLeftAndRightModifiers = () => mc(this.WARN_MixingLeftAndRightModifiers, `Left and right modifiers should not both be used in the same rule`);
|
||||
|
||||
static WARN_LanguageHeadersDeprecatedInKeyman10 = SevWarn | 0x0A5;
|
||||
static Warn_LanguageHeadersDeprecatedInKeyman10 = () => mc(this.WARN_LanguageHeadersDeprecatedInKeyman10, `This language header has been deprecated in Keyman 10. Instead, add language metadata in the package file`);
|
||||
static Warn_LanguageHeadersDeprecatedInKeyman10 = () => mc(this.WARN_LanguageHeadersDeprecatedInKeyman10, `This language header was deprecated in Keyman 10. Instead, add language metadata in the package file. This header is scheduled to be removed in Keyman 20.`);
|
||||
|
||||
static HINT_NonUnicodeFile = SevHint | 0x0A6;
|
||||
static Hint_NonUnicodeFile = () => mc(this.HINT_NonUnicodeFile, `Keyman Developer has detected that the file has ANSI encoding. Consider converting this file to UTF-8`);
|
||||
|
|
@ -914,10 +912,22 @@ export class KmnCompilerMessages {
|
|||
square brackets, control characters, or Unicode non-characters.`
|
||||
);
|
||||
|
||||
static WARN_DeprecatedStatement = SevWarn | 0x0BB;
|
||||
static Warn_DeprecatedStatement = (o: KmcmpLibMessageParameters) => mc(
|
||||
this.WARN_DeprecatedStatement,
|
||||
`The statement '${def(o.p?.[0])}' has been deprecated in Keyman ${def(o.p?.[1])}`,
|
||||
static WARN_DeprecatedValueFormat = SevWarn | 0x0BC;
|
||||
static Warn_DeprecatedValueFormat = () => mc(
|
||||
this.WARN_DeprecatedValueFormat,
|
||||
`The decimal (d###), octal (###), and hexadecimal (x###) value formats were deprecated in Keyman 19 and are scheduled to be removed in Keyman 20.`,
|
||||
);
|
||||
|
||||
static WARN_DeprecatedCompileTarget = SevWarn | 0x0BD;
|
||||
static Warn_DeprecatedCompileTarget = (o: KmcmpLibMessageParameters) => mc(
|
||||
this.WARN_DeprecatedCompileTarget,
|
||||
`Compile target '${def(o.p?.[0])}' was deprecated in Keyman 19 and will cause the line to always be ignored by kmc in Keyman 20.`,
|
||||
);
|
||||
|
||||
static ERROR_StoreContainsUnsupportedStatement = SevError | 0x0BE;
|
||||
static Error_StoreContainsUnsupportedStatement = () => mc(
|
||||
this.ERROR_StoreContainsUnsupportedStatement,
|
||||
`A store can contain only characters, deadkeys, virtual keys, and 'outs()' statements.`,
|
||||
);
|
||||
|
||||
static FATAL_BufferOverflow = SevFatal | 0x0C0;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ KMXCodeNames: string[] = [
|
|||
'',
|
||||
'any', 'index', 'context', 'nul', 'use', 'return', 'beep', 'deadkey',
|
||||
'',
|
||||
'extended', '', 'switch', 'key', 'clearcontext', 'call',
|
||||
'extended', '', ''/*switch*/, ''/*key*/, ''/*clearcontext*/, 'call',
|
||||
'', 'contextex', 'notany',
|
||||
'set', 'if', 'save', 'reset', // I3429
|
||||
'if(&system)', 'set(&system)']; // I3430 // I3437
|
||||
|
|
|
|||
|
|
@ -248,7 +248,6 @@ export function incxstr(p: string, x: number): number {
|
|||
case KMX.KMXFile.CODE_CONTEXTEX: x += 2; break;
|
||||
case KMX.KMXFile.CODE_NOTANY: x += 2; break;
|
||||
|
||||
case KMX.KMXFile.CODE_CLEARCONTEXT: x += 2; break; // deprecated in 19.0
|
||||
case KMX.KMXFile.CODE_IFOPT: x += 4; break;
|
||||
case KMX.KMXFile.CODE_IFSYSTEMSTORE: x += 4; break;
|
||||
case KMX.KMXFile.CODE_SETOPT: x += 3; break;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-any'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
store(letter) 'F'
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement
|
||||
store(bad-any) any(letter)
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-baselayout'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
store(opt) 'opt'
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement; note baselayout() compiles to CODE_IFSYSTEMSTORE
|
||||
store(bad-baselayout) baselayout('us')
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-beep'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement
|
||||
store(bad-beep) beep
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-call'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
store(callee) 'dll.dll:func'
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement
|
||||
store(bad-call) call(callee)
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-context'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement
|
||||
store(bad-context) context
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-contextex'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement
|
||||
store(bad-contextex) context(1)
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-ifopt'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
store(opt) 'opt'
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement
|
||||
store(bad-if) if(opt='F')
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-ifsystemstore'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement
|
||||
store(bad-ifs) if(&layer='ah') 'eek'
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-index'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
store(letter) 'F'
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement
|
||||
store(bad-index) index(letter, 1)
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-layer'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
store(opt) 'opt'
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement; note layer() compiles to CODE_IFSYSTEMSTORE
|
||||
store(bad-layer) layer('shift')
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-notany'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
store(letter) 'F'
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement
|
||||
store(bad-notany) notany(letter)
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-nul'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement
|
||||
store(bad-nul) nul
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-platform'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
store(opt) 'opt'
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement; note platform() compiles to CODE_IFSYSTEMSTORE
|
||||
store(bad-platform) platform('windows')
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-resetopt'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
store(opt) 'opt'
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement
|
||||
store(bad-reset) reset(opt)
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-return'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement
|
||||
store(bad-return) return
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-saveopt'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
store(opt) 'opt'
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement
|
||||
store(bad-save) save(opt)
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-setopt'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
store(opt) 'opt'
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement
|
||||
store(bad-set) set(opt='X')
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-setsystemstore'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement
|
||||
store(bad-setsystemstore) set(&layer='X')
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&NAME) 'error_store_contains_unsupported_statement-use'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
c ERROR_StoreContainsUnsupportedStatement
|
||||
store(bad-use) use(main)
|
||||
11
developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_virtual_key_in_context-any.kmn
vendored
Normal file
11
developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_virtual_key_in_context-any.kmn
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
store(&NAME) 'ERROR_VirtualKeyInContext-any'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
store(keys) [NCAPS SHIFT K_S]
|
||||
|
||||
c This should generate warning KM02074 ERROR_VirtualKeyInContext
|
||||
any(keys) + 'X' > 'x'
|
||||
12
developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_virtual_key_in_context-index.kmn
vendored
Normal file
12
developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_virtual_key_in_context-index.kmn
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
store(&NAME) 'ERROR_VirtualKeyInContext-index'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
store(keys) [NCAPS SHIFT K_S]
|
||||
store(letter) 'F'
|
||||
|
||||
c This should generate warning KM02074 ERROR_VirtualKeyInContext
|
||||
any(letter) index(keys, 1) + 'X' > 'x'
|
||||
11
developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_virtual_key_in_context-notany.kmn
vendored
Normal file
11
developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_virtual_key_in_context-notany.kmn
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
store(&NAME) 'ERROR_VirtualKeyInContext-any'
|
||||
store(&VERSION) '9.0'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
store(keys) [NCAPS SHIFT K_S]
|
||||
|
||||
c This should generate warning KM02074 ERROR_VirtualKeyInContext
|
||||
notany(keys) + 'X' > 'x'
|
||||
12
developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_virtual_key_in_output-index.kmn
vendored
Normal file
12
developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_virtual_key_in_output-index.kmn
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
store(&VERSION) '10.0'
|
||||
store(&NAME) 'WARN_VirtualKeyInOutput'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
store(keys) [NCAPS SHIFT K_S]
|
||||
store(outputs) [NCAPS SHIFT K_S]
|
||||
|
||||
c This should generate warning KM020AF WARN_VirtualKeyInOutput
|
||||
+ any(keys) > index(outputs,1)
|
||||
BIN
developer/src/kmc-kmn/test/fixtures/keyboards/test.bmp
vendored
Normal file
BIN
developer/src/kmc-kmn/test/fixtures/keyboards/test.bmp
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 246 B |
9
developer/src/kmc-kmn/test/fixtures/keyboards/warn_deprecated_compile_target-keymanonly.kmn
vendored
Normal file
9
developer/src/kmc-kmn/test/fixtures/keyboards/warn_deprecated_compile_target-keymanonly.kmn
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) '19.0'
|
||||
store(&NAME) 'warn_deprecated_compile_target-keymanonly'
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
c $keymanonly: deprecated in v19 compiler, will not work in v20+, so always warn regardless of target version
|
||||
$keymanonly: + ' ' > 'hello'
|
||||
9
developer/src/kmc-kmn/test/fixtures/keyboards/warn_deprecated_compile_target-keymanweb.kmn
vendored
Normal file
9
developer/src/kmc-kmn/test/fixtures/keyboards/warn_deprecated_compile_target-keymanweb.kmn
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) '19.0'
|
||||
store(&NAME) 'warn_deprecated_compile_target-keymanweb'
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
c $keymanweb: deprecated in v19 compiler, will not work in v20+, so always warn regardless of target version
|
||||
$keymanweb: + ' ' > 'hello'
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
store(&NAME) 'warn_deprecated_statement-clearcontext-17'
|
||||
store(&VERSION) '17.0'
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
c NOTE: using `clearcontext` should not generate a warning in v17 target version compile (unlike v19 target version)
|
||||
+ 'x' > clearcontext
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
store(&NAME) 'warn_deprecated_statement-clearcontext-19'
|
||||
store(&VERSION) '19.0'
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
c NOTE: using `clearcontext` SHOULD generate a warning in v19 target version compile (unlike v17 target version)
|
||||
+ 'x' > clearcontext
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
store(&NAME) 'warn_deprecated_statement-fix-17'
|
||||
store(&VERSION) '17.0'
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
c NOTE: using `fix` should not generate a warning in v17 target version compile (unlike v19 target version)
|
||||
+ 'x' > fix
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
store(&NAME) 'warn_deprecated_statement-fix-19'
|
||||
store(&VERSION) '19.0'
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
c NOTE: using `fix` SHOULD generate a warning in v19 target version compile (unlike v17 target version)
|
||||
+ 'x' > fix
|
||||
9
developer/src/kmc-kmn/test/fixtures/keyboards/warn_deprecated_value_format-decimal.kmn
vendored
Normal file
9
developer/src/kmc-kmn/test/fixtures/keyboards/warn_deprecated_value_format-decimal.kmn
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) '10.0'
|
||||
store(&NAME) 'warn_deprecated_value_format-decimal'
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
c d### deprecated in v19 compiler, so always warn regardless of target version
|
||||
+ ' ' > d160
|
||||
9
developer/src/kmc-kmn/test/fixtures/keyboards/warn_deprecated_value_format-hexadecimal.kmn
vendored
Normal file
9
developer/src/kmc-kmn/test/fixtures/keyboards/warn_deprecated_value_format-hexadecimal.kmn
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) '10.0'
|
||||
store(&NAME) 'warn_deprecated_value_format-hexadecimal'
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
c x## deprecated in v19 compiler, so always warn regardless of target version
|
||||
+ ' ' > xA0
|
||||
9
developer/src/kmc-kmn/test/fixtures/keyboards/warn_deprecated_value_format-octal.kmn
vendored
Normal file
9
developer/src/kmc-kmn/test/fixtures/keyboards/warn_deprecated_value_format-octal.kmn
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) '10.0'
|
||||
store(&NAME) 'warn_deprecated_value_format-octal'
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
c ### deprecated in v19 compiler, so always warn regardless of target version
|
||||
+ ' ' > 240
|
||||
9
developer/src/kmc-kmn/test/fixtures/keyboards/warn_header_statement_is_deprecated-bitmap.kmn
vendored
Normal file
9
developer/src/kmc-kmn/test/fixtures/keyboards/warn_header_statement_is_deprecated-bitmap.kmn
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) '19.0'
|
||||
store(&NAME) 'warn_header_statement_is_deprecated-bitmap'
|
||||
BITMAP test.bmp
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
+ ' ' > 'hello'
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) '19.0'
|
||||
store(&NAME) 'warn_header_statement_is_deprecated-bitmaps'
|
||||
BITMAPS test,test
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
+ ' ' > 'hello'
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) '19.0'
|
||||
store(&NAME) 'warn_header_statement_is_deprecated-caps-always-off'
|
||||
CAPS ALWAYS OFF
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
+ ' ' > 'hello'
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) '19.0'
|
||||
store(&NAME) 'warn_header_statement_is_deprecated-caps-on-only'
|
||||
CAPS ON ONLY
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
+ ' ' > 'hello'
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) '19.0'
|
||||
store(&NAME) 'warn_header_statement_is_deprecated-copyright'
|
||||
COPYRIGHT "SIL Global"
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
+ ' ' > 'hello'
|
||||
9
developer/src/kmc-kmn/test/fixtures/keyboards/warn_header_statement_is_deprecated-hotkey.kmn
vendored
Normal file
9
developer/src/kmc-kmn/test/fixtures/keyboards/warn_header_statement_is_deprecated-hotkey.kmn
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) '19.0'
|
||||
store(&NAME) 'warn_header_statement_is_deprecated-hotkey'
|
||||
HOTKEY "^+P"
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
+ ' ' > 'hello'
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) '19.0'
|
||||
store(&NAME) 'warn_header_statement_is_deprecated-language'
|
||||
LANGUAGE x1d, x1
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
+ ' ' > 'hello'
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) '19.0'
|
||||
store(&NAME) 'warn_header_statement_is_deprecated-languagename'
|
||||
LANGUAGENAME "test"
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
+ ' ' > 'hello'
|
||||
9
developer/src/kmc-kmn/test/fixtures/keyboards/warn_header_statement_is_deprecated-layout.kmn
vendored
Normal file
9
developer/src/kmc-kmn/test/fixtures/keyboards/warn_header_statement_is_deprecated-layout.kmn
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) '19.0'
|
||||
store(&NAME) 'warn_header_statement_is_deprecated-layout'
|
||||
LAYOUT x11
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
+ ' ' > 'hello'
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) '19.0'
|
||||
store(&NAME) 'warn_header_statement_is_deprecated-test'
|
||||
MESSAGE "test"
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
+ ' ' > 'hello'
|
||||
8
developer/src/kmc-kmn/test/fixtures/keyboards/warn_header_statement_is_deprecated-name.kmn
vendored
Normal file
8
developer/src/kmc-kmn/test/fixtures/keyboards/warn_header_statement_is_deprecated-name.kmn
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
store(&VERSION) '19.0'
|
||||
NAME "warn_header_statement_is_deprecated-name"
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
+ ' ' > 'hello'
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) '19.0'
|
||||
store(&NAME) 'warn_header_statement_is_deprecated-shift-frees-caps'
|
||||
SHIFT FREES CAPS
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
+ ' ' > 'hello'
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
VERSION 19.0
|
||||
store(&NAME) 'warn_header_statement_is_deprecated-version'
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
+ ' ' > 'hello'
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) "19.0"
|
||||
store(&NAME) 'warn_language_headers_deprecated_in_keyman10-ethnologuecode'
|
||||
store(ÐNOLOGUECODE) "eng"
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
+ ' ' > 'hello'
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) "19.0"
|
||||
store(&NAME) 'warn_language_headers_deprecated_in_keyman10-language'
|
||||
store(&LANGUAGE) "x401"
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
+ ' ' > 'hello'
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
store(&VERSION) "19.0"
|
||||
store(&NAME) 'warn_language_headers_deprecated_in_keyman10-windowslanguages'
|
||||
store(&WINDOWSLANGUAGES) "x401"
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
||||
+ ' ' > 'hello'
|
||||
|
|
@ -62,7 +62,7 @@ describe('KmnCompilerMessages', function () {
|
|||
const params = getParamNames(m[f]);
|
||||
if(params.length) {
|
||||
const v2: KmcKmnCompilerEvent = m[f]({p:['1','2','3','4','5','6','7','8','9']});
|
||||
assert.notEqual(v.message, v2.message, `Message '${key}' (${hex}) must use KmcmpLibMessageParameters pattern`);
|
||||
assert.notEqual(v.message, v2.message, `Message '${key}' (${hex}) must use \`(o: KmcmpLibMessageParameters)\` pattern or have no parameters`);
|
||||
}
|
||||
}
|
||||
} else if(code >= KmnCompilerMessageRanges.RANGE_LEXICAL_MODEL_MIN && code <= KmnCompilerMessageRanges.RANGE_LEXICAL_MODEL_MAX) {
|
||||
|
|
@ -157,7 +157,11 @@ describe('KmnCompilerMessages', function () {
|
|||
await compiler.run(kmnPath, null);
|
||||
|
||||
if(Array.isArray(messageId)) {
|
||||
assert.sameMembers(messageId, callbacks.messages.map(m=>m.code));
|
||||
assert.sameMembers(
|
||||
callbacks.messages.map(m=>m.code),
|
||||
messageId,
|
||||
`messages did not match, received ${JSON.stringify(callbacks.messages,null,2)}, expected: ${JSON.stringify(messageId)}`
|
||||
);
|
||||
} else if(messageId) {
|
||||
assert.isTrue(callbacks.hasMessage(messageId), `messageId ${messageId.toString(16)} not generated, instead got: `+JSON.stringify(callbacks.messages,null,2));
|
||||
assert.lengthOf(callbacks.messages, 1, `messages should have 1 entry, instead has: `+JSON.stringify(callbacks.messages,null,2));
|
||||
|
|
@ -194,6 +198,9 @@ describe('KmnCompilerMessages', function () {
|
|||
|
||||
it('should generate ERROR_VirtualKeyInContext if a virtual key is found in the context part of a rule', async function() {
|
||||
await testForMessage(this, ['invalid-keyboards', 'error_virtual_key_in_context.kmn'], KmnCompilerMessages.ERROR_VirtualKeyInContext);
|
||||
await testForMessage(this, ['invalid-keyboards', 'error_virtual_key_in_context-any.kmn'], KmnCompilerMessages.ERROR_VirtualKeyInContext);
|
||||
await testForMessage(this, ['invalid-keyboards', 'error_virtual_key_in_context-index.kmn'], KmnCompilerMessages.ERROR_VirtualKeyInContext);
|
||||
await testForMessage(this, ['invalid-keyboards', 'error_virtual_key_in_context-notany.kmn'], KmnCompilerMessages.ERROR_VirtualKeyInContext);
|
||||
});
|
||||
|
||||
// WARN_TouchLayoutUnidentifiedKey
|
||||
|
|
@ -213,6 +220,7 @@ describe('KmnCompilerMessages', function () {
|
|||
|
||||
it('should generate WARN_VirtualKeyInOutput if a virtual key is found in the output part of a rule', async function() {
|
||||
await testForMessage(this, ['invalid-keyboards', 'warn_virtual_key_in_output.kmn'], KmnCompilerMessages.WARN_VirtualKeyInOutput);
|
||||
await testForMessage(this, ['invalid-keyboards', 'warn_virtual_key_in_output-index.kmn'], KmnCompilerMessages.WARN_VirtualKeyInOutput);
|
||||
});
|
||||
|
||||
// ERROR_OutsTooLong
|
||||
|
|
@ -347,13 +355,67 @@ describe('KmnCompilerMessages', function () {
|
|||
await testForMessage(this, ['invalid-keyboards', 'error_name_must_not_contain_square_brackets-deadkey.kmn'], [KmnCompilerMessages.ERROR_NameMustNotContainSquareBrackets, KmnCompilerMessages.ERROR_InvalidDeadkey]);
|
||||
});
|
||||
|
||||
// WARN_DeprecatedStatement
|
||||
//
|
||||
// Deprecations
|
||||
//
|
||||
|
||||
it('should generate WARN_DeprecatedStatement if the file has `clearcontext` or `fix` statements and is 19.0', async function() {
|
||||
await testForMessage(this, ['keyboards', 'warn_deprecated_statement-clearcontext-19.kmn'], KmnCompilerMessages.WARN_DeprecatedStatement);
|
||||
await testForMessage(this, ['keyboards', 'warn_deprecated_statement-fix-19.kmn'], KmnCompilerMessages.WARN_DeprecatedStatement);
|
||||
await testForMessage(this, ['keyboards', 'warn_deprecated_statement-clearcontext-17.kmn']);
|
||||
await testForMessage(this, ['keyboards', 'warn_deprecated_statement-fix-17.kmn']);
|
||||
// WARN_DeprecatedValueFormat
|
||||
|
||||
it('should generate WARN_DeprecatedValueFormat if the file has decimal, octal, or hexadecimal value formats', async function() {
|
||||
await testForMessage(this, ['keyboards', 'warn_deprecated_value_format-decimal.kmn'], KmnCompilerMessages.WARN_DeprecatedValueFormat);
|
||||
await testForMessage(this, ['keyboards', 'warn_deprecated_value_format-octal.kmn'], KmnCompilerMessages.WARN_DeprecatedValueFormat);
|
||||
await testForMessage(this, ['keyboards', 'warn_deprecated_value_format-hexadecimal.kmn'], KmnCompilerMessages.WARN_DeprecatedValueFormat);
|
||||
});
|
||||
|
||||
// WARN_DeprecatedCompileTarget
|
||||
|
||||
it('should generate WARN_DeprecatedCompileTarget if the file contains a deprecated compile target', async function() {
|
||||
await testForMessage(this, ['keyboards', 'warn_deprecated_compile_target-keymanonly.kmn'], KmnCompilerMessages.WARN_DeprecatedCompileTarget);
|
||||
await testForMessage(this, ['keyboards', 'warn_deprecated_compile_target-keymanweb.kmn'], KmnCompilerMessages.WARN_DeprecatedCompileTarget);
|
||||
});
|
||||
|
||||
// WARN_HeaderStatementIsDeprecated
|
||||
|
||||
['bitmap', 'bitmaps', 'caps-always-off', 'caps-on-only', 'copyright', 'hotkey', 'message', 'name', 'shift-frees-caps', 'version'].forEach(statement =>
|
||||
it(`should generate WARN_HeaderStatementIsDeprecated if the file contains deprecated header statement "${statement.replaceAll('-',' ').toUpperCase()}"`, async function() {
|
||||
await testForMessage(this, ['keyboards', `warn_header_statement_is_deprecated-${statement}.kmn`], KmnCompilerMessages.WARN_HeaderStatementIsDeprecated);
|
||||
})
|
||||
);
|
||||
|
||||
['language', 'languagename'].forEach(statement =>
|
||||
// Two messages generated for these legacy header statements
|
||||
it(`should generate WARN_HeaderStatementIsDeprecated and WARN_LanguageHeadersDeprecatedInKeyman10 if the file contains deprecated header statement "${statement.replaceAll('-',' ').toUpperCase()}"`, async function() {
|
||||
await testForMessage(this, ['keyboards', `warn_header_statement_is_deprecated-${statement}.kmn`], [
|
||||
KmnCompilerMessages.WARN_HeaderStatementIsDeprecated, KmnCompilerMessages.WARN_LanguageHeadersDeprecatedInKeyman10
|
||||
]);
|
||||
})
|
||||
);
|
||||
|
||||
['layout'].forEach(statement =>
|
||||
// LAYOUT statement requires LANGUAGE as well, so we'll get two messages here
|
||||
it(`should generate WARN_HeaderStatementIsDeprecated and ERROR_LayoutButNoLanguage if the file contains deprecated header statement "${statement.replaceAll('-',' ').toUpperCase()}"`, async function() {
|
||||
await testForMessage(this, ['keyboards', `warn_header_statement_is_deprecated-${statement}.kmn`], [
|
||||
KmnCompilerMessages.WARN_HeaderStatementIsDeprecated, KmnCompilerMessages.ERROR_LayoutButNoLanguage
|
||||
]);
|
||||
})
|
||||
);
|
||||
|
||||
// WARN_LanguageHeadersDeprecatedInKeyman10
|
||||
|
||||
['ethnologuecode', 'language', 'windowslanguages'].forEach(storeName =>
|
||||
it(`should generate WARN_LanguageHeadersDeprecatedInKeyman10 if the file contains deprecated system store "&${storeName}"`, async function() {
|
||||
await testForMessage(this, ['keyboards', `warn_language_headers_deprecated_in_keyman10-${storeName}.kmn`], KmnCompilerMessages.WARN_LanguageHeadersDeprecatedInKeyman10);
|
||||
})
|
||||
);
|
||||
|
||||
// ERROR_StoreContainsUnsupportedStatement
|
||||
|
||||
['any', 'index', 'context', 'nul', 'use', 'return', 'beep',
|
||||
'call', 'contextex', 'notany', 'setopt',
|
||||
'ifopt', 'baselayout', 'layer', 'platform',
|
||||
'saveopt', 'resetopt', 'ifsystemstore', 'setsystemstore'].forEach(statement =>
|
||||
it(`should generate ERROR_StoreContainsUnsupportedStatement if a store contains statement "${statement}"`, async function() {
|
||||
await testForMessage(this, ['invalid-keyboards', `error_store_contains_unsupported_statement-${statement}.kmn`], KmnCompilerMessages.ERROR_StoreContainsUnsupportedStatement);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*
|
||||
* Assign collected metadata from keyboards to package metadata fields
|
||||
*/
|
||||
import { KeyboardMetadataCollection } from './package-metadata-collector.js';
|
||||
|
||||
export class PackageMetadataUpdater {
|
||||
|
|
@ -5,7 +10,7 @@ export class PackageMetadataUpdater {
|
|||
public updatePackage(metadata: KeyboardMetadataCollection) {
|
||||
for(const id of Object.keys(metadata)) {
|
||||
const keyboard = metadata[id];
|
||||
keyboard.keyboard.name = keyboard.data.keyboardName;
|
||||
keyboard.keyboard.name = keyboard.data.keyboardName ?? id;
|
||||
keyboard.keyboard.rtl = keyboard.data.isRtl ? true : undefined;
|
||||
keyboard.keyboard.version = keyboard.data.keyboardVersion ?? '1.0';
|
||||
}
|
||||
|
|
|
|||
6
developer/src/kmc-package/test/fixtures/invalid/kmx_no_name.kmn
vendored
Normal file
6
developer/src/kmc-package/test/fixtures/invalid/kmx_no_name.kmn
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
c no &name store for testing #16681
|
||||
store(&keyboardversion) '1.0'
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
BIN
developer/src/kmc-package/test/fixtures/invalid/kmx_no_name.kmx
vendored
Normal file
BIN
developer/src/kmc-package/test/fixtures/invalid/kmx_no_name.kmx
vendored
Normal file
Binary file not shown.
39
developer/src/kmc-package/test/fixtures/invalid/kmx_no_name.kps
vendored
Normal file
39
developer/src/kmc-package/test/fixtures/invalid/kmx_no_name.kps
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Package>
|
||||
<System>
|
||||
<KeymanDeveloperVersion>15.0.266.0</KeymanDeveloperVersion>
|
||||
<FileVersion>7.0</FileVersion>
|
||||
</System>
|
||||
<Options>
|
||||
<FollowKeyboardVersion/>
|
||||
</Options>
|
||||
<StartMenu>
|
||||
<Folder></Folder>
|
||||
<Items/>
|
||||
</StartMenu>
|
||||
<Info>
|
||||
<Name URL="">Khmer Angkor</Name>
|
||||
<Copyright URL="">© 2015-2022 SIL International</Copyright>
|
||||
<Author URL="mailto:makara_sok@sil.org">Makara Sok</Author>
|
||||
<Version URL=""></Version>
|
||||
<WebSite URL="https://keyman.com/keyboards/khmer_angkor">https://keyman.com/keyboards/khmer_angkor</WebSite>
|
||||
</Info>
|
||||
<Files>
|
||||
<File>
|
||||
<Name>kmx_no_name.kmx</Name>
|
||||
<Description>Keyboard kmx_no_name</Description>
|
||||
<CopyLocation>0</CopyLocation>
|
||||
<FileType>.kmx</FileType>
|
||||
</File>
|
||||
</Files>
|
||||
<Keyboards>
|
||||
<Keyboard>
|
||||
<ID>kmx_no_name</ID>
|
||||
<Version>1.3</Version>
|
||||
<Languages>
|
||||
<Language ID="km">Central Khmer (Khmer, Cambodia)</Language>
|
||||
</Languages>
|
||||
</Keyboard>
|
||||
</Keyboards>
|
||||
<Strings/>
|
||||
</Package>
|
||||
|
|
@ -274,6 +274,12 @@ describe('KmpCompiler', function () {
|
|||
assert.equal(kmpJson.keyboards[0].name, 'version 4'); // picks up example.kmx's name
|
||||
});
|
||||
|
||||
it(`should load a package with a .kmx file without a &name store`, function () {
|
||||
const kmpJson = kmpCompiler.transformKpsToKmpObject(makePathToFixture('invalid', 'kmx_no_name.kps'));
|
||||
assert.isNotNull(kmpJson);
|
||||
assert.equal(kmpJson.keyboards[0].name, 'kmx_no_name'); // picks up kmx_no_name's id
|
||||
});
|
||||
|
||||
it(`should load a package with missing keyboard version metadata`, function () {
|
||||
const kmpJson = kmpCompiler.transformKpsToKmpObject(makePathToFixture('invalid', 'missing_keyboard_version.kps'));
|
||||
assert.equal(kmpJson.keyboards[0].version, '4.0'); // picks up example.kmx's version
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import 'mocha';
|
|||
import { unitTestEndpoints } from '../src/util/extendedCompilerOptions.js';
|
||||
import { InfrastructureMessages } from '../src/messages/infrastructureMessages.js';
|
||||
import { CompilerError, CompilerMessageOverride, CompilerErrorSeverity } from '@keymanapp/developer-utils';
|
||||
import { KmnCompilerMessages } from '@keymanapp/kmc-kmn';
|
||||
|
||||
interface MessageTest {input: string, result: CompilerMessageOverride};
|
||||
interface InvalidMessageTest {input: string, code: number};
|
||||
|
|
@ -25,7 +24,6 @@ describe('commandOptionsMessageToCompilerOptionsMessage', function () {
|
|||
|
||||
// Test hint and warn messages
|
||||
{input: 'KM05009:E', result: {code: InfrastructureMessages.HINT_FilenameHasDifferingCase, level: CompilerErrorSeverity.Error } },
|
||||
{input: 'KM02082:E', result: {code: KmnCompilerMessages.WARN_BitmapNotUsed, level: CompilerErrorSeverity.Error } },
|
||||
|
||||
// Test different allowable patterns
|
||||
{input: '5002', result: {code: InfrastructureMessages.INFO_BuildingFile, level: 'disable' } },
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ bool CompileKeyboardBuffer(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk)
|
|||
while ((msg = ReadLine(infile, sz, offset, str, TRUE)) == STATUS_Success)
|
||||
{
|
||||
p = str;
|
||||
switch (LineTokenType(&p))
|
||||
switch (LineTokenType(fk, &p, FALSE))
|
||||
{
|
||||
case T_VERSION:
|
||||
*(p + 4) = 0;
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ KMX_DWORD GetRHS(PFILE_KEYBOARD fk, PKMX_WCHAR p, PKMX_WCHAR buf, int bufsize, i
|
|||
PKMX_WCHAR GetDelimitedString(PKMX_WCHAR *p, KMX_WCHAR const * Delimiters, KMX_WORD Flags);
|
||||
KMX_DWORD GetXString(PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX_WCHAR const * token, PKMX_WCHAR output, int max, int offset, PKMX_WCHAR *newp, int isVKey, int isUnicode);
|
||||
KMX_BOOL GetCompileTargetsFromTargetsStore(KMX_WCHAR *store, int &targets);
|
||||
KMX_BOOL DoesStoreContainInvalidStatement(PKMX_WCHAR store);
|
||||
|
||||
int GetGroupNum(PFILE_KEYBOARD fk, PKMX_WCHAR p);
|
||||
|
||||
|
|
@ -361,12 +362,16 @@ KMX_BOOL ParseLine(PFILE_KEYBOARD fk, PKMX_WCHAR str) {
|
|||
p = str;
|
||||
pp = str;
|
||||
|
||||
switch (LineTokenType(&p))
|
||||
switch (LineTokenType(fk, &p, TRUE))
|
||||
{
|
||||
case T_BLANK:
|
||||
case T_COMMENT:
|
||||
break; // Ignore the line
|
||||
|
||||
case T_VERSION:
|
||||
kmcmp::WarnDeprecatedHeader();
|
||||
break; // The line has already been processed
|
||||
|
||||
case T_STORE:
|
||||
break; // The line has already been processed
|
||||
|
||||
|
|
@ -523,7 +528,7 @@ KMX_BOOL ParseLine(PFILE_KEYBOARD fk, PKMX_WCHAR str) {
|
|||
{
|
||||
kmcmp::WarnDeprecatedHeader(); // I4866
|
||||
KMX_WCHAR *tokcontext = NULL;
|
||||
ReportCompilerMessage(KmnCompilerMessages::WARN_BitmapNotUsed);
|
||||
// ReportCompilerMessage(KmnCompilerMessages::WARN_BitmapNotUsed); : redundant, have WarnDeprecatedHeader
|
||||
|
||||
if ((q = u16tok(p, p_sep, &tokcontext)) == NULL) {
|
||||
ReportCompilerMessage(KmnCompilerMessages::ERROR_InvalidBitmapLine); // I3481
|
||||
|
|
@ -839,6 +844,11 @@ KMX_BOOL ProcessStoreLine(PFILE_KEYBOARD fk, PKMX_WCHAR p) {
|
|||
kmcmp::CodeConstants->reindex(); // has to be done after every character add due to possible use in another store. // I4982
|
||||
}
|
||||
|
||||
if(DoesStoreContainInvalidStatement(sp->dpString)) {
|
||||
ReportCompilerMessage(KmnCompilerMessages::ERROR_StoreContainsUnsupportedStatement);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fk->cxStoreArray++; // increment now, because GetXString refers to stores
|
||||
|
||||
if (i > 0) {
|
||||
|
|
@ -1155,7 +1165,7 @@ KMX_BOOL ProcessSystemStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, PFILE_STORE s
|
|||
else if (u16ncmp(p, u"15.0", 4) == 0) fk->version = VERSION_150; // Adds support for U_xxxx_yyyy #2858
|
||||
else if (u16ncmp(p, u"16.0", 4) == 0) fk->version = VERSION_160; // KMXPlus
|
||||
else if (u16ncmp(p, u"17.0", 4) == 0) fk->version = VERSION_170; // Flicks and gestures
|
||||
else if (u16ncmp(p, u"19.0", 4) == 0) fk->version = VERSION_190; // Deprecations - fix, clearcontext
|
||||
else if (u16ncmp(p, u"19.0", 4) == 0) fk->version = VERSION_190; // Deprecations - compile targets $keymanonly, $keymanweb
|
||||
|
||||
else {
|
||||
ReportCompilerMessage(KmnCompilerMessages::ERROR_InvalidVersion);
|
||||
|
|
@ -1522,12 +1532,33 @@ KMX_DWORD CheckStatementOffsets(PFILE_KEYBOARD fk, PFILE_GROUP gp, PKMX_WCHAR co
|
|||
return STATUS_Success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores can contain only characters, deadkeys, and virtual keys (and `outs`).
|
||||
* Note that `outs()` is expanded during read so there is no `CODE_OUTS`.
|
||||
*
|
||||
* @param store
|
||||
* @return KMX_BOOL
|
||||
*/
|
||||
KMX_BOOL DoesStoreContainInvalidStatement(PKMX_WCHAR store) {
|
||||
for (PKMX_WCHAR p = store; *p; p = incxstr(p)) {
|
||||
if (*p == UC_SENTINEL) {
|
||||
auto code = *(p + 1);
|
||||
if(code == CODE_DEADKEY || code == CODE_EXTENDED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// No other codes are permitted; note, outs() does not have a code as it is expanded at compile time
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the order of statements in the context matches the specification.
|
||||
* Rule structure: [context] ['+' key] '>' output
|
||||
* Context structure: [nul] [if()|baselayout()|platform()]+ [char|any|context()|deadkey()|dk()|index()|notany()|outs()]
|
||||
* Test that nul is first, then if(), baselayout(), platform() statements are before any other content.
|
||||
* Also verifies that virtual keys are not found in the context.
|
||||
*/
|
||||
void CheckContextStatementPositions(PKMX_WCHAR context) {
|
||||
KMX_BOOL hadContextChar = FALSE;
|
||||
|
|
@ -1545,9 +1576,6 @@ void CheckContextStatementPositions(PKMX_WCHAR context) {
|
|||
ReportCompilerMessage(KmnCompilerMessages::WARN_IfShouldBeAtStartOfContext);
|
||||
}
|
||||
break;
|
||||
case CODE_EXTENDED:
|
||||
ReportCompilerMessage(KmnCompilerMessages::ERROR_VirtualKeyInContext);
|
||||
break;
|
||||
default:
|
||||
hadContextChar = TRUE;
|
||||
}
|
||||
|
|
@ -1575,18 +1603,50 @@ KMX_DWORD CheckUseStatementsInOutput(PKMX_WCHAR output) {
|
|||
return STATUS_Success;
|
||||
}
|
||||
|
||||
KMX_BOOL DoesStringContainVirtualKeys(PFILE_KEYBOARD fk, PKMX_WCHAR p) {
|
||||
for (; *p; p = incxstr(p)) {
|
||||
if (*p == UC_SENTINEL) {
|
||||
auto code = *(p+1);
|
||||
if(code == CODE_EXTENDED) {
|
||||
return TRUE;
|
||||
} else if(code == CODE_INDEX) {
|
||||
PFILE_STORE s;
|
||||
s = &fk->dpStoreArray[*(p + 2) - 1];
|
||||
if(DoesStringContainVirtualKeys(fk, s->dpString)) {
|
||||
return TRUE;
|
||||
}
|
||||
} else if(code == CODE_ANY || code == CODE_NOTANY) {
|
||||
PFILE_STORE s;
|
||||
s = &fk->dpStoreArray[*(p + 2) - 1];
|
||||
if(DoesStringContainVirtualKeys(fk, s->dpString)) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Warn if output has virtual keys in it, which is not supported by Core at all,
|
||||
* but was unofficially supported, but never worked properly, in Keyman for
|
||||
* Windows for many years
|
||||
*/
|
||||
KMX_DWORD CheckVirtualKeysInOutput(PKMX_WCHAR output) {
|
||||
PKMX_WCHAR p;
|
||||
for (p = output; *p; p = incxstr(p)) {
|
||||
if (*p == UC_SENTINEL && *(p + 1) == CODE_EXTENDED) {
|
||||
ReportCompilerMessage(KmnCompilerMessages::WARN_VirtualKeyInOutput);
|
||||
break;
|
||||
}
|
||||
KMX_DWORD CheckVirtualKeysInOutput(PFILE_KEYBOARD fk, PKMX_WCHAR output) {
|
||||
if(DoesStringContainVirtualKeys(fk, output)) {
|
||||
ReportCompilerMessage(KmnCompilerMessages::WARN_VirtualKeyInOutput);
|
||||
return STATUS_Success;
|
||||
}
|
||||
return STATUS_Success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Error if context has virtual keys in it -- context can never contain keys,
|
||||
* only characters and deadkeys.
|
||||
*/
|
||||
KMX_DWORD CheckVirtualKeysInContext(PFILE_KEYBOARD fk, PKMX_WCHAR context) {
|
||||
if(DoesStringContainVirtualKeys(fk, context)) {
|
||||
return KmnCompilerMessages::ERROR_VirtualKeyInContext;
|
||||
}
|
||||
return STATUS_Success;
|
||||
}
|
||||
|
|
@ -1604,9 +1664,9 @@ const KMX_BOOL CODE__IS_TEXTUAL[] = {
|
|||
-1, // unused 0x09
|
||||
TRUE, // CODE_EXTENDED 0x0A
|
||||
-1, // CODE_EXTENDEDEND 0x0B (unused)
|
||||
FALSE, // CODE_SWITCH 0x0C
|
||||
-1, // CODE_KEY 0x0D (never used)
|
||||
FALSE, // CODE_CLEARCONTEXT 0x0E (deprecated in 19.0)
|
||||
FALSE, // CODE_SWITCH 0x0C (unused, removed in 19.0)
|
||||
-1, // CODE_KEY 0x0D (unused, removed in 19.0)
|
||||
FALSE, // CODE_CLEARCONTEXT 0x0E (unused, removed in 19.0)
|
||||
FALSE, // CODE_CALL 0x0F // may trigger text effects but indirectly
|
||||
-1, // UC_SENTINEL_EXTENDEDEND 0x10 (not valid with UC_SENTINEL)
|
||||
TRUE, // CODE_CONTEXTEX 0x11
|
||||
|
|
@ -1781,6 +1841,9 @@ KMX_DWORD ProcessKeyLineImpl(PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX_BOOL IsUnico
|
|||
|
||||
CheckContextStatementPositions(pklIn);
|
||||
|
||||
// Error if virtual keys are used in the context
|
||||
if ((msg = CheckVirtualKeysInContext(fk, pklIn)) != STATUS_Success) return msg;
|
||||
|
||||
// Test index and context offsets in context
|
||||
if ((msg = CheckStatementOffsets(fk, gp, pklIn, pklOut, pklKey)) != STATUS_Success) return msg;
|
||||
|
||||
|
|
@ -1790,7 +1853,7 @@ KMX_DWORD ProcessKeyLineImpl(PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX_BOOL IsUnico
|
|||
}
|
||||
|
||||
// Warn if virtual keys are used in the output, as they are unsupported by Core
|
||||
if ((msg = CheckVirtualKeysInOutput(pklOut)) != STATUS_Success) {
|
||||
if ((msg = CheckVirtualKeysInOutput(fk, pklOut)) != STATUS_Success) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
|
@ -2074,7 +2137,7 @@ LinePrefixType GetLinePrefixType(PKMX_WCHAR *p)
|
|||
return lptOther;
|
||||
}
|
||||
|
||||
int LineTokenType(PKMX_WCHAR *str)
|
||||
int LineTokenType(PFILE_KEYBOARD fk, PKMX_WCHAR *str, KMX_BOOL checkDeprecations)
|
||||
{
|
||||
int i;
|
||||
size_t l;
|
||||
|
|
@ -2084,6 +2147,14 @@ int LineTokenType(PKMX_WCHAR *str)
|
|||
if (lpt == lptOther) return T_BLANK;
|
||||
|
||||
/* Test KeymanWeb, Keyman and KeymanOnly prefixes */
|
||||
|
||||
if(checkDeprecations && lpt == lptKeymanWebOnly) {
|
||||
kmcmp::WarnDeprecatedCompileTarget(fk, u"$keymanweb:");
|
||||
}
|
||||
if(checkDeprecations && lpt == lptKeymanOnly) {
|
||||
kmcmp::WarnDeprecatedCompileTarget(fk, u"$keymanonly:");
|
||||
}
|
||||
|
||||
if (kmcmp::CompileTarget == CKF_KEYMAN && lpt == lptKeymanWebOnly) return T_BLANK;
|
||||
if (kmcmp::CompileTarget == CKF_KEYMANWEB && lpt == lptKeymanOnly) return T_BLANK;
|
||||
|
||||
|
|
@ -2165,13 +2236,6 @@ KMX_DWORD GetXStringImpl(PKMX_WCHAR tstr, PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX
|
|||
|
||||
ErrChr = (int)(p - str) + offset + 1;
|
||||
|
||||
/*
|
||||
char *tokenTypes[] = {
|
||||
"clearcontext", "deadkey", "context", "return", "switch",
|
||||
"index", "outs", "beep", "nul", "use", "any", "fix", "dk", "k_", "x", "d", "c",
|
||||
"[", "]" };
|
||||
*/
|
||||
|
||||
switch (towupper(*p))
|
||||
{
|
||||
case 'X':
|
||||
|
|
@ -2182,7 +2246,7 @@ KMX_DWORD GetXStringImpl(PKMX_WCHAR tstr, PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX
|
|||
case 'B': type = 4; break; // beep, baselayout (synonym for if(&baselayout)) // I3430
|
||||
case 'I': type = 5; break; // index(s,n), if
|
||||
case 'O': type = 6; break; // outs(s)
|
||||
case 'C': type = 7; break; // context, comments, clearcontext, call(s)
|
||||
case 'C': type = 7; break; // context, comments, call(s)
|
||||
case 'N': type = 8; break; // nul, notany
|
||||
case 'U': type = 9; break; // use(g)
|
||||
case 'R': type = 10; break; // return, reset
|
||||
|
|
@ -2190,7 +2254,7 @@ KMX_DWORD GetXStringImpl(PKMX_WCHAR tstr, PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX
|
|||
//case ']': type = 12; break; // end of vkey section
|
||||
//case 'K': type = 13; break; // virtual key name or "key"
|
||||
case 'S': type = 14; break; // switch, set, save
|
||||
case 'F': type = 15; break; // fix (synonym for clearcontext)
|
||||
// 15 was 'F', for undocumented, unused statement 'fix'
|
||||
case '$': type = 16; break; // named code constants
|
||||
case 'P': type = 17; break; // platform (synonym for if(&platform)) // I3430
|
||||
case 'L': type = 18; break; // layer (synonym for set(&layer)) // I3437
|
||||
|
|
@ -2234,6 +2298,7 @@ KMX_DWORD GetXStringImpl(PKMX_WCHAR tstr, PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX
|
|||
tstr[mx++] = n1;
|
||||
if (n2 >= 0) tstr[mx++] = n2;
|
||||
tstr[mx] = 0;
|
||||
kmcmp::WarnDeprecatedValueFormat();
|
||||
}
|
||||
continue;
|
||||
|
||||
|
|
@ -2398,17 +2463,6 @@ KMX_DWORD GetXStringImpl(PKMX_WCHAR tstr, PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX
|
|||
tstr[mx] = 0;
|
||||
}
|
||||
}
|
||||
else if (u16nicmp(p, u"clearcontext", 12) == 0)
|
||||
{
|
||||
// deprecated in 19.0
|
||||
if(fk->version >= VERSION_190) {
|
||||
ReportCompilerMessage(KmnCompilerMessages::WARN_DeprecatedStatement, {"clearcontext", "19.0"}); // I3438
|
||||
}
|
||||
p += 12;
|
||||
tstr[mx++] = UC_SENTINEL;
|
||||
tstr[mx++] = CODE_CLEARCONTEXT;
|
||||
tstr[mx] = 0;
|
||||
}
|
||||
else if (u16nicmp(p, u"call", 4) == 0)
|
||||
{
|
||||
if(!VerifyKeyboardVersion(fk, VERSION_501)) {
|
||||
|
|
@ -2714,30 +2768,8 @@ KMX_DWORD GetXStringImpl(PKMX_WCHAR tstr, PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX
|
|||
}
|
||||
else
|
||||
{
|
||||
if (u16nicmp(p, u"switch", 6) != 0) return KmnCompilerMessages::ERROR_InvalidToken;
|
||||
p += 6;
|
||||
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
|
||||
if (!q || !*q) return KmnCompilerMessages::ERROR_InvalidSwitch;
|
||||
tstr[mx++] = UC_SENTINEL;
|
||||
tstr[mx++] = CODE_SWITCH;
|
||||
tstr[mx++] = atoiW(q);
|
||||
tstr[mx] = 0;
|
||||
}
|
||||
continue;
|
||||
case 15:
|
||||
if (u16nicmp(p, u"fix", 3) == 0)
|
||||
{
|
||||
if(fk->version >= VERSION_190) {
|
||||
// deprecated in 19.0
|
||||
ReportCompilerMessage(KmnCompilerMessages::WARN_DeprecatedStatement, {"fix", "19.0"}); // I3438
|
||||
}
|
||||
p += 3;
|
||||
tstr[mx++] = UC_SENTINEL;
|
||||
tstr[mx++] = CODE_CLEARCONTEXT;
|
||||
tstr[mx] = 0;
|
||||
}
|
||||
else
|
||||
return KmnCompilerMessages::ERROR_InvalidToken;
|
||||
}
|
||||
continue;
|
||||
case 16:
|
||||
if(!VerifyKeyboardVersion(fk, VERSION_60)) {
|
||||
|
|
|
|||
|
|
@ -8,10 +8,29 @@
|
|||
|
||||
void kmcmp::WarnDeprecatedHeader() { // I4866
|
||||
if (AWarnDeprecatedCode_GLOBAL_LIB) {
|
||||
// We warn on this for any keyboard version; keyboard authors should
|
||||
// be moving to system stores
|
||||
ReportCompilerMessage(KmnCompilerMessages::WARN_HeaderStatementIsDeprecated);
|
||||
}
|
||||
}
|
||||
|
||||
void kmcmp::WarnDeprecatedValueFormat() {
|
||||
if (AWarnDeprecatedCode_GLOBAL_LIB) {
|
||||
// We warn on this for any keyboard version; keyboard authors should
|
||||
// be moving to U+xxxx format
|
||||
ReportCompilerMessage(KmnCompilerMessages::WARN_DeprecatedValueFormat);
|
||||
}
|
||||
}
|
||||
|
||||
void kmcmp::WarnDeprecatedCompileTarget(PFILE_KEYBOARD fk, const KMX_WCHAR *compileTarget) {
|
||||
if (AWarnDeprecatedCode_GLOBAL_LIB && fk->version >= VERSION_190) {
|
||||
// We will warn on this for any keyboard version >= 19
|
||||
ReportCompilerMessage(KmnCompilerMessages::WARN_DeprecatedCompileTarget, {
|
||||
/* compileTarget */ string_from_u16string(compileTarget)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* Flag presence of deprecated features */
|
||||
void kmcmp::CheckForDeprecatedFeatures(PFILE_KEYBOARD fk) {
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -5,5 +5,8 @@
|
|||
|
||||
namespace kmcmp{
|
||||
void WarnDeprecatedHeader();
|
||||
void WarnDeprecatedValueFormat();
|
||||
void WarnDeprecatedCompileTarget(PFILE_KEYBOARD fk, const KMX_WCHAR *compileTarget);
|
||||
void WarnDeprecatedFix(PFILE_KEYBOARD fk);
|
||||
void CheckForDeprecatedFeatures(PFILE_KEYBOARD fk);
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue