Merge pull request #8850 from keymanapp/refactor/developer/wasm-compiler-interface

refactor(developer): compiler interface part 1 for wasm
This commit is contained in:
Marc Durdin 2023-05-26 18:43:24 +10:00 • committed by GitHub
commit 18c4ac5bb2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 389 additions and 196 deletions

View file

@ -35,10 +35,17 @@ export default class KVKSFileReader {
parser.parseString(file, (e: unknown, r: unknown) => { source = r as KVKSourceFile });
source = this.boxArrays(source);
this.cleanupFlags(source);
this.cleanupUnderscore('visualkeyboard', source.visualkeyboard);
return source;
}
private cleanupFlags(source: any) {
if(source.visualkeyboard?.header?.flags === '') {
source.visualkeyboard.header.flags = {};
}
}
/**
* The only element that allows spaces is <key>. Remove
* all other empty whitespace-only values.

View file

@ -109,6 +109,7 @@ export interface CompilerFileSystemCallbacks {
readFileSync(path: string, options?: { encoding?: null; flag?: string; } | null): Uint8Array;
readFileSync(path: string, options: { encoding: string; flag?: string; } | string): string;
readFileSync(path: string, options?: { encoding?: string | null; flag?: string; } | string | null): string | Uint8Array;
writeFileSync(path: string, data: Uint8Array): void;
existsSync(name: string): boolean;
}

View file

@ -126,6 +126,8 @@ type
dpDeadKeyArray: PFILE_DEADKEY; // temp - dead key array
cxVKDictionary: DWORD; // I3438
dpVKDictionary: PFILE_VKDICTIONARY; // I3438 // temp - virtual key dictionary
extra: Pointer;
end;
PFILE_KEYBOARD = ^FILE_KEYBOARD;
@ -152,13 +154,13 @@ const
const
// kcframe --sizeof returns these values
{$IFDEF WIN64}
FILE_KEYBOARD_SIZE = 2984;
FILE_KEYBOARD_SIZE = 2992;
FILE_GROUP_SIZE = 200;
FILE_STORE_SIZE = 200;
FILE_KEY_SIZE = 32;
FILE_DEADKEY_SIZE = 160;
{$ELSE}
FILE_KEYBOARD_SIZE = 2952;
FILE_KEYBOARD_SIZE = 2956;
FILE_GROUP_SIZE = 188;
FILE_STORE_SIZE = 192;
FILE_KEY_SIZE = 20;

View file

@ -1,31 +1,26 @@
/*
TODO: implement additional interfaces:
extern "C" bool kmcmp_CompileKeyboardFileToBuffer(
char* pszInfile,
void* pfkBuffer,
bool ACompilerWarningsAsErrors,
bool AWarnDeprecatedCode,
kmcmp_CompilerMessageProc pMsgproc,
void* AmsgprocContext,
int Target
);
typedef bool (*kmcmp_ValidateJsonMessageProc)(int64_t offset, const char* szText, void* context);
extern "C" bool kmcmp_ValidateJsonFile(
std::fstream& f,
std::fstream& fd,
kmcmp_ValidateJsonMessageProc MessageProc,
void* context
);
typedef bool (*kmcmp_ValidateJsonMessageProc)();
extern "C" bool kmcmp_ValidateJsonFile();
*/
// TODO: rename wasm-host?
import { CompilerCallbacks, CompilerEvent } from '@keymanapp/common-types';
import { CompilerCallbacks, CompilerEvent, KvkFileWriter, KvksFileReader } from '@keymanapp/common-types';
import loadWasmHost from '../import/kmcmplib/wasm-host.js';
import { CompilerMessages, mapErrorFromKmcmplib } from './messages.js';
export interface CompilerResultFile {
filename: string;
data: Uint8Array;
};
export interface CompilerResult {
kmx?: CompilerResultFile;
kvk?: CompilerResultFile;
js?: CompilerResultFile;
};
export interface CompilerOptions {
shouldAddCompilerVersion?: boolean;
saveDebug?: boolean;
@ -136,7 +131,19 @@ export class KmnCompiler {
// TODO: use callbacks for file access -- so kmc-kmn is entirely fs agnostic
let result = this.runCompiler(infile, outfile, options);
delete (globalThis as any)[this.callbackName];
return result;
//TODO: write the file out!
if(result) {
if(result.kmx) {
this.callbacks.fs.writeFileSync(result.kmx.filename, result.kmx.data);
}
if(result.kvk) {
this.callbacks.fs.writeFileSync(result.kvk.filename, result.kvk.data);
}
if(result.js) {
this.callbacks.fs.writeFileSync(result.js.filename, result.js.data);
}
}
return !!result;
}
private compilerMessageCallback = (line: number, code: number, msg: string): number => {
@ -144,24 +151,71 @@ export class KmnCompiler {
return 1;
}
private runCompiler(infile: string, outfile: string, options: CompilerOptions): boolean {
private runCompiler(infile: string, outfile: string, options: CompilerOptions): CompilerResult {
let result: CompilerResult = {};
let wasm_interface = new this.wasm.Module.CompilerInterface();
let wasm_result = null;
try {
if (!this.wasm.setCompilerOptions(options.shouldAddCompilerVersion ? 1 : 0)) {
this.callbacks.reportMessage(CompilerMessages.Fatal_UnableToSetCompilerOptions());
wasm_interface.saveDebug = options.saveDebug;
wasm_interface.compilerWarningsAsErrors = options.compilerWarningsAsErrors;
wasm_interface.warnDeprecatedCode = options.warnDeprecatedCode;
wasm_interface.messageCallback = this.callbackName;
wasm_interface.loadFileCallback = this.callbackName; // TODO: this is wrong, needs to be a new callback; not yet used though
wasm_result = this.wasm.Module.kmcmp_compile(infile, wasm_interface);
if(!wasm_result.result) {
return null;
}
return this.wasm.compileKeyboardFile(
infile,
outfile,
options.saveDebug ? 1 : 0,
options.compilerWarningsAsErrors ? 1 : 0,
options.warnDeprecatedCode ? 1 : 0,
this.callbackName);
if(wasm_result.kvksFilename) {
result.kvk = this.runKvkCompiler(wasm_result.kvksFilename, infile, outfile);
if(!result.kvk) {
return null;
}
}
result.kmx = {
filename: outfile,
data: new Uint8Array(this.wasm.Module.HEAP8.buffer, wasm_result.kmx, wasm_result.kmxSize)
};
return result;
} catch(e) {
this.callbacks.reportMessage(CompilerMessages.Fatal_UnexpectedException({e:e}));
return false;
return null;
} finally {
if(wasm_result) {
wasm_result.delete();
}
wasm_interface.delete();
}
}
private runKvkCompiler(kvksFilename: string, kmnFilename: string, kmxFilename: string) {
// The compiler detected a .kvks file, which needs to be captured
let reader = new KvksFileReader();
kvksFilename = this.callbacks.resolveFilename(kmnFilename, kvksFilename);
let kvks = reader.read(this.callbacks.loadFile(kvksFilename));
try {
reader.validate(kvks, this.callbacks.loadSchema('kvks'));
} catch(e) {
console.log(e);
// TODO: this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvksFile({e}));
return null;
}
let errors: any = []; //TODO: KVKSParseError[];
let vk = reader.transform(kvks, errors);
if(!vk || errors.length) {
console.dir(errors);
// TODO: this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvksFile({e}));
return null;
}
let writer = new KvkFileWriter();
return {
filename: this.callbacks.path.join(this.callbacks.path.dirname(kmxFilename), this.callbacks.path.basename(kvksFilename, '.kvks') + '.kvk'),
data: writer.write(vk)
};
}
/**
*
* @param pattern UnicodeSet pattern such as `[a-z]`

View file

@ -1,7 +1,5 @@
import 'mocha';
import sinon from 'sinon';
import chai, { assert } from 'chai';
import sinonChai from 'sinon-chai';
import { assert } from 'chai';
import { KmnCompiler } from '../src/main.js';
import { dirname } from 'path';
import { fileURLToPath } from 'url';
@ -9,21 +7,10 @@ import fs from 'fs';
import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers';
const __dirname = dirname(fileURLToPath(import.meta.url)).replace(/\\/g, '/');
const baselineDir = __dirname + '/../../../../../common/test/keyboards/baseline/';
chai.use(sinonChai);
const keyboardsDir = __dirname + '/../../../../../common/test/keyboards/';
const baselineDir = keyboardsDir + 'baseline/';
describe('Compiler class', function() {
let consoleLog: any;
// TODO: do we need this?
beforeEach(function() {
consoleLog = sinon.spy(console, 'log');
});
afterEach(function() {
consoleLog.restore();
});
it('should throw on failure', async function() {
const compiler = new KmnCompiler();
const callbacks : any = null; // ERROR
@ -87,4 +74,35 @@ describe('Compiler class', function() {
}
}
});
it('should compile a keyboard with visual keyboard', async function() {
const compiler = new KmnCompiler();
const callbacks = new TestCompilerCallbacks();
assert(await compiler.init(callbacks));
assert(compiler.verifyInitialized());
const fixtureDir = keyboardsDir + 'caps_lock_layer_3620/'
const infile = fixtureDir + 'source/caps_lock_layer_3620.kmn';
const kmxFixture = fixtureDir + '/binary/caps_lock_layer_3620.kmx';
const kvkFixture = fixtureDir + '/binary/caps_lock_layer_3620.kvk';
const kmxfile = __dirname + '/caps_lock_layer_3620.kmx';
const kvkfile = __dirname + '/caps_lock_layer_3620.kvk';
assert(compiler.run(infile, kmxfile, {saveDebug: true, shouldAddCompilerVersion: false}));
assert(fs.existsSync(kmxfile));
assert(fs.existsSync(kvkfile));
const kmxData = fs.readFileSync(kmxfile);
const kmxFixtureData = fs.readFileSync(kmxFixture);
assert.equal(kmxData.byteLength, kmxFixtureData.byteLength);
assert.deepEqual(kmxData, kmxFixtureData);
const kvkData = fs.readFileSync(kvkfile);
const kvkFixtureData = fs.readFileSync(kvkFixture);
assert.equal(kvkData.byteLength, kvkFixtureData.byteLength);
assert.deepEqual(kvkData, kvkFixtureData);
});
});

View file

@ -22,6 +22,13 @@
#include "../../../common/windows/cpp/include/legacy_kmx_file.h"
// This file is deprecated; see kmcmplib/src/compfile.h. However, as long as
// this file continues to live, we need to keep structures in it in exact sync
// with kmcmplib/src/compfile.h, as FILE_KEYBOARD is passed between kmcmplib and
// kmcmpdll. KMX_WCHAR on Windows is identical to wchar_t, so it is safe to map
// accordingly.
#define LINESIZE 8192
#define GLOBAL_BUFSIZE 4096
@ -70,9 +77,9 @@
enum FileStoreType { FST_STORE, FST_OPTION, FST_RESERVED };
struct FILE_STORE {
DWORD dwSystemID;
WCHAR szName[SZMAX_STORENAME]; // the name of the store
PWSTR dpString; // from start of store structure
DWORD dwSystemID;
WCHAR szName[SZMAX_STORENAME]; // the name of the store
PWSTR dpString; // from start of store structure
//FileStoreType fstType;
BOOL fIsStore;
BOOL fIsReserved;
@ -80,77 +87,75 @@ struct FILE_STORE {
BOOL fIsDebug;
BOOL fIsCall;
int line; // TODO: int vs dword, line vs Line (see FILE_KEY, FILE_GROUP)
};
};
typedef FILE_STORE *PFILE_STORE;
struct FILE_KEY {
WCHAR Key; // WCHAR for consistency; only a byte used however
WORD LineStoreIndex;
DWORD Line;
DWORD ShiftFlags;
PWSTR dpOutput; // from start of key structure
PWSTR dpContext; // from start of key structure
};
WCHAR Key; // WCHAR for consistency; only a byte used however
WORD LineStoreIndex;
DWORD Line;
DWORD ShiftFlags;
PWSTR dpOutput; // from start of key structure
PWSTR dpContext; // from start of key structure
};
typedef FILE_KEY *PFILE_KEY;
struct FILE_GROUP {
WCHAR szName[SZMAX_GROUPNAME];
PFILE_KEY dpKeyArray; // address of first item in key array, from start of group structure
PWSTR dpMatch; // from start of group structure
PWSTR dpNoMatch; // from start of group structure
DWORD cxKeyArray; // in array items
BOOL fUsingKeys; // group(xx) [using keys] <-- specified or not
WCHAR szName[SZMAX_GROUPNAME];
PFILE_KEY dpKeyArray; // address of first item in key array, from start of group structure
PWSTR dpMatch; // from start of group structure
PWSTR dpNoMatch; // from start of group structure
DWORD cxKeyArray; // in array items
BOOL fUsingKeys; // group(xx) [using keys] <-- specified or not
BOOL fReadOnly; // group(xx) [readonly] <-- specified or not
DWORD Line;
};
typedef FILE_GROUP *PFILE_GROUP;
struct FILE_DEADKEY
{
WCHAR szName[SZMAX_DEADKEYNAME];
struct FILE_DEADKEY {
WCHAR szName[SZMAX_DEADKEYNAME];
};
typedef FILE_DEADKEY *PFILE_DEADKEY;
struct FILE_VKDICTIONARY
{
struct FILE_VKDICTIONARY {
WCHAR szName[SZMAX_VKDICTIONARYNAME];
};
typedef FILE_VKDICTIONARY *PFILE_VKDICTIONARY;
struct FILE_KEYBOARD {
DWORD KeyboardID; // as stored in HKEY_LOCAL_MACHINE//system//currentcontrolset//control//keyboard layouts
DWORD KeyboardID; // deprecated, unused
DWORD version; // keyboard file version with VERSION keyword
DWORD version; // keyboard file version with VERSION keyword
PFILE_STORE dpStoreArray; // address of first item in store array, from start of store structure
PFILE_GROUP dpGroupArray; // address of first item in group array, from start of group structure
PFILE_STORE dpStoreArray; // address of first item in store array, from start of store structure
PFILE_GROUP dpGroupArray; // address of first item in group array, from start of group structure
DWORD cxStoreArray; // in number of items
DWORD cxGroupArray; // in number of items
DWORD StartGroup[2]; // index of starting groups [ANSI=0, Unicode=1]
DWORD cxStoreArray; // in number of items
DWORD cxGroupArray; // in number of items
DWORD StartGroup[2]; // index of starting groups [ANSI=0, Unicode=1]
DWORD dwHotKey; // standard windows hotkey (hiword=shift/ctrl/alt stuff, loword=vkey)
DWORD dwHotKey; // standard windows hotkey (hiword=shift/ctrl/alt stuff, loword=vkey)
WCHAR szName[SZMAX_KEYBOARDNAME]; // Keyboard layout name
WCHAR szLanguageName[SZMAX_LANGUAGENAME]; // Language name
WCHAR szCopyright[SZMAX_COPYRIGHT]; // Copyright information
WCHAR szMessage[SZMAX_MESSAGE]; // General information about the keyboard
PBYTE lpBitmap;
DWORD dwBitmapSize;
DWORD dwFlags; // Flags for the keyboard file
WCHAR szName[SZMAX_KEYBOARDNAME]; // Keyboard layout name
WCHAR szLanguageName[SZMAX_LANGUAGENAME]; // Language name
WCHAR szCopyright[SZMAX_COPYRIGHT]; // Copyright information
WCHAR szMessage[SZMAX_MESSAGE]; // General information about the keyboard
PBYTE lpBitmap;
DWORD dwBitmapSize;
DWORD dwFlags; // Flags for the keyboard file
DWORD currentGroup; // temp - current processing group
DWORD currentStore; // temp - current processing store
DWORD cxDeadKeyArray;
PFILE_DEADKEY dpDeadKeyArray; // temp - dead key array
DWORD currentGroup; // temp - current processing group
DWORD currentStore; // temp - current processing store
DWORD cxDeadKeyArray;
PFILE_DEADKEY dpDeadKeyArray; // temp - dead key array
DWORD cxVKDictionary;
PFILE_VKDICTIONARY dpVKDictionary; // temp - virtual key dictionary
};
void* extra; // used by kmcmplib and its consumers; unused in kmcmpdll
};
typedef FILE_KEYBOARD *PFILE_KEYBOARD;
@ -168,34 +173,34 @@ const DWORD sz_FILE_VKDICTIONARY = sizeof(FILE_VKDICTIONARY);
const DWORD sz_FILE_KEYBOARD = sizeof(FILE_KEYBOARD);
struct COMPMSG {
char szText[SZMAX_ERRORTEXT];
DWORD Line;
DWORD dwMsgCode;
};
char szText[SZMAX_ERRORTEXT];
DWORD Line;
DWORD dwMsgCode;
};
typedef COMPMSG *PCOMPMSG;
struct COMPILEMESSAGES {
int nMessages;
int nErrors;
int nMessages;
int nErrors;
PCOMPMSG cm;
PCOMPMSG cm;
DWORD fatalCode;
char szFatalText[SZMAX_ERRORTEXT];
DWORD fatalCode;
char szFatalText[SZMAX_ERRORTEXT];
DWORD currentLine;
};
DWORD currentLine;
};
typedef COMPILEMESSAGES *PCOMPILEMESSAGES;
/*
struct TVersion
{
//int MinVersion; // 0x0500 usually
//int CompilerVersion[4];
//int MinCompilerVersion[4];
int KeyboardVersion; // 0x0500 usually
//int MinVersion; // 0x0500 usually
//int CompilerVersion[4];
//int MinCompilerVersion[4];
int KeyboardVersion; // 0x0500 usually
};
extern TVersion FVersionInfo;

View file

@ -24,6 +24,8 @@
#include <compfile.h>
extern "C" BOOL CompileKeyboardFile(PSTR pszInfile, PSTR pszOutfile, BOOL FSaveDebug, BOOL ACompilerWarningsAsErrors, BOOL AWarnDeprecatedCode, CompilerMessageProc pMsgProc); // I4865 // I4866
int WINAPI msgproc(int line, DWORD dwMsgCode, LPSTR szText)
{
printf("line %d error %x %s\n", line, (unsigned int) dwMsgCode, szText);

View file

@ -4,6 +4,8 @@
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#include <emscripten/bind.h>
#else
#define EMSCRIPTEN_KEEPALIVE
#endif

View file

@ -10,7 +10,8 @@ project('kmcmplib', 'cpp', 'c',
default_options : ['buildtype=release',
'cpp_std=c++14',
'b_vscrt=static_from_buildtype',
'default_library=static'])
'default_library=static',
'debug=true'])
# Import our standard compiler defines; this is copied from
# /resources/build/standard.meson.build by build.sh, because

View file

@ -784,7 +784,7 @@ KMX_DWORD ProcessStoreLine(PFILE_KEYBOARD fk, PKMX_WCHAR p)
return CheckForDuplicateStore(fk, sp);
}
KMX_DWORD AddStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, KMX_WCHAR const * str, KMX_DWORD *dwStoreID)
KMX_DWORD AddStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, const KMX_WCHAR * str, KMX_DWORD *dwStoreID)
{
PFILE_STORE sp;
sp = new FILE_STORE[fk->cxStoreArray + 1];
@ -1023,6 +1023,9 @@ KMX_DWORD ProcessSystemStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, PFILE_STORE
case TSS_VISUALKEYBOARD:
VERIFY_KEYBOARD_VERSION(fk, VERSION_70, CERR_70FeatureOnly);
{
// Store extra metadata for callers as we mutate this store during
// compilation
fk->extra->kvksFilename = sp->dpString;
// Strip path from the store, leaving bare filename only
p = sp->dpString;

View file

@ -14,6 +14,10 @@
#define SetError(err) { if(AddCompileError(err) || (err & CERR_FATAL)) return FALSE; }
bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk);
bool CompileKeyboard(const char* pszInfile,
void* pfkBuffer, bool ASaveDebug, bool ACompilerWarningsAsErrors,
bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, const void* AmsgprocContext,
int Target);
EXTERN bool kmcmp_SetCompilerOptions(KMCMP_COMPILER_OPTIONS* options) {
//printf("°°-> changed to SetCompilerOptions() of kmcmplib \n");
@ -44,6 +48,7 @@ int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, char* szText, void* c
return wasm_msgproc(line, dwMsgCode, szText, msgProc);
}
//DEPRECATED
EXTERN bool kmcmp_Wasm_SetCompilerOptions(int ShouldAddCompilerVersion) {
KMCMP_COMPILER_OPTIONS options;
options.dwSize = sizeof(KMCMP_COMPILER_OPTIONS);
@ -51,6 +56,7 @@ EXTERN bool kmcmp_Wasm_SetCompilerOptions(int ShouldAddCompilerVersion) {
return kmcmp_SetCompilerOptions(&options);
}
//DEPRECATED
EXTERN bool kmcmp_Wasm_CompileKeyboardFile(char* pszInfile,
char* pszOutfile, int ASaveDebug, int ACompilerWarningsAsErrors,
int AWarnDeprecatedCode, char* msgProc
@ -74,11 +80,97 @@ EXTERN int kmcmp_Wasm_ParseUnicodeSet(char* pat,
);
}
struct COMPILER_INTERFACE {
bool saveDebug;
bool compilerWarningsAsErrors;
bool warnDeprecatedCode;
bool shouldAddCompilerVersion;
int target; // CKF_KEYMAN, CKF_KEYMANWEB
std::string messageCallback; // int line, uint32_t dwMsgCode, char* szText
std::string loadFileCallback; // char* infile, char* filenameRelativeToInfile --> buffer
};
struct COMPILER_RESULT {
bool result;
// Following are pointer offsets in heap + buffer size
int kmx;
int kmxSize;
// Following are compiler side-channel data, required for
// follow-on transform
std::string kvksFilename;
// TODO: additional data to be passed back
};
COMPILER_RESULT kmcmp_compile(std::string pszInfile, const COMPILER_INTERFACE intf) {
COMPILER_RESULT r = {false};
FILE_KEYBOARD fk;
// TODO: this should be included in CompileKeyboard?
kmcmp::FShouldAddCompilerVersion = intf.shouldAddCompilerVersion;
r.result = CompileKeyboard(
pszInfile.c_str(),
&fk,
intf.saveDebug,
intf.compilerWarningsAsErrors,
intf.warnDeprecatedCode,
wasm_CompilerMessageProc,
intf.messageCallback.c_str(),
intf.target);
if(!r.result) {
return r;
}
KMX_DWORD msg;
KMX_BYTE* data = nullptr;
size_t dataSize = 0;
msg = WriteCompiledKeyboard(&fk, &data, dataSize);
//TODO: FreeKeyboardPointers(fk);
if(msg != CERR_None) {
AddCompileError(msg);
r.result = FALSE;
return r;
}
r.kmx = (int) data;
r.kmxSize = (int) dataSize;
r.kvksFilename = string_from_u16string(fk.extra->kvksFilename); // convert to UTF8
return r;
}
EMSCRIPTEN_BINDINGS(compiler_interface) {
emscripten::class_<COMPILER_INTERFACE>("CompilerInterface")
.constructor<>()
.property("saveDebug", &COMPILER_INTERFACE::saveDebug)
.property("compilerWarningsAsErrors", &COMPILER_INTERFACE::compilerWarningsAsErrors)
.property("warnDeprecatedCode", &COMPILER_INTERFACE::warnDeprecatedCode)
.property("shouldAddCompilerVersion", &COMPILER_INTERFACE::shouldAddCompilerVersion)
.property("target", &COMPILER_INTERFACE::target)
.property("messageCallback", &COMPILER_INTERFACE::messageCallback)
.property("loadFileCallback", &COMPILER_INTERFACE::loadFileCallback)
;
emscripten::class_<COMPILER_RESULT>("CompilerResult")
.constructor<>()
.property("result", &COMPILER_RESULT::result)
.property("kmx", &COMPILER_RESULT::kmx)
.property("kmxSize", &COMPILER_RESULT::kmxSize)
.property("kvksFilename", &COMPILER_RESULT::kvksFilename)
;
emscripten::function("kmcmp_compile", &kmcmp_compile);
}
#endif
bool CompileKeyboard(char* pszInfile,
bool CompileKeyboard(const char* pszInfile,
void* pfkBuffer, bool ASaveDebug, bool ACompilerWarningsAsErrors,
bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, void* AmsgprocContext,
bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, const void* AmsgprocContext,
int Target) {
FILE* fp_in = NULL;
@ -95,7 +187,7 @@ bool CompileKeyboard(char* pszInfile,
PKMX_STR p;
if ((p = strrchr_slash(pszInfile)) != nullptr)
if ((p = strrchr_slash((char*)pszInfile)) != nullptr)
{
strncpy(kmcmp::CompileDir, pszInfile, (int)(p - pszInfile + 1)); // I3481
kmcmp::CompileDir[(int)(p - pszInfile + 1)] = 0;
@ -104,7 +196,7 @@ bool CompileKeyboard(char* pszInfile,
kmcmp::CompileDir[0] = 0;
msgproc = pMsgproc;
msgprocContext = AmsgprocContext;
msgprocContext = (void*)AmsgprocContext;
kmcmp::currentLine = 0;
kmcmp::nErrors = 0;
@ -231,7 +323,8 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk)
fk->dpDeadKeyArray = NULL;
fk->cxVKDictionary = 0; // I3438
fk->dpVKDictionary = NULL; // I3438
fk->extra = new FILE_KEYBOARD_EXTRA;
fk->extra->kvksFilename = u"";
/* fk->szMessage[0] = 0;
fk->szLanguageName[0] = 0;*/
fk->dwBitmapSize = 0;
@ -251,12 +344,8 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk)
}
/* Add a system store for the Keyman edition number */
u16sprintf(str, LINESIZE, L"%d", 0); // I3481
AddStore(fk, TSS_CUSTOMKEYMANEDITION, str);
PKMX_WCHAR tbuf = strtowstr((KMX_CHAR*) "Keyman");
AddStore(fk, TSS_CUSTOMKEYMANEDITIONNAME, tbuf);
delete tbuf;
AddStore(fk, TSS_CUSTOMKEYMANEDITION, u"0");
AddStore(fk, TSS_CUSTOMKEYMANEDITIONNAME, u"Keyman");
// must preprocess for group and store names -> this isn't really necessary, but never mind!
while ((msg = ReadLine(fp_in, str, TRUE)) == CERR_None)

View file

@ -22,6 +22,7 @@
#include "kmcompx.h"
#include <kmx_file.h>
#include <string>
#define LINESIZE 8192
#define GLOBAL_BUFSIZE 4096
@ -71,85 +72,93 @@
enum FileStoreType { FST_STORE, FST_OPTION, FST_RESERVED };
struct FILE_STORE {
KMX_DWORD dwSystemID;
KMX_WCHAR szName[SZMAX_STORENAME]; // the name of the store
PKMX_WCHAR dpString; // from start of store structure
//FileStoreType fstType;
KMX_BOOL fIsStore;
KMX_BOOL fIsReserved;
KMX_BOOL fIsOption;
KMX_BOOL fIsDebug;
KMX_BOOL fIsCall;
int line;
};
typedef FILE_STORE * PFILE_STORE;
KMX_DWORD dwSystemID;
KMX_WCHAR szName[SZMAX_STORENAME]; // the name of the store
PKMX_WCHAR dpString; // from start of store structure
//FileStoreType fstType;
KMX_BOOL fIsStore;
KMX_BOOL fIsReserved;
KMX_BOOL fIsOption;
KMX_BOOL fIsDebug;
KMX_BOOL fIsCall;
int line;
};
typedef FILE_STORE *PFILE_STORE;
struct FILE_KEY {
KMX_WCHAR Key; // WCHAR for consistency; only a byte used however
KMX_WORD LineStoreIndex;
KMX_DWORD Line;
KMX_DWORD ShiftFlags;
PKMX_WCHAR dpOutput; // from start of key structure
PKMX_WCHAR dpContext; // from start of key structure
};
KMX_WCHAR Key; // WCHAR for consistency; only a byte used however
KMX_WORD LineStoreIndex;
KMX_DWORD Line;
KMX_DWORD ShiftFlags;
PKMX_WCHAR dpOutput; // from start of key structure
PKMX_WCHAR dpContext; // from start of key structure
};
typedef FILE_KEY *PFILE_KEY;
struct FILE_GROUP {
KMX_WCHAR szName[SZMAX_GROUPNAME];
PFILE_KEY dpKeyArray; // address of first item in key array, from start of group structure
PKMX_WCHAR dpMatch; // from start of group structure
PKMX_WCHAR dpNoMatch; // from start of group structure
KMX_DWORD cxKeyArray; // in array items
KMX_BOOL fUsingKeys; // group(xx) [using keys] <-- specified or not
KMX_BOOL fReadOnly; // group(xx) [readonly] <-- specified or not
KMX_DWORD Line;
};
KMX_WCHAR szName[SZMAX_GROUPNAME];
PFILE_KEY dpKeyArray; // address of first item in key array, from start of group structure
PKMX_WCHAR dpMatch; // from start of group structure
PKMX_WCHAR dpNoMatch; // from start of group structure
KMX_DWORD cxKeyArray; // in array items
KMX_BOOL fUsingKeys; // group(xx) [using keys] <-- specified or not
KMX_BOOL fReadOnly; // group(xx) [readonly] <-- specified or not
KMX_DWORD Line;
};
typedef FILE_GROUP *PFILE_GROUP;
struct FILE_DEADKEY
{
KMX_WCHAR szName[SZMAX_DEADKEYNAME];
struct FILE_DEADKEY {
KMX_WCHAR szName[SZMAX_DEADKEYNAME];
};
typedef FILE_DEADKEY *PFILE_DEADKEY;
struct FILE_VKDICTIONARY
{
KMX_WCHAR szName[SZMAX_VKDICTIONARYNAME];
struct FILE_VKDICTIONARY {
KMX_WCHAR szName[SZMAX_VKDICTIONARYNAME];
};
typedef FILE_VKDICTIONARY *PFILE_VKDICTIONARY;
/**
* Extra metadata for API consumers
*/
struct FILE_KEYBOARD_EXTRA {
std::u16string kvksFilename; // original TSS_VISUALKEYBOARD value
};
typedef struct FILE_KEYBOARD_EXTRA* PFILE_KEYBOARD_EXTRA;
struct FILE_KEYBOARD {
KMX_DWORD KeyboardID; // as stored in HKEY_LOCAL_MACHINE//system//currentcontrolset//control//keyboard layouts
KMX_DWORD KeyboardID; // deprecated, unused
KMX_DWORD version; // keyboard file version with VERSION keyword
KMX_DWORD version; // keyboard file version with VERSION keyword
PFILE_STORE dpStoreArray; // address of first item in store array, from start of store structure
PFILE_GROUP dpGroupArray; // address of first item in group array, from start of group structure
PFILE_STORE dpStoreArray; // address of first item in store array, from start of store structure
PFILE_GROUP dpGroupArray; // address of first item in group array, from start of group structure
KMX_DWORD cxStoreArray; // in number of items
KMX_DWORD cxGroupArray; // in number of items
KMX_DWORD StartGroup[2]; // index of starting groups [ANSI=0, Unicode=1]
KMX_DWORD cxStoreArray; // in number of items
KMX_DWORD cxGroupArray; // in number of items
KMX_DWORD StartGroup[2]; // index of starting groups [ANSI=0, Unicode=1]
KMX_DWORD dwHotKey; // standard windows hotkey (hiword=shift/ctrl/alt stuff, loword=vkey)
KMX_DWORD dwHotKey; // standard windows hotkey (hiword=shift/ctrl/alt stuff, loword=vkey)
KMX_WCHAR szName[SZMAX_KEYBOARDNAME]; // Keyboard layout name
KMX_WCHAR szLanguageName[SZMAX_LANGUAGENAME]; // Language name
KMX_WCHAR szCopyright[SZMAX_COPYRIGHT]; // Copyright information
KMX_WCHAR szMessage[SZMAX_MESSAGE]; // General information about the keyboard
PKMX_BYTE lpBitmap;
KMX_DWORD dwBitmapSize;
KMX_DWORD dwFlags; // Flags for the keyboard file
KMX_WCHAR szName[SZMAX_KEYBOARDNAME]; // Keyboard layout name
KMX_WCHAR szLanguageName[SZMAX_LANGUAGENAME]; // Language name
KMX_WCHAR szCopyright[SZMAX_COPYRIGHT]; // Copyright information
KMX_WCHAR szMessage[SZMAX_MESSAGE]; // General information about the keyboard
PKMX_BYTE lpBitmap;
KMX_DWORD dwBitmapSize;
KMX_DWORD dwFlags; // Flags for the keyboard file
KMX_DWORD currentGroup; // temp - current processing group
KMX_DWORD currentStore; // temp - current processing store
KMX_DWORD cxDeadKeyArray;
PFILE_DEADKEY dpDeadKeyArray; // temp - dead key array
KMX_DWORD cxVKDictionary;
PFILE_VKDICTIONARY dpVKDictionary; // temp - virtual key dictionary
};
KMX_DWORD currentGroup; // temp - current processing group
KMX_DWORD currentStore; // temp - current processing store
KMX_DWORD cxDeadKeyArray;
PFILE_DEADKEY dpDeadKeyArray; // temp - dead key array
KMX_DWORD cxVKDictionary;
PFILE_VKDICTIONARY dpVKDictionary; // temp - virtual key dictionary
PFILE_KEYBOARD_EXTRA extra;
};
typedef FILE_KEYBOARD *PFILE_KEYBOARD;
@ -167,34 +176,34 @@ const KMX_DWORD sz_FILE_VKDICTIONARY = sizeof(FILE_VKDICTIONARY);
const KMX_DWORD sz_FILE_KEYBOARD = sizeof(FILE_KEYBOARD);
struct COMPMSG {
KMX_CHAR szText[SZMAX_ERRORTEXT];
KMX_DWORD Line;
KMX_DWORD dwMsgCode;
};
KMX_CHAR szText[SZMAX_ERRORTEXT];
KMX_DWORD Line;
KMX_DWORD dwMsgCode;
};
typedef COMPMSG *PCOMPMSG;
struct COMPILEMESSAGES {
int nMessages;
int nErrors;
int nMessages;
int nErrors;
PCOMPMSG cm;
PCOMPMSG cm;
KMX_DWORD fatalCode;
KMX_CHAR szFatalText[SZMAX_ERRORTEXT];
KMX_DWORD fatalCode;
KMX_CHAR szFatalText[SZMAX_ERRORTEXT];
KMX_DWORD currentLine;
};
KMX_DWORD currentLine;
};
typedef COMPILEMESSAGES *PCOMPILEMESSAGES;
/*
struct TVersion
{
//int MinVersion; // 0x0500 usually
//int CompilerVersion[4];
//int MinCompilerVersion[4];
int KeyboardVersion; // 0x0500 usually
//int MinVersion; // 0x0500 usually
//int CompilerVersion[4];
//int MinCompilerVersion[4];
int KeyboardVersion; // 0x0500 usually
};
extern TVersion FVersionInfo;

View file

@ -42,7 +42,7 @@ PKMX_WCHAR strtowstr(PKMX_STR in);
PFILE_STORE FindSystemStore(PFILE_KEYBOARD fk, KMX_DWORD dwSystemID);
FILE* UTF16TempFromUTF8(FILE* fp_in , KMX_BOOL hasPreamble);
KMX_DWORD WriteCompiledKeyboard(PFILE_KEYBOARD fk, KMX_BYTE**data, size_t& dataSize);
KMX_DWORD AddStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, KMX_WCHAR const * str, KMX_DWORD *dwStoreID= NULL);
KMX_DWORD AddStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, const KMX_WCHAR * str, KMX_DWORD *dwStoreID= NULL);
KMX_DWORD ReadLine(FILE* fp_in , PKMX_WCHAR wstr, KMX_BOOL PreProcess);
KMX_DWORD ParseLine(PFILE_KEYBOARD fk, PKMX_WCHAR str);
KMX_DWORD ProcessGroupLine(PFILE_KEYBOARD fk, PKMX_WCHAR p);

View file

@ -24,7 +24,7 @@ endif
name_suffix = []
if cpp_compiler.get_id() == 'emscripten'
links += ['-lnodefs.js', '-sMODULARIZE', '-sEXPORT_ES6', '-sEXPORTED_RUNTIME_METHODS=[\'cwrap\', \'UTF8ToString\']']
links += ['-lnodefs.js', '-sMODULARIZE', '-sEXPORT_ES6', '--whole-archive', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'cwrap\', \'UTF8ToString\']']
# tests are building as ES6 so we need to declare the file extension
# note that meson currently struggles with the sanitycheckc_cross.exe
# program, because it has a hard coded extension (.exe) which is not