- The path must include the .kpj filename and may optionally begin with a forward slash.
- The following are valid examples:
- github:keymanapp/keyboards:master:release/k/khmer_angkor/khmer_angkor.kpj
- github:keymanapp/keyboards:release/k/khmer_angkor/khmer_angkor.kpj
- github:keymanapp/keyboards:/release/k/khmer_angkor/khmer_angkor.kpj`
- );
+ // 0x0011 unused
static ERROR_CannotDownloadFolderFromGitHub = SevError | 0x0012;
static Error_CannotDownloadFolderFromGitHub = (o:{ref: string, message?: string, cause?: string}) => m(
diff --git a/developer/src/kmc-copy/test/copier.tests.ts b/developer/src/kmc-copy/test/copier.tests.ts
index 3cf9e4c0ee6..6d583862aea 100644
--- a/developer/src/kmc-copy/test/copier.tests.ts
+++ b/developer/src/kmc-copy/test/copier.tests.ts
@@ -12,6 +12,7 @@ import { assert } from 'chai';
import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers';
import { KeymanProjectCopier } from '../src/KeymanProjectCopier.js';
import { makePathToFixture } from './helpers/index.js';
+import { GitHubRef } from './cloud.js';
const { TEST_SAVE_ARTIFACTS, TEST_SAVE_FIXTURES } = env;
let outputRoot: string = '/an/imaginary/root/';
@@ -374,7 +375,7 @@ describe('KeymanProjectCopier', function() {
// armenian_mnemonic selected because (a) small, and (b) has v2.0 project, so
// that exercises the folder retrieval as well
- const result = await copier.run('github:keymanapp/keyboards:release/a/armenian_mnemonic/armenian_mnemonic.kpj');
+ const result = await copier.run('github.com/keymanapp/keyboards/tree/master/release/a/armenian_mnemonic/armenian_mnemonic.kpj');
// We should have no messages and a successful result
assert.isOk(result);
@@ -416,6 +417,81 @@ describe('KeymanProjectCopier', function() {
});
});
+ // Keyman Cloud patterns
+
+ const cloud_khmer_angkor: GitHubRef = { branch: 'master', owner: 'keymanapp', repo: 'keyboards', path: '/release/k/khmer_angkor/khmer_angkor.kpj' };
+ const cloud_nrc_en_mtnt: GitHubRef = { branch: 'master', owner: 'keymanapp', repo: 'lexical-models', path: '/release/nrc/nrc.en.mtnt/nrc.en.mtnt.kpj' };
+ const cloud_urls: [string,GitHubRef][] = [
+ ['cloud:khmer_angkor', cloud_khmer_angkor],
+ ['https://keyman.com/keyboards/khmer_angkor', cloud_khmer_angkor],
+ ['https://keyman.com/keyboards/khmer_angkor/', cloud_khmer_angkor],
+ ['keyman.com/keyboards/khmer_angkor/', cloud_khmer_angkor],
+ ['http://keyman.com/keyboards/khmer_angkor#abc', cloud_khmer_angkor],
+ ['cloud:nrc.en.mtnt', cloud_nrc_en_mtnt],
+ ];
+
+ cloud_urls.forEach(url => {
+ it(`should parse URL '${url[0]}' and figure out the .kpj`, async function() {
+ // url -->
+ const copier = new KeymanProjectCopier();
+ assert.isTrue(await copier.init(callbacks, {
+ dryRun: false,
+ outPath: ''
+ }));
+
+ const ref = await copier.unitTestEndPoints.getCloudSourceProject(url[0]);
+ assert.isNotNull(ref);
+ assert.deepEqual(ref, url[1]);
+ });
+ })
+
+
+ // GitHub patterns that should match as inputs for kmc-copy source
+
+ const armenian_mnemonic_urls = [ {
+ branch: 'master', urls: [
+ 'github.com/keymanapp/keyboards/tree/master/release/a/armenian_mnemonic',
+ 'http://github.com/keymanapp/keyboards/tree/master/release/a/armenian_mnemonic',
+ 'https://github.com/keymanapp/keyboards/tree/master/release/a/armenian_mnemonic',
+ 'https://github.com/keymanapp/keyboards/tree/master/release/a/armenian_mnemonic/',
+ 'https://github.com/keymanapp/keyboards/tree/refs/heads/master/release/a/armenian_mnemonic',
+ 'https://github.com/keymanapp/keyboards/tree/refs/heads/master/release/a/armenian_mnemonic/',
+ 'https://github.com/keymanapp/keyboards/raw/refs/heads/master/release/a/armenian_mnemonic/armenian_mnemonic.kpj',
+ 'https://github.com/keymanapp/keyboards/raw/master/release/a/armenian_mnemonic/armenian_mnemonic.kpj',
+ 'https://github.com/keymanapp/keyboards/blob/refs/heads/master/release/a/armenian_mnemonic/armenian_mnemonic.kpj',
+ 'https://github.com/keymanapp/keyboards/blob/master/release/a/armenian_mnemonic/armenian_mnemonic.kpj',
+
+ // And similar patterns for raw.githubusercontent.com
+
+ 'https://raw.githubusercontent.com/keymanapp/keyboards/refs/heads/master/release/a/armenian_mnemonic/armenian_mnemonic.kpj',
+ 'https://raw.githubusercontent.com/keymanapp/keyboards/master/release/a/armenian_mnemonic/armenian_mnemonic.kpj',
+ ]}, {
+ branch: '78b6f98e5db4a249cc4231f8744f5fe4e5fd29f2', urls: [
+ 'https://github.com/keymanapp/keyboards/blob/78b6f98e5db4a249cc4231f8744f5fe4e5fd29f2/release/a/armenian_mnemonic/armenian_mnemonic.kpj',
+ 'https://github.com/keymanapp/keyboards/tree/78b6f98e5db4a249cc4231f8744f5fe4e5fd29f2/release/a/armenian_mnemonic',
+ 'https://github.com/keymanapp/keyboards/tree/78b6f98e5db4a249cc4231f8744f5fe4e5fd29f2/release/a/armenian_mnemonic/',
+ 'https://raw.githubusercontent.com/keymanapp/keyboards/78b6f98e5db4a249cc4231f8744f5fe4e5fd29f2/release/a/armenian_mnemonic/armenian_mnemonic.kpj',
+ ]}];
+
+ armenian_mnemonic_urls.forEach(({branch,urls}) => urls.forEach(url => {
+ it(`should parse URL '${url}' and figure out the .kpj`, async function() {
+ // url -->
+ const copier = new KeymanProjectCopier();
+ assert.isTrue(await copier.init(callbacks, {
+ dryRun: false,
+ outPath: ''
+ }));
+
+ const ref = await copier.unitTestEndPoints.getGithubSourceProject(url);
+ assert.deepEqual(ref, {
+ branch,
+ owner: 'keymanapp',
+ repo: 'keyboards',
+ path: '/release/a/armenian_mnemonic/armenian_mnemonic.kpj'
+ });
+ });
+ }));
+
// TODO-COPY: additional tests
it.skip('should copy a disorganized project into current structure', async function() {});
it.skip('should copy a standalone .kmn into a new project', async function() {});
diff --git a/developer/src/kmc-copy/test/fixtures/online/api.keyman.com/#keyboard#khmer_angkor b/developer/src/kmc-copy/test/fixtures/online/api.keyman.com/#keyboard#khmer_angkor
new file mode 100644
index 00000000000..17b495a24bb
--- /dev/null
+++ b/developer/src/kmc-copy/test/fixtures/online/api.keyman.com/#keyboard#khmer_angkor
@@ -0,0 +1,65 @@
+{
+ "id": "khmer_angkor",
+ "name": "Khmer Angkor",
+ "license": "mit",
+ "authorName": "Makara Sok",
+ "authorEmail": "makara_sok@sil.org",
+ "description": "Khmer Unicode keyboard layout based on the NiDA keyboard layout.\nAutomatically corrects many common keying errors.
",
+ "languages": {
+ "km": {
+ "examples": [
+ {
+ "keys": "x j m E r",
+ "note": "Name of language",
+ "text": "\u1781\u17d2\u1798\u17c2\u179a"
+ }
+ ],
+ "font": {
+ "family": "Khmer Mondulkiri",
+ "source": [
+ "Mondulkiri-R.ttf"
+ ]
+ },
+ "oskFont": {
+ "family": "KbdKhmr",
+ "source": [
+ "KbdKhmr.ttf"
+ ]
+ },
+ "languageName": "Khmer",
+ "displayName": "Khmer"
+ }
+ },
+ "lastModifiedDate": "2024-07-03T15:47:38.000Z",
+ "packageFilename": "khmer_angkor.kmp",
+ "packageFileSize": 4259005,
+ "jsFilename": "khmer_angkor.js",
+ "jsFileSize": 70494,
+ "packageIncludes": [
+ "visualKeyboard",
+ "welcome",
+ "fonts",
+ "documentation"
+ ],
+ "version": "1.5",
+ "encodings": [
+ "unicode"
+ ],
+ "platformSupport": {
+ "windows": "full",
+ "macos": "full",
+ "linux": "full",
+ "desktopWeb": "full",
+ "ios": "full",
+ "android": "full",
+ "mobileWeb": "full"
+ },
+ "minKeymanVersion": "10.0",
+ "sourcePath": "release/k/khmer_angkor",
+ "helpLink": "https://help.keyman.com/keyboard/khmer_angkor",
+ "related": {
+ "khmer10": {
+ "deprecates": true
+ }
+ }
+}
\ No newline at end of file
diff --git a/developer/src/kmc-copy/test/fixtures/online/api.keyman.com/#model#nrc.en.mtnt b/developer/src/kmc-copy/test/fixtures/online/api.keyman.com/#model#nrc.en.mtnt
new file mode 100644
index 00000000000..bee31a4fe4a
--- /dev/null
+++ b/developer/src/kmc-copy/test/fixtures/online/api.keyman.com/#model#nrc.en.mtnt
@@ -0,0 +1,23 @@
+{
+ "languages": [
+ "en",
+ "en-us",
+ "en-ca"
+ ],
+ "id": "nrc.en.mtnt",
+ "name": "English language model mined from MTNT",
+ "license": "mit",
+ "authorName": "Eddie Antonio Santos",
+ "authorEmail": "easantos@ualberta.ca",
+ "description": "A unigram language model for English derived from the MTNT corpus http://www.cs.cmu.edu/~pmichel1/mtnt/ . This corpus itself is gathered from Reddit, so it is unfiltered internet discussion. This is not humanity at its prettiest!
",
+ "lastModifiedDate": "2024-09-16T01:05:45.000Z",
+ "packageFilename": "https://keyman.com/go/package/download/model/nrc.en.mtnt?version=0.3.3&update=1",
+ "packageFileSize": 332955,
+ "jsFilename": "https://downloads.keyman.com/models/nrc.en.mtnt/0.3.3/nrc.en.mtnt.model.js",
+ "jsFileSize": 2713050,
+ "packageIncludes": [],
+ "version": "0.3.3",
+ "minKeymanVersion": "12.0",
+ "helpLink": "https://help.keyman.com/model/nrc.en.mtnt",
+ "sourcePath": "release/nrc/nrc.en.mtnt"
+}
\ No newline at end of file
diff --git a/developer/src/kmc-ldml/test/fixtures/sections/keys/import-local.xml b/developer/src/kmc-ldml/test/fixtures/sections/keys/import-local.xml
new file mode 100644
index 00000000000..d97d711301d
--- /dev/null
+++ b/developer/src/kmc-ldml/test/fixtures/sections/keys/import-local.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/developer/src/kmc-ldml/test/fixtures/sections/keys/keys-Zyyy-morepunctuation.xml b/developer/src/kmc-ldml/test/fixtures/sections/keys/keys-Zyyy-morepunctuation.xml
new file mode 100644
index 00000000000..768e81e7cd2
--- /dev/null
+++ b/developer/src/kmc-ldml/test/fixtures/sections/keys/keys-Zyyy-morepunctuation.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/developer/src/kmc-ldml/test/helpers/index.ts b/developer/src/kmc-ldml/test/helpers/index.ts
index 3bb67278fbe..bd438c4ca11 100644
--- a/developer/src/kmc-ldml/test/helpers/index.ts
+++ b/developer/src/kmc-ldml/test/helpers/index.ts
@@ -38,7 +38,8 @@ export const compilerTestCallbacks = new TestCompilerCallbacks();
export const compilerTestOptions: LdmlCompilerOptions = {
readerOptions: {
- importsPath: fileURLToPath(new URL(...LDMLKeyboardXMLSourceFileReader.defaultImportsURL))
+ cldrImportsPath: fileURLToPath(new URL(...LDMLKeyboardXMLSourceFileReader.defaultImportsURL)),
+ localImportsPaths: [], // will be fixed up in loadSectionFixture
}
};
@@ -59,8 +60,14 @@ export async function loadSectionFixture(compilerClass: SectionCompilerNew, file
const data = callbacks.loadFile(inputFilename);
assert.isNotNull(data, `Failed to read file ${inputFilename}`);
+ compilerTestOptions.readerOptions.localImportsPaths = [ path.dirname(inputFilename) ];
+
const reader = new LDMLKeyboardXMLSourceFileReader(compilerTestOptions.readerOptions, callbacks);
const source = reader.load(data);
+ if (!source) {
+ // print any callbacks here
+ assert.sameDeepMembers(callbacks.messages, [], `Errors loading ${inputFilename}`);
+ }
assert.isNotNull(source, `Failed to load XML from ${inputFilename}`);
if (!reader.validate(source)) {
diff --git a/developer/src/kmc-ldml/test/keys.tests.ts b/developer/src/kmc-ldml/test/keys.tests.ts
index b639c194cc3..cfb37e6baf5 100644
--- a/developer/src/kmc-ldml/test/keys.tests.ts
+++ b/developer/src/kmc-ldml/test/keys.tests.ts
@@ -199,6 +199,19 @@ describe('keys', function () {
assert.equal(flickw.flicks[0].keyId.value, 'dd');
},
},
+ {
+ subpath: 'sections/keys/import-local.xml',
+ callback: (keys, subpath, callbacks) => {
+ assert.isNotNull(keys);
+ assert.equal((keys).keys.length, 2 + KeysCompiler.reserved_count);
+ const [snail] = (keys).keys.filter(({ id }) => id.value === 'snail');
+ assert.ok(snail,`Missing the snail`);
+ assert.equal(snail.to.value, `@`, `Snail's value`);
+ const [interrobang] = (keys).keys.filter(({ id }) => id.value === 'interrobang');
+ assert.ok(interrobang,`Missing the interrobang`);
+ assert.equal(interrobang.to.value, `‽`, `Interrobang's value`);
+ },
+ },
], keysDependencies);
});
diff --git a/developer/src/kmc-package/test/fixtures/bcp47/invalid_bcp47_1.kps b/developer/src/kmc-package/test/fixtures/bcp47/invalid_bcp47_1.kps
new file mode 100644
index 00000000000..8a656e38baa
--- /dev/null
+++ b/developer/src/kmc-package/test/fixtures/bcp47/invalid_bcp47_1.kps
@@ -0,0 +1,27 @@
+
+
+
+ 10.0.700.0
+ 7.0
+
+
+ 1.0
+ valid_bcp47
+
+
+
+ test.kmx
+
+
+
+
+ Invalid BCP 47
+ test
+ 1.0
+
+ Not a language tag
+
+
+
+
+
diff --git a/developer/src/kmc-package/test/fixtures/bcp47/test.kmx b/developer/src/kmc-package/test/fixtures/bcp47/test.kmx
new file mode 100644
index 00000000000..9e4bd15d391
Binary files /dev/null and b/developer/src/kmc-package/test/fixtures/bcp47/test.kmx differ
diff --git a/developer/src/kmc-package/test/fixtures/bcp47/valid_bcp47.kps b/developer/src/kmc-package/test/fixtures/bcp47/valid_bcp47.kps
new file mode 100644
index 00000000000..72461e04c28
--- /dev/null
+++ b/developer/src/kmc-package/test/fixtures/bcp47/valid_bcp47.kps
@@ -0,0 +1,39 @@
+
+
+
+ 10.0.700.0
+ 7.0
+
+
+
+
+
+
+
+
+
+
+
+ 1.0
+ valid_bcp47
+
+
+
+ test.kmx
+
+
+
+
+ Valid BCP 47
+ test
+ 1.0
+
+ Central Khmer (Khmer, Cambodia)
+ SENCOTEN
+ Unregistered variant of Straits Salish
+ Private variant of "Old" Khmer
+
+
+
+
+
diff --git a/developer/src/kmc-package/test/package-compiler.tests.ts b/developer/src/kmc-package/test/package-compiler.tests.ts
index 7952e2145a2..16c523bda9a 100644
--- a/developer/src/kmc-package/test/package-compiler.tests.ts
+++ b/developer/src/kmc-package/test/package-compiler.tests.ts
@@ -12,6 +12,7 @@ import { makePathToFixture } from './helpers/index.js';
import { KmpCompiler } from '../src/compiler/kmp-compiler.js';
import { PackageCompilerMessages } from '../src/compiler/package-compiler-messages.js';
+import { PackageValidation } from '../src/compiler/package-validation.js';
const debug = false;
@@ -29,6 +30,13 @@ describe('KmpCompiler', function () {
assert.isTrue(await kmpCompiler.init(callbacks, null));
});
+ this.afterEach(function() {
+ if(this.currentTest?.isFailed()) {
+ callbacks.printMessages();
+ }
+ callbacks.clear();
+ });
+
for (let modelID of MODELS) {
const kpsPath = modelID.includes('withfolders') ?
makePathToFixture(modelID, 'source', `${modelID}.model.kps`) : makePathToFixture(modelID, `${modelID}.model.kps`);
@@ -284,4 +292,20 @@ describe('KmpCompiler', function () {
assert.equal(kmpJson.keyboards[0].version, '4.0'); // picks up example.kmx's version
});
+ it(`should handle a range of valid BCP47 tags`, function () {
+ const inputFilename = makePathToFixture('bcp47', 'valid_bcp47.kps');
+ const kmpJson = kmpCompiler.transformKpsToKmpObject(inputFilename);
+ assert.isNotNull(kmpJson);
+ const validation = new PackageValidation(callbacks, {});
+ assert.isTrue(validation.validate(inputFilename, kmpJson));
+ });
+
+ it(`should reject an invalid BCP47 tag`, function () {
+ const inputFilename = makePathToFixture('bcp47', 'invalid_bcp47_1.kps');
+ const kmpJson = kmpCompiler.transformKpsToKmpObject(inputFilename);
+ assert.isNotNull(kmpJson);
+ const validation = new PackageValidation(callbacks, {});
+ assert.isFalse(validation.validate(inputFilename, kmpJson));
+ });
+
});
diff --git a/developer/src/kmc/src/commands/buildClasses/BuildLdmlKeyboard.ts b/developer/src/kmc/src/commands/buildClasses/BuildLdmlKeyboard.ts
index 6ac98c9b92e..6a6300b646b 100644
--- a/developer/src/kmc/src/commands/buildClasses/BuildLdmlKeyboard.ts
+++ b/developer/src/kmc/src/commands/buildClasses/BuildLdmlKeyboard.ts
@@ -4,6 +4,7 @@ import { CompilerOptions, CompilerCallbacks } from '@keymanapp/developer-utils';
import { LDMLKeyboardXMLSourceFileReader } from '@keymanapp/developer-utils';
import { BuildActivity } from './BuildActivity.js';
import { fileURLToPath } from 'url';
+import { dirname } from 'node:path';
export class BuildLdmlKeyboard extends BuildActivity {
public get name(): string { return 'LDML keyboard'; }
@@ -13,7 +14,8 @@ export class BuildLdmlKeyboard extends BuildActivity {
public async build(infile: string, outfile: string, callbacks: CompilerCallbacks, options: CompilerOptions): Promise {
// TODO-LDML: consider hardware vs touch -- touch-only layout will not have a .kvk
const ldmlCompilerOptions: kmcLdml.LdmlCompilerOptions = {...options, readerOptions: {
- importsPath: fileURLToPath(new URL(...LDMLKeyboardXMLSourceFileReader.defaultImportsURL))
+ cldrImportsPath: fileURLToPath(new URL(...LDMLKeyboardXMLSourceFileReader.defaultImportsURL)),
+ localImportsPaths: [ dirname(infile) ], // local dir
}};
const compiler = new kmcLdml.LdmlKeyboardCompiler();
return await super.runCompiler(compiler, infile, outfile, callbacks, ldmlCompilerOptions);
diff --git a/developer/src/kmc/src/commands/buildTestData/index.ts b/developer/src/kmc/src/commands/buildTestData/index.ts
index c958673c2fa..5343c81702d 100644
--- a/developer/src/kmc/src/commands/buildTestData/index.ts
+++ b/developer/src/kmc/src/commands/buildTestData/index.ts
@@ -7,6 +7,7 @@ import { fileURLToPath } from 'url';
import { CommandLineBaseOptions } from 'src/util/baseOptions.js';
import { exitProcess } from '../../util/sysexits.js';
import { InfrastructureMessages } from '../../messages/infrastructureMessages.js';
+import { dirname } from 'node:path';
export async function buildTestData(infile: string, _options: any, commander: any): Promise {
const options: CommandLineBaseOptions = commander.optsWithGlobals();
@@ -17,7 +18,8 @@ export async function buildTestData(infile: string, _options: any, commander: an
saveDebug: false,
shouldAddCompilerVersion: false,
readerOptions: {
- importsPath: fileURLToPath(new URL(...LDMLKeyboardXMLSourceFileReader.defaultImportsURL))
+ cldrImportsPath: fileURLToPath(new URL(...LDMLKeyboardXMLSourceFileReader.defaultImportsURL)),
+ localImportsPaths: [ dirname(infile) ], // local dir
}
};
diff --git a/developer/src/kmc/src/commands/copy.ts b/developer/src/kmc/src/commands/copy.ts
index 9231ba3a5ec..2f22b24a0a4 100644
--- a/developer/src/kmc/src/commands/copy.ts
+++ b/developer/src/kmc/src/commands/copy.ts
@@ -27,8 +27,9 @@ export function declareCopy(program: Command) {
* a .kpj file, e.g. ./keyboards/khmer_angkor/khmer_angkor.kpj
* a local folder (with a .kpj file in it), e.g. ./keyboards/khmer_angkor
* a cloud keyboard or lexical model, cloud:id, e.g. cloud:khmer_angkor
- * a GitHub repository, optional branch, and path, github:owner/repo[:branch]:path
- e.g. github:keyman-keyboards/khmer_angkor:main:/khmer_angkor.kpj
+ * a GitHub repository, branch, and path, [https://]github.com/owner/repo/tree/branch/path
+ e.g. https://github.com/keyman-keyboards/khmer_angkor/tree/main/khmer_angkor.kpj or
+ github.com/keymanapp/keyboards/tree/master/release/k/khmer_angkor
`);
}
diff --git a/linux/debian/libkeymancore2.symbols b/linux/debian/libkeymancore2.symbols
index 968f155551b..5ecfeb58a28 100644
--- a/linux/debian/libkeymancore2.symbols
+++ b/linux/debian/libkeymancore2.symbols
@@ -18,7 +18,6 @@ libkeymancore.so.2 libkeymancore2 #MINVER#
km_core_keyboard_get_key_list@Base 17.0.195
km_core_keyboard_imx_list_dispose@Base 17.0.195
km_core_keyboard_key_list_dispose@Base 17.0.195
- km_core_keyboard_load@Base 17.0.195
km_core_keyboard_load_from_blob@Base 18.0.101
km_core_options_list_size@Base 17.0.195
km_core_process_event@Base 17.0.195
diff --git a/linux/debian/tests/test-build b/linux/debian/tests/test-build
index 9a48325793c..45186784abe 100755
--- a/linux/debian/tests/test-build
+++ b/linux/debian/tests/test-build
@@ -41,7 +41,7 @@ int main(int argc, char *argv[]) {
km_core_option_item opts[] = {KM_CORE_OPTIONS_END};
km_core_keyboard *kb = NULL;
km_core_state *state = NULL;
- km_core_keyboard_load(NULL, &kb);
+ km_core_keyboard_load_from_blob(NULL, NULL, 0, &kb);
km_core_state_create(kb, opts, &state);
km_core_actions const *a = km_core_state_get_actions(state);
}
@@ -62,7 +62,7 @@ echo "build 3: OK"
# km_core_option_item opts[] = {KM_CORE_OPTIONS_END};
# km_core_keyboard *kb = NULL;
# km_core_state *state = NULL;
-# km_core_keyboard_load(NULL, &kb);
+# km_core_keyboard_load_from_blob(NULL, NULL, 0, &kb);
# km_core_state_create(kb, opts, &state);
# km_core_actions const *a = km_core_state_get_actions(state);
# }
diff --git a/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj b/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj
index 51cf7185509..483998a16e0 100644
--- a/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj
+++ b/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj
@@ -35,6 +35,7 @@
29BE9D872CA3C21900B67DE7 /* KMModifierMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 29BE9D862CA3C21900B67DE7 /* KMModifierMapping.m */; };
29C1CDE22C5B2F8B003C23BB /* KMSettingsRepository.m in Sources */ = {isa = PBXBuildFile; fileRef = D861B03E2C5747F70003675E /* KMSettingsRepository.m */; };
29C1CDE32C5B2F8B003C23BB /* KMDataRepository.m in Sources */ = {isa = PBXBuildFile; fileRef = 29015ABC2C58D86F00CCBB94 /* KMDataRepository.m */; };
+ 29DD5F442CFEF88000683388 /* SILAndikaV1RGB.png in Resources */ = {isa = PBXBuildFile; fileRef = 29DD5F432CFEF88000683388 /* SILAndikaV1RGB.png */; };
37A245C12565DFA6000BBF92 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 37A245C02565DFA6000BBF92 /* Assets.xcassets */; };
37AE5C9D239A7B770086CC7C /* qrcode.min.js in Resources */ = {isa = PBXBuildFile; fileRef = 37AE5C9C239A7B770086CC7C /* qrcode.min.js */; };
37C2B0CB25FF2C350092E16A /* Help in Resources */ = {isa = PBXBuildFile; fileRef = 37C2B0CA25FF2C340092E16A /* Help */; };
@@ -84,7 +85,6 @@
E213601E2142D7C000A043B7 /* keyman-88.png in Resources */ = {isa = PBXBuildFile; fileRef = E213601D2142D7BF00A043B7 /* keyman-88.png */; };
E21799051FC5B7BC00F2D66A /* KMInputMethodEventHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = E21799041FC5B7BC00F2D66A /* KMInputMethodEventHandler.m */; };
E21E645820C04EA8000D6274 /* logo.png in Resources */ = {isa = PBXBuildFile; fileRef = E21E645720C04EA7000D6274 /* logo.png */; };
- E23380FB21407AA100B90591 /* SILInBlue76.png in Resources */ = {isa = PBXBuildFile; fileRef = E23380FA21407AA100B90591 /* SILInBlue76.png */; };
E240F599202DED740000067D /* KMPackage.m in Sources */ = {isa = PBXBuildFile; fileRef = E240F598202DED740000067D /* KMPackage.m */; };
E2585A7F20DD6C3C00CBB994 /* KMMethodEventHandlerTests.kmx in Resources */ = {isa = PBXBuildFile; fileRef = E2585A7E20DD6C3C00CBB994 /* KMMethodEventHandlerTests.kmx */; };
E2585A8120DD7CF100CBB994 /* TestAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E2585A8020DD7CF100CBB994 /* TestAppDelegate.m */; };
@@ -275,6 +275,7 @@
29D470972C648D5200224B4F /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/KMKeyboardHelpWindowController.strings; sourceTree = ""; };
29D470982C648D5200224B4F /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/MainMenu.strings; sourceTree = ""; };
29D470992C648D7100224B4F /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/Localizable.strings; sourceTree = ""; };
+ 29DD5F432CFEF88000683388 /* SILAndikaV1RGB.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = SILAndikaV1RGB.png; sourceTree = ""; };
29DD8400276C49E20066A16E /* am */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = am; path = am.lproj/KMAboutWindowController.strings; sourceTree = ""; };
29DD8401276C49E20066A16E /* am */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = am; path = am.lproj/preferences.strings; sourceTree = ""; };
29DD8402276C49E30066A16E /* am */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = am; path = am.lproj/KMInfoWindowController.strings; sourceTree = ""; };
@@ -379,7 +380,6 @@
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/KMConfiguration/logo.png; sourceTree = SOURCE_ROOT; };
- E23380FA21407AA100B90591 /* SILInBlue76.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = SILInBlue76.png; path = Keyman4MacIM/Images/SILInBlue76.png; sourceTree = SOURCE_ROOT; };
E240F597202DED300000067D /* KMPackage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KMPackage.h; sourceTree = ""; };
E240F598202DED740000067D /* KMPackage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KMPackage.m; sourceTree = ""; };
E2585A7E20DD6C3C00CBB994 /* KMMethodEventHandlerTests.kmx */ = {isa = PBXFileReference; lastKnownFileType = file; path = KMMethodEventHandlerTests.kmx; sourceTree = ""; };
@@ -639,7 +639,7 @@
98BF92421BF01CBE0002126A /* KMAboutWindowController.m */,
293EA3E827140D8100545EED /* KMAboutWindowController.xib */,
E213601D2142D7BF00A043B7 /* keyman-88.png */,
- E23380FA21407AA100B90591 /* SILInBlue76.png */,
+ 29DD5F432CFEF88000683388 /* SILAndikaV1RGB.png */,
98BF92461BF01D890002126A /* image.jpg */,
98BF92531BF040A50002126A /* title.png */,
);
@@ -846,7 +846,6 @@
989C9C131A7876DE00A20425 /* Images.xcassets in Resources */,
98E2CEA11A92C39C00AE2455 /* InfoPlist.strings in Resources */,
E21E645820C04EA8000D6274 /* logo.png in Resources */,
- E23380FB21407AA100B90591 /* SILInBlue76.png in Resources */,
9874C3211B536847000BB543 /* info.png in Resources */,
98E672A01B532F5E00DBDE2F /* KMDownloadKBWindowController.xib in Resources */,
37AE5C9D239A7B770086CC7C /* qrcode.min.js in Resources */,
@@ -862,6 +861,7 @@
293EA3E627140D8100545EED /* KMAboutWindowController.xib in Resources */,
37A245C12565DFA6000BBF92 /* Assets.xcassets in Resources */,
293EA3EB27140DEC00545EED /* preferences.xib in Resources */,
+ 29DD5F442CFEF88000683388 /* SILAndikaV1RGB.png in Resources */,
9800EC5A1C02940300BF0FB5 /* keyman-for-mac-os-license.html in Resources */,
989C9C161A7876DE00A20425 /* MainMenu.xib in Resources */,
29B42A602728343B00EDD5D3 /* KMKeyboardHelpWindowController.xib in Resources */,
diff --git a/mac/Keyman4MacIM/Keyman4MacIM/Images/SILInBlue76.png b/mac/Keyman4MacIM/Keyman4MacIM/Images/SILInBlue76.png
deleted file mode 100644
index 0275859531c..00000000000
Binary files a/mac/Keyman4MacIM/Keyman4MacIM/Images/SILInBlue76.png and /dev/null differ
diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/Base.lproj/KMAboutWindowController.xib b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/Base.lproj/KMAboutWindowController.xib
index b6c018d1a56..fa15b43024f 100644
--- a/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/Base.lproj/KMAboutWindowController.xib
+++ b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/Base.lproj/KMAboutWindowController.xib
@@ -1,8 +1,8 @@
-
+
-
+
@@ -20,7 +20,7 @@
-
+
@@ -42,8 +42,12 @@
-
-
+
+
+
+
+
+
@@ -100,29 +104,29 @@
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
+
@@ -165,7 +169,7 @@
-
+
@@ -175,7 +179,7 @@
-
+
diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMAboutBGView.m b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMAboutBGView.m
index 361967506ed..de5e5017519 100644
--- a/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMAboutBGView.m
+++ b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMAboutBGView.m
@@ -34,6 +34,7 @@ - (void)drawRect:(NSRect)rect {
NSRectFillUsingOperation(topFill, NSCompositingOperationSourceOver);
[[NSColor windowBackgroundColor] setFill];
NSRectFillUsingOperation(botFill, NSCompositingOperationSourceOver);
+
}
- (BOOL)mouseDownCanMoveWindow {
diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMBarView.m b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMBarView.m
index b9a400706a3..8364a6cb310 100644
--- a/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMBarView.m
+++ b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMBarView.m
@@ -7,31 +7,39 @@
//
#import "KMBarView.h"
+#import "KMLogs.h"
@implementation KMBarView
+/**
+ * draws stripe in three colors as part of Keyman branding
+ * over half is orange, followed by red and blue segments
+ */
- (void)drawRect:(NSRect)rect {
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext];
- NSRect rect1 = NSMakeRect(0, 0, rect.size.width*0.56, rect.size.height);
- NSRect rect2 = NSMakeRect(rect1.size.width, 0, rect.size.width*0.23, rect.size.height);
- NSRect rect3 = NSMakeRect(rect2.origin.x + rect2.size.width, 0, rect.size.width*0.21, rect.size.height);
+ NSRect barRect = self.frame;
+ os_log_debug([KMLogs uiLog], "KMBarView drawRect: %{public}@ frame: %{public}@", NSStringFromRect(rect), NSStringFromRect(barRect));
+
+ NSRect orangeRect = NSMakeRect(0, 0, barRect.size.width*0.56, barRect.size.height);
+ NSRect redRect = NSMakeRect(orangeRect.size.width, 0, barRect.size.width*0.23, barRect.size.height);
+ NSRect blueRect = NSMakeRect(redRect.origin.x + redRect.size.width, 0, barRect.size.width*0.21, barRect.size.height);
CGContextSetFillColorWithColor(context, [NSColor colorWithSRGBRed:246.0/255.0 green:137.0/255.0 blue:36.0/255.0 alpha:1.0].CGColor);
CGContextBeginPath(context);
- CGContextAddRect(context, rect1);
+ CGContextAddRect(context, orangeRect);
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFill);
CGContextSetFillColorWithColor(context, [NSColor colorWithSRGBRed:204.0/255.0 green:56.0/255.0 blue:70.0/255.0 alpha:1.0].CGColor);
CGContextBeginPath(context);
- CGContextAddRect(context, rect2);
+ CGContextAddRect(context, redRect);
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFill);
CGContextSetFillColorWithColor(context, [NSColor colorWithSRGBRed:121.0/255.0 green:195.0/255.0 blue:218.0/255.0 alpha:1.0].CGColor);
CGContextBeginPath(context);
- CGContextAddRect(context, rect3);
+ CGContextAddRect(context, blueRect);
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFill);
}
diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/SILAndikaV1RGB.png b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/SILAndikaV1RGB.png
new file mode 100644
index 00000000000..c58f4d70063
Binary files /dev/null and b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/SILAndikaV1RGB.png differ
diff --git a/resources/shellHelperFunctions.sh b/resources/shellHelperFunctions.sh
index eaa369b0304..bcd3da0d853 100755
--- a/resources/shellHelperFunctions.sh
+++ b/resources/shellHelperFunctions.sh
@@ -281,13 +281,17 @@ verify_npm_setup() {
# see /docs/build/node.md
_select_node_version_with_nvm() {
local REQUIRED_NODE_VERSION="$("$JQ" -r '.engines.node' "$KEYMAN_ROOT/package.json")"
+ local CURRENT_NODE_VERSION
if [[ $BUILDER_OS != win ]]; then
# launch nvm in a sub process, see _builder_nvm.sh for details
"$KEYMAN_ROOT/resources/build/_builder_nvm.sh" "$REQUIRED_NODE_VERSION"
else
- nvm install "$REQUIRED_NODE_VERSION"
- nvm use "$REQUIRED_NODE_VERSION"
+ CURRENT_NODE_VERSION="$(node --version)"
+ if [[ "$CURRENT_NODE_VERSION" != "v$REQUIRED_NODE_VERSION" ]]; then
+ start //wait //b nvm install "$REQUIRED_NODE_VERSION"
+ start //wait //b nvm use "$REQUIRED_NODE_VERSION"
+ fi
fi
# Now, check that the node version is correct, on all systems
@@ -296,7 +300,7 @@ _select_node_version_with_nvm() {
# https://github.com/coreybutler/nvm-windows/issues/738
# note the 'v' prefix that node emits (and npm doesn't!)
- local CURRENT_NODE_VERSION="$(node --version)"
+ CURRENT_NODE_VERSION="$(node --version)"
if [[ "$CURRENT_NODE_VERSION" != "v$REQUIRED_NODE_VERSION" ]]; then
builder_die "Attempted to select node.js version $REQUIRED_NODE_VERSION but found $CURRENT_NODE_VERSION instead"
fi
@@ -306,13 +310,13 @@ check-markdown() {
node "$KEYMAN_ROOT/resources/tools/check-markdown" --root "$1"
}
-#
+#
# Runs eslint, builds tests, and then runs tests with mocha + c8 (coverage)
-#
+#
# Usage:
# builder_run_action test builder_do_typescript_tests [coverage_threshold]
# Parameters:
-# 1: coverage_threshold optional, minimum coverage for c8 to pass tests,
+# 1: coverage_threshold optional, minimum coverage for c8 to pass tests,
# defaults to 90 (percent)
#
# Todo:
@@ -342,4 +346,4 @@ builder_do_typescript_tests() {
builder_echo warning "Coverage thresholds are currently $C8_THRESHOLD%, which is lower than ideal."
builder_echo warning "Please increase threshold in build.sh as test coverage improves."
fi
-}
\ No newline at end of file
+}
diff --git a/windows/src/desktop/kmshell/locale/it-IT/strings.xml b/windows/src/desktop/kmshell/locale/it-IT/strings.xml
index 13e1cee8164..797fb766335 100644
--- a/windows/src/desktop/kmshell/locale/it-IT/strings.xml
+++ b/windows/src/desktop/kmshell/locale/it-IT/strings.xml
@@ -296,7 +296,7 @@
- Allow right modifier for hotkeys
+ Consenti tasti modificatori a destra
@@ -425,11 +425,11 @@
- Created by %1$s
+ Creato da %1$s
- Copyright © %1$s. All Rights Reserved.
+ Copyright ©️ %1$s. Tutti i diritti riservati.
@@ -629,7 +629,7 @@ che usi in Windows. Le tastiere Keyman si adatteranno automaticamente al layout
- Start %1$s
+ Avvia %1$s
diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp
index 6ad3fc90b2a..a1a927ab6fa 100644
--- a/windows/src/engine/keyman32/K32_load.cpp
+++ b/windows/src/engine/keyman32/K32_load.cpp
@@ -127,7 +127,7 @@ BOOL LoadlpKeyboard(int i)
free(buffer);
if (err_status != KM_CORE_STATUS_OK) {
- SendDebugMessageFormat("km_core_keyboard_load failed for %ls with error status [%d]", keyboardPath, err_status);
+ SendDebugMessageFormat("km_core_keyboard_load_from_blob failed for %ls with error status [%d]", keyboardPath, err_status);
goto ExitError;
}
delete[] keyboardPath;
diff --git a/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp
index 282ee48ac63..ad9799724a0 100644
--- a/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp
+++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp
@@ -16,7 +16,7 @@ TEST(KEYBOARDOPTIONS, SetupCoreEnvironment) {
km_core_path_name dummyPath = L"dummyActions.mock";
EXPECT_EQ(SetupCoreEnvironment(&core_env_opts), TRUE);
- EXPECT_EQ(km_core_keyboard_load(dummyPath, &kp->lpCoreKeyboard), KM_CORE_STATUS_OK);
+ EXPECT_EQ(km_core_keyboard_load_from_blob(dummyPath, (void *)"MOCK", 4, &kp->lpCoreKeyboard), KM_CORE_STATUS_OK);
EXPECT_EQ(km_core_state_create(kp->lpCoreKeyboard, core_env_opts, &kp->lpCoreKeyboardState), KM_CORE_STATUS_OK);
km_core_option_item *expected_items = new km_core_option_item[5];