-#include "kmx_u16.h"
+#include "../src/kmx_u16.h"
// Opens files on windows and non-windows platforms. Datatypes for Filename and mode must be the same.
// returns FILE* if file could be opened; FILE needs to be closed in calling function
@@ -10,3 +10,6 @@ FILE* Open_File(const KMX_WCHART* Filename, const KMX_WCHART* mode);
FILE* Open_File(const KMX_WCHAR* Filename, const KMX_WCHAR* mode);
KMX_BOOL kmcmp_FileExists(const KMX_CHAR *filename);
KMX_BOOL kmcmp_FileExists(const KMX_WCHAR *filename);
+
+bool IsRelativePath(KMX_CHAR const * p);
+bool IsRelativePath(KMX_WCHAR const * p);
diff --git a/developer/src/kmcomp/main.pas b/developer/src/kmcomp/main.pas
index 5a29927a807bccd47dea671dbb6ce8d629a1f727..4aa29cf6c1ace54494285d0f9bd9c1f701d45040 100644
--- a/developer/src/kmcomp/main.pas
+++ b/developer/src/kmcomp/main.pas
@@ -65,7 +65,7 @@ uses
UKeymanTargets;
function CompileKeyboard(FInFile, FOutFile: string; FDebug, FWarnAsError: Boolean): Boolean; forward; // I4706
-function KCSetCompilerOptions(const FInFile: string; FShouldAddCompilerVersion, FUseKmcmpLib: Boolean): Boolean; forward;
+function KCSetCompilerOptions(const FInFile: string; FShouldAddCompilerVersion: Boolean): Boolean; forward;
//function CompilerMessage(line: Integer; msgcode: LongWord; text: PAnsiChar): Integer; stdcall; forward;
procedure FixupPathSlashes(var path: string); forward;
@@ -90,7 +90,6 @@ var
FParamDistribution: Boolean;
FMergingValidateIds: Boolean;
FShouldAddCompilerVersion: Boolean;
- FUseKmcmpLib: Boolean;
FJsonSchemaPath: string;
FParamSourcePath: string;
FParamHelpLink: string;
@@ -117,7 +116,6 @@ begin
FColorMode := cmDefault;
FShouldAddCompilerVersion := True;
- FUseKmcmpLib := True;
FParamInfile := '';
FParamOutfile := '';
@@ -193,8 +191,6 @@ begin
FColorMode := cmForceNoColor
else if s = '-no-compiler-version' then
FShouldAddCompilerVersion := False
- else if s = '-use-legacy-compiler' then
- FUseKmcmpLib := False
else if (s = '-help') or (s = '-h') then
begin
// Force help
@@ -223,8 +219,6 @@ begin
writeln(SKeymanDeveloperName + ' Compiler (32-bit)');
{$ENDIF}
writeln('Version ' + CKeymanVersionInfo.VersionWithTag + ', ' + GetVersionCopyright);
- if not FUseKmcmpLib then
- writeln('Note: using legacy compiler');
end;
if FError or (FParamInfile = '') then
@@ -234,7 +228,7 @@ begin
writeln('');
writeln('Usage: '+cmd+' [-s[s]] [-nologo] [-c] [-d] [-w] [-cfc] [-v[s|d]] [-source-path path] [-schema-path path] ');
writeln(' '+spc+' [-m] infile [-m infile] [-t target] [outfile.kmx|outfile.js [error.log]]'); // I4699
- writeln(' '+spc+' [-add-help-link path] [-color|-no-color] [-no-compiler-version] [-use-legacy-compiler]');
+ writeln(' '+spc+' [-add-help-link path] [-color|-no-color] [-no-compiler-version]');
writeln(' '+spc+' [-extract-keyboard-info field[,field...]]');
writeln(' infile can be a .kmn file (Keyboard Source, .kps file (Package Source), or .kpj (project)'); // I4699 // I4825
writeln(' if -v specified, can also be a .keyboard_info file');
@@ -258,7 +252,6 @@ begin
writeln(' uses console mode to determine whether color should be used.');
writeln;
writeln(' -no-compiler-version Don''t embed the compiler version stores, useful for regression tests.');
- writeln(' -use-legacy-compiler Use legacy compiler (will be removed in 18.0)');
writeln;
writeln(' JSON .keyboard_info compile targets:');
writeln(' -v[s] validate infile against source schema');
@@ -298,7 +291,7 @@ begin
TProjectLogConsole.Create(FSilent, FFullySilent, hOutfile, FColorMode);
- KCSetCompilerOptions(FParamInfile, FShouldAddCompilerVersion, FUseKmcmpLib);
+ KCSetCompilerOptions(FParamInfile, FShouldAddCompilerVersion);
if FValidateRepoChanges then
FError := not TValidateRepoChanges.Execute(FParamInfile, FParamOutfile)
@@ -324,7 +317,7 @@ begin
ExitCode := 1;
end;
-function KCSetCompilerOptions(const FInFile: string; FShouldAddCompilerVersion, FUseKmcmpLib: Boolean): Boolean;
+function KCSetCompilerOptions(const FInFile: string; FShouldAddCompilerVersion: Boolean): Boolean;
var
opt: TCompilerOptions;
begin
@@ -332,7 +325,6 @@ begin
opt.dwSize := sizeof(TCompilerOptions);
opt.ShouldAddCompilerVersion := FShouldAddCompilerVersion;
- opt.UseKmcmpLib := FUseKmcmpLib;
Result := SetCompilerOptions(@opt, @CompilerMessageW);
diff --git a/developer/src/test/auto/Makefile b/developer/src/test/auto/Makefile
index 635d933bd104e408c2ffe9ab6ee2b786009cecc8..ebbdf290160a8222ffcdda4a7c821c28bacc7d4b 100644
--- a/developer/src/test/auto/Makefile
+++ b/developer/src/test/auto/Makefile
@@ -26,7 +26,7 @@ developer-tests: \
model-ts-parser \
package-info \
kmc \
- kmc-keyboard \
+ kmc-ldml \
kmc-model \
kmc-model-info \
kmc-package
@@ -87,8 +87,8 @@ kmc: .virtual
cd $(DEVELOPER_ROOT)\src\kmc
$(MAKE) $(TARGET)
-kmc-keyboard: .virtual
- cd $(DEVELOPER_ROOT)\src\kmc-keyboard
+kmc-ldml: .virtual
+ cd $(DEVELOPER_ROOT)\src\kmc-ldml
$(MAKE) $(TARGET)
kmc-model: .virtual
diff --git a/developer/src/tike/compile/keyman32_int.pas b/developer/src/tike/compile/keyman32_int.pas
deleted file mode 100644
index 37ddbe93475c8994379563db135fcb7371618ba7..0000000000000000000000000000000000000000
--- a/developer/src/tike/compile/keyman32_int.pas
+++ /dev/null
@@ -1,108 +0,0 @@
-unit keyman32_int;
-
-interface
-
-uses Windows, SysUtils, Forms;
-
-function Keyman_Initialise(Handle: HWND; FSingleApp: Boolean): Boolean;
-function Keyman_Exit: Boolean;
-function Keyman_ForceKeyboard(const s: string): Boolean;
-function Keyman_StopForcingKeyboard: Boolean;
-
-implementation
-
-uses TikeUtils;
-
-type TKeyman_ForceKeyboard = function (s: PChar): Boolean; stdcall;
-type TKeyman_StopForcingKeyboard = function: Boolean; stdcall;
-type TKeyman_Initialise = function(h: THandle; FSingleApp: LongBool): Boolean; stdcall;
-type TKeyman_Exit = function: Boolean; stdcall;
-
-var
- FInitKeyman: Boolean = False;
- FKeyman32Path: string = '';
-
-function Keyman_Initialise(Handle: HWND; FSingleApp: Boolean): Boolean;
-var
- hkeyman: THandle;
- FLoad: Boolean;
- ki: TKeyman_Initialise;
-begin
- Result := False;
- FLoad := False;
- hkeyman := GetModuleHandle('keyman32.dll');
- if hkeyman = 0 then
- begin
- hkeyman := LoadLibrary(PChar(GetKeymanInstallPath+'keyman32.dll'));
- if hkeyman = 0 then Exit;
- FLoad := True;
- end;
- ki := TKeyman_Initialise(GetProcAddress(hkeyman, 'Keyman_Initialise'));
- if not Assigned(@ki) then Exit;
- if not ki(Handle, FSingleApp) then
- begin
- if FLoad then FreeLibrary(hkeyman);
- Exit;
- end;
-
- FInitKeyman := True;
- Result := True;
-end;
-
-function Keyman_Exit: Boolean;
-var
- hkeyman: THandle;
- ke: TKeyman_Exit;
-begin
- if not FInitKeyman then
- begin
- Result := True;
- Exit;
- end;
- Result := False;
- hkeyman := GetModuleHandle('keyman32.dll');
- if hkeyman = 0 then Exit;
- ke := TKeyman_Exit(GetProcAddress(hkeyman, 'Keyman_Exit'));
- if not Assigned(@ke) then Exit;
- if not ke then Exit;
- if FInitKeyman then FreeLibrary(hkeyman);
- FInitKeyman := False;
- Result := True;
-end;
-
-function Keyman_ForceKeyboard(const s: string): Boolean;
-var
- hkeyman: THandle;
- fk: TKeyman_ForceKeyboard;
-begin
- Result := False;
- hkeyman := GetModuleHandle('keyman32.dll');
- if hkeyman = 0 then
- begin
- if not Keyman_Initialise(Application.MainForm.Handle, True) then Exit;
- hkeyman := GetModuleHandle('keyman32.dll');
- if hkeyman = 0 then Exit;
- end;
- fk := TKeyman_ForceKeyboard(GetProcAddress(hkeyman, 'Keyman_ForceKeyboard'));
- if(Assigned(@fk)) then
- Result := fk(PChar(s));
-end;
-
-function Keyman_StopForcingKeyboard: Boolean;
-var
- hkeyman: THandle;
- sfk: TKeyman_StopForcingKeyboard;
-begin
- Result := False;
- hkeyman := GetModuleHandle('keyman32.dll');
- if hkeyman = 0 then Exit;
- sfk := TKeyman_StopForcingKeyboard(GetProcAddress(hkeyman, 'Keyman_StopForcingKeyboard'));
- if(Assigned(@sfk)) then
- Result := sfk;
- Keyman_Exit;
-end;
-
-initialization
-finalization
- Keyman_Exit;
-end.
diff --git a/developer/src/tike/project/Keyman.Developer.System.Project.kmnProjectFileAction.pas b/developer/src/tike/project/Keyman.Developer.System.Project.kmnProjectFileAction.pas
index 703a1e4a0b6edd891950b647e5240c2e1250f02b..2b6dea94ec580d34adc0c54f471f021683ec3b44 100644
--- a/developer/src/tike/project/Keyman.Developer.System.Project.kmnProjectFileAction.pas
+++ b/developer/src/tike/project/Keyman.Developer.System.Project.kmnProjectFileAction.pas
@@ -115,7 +115,7 @@ begin
TProject.CompilerMessageFile := Self;
options.dwSize := sizeof(COMPILER_OPTIONS);
options.ShouldAddCompilerVersion := addVersion;
- options.UseKmcmpLib := not useLegacyCompiler;
+ // TODO: useLegacyCompiler means we switch to kmcmpdll vs kmc
if not SetCompilerOptions(@options, ProjectCompilerMessage) then
begin
Log(plsFatal, 'Unable to set compiler options', CERR_FATAL, 0);
diff --git a/docs/build/linux-ubuntu.md b/docs/build/linux-ubuntu.md
index 36583d4576d991e7d5c044732ed5e4659f0af6ae..5b576a6ce89f397ca342dda79e58a42ddf81cbea 100644
--- a/docs/build/linux-ubuntu.md
+++ b/docs/build/linux-ubuntu.md
@@ -100,25 +100,33 @@ docker run -it --rm -v $(pwd):/home/build/src/keyman -u root -w /home/build/src/
## Keyman for Android
-**Dependencies**:
+**Dependencies:**
+
* [Base](#base-dependencies)
* [Web](./windows#web-dependencies)
-**Additional requirements**:
+**Additional requirements:**
+
* Android SDK
* [Android Studio](https://developer.android.com/studio/install#linux)
* Gradle
* Maven
* OpenJDK 11 (for Keyman 17.0+)
-
+* pandoc
Run Android Studio once after installation to install additional components
such as emulator images and SDK updates.
-**Required environment variables**:
+**Required environment variable:**
+
+* `ANDROID_HOME` pointing to Android SDK (`$HOME/Android/Sdk`)
+
+**Recommended environment variable:**
+
* [`JAVA_HOME`](#java_home)
Building:
+
* [Building Keyman for Android](../../android/README.md)
## Prerequisites
@@ -127,20 +135,32 @@ Many dependencies are only required for specific projects.
### Base Dependencies
-**Environment variables**:
+**Environment variables:**
+* --
## Notes on Environment Variables
### JAVA_HOME
-This environment variable tells Gradle what version of Java to use for building Keyman for Android.
-OpenJDK 11 is used for master. It's recommended to set the environment variables to:
+This environment variable tells Gradle what version of Java to use for building
+Keyman for Android. OpenJDK 11 is used for master.
+
+It's recommended to set the environment variables to:
+
```bash
-EXPORT JAVA_HOME="[path to OpenJDK 11]"
+export JAVA_HOME="[path to OpenJDK 11]"
```
Also edit `/etc/profile.d/jvm.sh` as sudo:
+
```bash
-EXPORT JAVA_HOME="[path to OpenJDK 11]"
+export JAVA_HOME="[path to OpenJDK 11]"
```
+
+**Multiple versions of Java:** If you need to build Keyman for Android 16.0 or
+older versions, you can set `JAVA_HOME_11` to the OpenJDK 11 path and
+`JAVA_HOME` to the OpenJDK 8 path. This will build both versions correctly
+from command line. But note that you do need to update your `JAVA_HOME` env
+var to the associated version before opening Android Studio and loading any
+Android projects. `JAVA_HOME_11` is mostly used by CI.
diff --git a/docs/linux/keyman-config.md b/docs/linux/keyman-config.md
index f050fd96ad0896b2bf9a83d064884d49dc064045..cfea5d14370a0b0b660c770adb7e1df6d045920c 100644
--- a/docs/linux/keyman-config.md
+++ b/docs/linux/keyman-config.md
@@ -35,10 +35,7 @@ or install it with pip:
pip3 install sentry-sdk
```
-Run the script `./createkeymandirs.sh` to create the directories for these
-programs to install the packages to.
-
-Also copy and compile the GSettings schema:
+Copy and compile the GSettings schema:
```bash
cd keyman_config
@@ -50,15 +47,16 @@ sudo glib-compile-schemas /usr/share/glib-2.0/schemas
Running `km-config` requires a language tag mapping file
`keyman_config/standards/lang_tags_map.py`. This file gets generated during a package
-build, and also when running `make`.
+build, and also when running `build.sh build`.
## Installing manually from the repo
-`make && sudo make install` will install locally to `/usr/local`.
+`linux/keyman-config/build.sh build && sudo linux/keyman-config/build.sh install`
+will install locally to `/usr/local`.
`pip3 help install` will give you more install options.
-To uninstall you can run `sudo make uninstall`.
+To uninstall you can run `sudo linux/keyman-config/build.sh uninstall`.
## Things to run from the command line
diff --git a/docs/linux/packaging.md b/docs/linux/packaging.md
index 91154934b44be5059f04bd4dca47717ea832a7bb..59f16880eb2ef028efe0620a71b1d47c5bd9a51d 100644
--- a/docs/linux/packaging.md
+++ b/docs/linux/packaging.md
@@ -239,7 +239,7 @@ You'll have to create the docker image.
```bash
cd $KEYMAN_ROOT
docker run -v $(pwd):/source -i -t -w /source --platform=linux/amd64 \
- sillsdev/jammy keyman_*.dsc /source
+ sillsdev/jammy jammy keyman_*.dsc
```
This will create the binary packages in `$KEYMAN_ROOT/artifacts`.
diff --git a/docs/npm-packages.md b/docs/npm-packages.md
index 57fbfb839f8ff1b43bc707f025502a863b04ddc0..040a6e11ccf48b052ec0cd51b925666664b53de8 100644
--- a/docs/npm-packages.md
+++ b/docs/npm-packages.md
@@ -13,8 +13,8 @@ Packages are **never** published from a developer's machine.
* `@keymanapp/common-types` -- located at `common/web/types`
* `@keymanapp/keyman-version` -- located at `common/web/keyman-version`
* `@keymanapp/kmc` -- located at `developer/src/kmc`
-* `@keymanapp/kmc-keyboard` -- located at `developer/src/kmc-keyboard`
* `@keymanapp/kmc-kmn` -- located at `developer/src/kmc-kmn`
+* `@keymanapp/kmc-ldml` -- located at `developer/src/kmc-ldml`
* `@keymanapp/kmc-model` -- located at `developer/src/kmc-model`
* `@keymanapp/kmc-model-info` -- located at `developer/src/kmc-model-info`
* `@keymanapp/kmc-package` -- located at `developer/src/kmc-package`
diff --git a/docs/settings/linux/settings.json b/docs/settings/linux/settings.json
index be15b13027d8b8a133b7c310d4ab9ad1160cf6d6..891507dd2ecfc3b11a2ad1eae765934819ac0506 100644
--- a/docs/settings/linux/settings.json
+++ b/docs/settings/linux/settings.json
@@ -107,4 +107,5 @@
"--external-sources --source-path=resources/build/"
],
"C_Cpp.errorSquiggles": "EnabledIfIncludesResolve",
+ "shellcheck.useWorkspaceRootAsCwd": false
}
diff --git a/docs/settings/linux/tasks.json b/docs/settings/linux/tasks.json
index 77df789fe318c41f7099a86255d6476ce05c3658..9728cd709e4f582510b38aca95e5b78a299d9ac9 100644
--- a/docs/settings/linux/tasks.json
+++ b/docs/settings/linux/tasks.json
@@ -158,5 +158,100 @@
"group": "test",
"detail": "unit test keyman-config"
},
+ {
+ "type": "shell",
+ "label": "keyman-system-service: clean",
+ "command": "${workspaceFolder}/linux/keyman-system-service/build.sh",
+ "args": [
+ "--debug",
+ "clean"
+ ],
+ "options": {
+ "cwd": "${workspaceFolder}/linux/keyman-system-service"
+ },
+ "group": "build",
+ "detail": "clean keyman-system-service"
+ },
+ {
+ "type": "shell",
+ "label": "keyman-system-service: build",
+ "command": "${workspaceFolder}/linux/keyman-system-service/build.sh",
+ "args": [
+ "--debug",
+ "build"
+ ],
+ "options": {
+ "cwd": "${workspaceFolder}/linux/keyman-system-service"
+ },
+ "problemMatcher": [
+ {
+ "owner": "cpp",
+ "source": "compiler",
+ "fileLocation": [
+ "relative",
+ "${workspaceFolder}/linux/keyman-system-service/"
+ ],
+ "pattern": [
+ {
+ "regexp": "^../../../(.*):(\\d+):(\\d+):\\s+(warning|error|note):\\s+(.*)(\\s+\\[.*\\])?$",
+ "file": 1,
+ "line": 2,
+ "column": 3,
+ "severity": 4,
+ "message": 5
+ }
+ ]
+ },
+ {
+ "owner": "cpp",
+ "source": "linker",
+ "fileLocation": "absolute",
+ "pattern": [
+ {
+ "regexp": "^(/usr/bin/ld:\\s+)?(.*):(\\d+):\\s+(.*)$",
+ "file": 2,
+ "location": 3,
+ "message": 4
+ }
+ ]
+ }
+ ],
+ "presentation": {
+ "clear": true
+ },
+ "group": "build",
+ "detail": "build keyman-system-service"
+ },
+ {
+ "type": "shell",
+ "label": "keyman-system-service: configure",
+ "command": "${workspaceFolder}/linux/keyman-system-service/build.sh",
+ "args": [
+ "--debug",
+ "configure"
+ ],
+ "options": {
+ "cwd": "${workspaceFolder}/linux/keyman-system-service",
+ },
+ "presentation": {
+ "clear": true
+ },
+ "group": "build",
+ "detail": "configure keyman-system-service"
+ },
+ {
+ "type": "shell",
+ "label": "keyman-system-service: test",
+ "command": "${workspaceFolder}/linux/keyman-system-service/build.sh",
+ "args": [
+ "--debug",
+ "test:arch"
+ ],
+ "problemMatcher": [
+ "$gcc"
+ ],
+ "group": "test",
+ "detail": "run tests for keyman-system-service"
+ },
]
}
diff --git a/ios/Cartfile b/ios/Cartfile
index 5ad8178ed48a4e7ad28589d41fe9ed382617a5c9..b265ef77af28f9f7d45032ba8f753477057e456f 100644
--- a/ios/Cartfile
+++ b/ios/Cartfile
@@ -1,5 +1,5 @@
github "marmelroy/Zip"
-github "DaveWoodCom/XCGLogger" ~> 6.1.0
+github "keymanapp/dependency-XCGLogger" "master"
github "devicekit/DeviceKit" ~> 5.0
github "ashleymills/Reachability.swift"
-github "getsentry/sentry-cocoa" ~> 6.2.1
+github "getsentry/sentry-cocoa" ~> 8.7.0
diff --git a/ios/Cartfile.resolved b/ios/Cartfile.resolved
index fe74a57322bc07d42adfbf6539596e6ad6035902..ff30a8871ddc681497e00c68287eb34808d94541 100644
--- a/ios/Cartfile.resolved
+++ b/ios/Cartfile.resolved
@@ -1,5 +1,5 @@
-github "DaveWoodCom/XCGLogger" "6.1.0"
github "ashleymills/Reachability.swift" "v5.1.0"
github "devicekit/DeviceKit" "5.0.0"
-github "getsentry/sentry-cocoa" "6.2.1"
+github "getsentry/sentry-cocoa" "8.7.0"
+github "keymanapp/dependency-XCGLogger" "57a7b975dbb6fe4fe90cef3d1bc52b8adbd89113"
github "marmelroy/Zip" "2.1.2"
diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Errors/SentryManager.swift b/ios/engine/KMEI/KeymanEngine/Classes/Errors/SentryManager.swift
index 127fcd12b5bd2b4fb8d900586073e0ab94971bcc..94f988507606db6fe75025f89cc91045ecc8ffd0 100644
--- a/ios/engine/KMEI/KeymanEngine/Classes/Errors/SentryManager.swift
+++ b/ios/engine/KMEI/KeymanEngine/Classes/Errors/SentryManager.swift
@@ -167,7 +167,7 @@ public class SentryManager {
public static func breadcrumbAndLog(crumb: Sentry.Breadcrumb, logLevel: XCGLogger.Level? = nil) {
// Guarded in case a library consumer decides against initializing Sentry.
if _started {
- SentrySDK.addBreadcrumb(crumb: crumb)
+ SentrySDK.addBreadcrumb(crumb)
}
let level = logLevel ?? mapLoggingLevel(crumb.level)
@@ -193,7 +193,7 @@ public class SentryManager {
}
public static func forceError() {
- SentrySDK.addBreadcrumb(crumb: Sentry.Breadcrumb(level: .info, category: "Deliberate testing error"))
+ SentrySDK.addBreadcrumb(Sentry.Breadcrumb(level: .info, category: "Deliberate testing error"))
SentrySDK.crash()
}
}
diff --git a/ios/tools/prepRelease.sh b/ios/tools/prepRelease.sh
index 1f22de45f096ec4a11cd41dc7fa14de36b423f7d..39b46722f79c973bee51d128192bfac1cc647c6f 100755
--- a/ios/tools/prepRelease.sh
+++ b/ios/tools/prepRelease.sh
@@ -70,17 +70,17 @@ KEYMAN_SAMPLES="samples"
echo "engine dest: $KMEI_DST"
-echo "Zipping ${UNI_FRAMEWORK} => ${UPLOAD_DIR}/${KMEI_DST}..."
+echo "Zipping ${FRAMEWORK} => ${UPLOAD_DIR}/${KMEI_DST}..."
cd "${KMEI_FRAMEWORK_BASE}"
-zip -qrX ${KMEI_DST} ${FRAMEWORK}
-cd $WORK_DIR
+zip -qrX "${KMEI_DST}" ${FRAMEWORK}
+cd "$WORK_DIR"
echo "Copying Keyman Engine samples into ${UPLOAD_DIR}/${KMEI_DST_NAME}..."
cp -rf "${KEYMAN_SAMPLES}" "${UPLOAD_DIR}/samples"
cd "${UPLOAD_DIR}"
zip -qr "${KMEI_DST_NAME}" "samples"
rm -rf "samples"
-cd $WORK_DIR
+cd "$WORK_DIR"
#
# Keyman app
diff --git a/linux/.gitignore b/linux/.gitignore
index 478f418b608e52d3898a613528475097a4d10e4d..0abbd99c585433153b15c9eca0fd5e604ebb33d2 100644
--- a/linux/.gitignore
+++ b/linux/.gitignore
@@ -17,7 +17,7 @@ dist/
upload/
launchpad
launchpad-*
-keyman-config/build
+build/
keyman-config/debian/man
keyman-config/experiments/*.txt
keyman-config/keyman_config/version.py
diff --git a/linux/Jenkinsfile b/linux/Jenkinsfile
index 15f5b27777d79d4442b63efac7d1d1650aa606f4..b70cb95d706cfc3c24ccf6e90a242f407d74ccae 100644
--- a/linux/Jenkinsfile
+++ b/linux/Jenkinsfile
@@ -5,7 +5,7 @@
@Library('lsdev-pipeline-library') _
keymanPackaging {
- distributionsToPackage = 'focal jammy kinetic'
+ distributionsToPackage = 'focal jammy kinetic lunar'
arches = 'amd64 i386'
packagesToBuild = ['keyman']
}
diff --git a/linux/build.sh b/linux/build.sh
index f0aaff70d57fd0652c942c611a864975d1f87662..6c7a92069b3b11bd1f1032e88e6db28fd03b5317 100755
--- a/linux/build.sh
+++ b/linux/build.sh
@@ -14,7 +14,9 @@ cd "$THIS_SCRIPT_PATH"
builder_describe \
"Build Keyman for Linux." \
- ":engine=ibus-keyman ibus-keyman" \
+ ":config=keyman-config keyman-config" \
+ ":engine=ibus-keyman ibus-keyman" \
+ ":service=keyman-system-service keyman-system-service" \
"clean" \
"configure" \
"build" \
diff --git a/linux/debian/com.keyman.config.appdata.xml b/linux/debian/com.keyman.config.appdata.xml
index f137be461df2923d2b9d3d197e7fd306d808e46e..9df49a37dc3a0500bbd40533c2ef608e4c3da5f0 100644
--- a/linux/debian/com.keyman.config.appdata.xml
+++ b/linux/debian/com.keyman.config.appdata.xml
@@ -14,8 +14,8 @@
Keyman makes it possible for you to type in over 2,000 languages on Windows, macOS, Linux,
iPhone, iPad, Android tablets and phones, and even instantly in your web browser. With the
-world’s most powerful keyboarding engine, intuitive and rapid text input is now possible in
-your language, and for over 99% of the global population’s mother tongues!
+world's most powerful keyboarding engine, intuitive and rapid text input is now possible in
+your language, and for over 99% of the global population's mother tongues!
Originally created in 1993 to type Lao on Windows, Keyman is now a free and
@@ -40,7 +40,7 @@ and mobile platforms.
The Keyman for Linux configuration window with a keyboard welcome window.
- https://keyman.com/go/linux/11.0/linux-configuration.png
+ https://keyman.com/go/linux/17.0/linux-configuration.png
diff --git a/linux/debian/com.keyman.ibus_keyman.metainfo.xml b/linux/debian/com.keyman.ibus_keyman.metainfo.xml
index eb02001da0d2a355fc4fe4dcbc5f2b97bbc54ec0..1f021d2fce346c76b90b38512af83d3cfc737b0e 100644
--- a/linux/debian/com.keyman.ibus_keyman.metainfo.xml
+++ b/linux/debian/com.keyman.ibus_keyman.metainfo.xml
@@ -1,39 +1,39 @@
- com.keyman.ibus_keyman
- MIT
+ com.keyman.ibus_keyman
+ MIT
GPL-2+
Keyman
SIL International
https://keyman.com/cdn/dev/img/keyman-logo.png
- ibus-keyman
- Keyman input method for IBus
-
-
- This input method provides the Keyman IM engine for IBus. With this module, you can
- use keyboard layouts designed for Keyman under the IBus platform.
-
-
- Originally created in 1993 to type Lao on Windows, Keyman is now a free and
- open source keyboarding platform which allows anyone to write a keyboard layout
- for their language. Keyman is available for many platforms, including Windows,
- macOS, iOS, Android, Linux and the web.
-
+ ibus-keyman
+ Keyman input method for IBus
+
- Keyboard layouts are defined with a clear and easy to understand keyboard
- grammar. Keyman's contextual input model means keyboard layouts can be
- intelligent and make it simple to type even the most complex languages.
- Keyboard layouts are distributed through an open catalog to all major desktop
- and mobile platforms.
+ This input method provides the Keyman IM engine for IBus. With this module, you can
+ use keyboard layouts designed for Keyman under the IBus platform.
+
+
+ Originally created in 1993 to type Lao on Windows, Keyman is now a free and
+ open source keyboarding platform which allows anyone to write a keyboard layout
+ for their language. Keyman is available for many platforms, including Windows,
+ macOS, iOS, Android, Linux and the web.
+
+
+ Keyboard layouts are defined with a clear and easy to understand keyboard
+ grammar. Keyman's contextual input model means keyboard layouts can be
+ intelligent and make it simple to type even the most complex languages.
+ Keyboard layouts are distributed through an open catalog to all major desktop
+ and mobile platforms.
+
+
+ Input methods are typing systems allowing users to input complex languages.
-
- Input methods are typing systems allowing users to input complex languages.
-
-
+
https://keyman.com/linux/
https://github.com/keymanapp/keyman/issues
https://help.keyman.com/
https://community.software.sil.org/c/keyman
https://donate.keyman.com/
-
+
diff --git a/linux/debian/control b/linux/debian/control
index 40b2065d7f7fb9292ce55170977ec5e758471b59..624f89fc0adc2e8a0406377363f5c70d14a5531b 100644
--- a/linux/debian/control
+++ b/linux/debian/control
@@ -28,10 +28,12 @@ Build-Depends:
python3-setuptools,
meson (>= 0.53),
ninja-build,
+ libevdev-dev,
libgtk-3-dev,
libicu-dev,
libibus-1.0-dev (>= 1.2),
libjson-glib-dev (>= 1.4.0),
+ libsystemd-dev,
pkg-config,
xserver-xephyr,
xvfb,
@@ -56,9 +58,9 @@ Recommends:
Description: Type in your language with Keyman for Linux
Keyman makes it possible for you to type in over 2,000 languages on Windows,
macOS, Linux, iPhone, iPad, Android tablets and phones, and even instantly
- in your web browser. With the world’s most powerful keyboarding engine,
+ in your web browser. With the world's most powerful keyboarding engine,
intuitive and rapid text input is now possible in your language, and for
- over 99% of the global population’s mother tongues!
+ over 99% of the global population's mother tongues!
.
Originally created in 1993 to type Lao on Windows, Keyman is now a free and
open source keyboarding platform which allows anyone to write a keyboard
@@ -160,6 +162,7 @@ Architecture: amd64 arm64 armel armhf i386 mipsel mips64el ppc64el riscv64
Depends:
ibus (>= 1.3.7),
libkmnkbp0-0 (= ${binary:Version}),
+ keyman-system-service (= ${binary:Version}),
${misc:Depends},
${shlibs:Depends},
Provides:
@@ -181,3 +184,24 @@ Description: Keyman engine for IBus
.
This package provides the Keyman IM engine for IBus. With this module, you
can use keyboard layouts designed for Keyman under the IBus platform.
+
+Package: keyman-system-service
+Architecture: any
+Depends:
+ libevdev2,
+ ${misc:Depends},
+ ${shlibs:Depends},
+Description: System service for Keyman
+ Originally created in 1993 to type Lao on Windows, Keyman is now a free and
+ open source keyboarding platform which allows anyone to write a keyboard
+ layout for their language. Keyman is available for many platforms, including
+ Windows, macOS, iOS, Android, Linux and the web.
+ .
+ Keyboard layouts are defined with a clear and easy to understand keyboard
+ grammar. Keyman's contextual input model means keyboard layouts can be
+ intelligent and make it simple to type even the most complex languages.
+ Keyboard layouts are distributed through an open catalog to all major desktop
+ and mobile platforms.
+ .
+ This package provides a DBus/systemd system service as a helper for
+ running Keyman with Wayland.
diff --git a/linux/debian/ibus-keyman.postinst b/linux/debian/ibus-keyman.postinst
index 4143effb61526534dedaf9110b5376235bc60d26..6cff5c525c0b8ae1c5c0d4c064cf9aa8210c9cd2 100644
--- a/linux/debian/ibus-keyman.postinst
+++ b/linux/debian/ibus-keyman.postinst
@@ -1,7 +1,7 @@
-#!/bin/sh
+#!/bin/bash
-# Don't call `set -e`. Even if some commands should fail, it's still
-# worth running the rest of the commands.
+# Exit on errors - Debian policy 10.4
+set -e
case "$1" in
@@ -12,7 +12,7 @@ case "$1" in
if which sudo > /dev/null && which ps > /dev/null; then
# check for gnome-shell as it works differently
- gspid=$(ps -C gnome-shell -o pid=|head -n 1)
+ ! gspid=$(ps -C gnome-shell -o pid=|head -n 1)
if [ "$gspid" != "" ]; then
# gnome-shell has multiple ibus-daemon processes and needs exit instead of restart
is_gnome_shell=1
@@ -21,7 +21,7 @@ case "$1" in
fi
# Restart IBus if it is running
- ibuspid=$(ps -C ibus-daemon -o pid=|head -n 1)
+ ! ibuspid=$(ps -C ibus-daemon -o pid=|head -n 1)
if [ "$ibuspid" != "" ]; then
if [ "$is_gnome_shell" = "1" ]; then
@@ -41,7 +41,7 @@ case "$1" in
# Verify that it's running now
if [ -n "$SUDO_USER" ] && id "$SUDO_USER" > /dev/null 2>/dev/null; then
- ibusdaemon=$(ps --user "$SUDO_USER" -o s= -o cmd | grep --regexp="^[^ZT] \(/usr/bin/\)\?ibus-daemon .*--xim.*")
+ ! ibusdaemon=$(ps --user "$SUDO_USER" -o s= -o cmd | grep --regexp="^[^ZT] \(/usr/bin/\)\?ibus-daemon .*--xim.*")
if [ "$ibusdaemon" = "" ]; then
# otherwise try to start it for the user installing the package
if [ "$is_gnome_shell" = "1" ]; then
diff --git a/linux/debian/keyman-system-service.install b/linux/debian/keyman-system-service.install
new file mode 100644
index 0000000000000000000000000000000000000000..f7ce93bd82b3a8f77baee2d76a13124ba317500f
--- /dev/null
+++ b/linux/debian/keyman-system-service.install
@@ -0,0 +1,5 @@
+usr/lib/systemd/system/systemd-keyman.service
+usr/libexec/keyman-system-service
+usr/share/dbus-1/interfaces/com.keyman.SystemService1.System.xml
+usr/share/dbus-1/system-services/com.keyman.SystemService1.service
+usr/share/dbus-1/system.d/com.keyman.SystemService1.conf
diff --git a/linux/debian/keyman-system-service.manpages b/linux/debian/keyman-system-service.manpages
new file mode 100644
index 0000000000000000000000000000000000000000..cb4d9f0500ee07505ba9e3e6271904dda002f802
--- /dev/null
+++ b/linux/debian/keyman-system-service.manpages
@@ -0,0 +1 @@
+linux/keyman-system-service/man/keyman-system-service.1
diff --git a/linux/debian/keyman.install b/linux/debian/keyman.install
index 8096e324aec4be58e43a6b10dc081bca41c79ad1..a036eb8a7361535fe2db5b3b2e7f1065c50656c2 100644
--- a/linux/debian/keyman.install
+++ b/linux/debian/keyman.install
@@ -1,4 +1,3 @@
-linux/keyman-config/com.keyman.gschema.xml usr/share/glib-2.0/schemas/
linux/keyman-config/icons/128/km-config.png usr/share/icons/hicolor/128x128/apps/
linux/keyman-config/icons/16/application-x-kmp.png usr/share/icons/hicolor/16x16/mimetypes/
linux/keyman-config/icons/24/application-x-kmp.png usr/share/icons/hicolor/24x24/mimetypes/
@@ -10,5 +9,6 @@ linux/keyman-config/icons/48/km-config.png usr/share/icons/hicolor/48x48/apps/
linux/keyman-config/icons/64/application-x-kmp.png usr/share/icons/hicolor/64x64/mimetypes/
linux/keyman-config/icons/64/km-config.png usr/share/icons/hicolor/64x64/apps/
linux/keyman-config/keyman_config/icons/* usr/share/keyman/icons/
-linux/keyman-config/km-config.desktop usr/share/applications
+linux/keyman-config/resources/com.keyman.gschema.xml usr/share/glib-2.0/schemas/
+linux/keyman-config/resources/km-config.desktop usr/share/applications
debian/com.keyman.config.appdata.xml usr/share/metainfo
diff --git a/linux/debian/rules b/linux/debian/rules
index e67ea1b5af5d2067f7b93a324564b00ee7971476..ec9178298cac3a121e8f353e8c8337d6b0ec5c2c 100755
--- a/linux/debian/rules
+++ b/linux/debian/rules
@@ -9,6 +9,10 @@ export PYBUILD_INSTALL_ARGS=--install-scripts=/usr/share/keyman-config/
export KEYMAN_PKG_BUILD=1
+export HOME=$(shell mktemp -d)
+export XDG_DATA_HOME=$(shell mktemp -d)
+export XDG_CONFIG_HOME=$(shell mktemp -d)
+
# xenial needs this to be explicit
export LC_ALL=C.UTF-8
@@ -22,57 +26,48 @@ include /usr/share/dpkg/pkg-info.mk
override_dh_auto_configure:
# keymankeyboardprocessor - we need to configure and build core before
# we can configure ibus-keyman!
- cd core && \
- ./build.sh --no-tests configure:arch build:arch -- --wrap-mode=nodownload --prefix=/usr --sysconfdir=/etc \
- --localstatedir=/var --libdir=lib/$(DEB_TARGET_MULTIARCH) \
- --libexecdir=lib/$(DEB_TARGET_MULTIARCH)
- # ibus-keyman
- cd linux/ibus-keyman && \
- ./build.sh configure -- --wrap-mode=nodownload --prefix=/usr --sysconfdir=/etc \
- --localstatedir=/var
- # keyman-config
+ core/build.sh --no-tests configure:arch build:arch -- \
+ --wrap-mode=nodownload --prefix=/usr --sysconfdir=/etc \
+ --localstatedir=/var --libdir=lib/$(DEB_TARGET_MULTIARCH) \
+ --libexecdir=lib/$(DEB_TARGET_MULTIARCH)
+ linux/ibus-keyman/build.sh configure -- \
+ --wrap-mode=nodownload --prefix=/usr --sysconfdir=/etc --localstatedir=/var
+ linux/keyman-system-service/build.sh configure -- \
+ --wrap-mode=nodownload --prefix=/usr --sysconfdir=/etc --localstatedir=/var
+ linux/keyman-config/build.sh configure
override_dh_auto_build:
- # keymankeyboardprocessor
- cd core && \
- ./build.sh --no-tests build:arch
- # ibus-keyman
- cd linux/ibus-keyman && \
- ./build.sh build
- # keyman-config
+ cp linux/keyman-config/resources/keyman.sharedmimeinfo debian/
+ core/build.sh --no-tests build:arch
+ linux/ibus-keyman/build.sh build
+ linux/keyman-system-service/build.sh build
+ linux/keyman-config/build.sh build
cd linux/keyman-config && \
- make man && \
sed -i -e "s/^__pkgversion__ = \"[^\"]*\"/__pkgversion__ = \"$(DEB_VERSION)\"/g" keyman_config/version.py && \
make compile-po
- dh_auto_build --sourcedir=linux/keyman-config --buildsystem=pybuild $@
override_dh_auto_test:
ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
- # keymankeyboardprocessor
- cd core && \
- ./build.sh --no-tests test:arch
- # ibus-keyman
- cd linux/ibus-keyman && \
- ./build.sh test
- # keyman-config
- dh_auto_test --sourcedir=linux/keyman-config --buildsystem=pybuild $@
+ core/build.sh --no-tests test:arch
+ linux/ibus-keyman/build.sh test
+ linux/keyman-system-service/build.sh test
+ linux/keyman-config/build.sh test
endif
override_dh_auto_install:
install -d $(CURDIR)/debian/tmp
- cd core && \
- DESTDIR=$(CURDIR)/debian/tmp ./build.sh --no-tests install:arch
- # ibus-keyman
- cd linux/ibus-keyman && \
- DESTDIR=$(CURDIR)/debian/tmp ./build.sh install
+ DESTDIR=$(CURDIR)/debian/tmp core/build.sh --no-tests install:arch
+ DESTDIR=$(CURDIR)/debian/tmp linux/ibus-keyman/build.sh install
+ DESTDIR=$(CURDIR)/debian/tmp linux/keyman-system-service/build.sh install
# keyman-config
install -d $(CURDIR)/debian/keyman/usr/share/
cp -r linux/keyman-config/locale/ $(CURDIR)/debian/keyman/usr/share/
rm $(CURDIR)/debian/keyman/usr/share/locale/*.po*
+ # Don't call `build.sh install` - dh_auto_install does some extra smarts
dh_auto_install --sourcedir=linux/keyman-config --buildsystem=pybuild $@
# Unfortunately bash-completion 2.10 (focal) doesn't yet provide dh-sequence-bash-completion,
# which we could add as build-dependency, so we'll have to explicitly call
- # dh_bash_completion here...
+ # dh_bash_completion here instead of using `dh $@ --with-python3 --with bash-completion`
dh_bash-completion -O--buildsystem=pybuild
dh_python3 -O--buildsystem=pybuild
diff --git a/linux/help/reference/index.md b/linux/help/reference/index.md
index 1089382c55113e46bb4d2a9b44af18f940653220..7b8f704018f0f0b1b7090300f678e63592fa5f5c 100644
--- a/linux/help/reference/index.md
+++ b/linux/help/reference/index.md
@@ -1,8 +1,8 @@
---
-title: Keyman 16.0 for Linux Reference
+title: Keyman 17.0 for Linux Reference
---
-## Keyman 16.0 for Linux Overview
+## Keyman 17.0 for Linux Overview
Keyman for Linux makes it possible for you to type in over 2,000 languages on Linux.
diff --git a/linux/ibus-keyman/build.sh b/linux/ibus-keyman/build.sh
index a73a720924d9fc0312b30fac491d050078d9cca2..8a16bbb1deafe1f08024fd91c3174f5429d35068 100755
--- a/linux/ibus-keyman/build.sh
+++ b/linux/ibus-keyman/build.sh
@@ -37,8 +37,7 @@ cd "$THIS_SCRIPT_PATH"
builder_describe_outputs \
configure "${MESON_PATH}/build.ninja" \
- build "${MESON_PATH}/src/ibus-engine-keyman" \
- build "${MESON_PATH}/tests/ibus-keyman-tests"
+ build "${MESON_PATH}/src/ibus-engine-keyman"
if builder_start_action clean; then
rm -rf "$THIS_SCRIPT_PATH/../build/"
diff --git a/linux/ibus-keyman/meson.build b/linux/ibus-keyman/meson.build
index e8548432d4234201853fe8bcfcce2079ddfe35fd..e4b31df7dbd59d02c6c790d8b9285d8cb42daf7b 100644
--- a/linux/ibus-keyman/meson.build
+++ b/linux/ibus-keyman/meson.build
@@ -9,16 +9,16 @@ project('ibus-keyman', 'c', 'cpp',
cc = meson.get_compiler('c')
conf = configuration_data()
-ibus = dependency('ibus-1.0', version: '>= 1.2.0')
-gtk = dependency('gtk+-3.0', version: '>= 2.4')
-x11 = dependency('x11', version: '>= 1.6')
-json_glib = dependency('json-glib-1.0', version: '>= 1.0')
+ibus = dependency('ibus-1.0', version: '>= 1.2.0')
+gtk = dependency('gtk+-3.0', version: '>= 2.4')
+json_glib = dependency('json-glib-1.0', version: '>= 1.0')
+systemd = dependency('libsystemd')
core_dir = meson.current_source_dir() / '../../core'
common_dir = meson.current_source_dir() / '../../common'
kmnkbp_lib = cc.find_library(
- 'libkmnkbp0',
+ 'kmnkbp0', # meson will prefix 'lib'
dirs: [ core_dir / 'build/arch' / get_option('buildtype') / 'src' ]
)
diff --git a/linux/ibus-keyman/src/KeymanSystemServiceClient.cpp b/linux/ibus-keyman/src/KeymanSystemServiceClient.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..90f459d1a21e853e0f5509756822c4292e2fd299
--- /dev/null
+++ b/linux/ibus-keyman/src/KeymanSystemServiceClient.cpp
@@ -0,0 +1,106 @@
+#include
+#include
+#include "KeymanSystemServiceClient.h"
+
+#define KEYMAN_BUS_NAME "com.keyman.SystemService1"
+#define KEYMAN_INTERFACE_NAME "com.keyman.SystemService1.System"
+#define KEYMAN_OBJECT_PATH "/com/keyman/SystemService1/System"
+
+extern gboolean testing;
+
+class KeymanSystemServiceClient {
+private:
+ sd_bus_error *error = NULL;
+ sd_bus_message *msg = NULL;
+ sd_bus *bus = NULL;
+
+public:
+ KeymanSystemServiceClient();
+ ~KeymanSystemServiceClient();
+
+ void SetCapsLockIndicator(guint32 capsLock);
+ gint32 GetCapsLockIndicator();
+};
+
+KeymanSystemServiceClient::KeymanSystemServiceClient() {
+ int result;
+ if (testing) {
+ result = sd_bus_open_user(&bus);
+ } else {
+ result = sd_bus_default_system(&bus);
+ }
+ if (result < 0) {
+ g_error("%s: Can't get connection: %s", __FUNCTION__, strerror(-result));
+ }
+}
+
+KeymanSystemServiceClient::~KeymanSystemServiceClient() {
+ if (error) { sd_bus_error_free(error); }
+ if (msg) { sd_bus_message_unref(msg); }
+ if (bus) { sd_bus_unref(bus); }
+}
+
+void KeymanSystemServiceClient::SetCapsLockIndicator(guint32 capsLock) {
+ // If Set/GetCapsLockIndicator is called more than once and previously
+ // failed, we will leak `error`.
+ assert(error == NULL);
+
+ if (!bus) {
+ // we already reported the error, so just return
+ return;
+ }
+
+ if (capsLock > 1) {
+ g_error("%s: Invalid value '%d' for parameter capsLock", __FUNCTION__, capsLock);
+ return;
+ }
+
+ int result = sd_bus_call_method(bus, KEYMAN_BUS_NAME, KEYMAN_OBJECT_PATH,
+ KEYMAN_INTERFACE_NAME, "SetCapsLockIndicator", error, &msg, "b", capsLock);
+ if (result < 0) {
+ g_error("%s: Failed to call method SetCapsLockIndicator: %s. %s. %s.",
+ __FUNCTION__, strerror(-result), error->name, error->message);
+ return;
+ }
+}
+
+gint32 KeymanSystemServiceClient::GetCapsLockIndicator() {
+ // If Set/GetCapsLockIndicator is called more than once and previously
+ // failed, we will leak `error`.
+ assert(error == NULL);
+
+ if (!bus) {
+ // we already reported the error, so just return
+ return -1;
+ }
+
+ int result = sd_bus_call_method(bus, KEYMAN_BUS_NAME, KEYMAN_OBJECT_PATH,
+ KEYMAN_INTERFACE_NAME, "GetCapsLockIndicator", error, &msg, "");
+ if (result < 0) {
+ g_error("%s: Failed to call method GetCapsLockIndicator: %s. %s. %s.",
+ __FUNCTION__, strerror(-result), error->name, error->message);
+ return -1;
+ }
+
+ guint32 capsLock = 0;
+ result = sd_bus_message_read(msg, "b", &capsLock);
+ if (result < 0) {
+ g_error("%s: Failed to parse response message: %s",
+ __FUNCTION__, strerror(-result));
+ return -1;
+ }
+
+ return capsLock;
+}
+
+void set_capslock_indicator(
+ guint32 capsLock
+) {
+ KeymanSystemServiceClient client;
+ client.SetCapsLockIndicator(capsLock);
+}
+
+gint32 get_capslock_indicator() {
+ KeymanSystemServiceClient client;
+ return client.GetCapsLockIndicator();
+}
diff --git a/linux/ibus-keyman/src/KeymanSystemServiceClient.h b/linux/ibus-keyman/src/KeymanSystemServiceClient.h
new file mode 100644
index 0000000000000000000000000000000000000000..746974df5194e43fca411ef8081fdae8f6a0b9ae
--- /dev/null
+++ b/linux/ibus-keyman/src/KeymanSystemServiceClient.h
@@ -0,0 +1,17 @@
+#ifndef __KEYMANSYSTEMSERVICECLIENT_H__
+#define __KEYMANSYSTEMSERVICECLIENT_H__
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void set_capslock_indicator(guint32 capsLockState);
+gint32 get_capslock_indicator();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __KEYMANSYSTEMSERVICECLIENT_H__
diff --git a/linux/ibus-keyman/src/engine.c b/linux/ibus-keyman/src/engine.c
index b7699f55623e46ac7f84f95697768d0ca141e401..49b9161f9a3f766786a8f60014470f4e2ba0a057 100644
--- a/linux/ibus-keyman/src/engine.c
+++ b/linux/ibus-keyman/src/engine.c
@@ -3,7 +3,7 @@
/*
* Keyman Input Method for IBUS (The Input Bus)
*
- * Copyright (C) 2009-2022 SIL International
+ * Copyright (C) 2009-2023 SIL International
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
@@ -28,21 +28,13 @@
#include
#include
-#ifdef GDK_WINDOWING_X11
-#include
-#include
-#endif
-
-#ifdef GDK_WINDOWING_WAYLAND
-#include
-#endif
-
#include
#include
#include "config.h"
#include "keymanutil.h"
#include "keyman-service.h"
+#include "KeymanSystemServiceClient.h"
#include "engine.h"
#include "keycodes.h"
@@ -90,12 +82,6 @@ struct _IBusKeymanEngine {
IBusLookupTable *table;
IBusProperty *status_prop;
IBusPropList *prop_list;
-#ifdef GDK_WINDOWING_X11
- Display *xdisplay;
-#endif
-#ifdef GDK_WINDOWING_WAYLAND
- GdkWaylandDisplay *wldisplay;
-#endif
commit_queue_item commit_queue[MAX_QUEUE_SIZE];
commit_queue_item *commit_item;
@@ -311,29 +297,6 @@ ibus_keyman_engine_init(IBusKeymanEngine *keyman) {
ibus_prop_list_append(keyman->prop_list, keyman->status_prop);
keyman->state = NULL;
-#ifdef GDK_WINDOWING_X11
- keyman->xdisplay = NULL;
-#endif
-#ifdef GDK_WINDOWING_WAYLAND
- keyman->wldisplay = NULL;
-#endif
-
- GdkDisplay *gdkDisplay = gdk_display_get_default();
-#ifdef GDK_WINDOWING_X11
- if (GDK_IS_X11_DISPLAY(gdkDisplay)) {
- g_debug("Using X11");
- keyman->xdisplay = GDK_DISPLAY_XDISPLAY(gdkDisplay);
- } else
-#endif
-#ifdef GDK_WINDOWING_WAYLAND
- if (GDK_IS_WAYLAND_DISPLAY(gdkDisplay)) {
- g_debug("Using Wayland");
- keyman->wldisplay = GDK_WAYLAND_DISPLAY(gdkDisplay);
- } else
-#endif
- {
- g_error("unsupported GDK backend");
- }
}
static km_kbp_cp* get_base_layout()
@@ -752,19 +715,7 @@ process_capslock_action(
) {
g_message("%s: %s caps-lock", __FUNCTION__, action_item->capsLock ? "Enable" : "Disable");
-#ifdef GDK_WINDOWING_X11
- if (keyman->xdisplay) {
- XkbLockModifiers(keyman->xdisplay, XkbUseCoreKbd, LockMask, action_item->capsLock ? LockMask : 0);
-
- XSync(keyman->xdisplay, False);
- }
-#endif
-#ifdef GDK_WINDOWING_WAYLAND
- // TODO
- if (keyman->wldisplay) {
-
- }
-#endif
+ set_capslock_indicator(action_item->capsLock);
return TRUE;
}
diff --git a/linux/ibus-keyman/src/kmpdetails.c b/linux/ibus-keyman/src/kmpdetails.c
index a6b7fbb18906326405f92f843fd3a84ddffeca77..eba95f4ef9752d4ce3b2c3fcd00480b068631e17 100644
--- a/linux/ibus-keyman/src/kmpdetails.c
+++ b/linux/ibus-keyman/src/kmpdetails.c
@@ -272,9 +272,6 @@ kmp_json_status get_keyboard_details(const char *kmp_dir, const char *id, keyboa
}
g_object_unref(parser);
return JSON_OK;
-
-
-
}
kmp_json_status get_kmp_details(const char *kmp_dir, kmp_details *details)
@@ -295,7 +292,6 @@ kmp_json_status get_kmp_details(const char *kmp_dir, kmp_details *details)
return JSON_FILE_NOT_EXISTS;
}
-
json_parser_load_from_file (parser,
kmp_json,
&error);
diff --git a/linux/ibus-keyman/src/main.c b/linux/ibus-keyman/src/main.c
index f791cb45640db610194765626ed3fb36c4a307c0..4252fa93e8953ee01ca55fc732cc21db2f4b5e8c 100644
--- a/linux/ibus-keyman/src/main.c
+++ b/linux/ibus-keyman/src/main.c
@@ -36,12 +36,14 @@ static IBusFactory *factory = NULL;
static gboolean xml = FALSE;
static gboolean ibus = FALSE;
static gboolean verbose = FALSE;
+gboolean testing = FALSE;
static const GOptionEntry entries[] =
{
{ "xml", 'x', 0, G_OPTION_ARG_NONE, &xml, "generate xml for engines", NULL },
{ "ibus", 'i', 0, G_OPTION_ARG_NONE, &ibus, "component is executed by ibus", NULL },
{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "verbose", NULL },
+ { "testing", 0, 0, G_OPTION_ARG_NONE, &testing, "component is executed by integration testing", NULL},
{ NULL },
};
diff --git a/linux/ibus-keyman/src/meson.build b/linux/ibus-keyman/src/meson.build
index 29f265290d51ab76130db7f37d03c4c435cfb1c0..2e83a6510650099ea69dd3686687f137ba52ddfb 100644
--- a/linux/ibus-keyman/src/meson.build
+++ b/linux/ibus-keyman/src/meson.build
@@ -1,17 +1,13 @@
util_files = files(
'keymanutil.c',
- 'keymanutil.h',
'kmpdetails.c',
- 'kmpdetails.h',
)
engine_files = files(
'main.c',
'engine.c',
- 'engine.h',
- 'keycodes.h',
'keyman-service.c',
- 'keyman-service.h',
+ 'KeymanSystemServiceClient.cpp',
)
include_dirs = [
@@ -20,7 +16,7 @@ include_dirs = [
include_directories(meson.current_build_dir() / '..'),
]
-deps = [ibus, gtk, x11, json_glib, kmnkbp_lib]
+deps = [ibus, gtk, json_glib, kmnkbp_lib, systemd]
prefix = get_option('prefix')
cfg = configuration_data()
diff --git a/linux/ibus-keyman/src/test/meson.build b/linux/ibus-keyman/src/test/meson.build
index c652d8f783f7bbe0be8aa3201bc388d725305f77..7e5cd21dbeab533bd4597326efbaf805e5ce1dc7 100644
--- a/linux/ibus-keyman/src/test/meson.build
+++ b/linux/ibus-keyman/src/test/meson.build
@@ -3,7 +3,7 @@ keymanutil_sources = [
util_files,
]
-keymanutil_deps = [ibus, gtk, x11, json_glib, kmnkbp_lib]
+keymanutil_deps = [ibus, gtk, json_glib, kmnkbp_lib]
test_env = [
'G_TEST_SRCDIR=' + meson.current_source_dir(),
diff --git a/linux/ibus-keyman/src/test/run-tests.sh b/linux/ibus-keyman/src/test/run-tests.sh
index 932f64b886163c707f2dd684e6b0f051a490fb5b..44a397582b45c8476d881ae3cf5fc417eb6fdf77 100755
--- a/linux/ibus-keyman/src/test/run-tests.sh
+++ b/linux/ibus-keyman/src/test/run-tests.sh
@@ -53,7 +53,7 @@ SCHEMA_DIR=$TEMP_DATA_DIR/glib-2.0/schemas
export XDG_DATA_DIRS=$TEMP_DATA_DIR:$XDG_DATA_DIRS
mkdir -p "$SCHEMA_DIR"
-cp "$SRCDIR/../keyman-config/com.keyman.gschema.xml" "$SCHEMA_DIR/"
+cp "$SRCDIR/../keyman-config/resources/com.keyman.gschema.xml" "$SCHEMA_DIR/"
glib-compile-schemas "$SCHEMA_DIR"
export GSETTINGS_BACKEND=memory
diff --git a/linux/ibus-keyman/tests/KmDbusTestServer.cpp b/linux/ibus-keyman/tests/KmDbusTestServer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1d4746163d5171fa3fcbf10d58db8d099e97b961
--- /dev/null
+++ b/linux/ibus-keyman/tests/KmDbusTestServer.cpp
@@ -0,0 +1,146 @@
+// DBus test server. The server will start and listen on a non-standard DBus.
+// It runs until the DBus Exit method gets called.
+#include
+#include
+#include
+#include
+
+#ifndef KEYMAN_TEST_SERVICE_PATH
+#warning KEYMAN_TEST_SERVICE_PATH is undefined
+#define KEYMAN_TEST_SERVICE_PATH "."
+#endif
+
+#define KEYMAN_TESTSVC_BUS_NAME "com.keyman.ExitTestService"
+#define KEYMAN_TESTSVC_INTERFACE_NAME "com.keyman.ExitTestService.Exit"
+#define KEYMAN_TESTSVC_OBJECT_PATH "/com/keyman/ExitTestService/Exit"
+
+using namespace std;
+
+class KmDbusTestServer
+{
+private:
+ GTestDBus *dbus;
+ sd_bus_slot *slot = NULL;
+ sd_bus *bus = NULL;
+
+public:
+ KmDbusTestServer();
+ ~KmDbusTestServer();
+
+ void Loop();
+};
+
+static int32_t
+on_exit_method(sd_bus_message *msg, void *user_data, sd_bus_error *ret_error) {
+ g_debug("%s called", __FUNCTION__);
+ guint *exitFlag = (guint *)user_data;
+ *exitFlag = TRUE;
+
+ return sd_bus_reply_method_return(msg, "");
+}
+
+static const sd_bus_vtable exit_test_service_vtable[] = {
+ SD_BUS_VTABLE_START(0),
+ SD_BUS_METHOD("Exit", "", "", on_exit_method, 0),
+ SD_BUS_VTABLE_END
+};
+
+KmDbusTestServer::KmDbusTestServer()
+{
+ dbus = g_test_dbus_new(G_TEST_DBUS_NONE);
+
+ // Add the private directory with our in-tree service files.
+ g_test_dbus_add_service_dir(dbus, KEYMAN_TEST_SERVICE_PATH);
+
+ std::cout << "Add service dir to " << KEYMAN_TEST_SERVICE_PATH << std::endl;
+
+ // Start the private D-Bus daemon
+ g_test_dbus_up(dbus);
+
+ const gchar *address = g_test_dbus_get_bus_address(dbus);
+
+ std::cout << "Test server running on: " << address << std::endl;
+
+ ofstream file("/tmp/km-test-server.env", ios_base::out);
+ if (file) {
+ // write the address to a file which can be sourced
+ file << "export DBUS_SESSION_BUS_ADDRESS=" << address << std::endl;
+ file.close();
+ }
+}
+
+KmDbusTestServer::~KmDbusTestServer()
+{
+ if (bus) sd_bus_release_name(bus, KEYMAN_TESTSVC_BUS_NAME);
+ if (slot) sd_bus_slot_unref(slot);
+ if (bus) sd_bus_close_unref(bus);
+
+ g_test_dbus_down(dbus);
+ g_object_unref(dbus);
+}
+
+void KmDbusTestServer::Loop()
+{
+ int ret;
+
+ ret = sd_bus_open_user(&bus);
+
+ if (ret < 0) {
+ g_error("Failed to connect to system bus: %s", strerror(-ret));
+ return;
+ }
+
+ guint exitFlag = FALSE;
+
+ // Install the object
+ ret = sd_bus_add_object_vtable(bus, &slot, KEYMAN_TESTSVC_OBJECT_PATH,
+ KEYMAN_TESTSVC_INTERFACE_NAME, exit_test_service_vtable, &exitFlag);
+ if (ret < 0) {
+ g_error("Failed to issue method call: %s", strerror(-ret));
+ return;
+ }
+
+ // Take a well-known service name so that clients can find us
+ ret = sd_bus_request_name(bus, KEYMAN_TESTSVC_BUS_NAME, 0);
+ if (ret < 0) {
+ g_error("Failed to acquire service name: %s", strerror(-ret));
+ return;
+ }
+
+ for (;;) {
+ // Process requests
+ ret = sd_bus_process(bus, NULL);
+ g_debug("sd_bus_process returned %d, exitFlag=%d", ret, exitFlag);
+ if (ret < 0) {
+ g_error("Failed to process bus: %s", strerror(-ret));
+ return;
+ }
+ if (exitFlag) {
+ // `exitFlag` can be modified by the callback function
+ // `on_exit_method` which can be called by `sd_bus_process`
+ g_debug("Exiting loop");
+ return;
+ }
+
+ if (ret > 0) {
+ // we processed a request, try to process another one, right-away
+ continue;
+ }
+
+ // Wait for the next request to process
+ ret = sd_bus_wait(bus, (uint64_t)-1);
+ g_debug("sd_bus_wait returned %d", ret);
+ if (ret < 0) {
+ g_error("Failed to wait on bus: %s", strerror(-ret));
+ return;
+ }
+ }
+}
+
+int
+main(int argc, char *argv[]) {
+ KmDbusTestServer testServer;
+ testServer.Loop();
+
+ return 0;
+}
diff --git a/linux/ibus-keyman/tests/StopTestServer.cpp b/linux/ibus-keyman/tests/StopTestServer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..97ce5bfbe7f8200624e02e8defa05bbb4d4ece42
--- /dev/null
+++ b/linux/ibus-keyman/tests/StopTestServer.cpp
@@ -0,0 +1,58 @@
+// Call the Exit method on the km-dbus-test-server. Remember to source
+// `/tmp/km-test-server.env` prior to running stop-test-server in order
+// to run on our non-standard DBus.
+#include
+#include
+
+using namespace std;
+
+class StopTestServer
+{
+private:
+ sd_bus_error* error = NULL;
+ sd_bus_message* msg = NULL;
+ sd_bus* bus = NULL;
+
+public:
+ StopTestServer();
+ ~StopTestServer();
+
+ int Run();
+};
+
+StopTestServer::StopTestServer()
+{
+}
+
+StopTestServer::~StopTestServer()
+{
+ if (error) { sd_bus_error_free(error); }
+ if (msg) { sd_bus_message_unref(msg); }
+ if (bus) { sd_bus_unref(bus); }
+}
+
+int StopTestServer::Run()
+{
+ int result;
+
+ result = sd_bus_open_user(&bus);
+ if (result < 0) {
+ std::cerr << "Can't get connection: " << strerror(-result) << std::endl;
+ return 1;
+ }
+
+ result = sd_bus_call_method(bus, "com.keyman.ExitTestService",
+ "/com/keyman/ExitTestService/Exit", "com.keyman.ExitTestService.Exit",
+ "Exit", error, &msg, "");
+ if (result < 0) {
+ std::cerr << "Failed to issue method call: " << strerror(-result) << std::endl;
+ return 1;
+ }
+ return 0;
+}
+
+int
+main(int argc, char* argv[]) {
+ StopTestServer stopServer;
+ return stopServer.Run();
+}
diff --git a/linux/ibus-keyman/tests/meson.build b/linux/ibus-keyman/tests/meson.build
index 8b2dea17a0e40953f4da58bcd6bf12b4e6611c08..130e3b8bce491473e0b172dd5c289f19494aebfe 100644
--- a/linux/ibus-keyman/tests/meson.build
+++ b/linux/ibus-keyman/tests/meson.build
@@ -1,21 +1,17 @@
test_files = [
'ibusimcontext.c',
- 'ibusimcontext.h',
'testfixture.cpp',
'testmodule.c',
- 'testmodule.h',
-]
-
-kmx_dir = [
- core_dir / 'build/arch' / get_option('buildtype') / 'tests/kmx_test_source'
+ '../src/KeymanSystemServiceClient.cpp',
]
kmnkbp_tests_lib = cc.find_library(
- 'libkmnkbp-tests',
- dirs: kmx_dir
+ 'kmnkbp-tests', # meson will prefix 'lib'
+ dirs: [ core_dir / 'build/arch' / get_option('buildtype') / 'tests/kmx_test_source' ]
)
-deps = [ibus, gtk, x11, json_glib, kmnkbp_lib, kmnkbp_tests_lib]
+test_deps = [ibus, gtk, json_glib, kmnkbp_lib, kmnkbp_tests_lib, systemd]
+dbus_deps = [gtk, systemd]
test_env = [
'G_TEST_SRCDIR=' + meson.current_source_dir(),
@@ -32,10 +28,27 @@ test_include_dirs = [
test_exe = executable(
'ibus-keyman-tests',
test_files, util_files,
- dependencies: deps,
+ dependencies: test_deps,
include_directories: test_include_dirs,
)
+system_service_dir = meson.current_source_dir() / '../../keyman-system-service/build' / build_machine.cpu_family() / get_option('buildtype') / 'tests/services'
+
+dbus_test_server = executable(
+ 'km-dbus-test-server',
+ 'KmDbusTestServer.cpp',
+ dependencies: dbus_deps,
+ cpp_args: [
+ '-DKEYMAN_TEST_SERVICE_PATH="' + system_service_dir + '"'
+ ]
+)
+
+stop_test_server = executable(
+ 'stop-test-server',
+ 'StopTestServer.cpp',
+ dependencies: dbus_deps,
+)
+
env_file = '/tmp/env.txt'
pid_file = '/tmp/ibus-keyman-test-pids'
@@ -84,7 +97,7 @@ test(
kmxtest_files = run_command(
find_tests,
- kmx_dir,
+ [ common_dir / 'test/keyboards/baseline' ],
check: true,
).stdout().split('\n')
diff --git a/linux/ibus-keyman/tests/scripts/run-single-test.sh b/linux/ibus-keyman/tests/scripts/run-single-test.sh
index c265c27ccdf3c9c78533dc58b37585b16fca611c..19baca7dd6f8a16d9e5c91f4ddc2e5392d9de29a 100755
--- a/linux/ibus-keyman/tests/scripts/run-single-test.sh
+++ b/linux/ibus-keyman/tests/scripts/run-single-test.sh
@@ -1,7 +1,8 @@
#!/usr/bin/env bash
+set -eu
TESTDIR=${XDG_DATA_HOME:-$HOME/.local/share}/keyman/test_kmx
-. "$(dirname "$0")"/test-helper.sh
+. "$(dirname "$0")"/test-helper.inc.sh
if [ -v KEYMAN_PKG_BUILD ]; then
# During package builds we skip these tests that require to start ibus because
diff --git a/linux/ibus-keyman/tests/scripts/run-tests.sh b/linux/ibus-keyman/tests/scripts/run-tests.sh
index 81f32bd4efc2b62e2b84f040ffbeac7a60949d85..92cae307ed3e232b10b35b21431bbeb5c3dfa36c 100755
--- a/linux/ibus-keyman/tests/scripts/run-tests.sh
+++ b/linux/ibus-keyman/tests/scripts/run-tests.sh
@@ -1,9 +1,17 @@
#!/usr/bin/env bash
+set -eu
-TOP_SRCDIR=${top_srcdir:-$(realpath "$(dirname "$0")/..")}
-TESTDIR=${XDG_DATA_HOME:-$HOME/.local/share}/keyman/test_kmx
+TOP_SRCDIR=${top_srcdir:-$(realpath "$(dirname "$0")/../..")}
+TESTBASEDIR=${XDG_DATA_HOME:-$HOME/.local/share}/keyman
+TESTDIR=${TESTBASEDIR}/test_kmx
+PID_FILE=/tmp/ibus-keyman-test-pids
+ENV_FILE=/tmp/keyman-env.txt
-. "$(dirname "$0")"/test-helper.sh
+. "$(dirname "$0")"/test-helper.inc.sh
+
+local_cleanup() {
+ cleanup "$PID_FILE"
+}
if [ -v KEYMAN_PKG_BUILD ]; then
# During package builds we skip these tests that require to start ibus because
@@ -20,16 +28,6 @@ if ! which Xvfb > /dev/null || ! which Xephyr > /dev/null || ! which metacity >
exit 1
fi
-function cleanup() {
- if [ -f "$PID_FILE" ]; then
- echo
- echo "# Shutting down processes..."
- bash "$PID_FILE" > /dev/null 2>&1
- rm "$PID_FILE"
- echo "# Finished shutdown of processes."
- fi
-}
-
function help() {
echo "Usage:"
echo " $0 [-k] [--tap] [--surrounding-text] [--no-surrounding-text] [--no-wayland] [--no-x11] [[--] TEST...]"
@@ -54,79 +52,24 @@ function run_tests() {
DISPLAY_SERVER=$1
shift
- echo > "$PID_FILE"
- TEMP_DATA_DIR=$(mktemp --directory)
- echo "rm -rf ${TEMP_DATA_DIR} || true" >> "$PID_FILE"
-
- COMMON_ARCH_DIR=
- [ -d "${TOP_SRCDIR}"/../../core/build/arch ] && COMMON_ARCH_DIR=${TOP_SRCDIR}/../../core/build/arch
-
- if [ -d "${COMMON_ARCH_DIR}"/release ]; then
- COMMON_ARCH_DIR=${COMMON_ARCH_DIR}/release
- elif [ -d "${COMMON_ARCH_DIR}"/debug ]; then
- COMMON_ARCH_DIR=${COMMON_ARCH_DIR}/debug
+ if [ -d "$(dirname "$0")/../../../build/$(arch)/debug" ]; then
+ CONFIG=debug
+ elif [ -d "$(dirname "$0")/../../../build/$(arch)/release" ]; then
+ CONFIG=release
else
- echo "Can't find neither ${COMMON_ARCH_DIR}/release nor ${COMMON_ARCH_DIR}/debug"
- exit 2
+ echo "Cannot find ../../../build/$(arch)/debug or ../../../build/$(arch)/release"
+ exit 9
fi
- # TODO: we are borrowing the KMX tests out of core; these should be shared in common
- # to avoid deep links like this in future
- KMX_TEST_DIR="${TOP_SRCDIR}"/../../common/test/keyboards/baseline
-
- if [ ! -d "$TESTDIR" ] || ! [[ $(find "${TESTDIR}/" -name \*.kmx 2>/dev/null | wc -l) -gt 0 ]]; then
- if [[ $(find "${KMX_TEST_DIR}/" -name \*.kmx 2>/dev/null | wc -l) -gt 0 ]]; then
- mkdir -p "$(realpath --canonicalize-missing "$TESTDIR"/..)"
- ln -sf "$(realpath "${KMX_TEST_DIR}")" "$TESTDIR"
- else
- echo "Can't find kmx files in ${KMX_TEST_DIR}"
- exit 3
- fi
- fi
+ G_TEST_BUILDDIR="$(dirname "$0")/../../../build/$(arch)/${CONFIG}/tests"
+
+ setup "$DISPLAY_SERVER" "$ENV_FILE" "$PID_FILE"
echo "# NOTE: When the tests fail check /tmp/ibus-engine-keyman.log and /tmp/ibus-daemon.log!"
echo ""
- if [ "$DISPLAY_SERVER" == "wayland" ]; then
- if ! can_run_wayland; then
- # support for --headless got added in mutter 40.x
- echo "ERROR: mutter doesn't support running headless. Can't run Wayland tests."
- exit 7
- fi
- echo "# Running on Wayland..."
- TMPFILE=$(mktemp)
- # mutter-Message: 18:56:15.422: Using Wayland display name 'wayland-1'
- mutter --wayland --headless --no-x11 --virtual-monitor 1024x768 &> "$TMPFILE" &
- echo "kill -9 $! || true" >> "$PID_FILE"
- sleep 1s
- export WAYLAND_DISPLAY
- WAYLAND_DISPLAY=$(cat "$TMPFILE" | grep "Using Wayland display" | cut -d"'" -f2)
- rm "$TMPFILE"
- else
- echo "# Starting Xvfb..."
- Xvfb -screen 0 1024x768x24 :33 &> /dev/null &
- echo "kill -9 $! || true" >> "$PID_FILE"
- sleep 1
- echo "# Starting Xephyr..."
- DISPLAY=:33 Xephyr :32 -screen 1024x768 &> /dev/null &
- echo "kill -9 $! || true" >> "$PID_FILE"
- sleep 1
- echo "# Starting metacity"
- metacity --display=:32 &> /dev/null &
- echo "kill -9 $! || true" >> "$PID_FILE"
-
- export DISPLAY=:32
- fi
-
- # Install schema to temporary directory. This removes the build dependency on the keyman package.
- SCHEMA_DIR=$TEMP_DATA_DIR/glib-2.0/schemas
- export XDG_DATA_DIRS=$TEMP_DATA_DIR:$XDG_DATA_DIRS
-
- mkdir -p "$SCHEMA_DIR"
- cp "${TOP_SRCDIR}"/../keyman-config/com.keyman.gschema.xml "$SCHEMA_DIR"/
- glib-compile-schemas "$SCHEMA_DIR"
-
if [ $# -gt 0 ]; then
+ #shellcheck disable=SC2206
TESTFILES=($@)
else
pushd "$TESTDIR" > /dev/null || exit
@@ -134,32 +77,20 @@ function run_tests() {
popd > /dev/null || exit
fi
- export LD_LIBRARY_PATH=${COMMON_ARCH_DIR}/src:$LD_LIBRARY_PATH
-
- # Ubuntu 18.04 Bionic doesn't have ibus-memconf, and glib is not compiled with the keyfile
- # backend enabled, so we just use the default backend. Otherwise we use the keyfile
- # store which interferes less when running on a dev machine.
- if [ -f /usr/libexec/ibus-memconf ]; then
- export GSETTINGS_BACKEND=keyfile
- IBUS_CONFIG=--config=/usr/libexec/ibus-memconf
- fi
-
- ibus-daemon "${ARG_VERBOSE-}" --panel=disable ${IBUS_CONFIG-} &> /tmp/ibus-daemon.log &
- echo "kill -9 $! || true" >> "$PID_FILE"
- sleep 1s
-
- ../src/ibus-engine-keyman "${ARG_VERBOSE-}" &> /tmp/ibus-engine-keyman.log &
- echo "kill -9 $! || true" >> "$PID_FILE"
- sleep 1s
-
echo "# Starting tests..."
+ # shellcheck disable=SC1090
+ source "$ENV_FILE"
+ echo "DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS"
+
# Note: -k and --tap are consumed by the GLib testing framework
- "${G_TEST_BUILDDIR:-.}"/ibus-keyman-tests "${ARG_K-}" "${ARG_TAP-}" \
- "${ARG_VERBOSE-}" "${ARG_DEBUG-}" "${ARG_SURROUNDING_TEXT-}" "${ARG_NO_SURROUNDING_TEXT-}" \
- --directory "$TESTDIR" --"${DISPLAY_SERVER}" "${TESTFILES[@]}"
+ #shellcheck disable=SC2068 # we want to split array elements!
+ #shellcheck disable=SC2086
+ "${G_TEST_BUILDDIR:-../../build/$(arch)/${CONFIG}/tests}/ibus-keyman-tests" ${ARG_K-} ${ARG_TAP-} \
+ ${ARG_VERBOSE-} ${ARG_DEBUG-} ${ARG_SURROUNDING_TEXT-} ${ARG_NO_SURROUNDING_TEXT-} \
+ --directory "$TESTDIR" --"${DISPLAY_SERVER}" ${TESTFILES[@]}
echo "# Finished tests."
- cleanup
+ cleanup "$PID_FILE"
}
USE_WAYLAND=1
@@ -182,7 +113,7 @@ while (( $# )); do
shift || (echo "Error: The last argument is missing a value. Exiting."; false) || exit 5
done
-if ! can_run_wayland; then
+if ! can_run_wayland && [ "$USE_WAYLAND" == "0" ]; then
# support for --headless got added in mutter 40.x
echo "# WARNING: mutter doesn't support running headless. Skipping Wayland tests."
USE_WAYLAND=0
@@ -197,13 +128,18 @@ if [ "$USE_WAYLAND" == "0" ] && [ "$USE_X11" == "0" ]; then
exit 6
fi
+G_TEST_BUILDDIR="${G_TEST_BUILDDIR:-../../build/$(arch)/debug/tests}"
+if [ ! -f "${G_TEST_BUILDDIR}/ibus-keyman-tests" ]; then
+ G_TEST_BUILDDIR="${G_TEST_BUILDDIR:-../../build/$(arch)/release/tests}"
+fi
+
echo > "$PID_FILE"
-trap cleanup EXIT SIGINT
+trap local_cleanup EXIT SIGINT
if [ "$USE_WAYLAND" == "1" ]; then
- run_tests wayland "$@"
+ ( run_tests wayland "$@" )
fi
if [ "$USE_X11" == "1" ]; then
- run_tests x11 "$@"
+ ( run_tests x11 "$@" )
fi
diff --git a/linux/ibus-keyman/tests/scripts/setup-tests.sh b/linux/ibus-keyman/tests/scripts/setup-tests.sh
index 94400d40f2602b5b768c673007ffcebbde796972..9d591869fbbe46f77252d509beb2257c0efeba71 100755
--- a/linux/ibus-keyman/tests/scripts/setup-tests.sh
+++ b/linux/ibus-keyman/tests/scripts/setup-tests.sh
@@ -1,114 +1,6 @@
#!/usr/bin/env bash
-DISPLAY_SERVER=$1
-ENV_FILE=$2
-PID_FILE=$3
+set -eu
-TOP_SRCDIR=${G_TEST_SRCDIR:-$(realpath "$(dirname "$0")/..")}/..
-TOP_BINDIR=${G_TEST_BUILDDIR:-$(realpath "$(dirname "$0/..")")}/..
-TESTDIR=${XDG_DATA_HOME:-$HOME/.local/share}/keyman/test_kmx
+. "$(dirname "$0")/test-helper.inc.sh"
-. "$(dirname "$0")"/test-helper.sh
-
-echo > "$ENV_FILE"
-
-if [ -f "$PID_FILE" ]; then
- # kill previous instances
- "$(dirname "$0")"/teardown-tests.sh "$PID_FILE"
-fi
-
-echo > "$PID_FILE"
-TEMP_DATA_DIR=$(mktemp --directory)
-echo "rm -rf ${TEMP_DATA_DIR} || true" >> "$PID_FILE"
-
-COMMON_ARCH_DIR=
-[ -d "${TOP_SRCDIR}"/../../core/build/arch ] && COMMON_ARCH_DIR=${TOP_SRCDIR}/../../core/build/arch
-
-if [ -d "${COMMON_ARCH_DIR}"/release ]; then
- COMMON_ARCH_DIR=${COMMON_ARCH_DIR}/release
-elif [ -d "${COMMON_ARCH_DIR}"/debug ]; then
- COMMON_ARCH_DIR=${COMMON_ARCH_DIR}/debug
-else
- echo "Can't find neither ${COMMON_ARCH_DIR}/release nor ${COMMON_ARCH_DIR}/debug"
- exit 2
-fi
-
-# TODO: we are borrowing the KMX tests out of core; these should be shared in common
-# to avoid deep links like this in future
-KMX_TEST_DIR="${TOP_SRCDIR}"/../../common/test/keyboards/baseline
-
-if [ ! -d "$TESTDIR" ] || ! [[ $(find "${TESTDIR}/" -name \*.kmx 2>/dev/null | wc -l) -gt 0 ]]; then
- if [[ $(find "${KMX_TEST_DIR}/" -name \*.kmx 2>/dev/null | wc -l) -gt 0 ]]; then
- mkdir -p "$(realpath --canonicalize-missing "$TESTDIR"/..)"
- ln -sf "$(realpath "${KMX_TEST_DIR}")" "$TESTDIR"
- else
- echo "Can't find kmx files in ${KMX_TEST_DIR}"
- exit 3
- fi
-fi
-
-if [ "$DISPLAY_SERVER" == "wayland" ]; then
- if ! can_run_wayland; then
- # support for --headless got added in mutter 40.x
- echo "ERROR: mutter doesn't support running headless. Can't run Wayland tests."
- exit 7
- fi
- echo "Running on Wayland..."
- TMPFILE=$(mktemp)
- # mutter-Message: 18:56:15.422: Using Wayland display name 'wayland-1'
- mutter --wayland --headless --no-x11 --virtual-monitor 1024x768 &> "$TMPFILE" &
- echo "kill -9 $! || true" >> "$PID_FILE"
- sleep 1s
- export WAYLAND_DISPLAY
- WAYLAND_DISPLAY=$(grep "Using Wayland display" "$TMPFILE" | cut -d"'" -f2)
- rm "$TMPFILE"
- echo "export WAYLAND_DISPLAY=\"$WAYLAND_DISPLAY\"" >> "$ENV_FILE"
-else
- echo "Starting Xvfb..."
- Xvfb -screen 0 1024x768x24 :33 &> /dev/null &
- echo "kill -9 $! || true" >> "$PID_FILE"
- sleep 1
- echo "Starting Xephyr..."
- DISPLAY=:33 Xephyr :32 -screen 1024x768 &> /dev/null &
- echo "kill -9 $! || true" >> "$PID_FILE"
- sleep 1
- echo "Starting metacity"
- metacity --display=:32 &> /dev/null &
- echo "kill -9 $! || true" >> "$PID_FILE"
-
- export DISPLAY=:32
- echo "export DISPLAY=\"$DISPLAY\"" >> "$ENV_FILE"
-fi
-
- # Install schema to temporary directory. This removes the build dependency on the keyman package.
- SCHEMA_DIR=$TEMP_DATA_DIR/glib-2.0/schemas
- export XDG_DATA_DIRS=$TEMP_DATA_DIR:$XDG_DATA_DIRS
- echo "export XDG_DATA_DIRS=\"$XDG_DATA_DIRS\"" >> "$ENV_FILE"
-
- mkdir -p "$SCHEMA_DIR"
- cp "${TOP_SRCDIR}"/../keyman-config/com.keyman.gschema.xml "$SCHEMA_DIR"/
- glib-compile-schemas "$SCHEMA_DIR"
-
- export LD_LIBRARY_PATH=${COMMON_ARCH_DIR}/src:$LD_LIBRARY_PATH
- echo "export LD_LIBRARY_PATH=\"$LD_LIBRARY_PATH\"" >> "$ENV_FILE"
-
- # Ubuntu 18.04 Bionic doesn't have ibus-memconf, and glib is not compiled with the keyfile
- # backend enabled, so we just use the default backend. Otherwise we use the keyfile
- # store which interferes less when running on a dev machine.
- if [ -f /usr/libexec/ibus-memconf ]; then
- export GSETTINGS_BACKEND=keyfile
- echo "export GSETTINGS_BACKEND=\"$GSETTINGS_BACKEND\"" >> "$ENV_FILE"
- IBUS_CONFIG=--config=/usr/libexec/ibus-memconf
- fi
-
- ibus-daemon "${ARG_VERBOSE-}" --daemonize --panel=disable ${IBUS_CONFIG-} &> /tmp/ibus-daemon.log
- echo "kill -9 $! || true" >> "$PID_FILE"
- sleep 1s
-
- IBUS_ADDRESS=$(ibus address)
- export IBUS_ADDRESS
-
- echo "export IBUS_ADDRESS=\"$IBUS_ADDRESS\"" >> "$ENV_FILE"
-
- "${TOP_BINDIR}"/src/ibus-engine-keyman "${ARG_VERBOSE-}" &> /tmp/ibus-engine-keyman.log &
- echo "kill -9 $! || true" >> "$PID_FILE"
- sleep 1s
+setup "$1" "$2" "$3"
diff --git a/linux/ibus-keyman/tests/scripts/teardown-tests.sh b/linux/ibus-keyman/tests/scripts/teardown-tests.sh
index 489769d7218efed5bce5bd5874ce412cf5f47b05..c3b955a13a3d7aefe846d5160171c5d444ee232d 100755
--- a/linux/ibus-keyman/tests/scripts/teardown-tests.sh
+++ b/linux/ibus-keyman/tests/scripts/teardown-tests.sh
@@ -1,7 +1,6 @@
#!/usr/bin/env bash
-PID_FILE=$1
+set -eu
-echo "Shutting down processes..."
-bash "$PID_FILE" > /dev/null 2>&1
-rm "$PID_FILE"
-echo "Finished shutdown of processes."
+. "$(dirname "$0")/test-helper.inc.sh"
+
+cleanup "$1"
diff --git a/linux/ibus-keyman/tests/scripts/test-helper.inc.sh b/linux/ibus-keyman/tests/scripts/test-helper.inc.sh
new file mode 100755
index 0000000000000000000000000000000000000000..2a3735d7084abf9b7752c29166335e893133f952
--- /dev/null
+++ b/linux/ibus-keyman/tests/scripts/test-helper.inc.sh
@@ -0,0 +1,229 @@
+#!/usr/bin/env bash
+
+function can_run_wayland() {
+ local MUTTER_VERSION
+ MUTTER_VERSION=$(mutter --version | head -1 | cut -f2 -d' ' | cut -f1 -d'.')
+ if (( MUTTER_VERSION < 40 )); then
+ return 1
+ else
+ return 0
+ fi
+}
+
+function generate_kmpjson() {
+ local TESTDIR
+ TESTDIR="$1"
+ pushd "$TESTDIR" > /dev/null || exit
+ KMPFILE="${TESTDIR}/kmp.json"
+ cat <<-EOF > "$KMPFILE"
+ {
+ "system": {
+ "keymanDeveloperVersion": "10.0.1099.0",
+ "fileVersion": "7.0"
+ },
+ "info": {
+ "name": {
+ "description": "Test Keyboards"
+ },
+ "version": {
+ "description": "0.0"
+ }
+ },
+ "files": [
+ {
+ "name": "kmp.json",
+ "description": "Package information (JSON)"
+ }
+EOF
+ for f in k_*.kmx; do
+ keyboard=$(basename "$f")
+ keyboard="${keyboard%.*}"
+ echo " ," >> "$KMPFILE"
+ cat <<-EOF >> "$KMPFILE"
+ {
+ "name": "$keyboard",
+ "description": "$keyboard"
+ }
+EOF
+ done
+ cat <<-EOF >> "$KMPFILE"
+ ],
+ "keyboards": [
+EOF
+ FIRST=true
+ for f in k_*.kmx; do
+ keyboard=$(basename "$f")
+ keyboard="${keyboard%.*}"
+ if $FIRST; then
+ FIRST=false
+ else
+ echo " ," >> "$KMPFILE"
+ fi
+ cat <<-EOF >> "$KMPFILE"
+ {
+ "name": "$keyboard",
+ "id": "$keyboard",
+ "version": "0.0",
+ "languages": [
+ {
+ "name": "Undetermined",
+ "id": "und"
+ }
+ ]
+ }
+EOF
+ done
+ echo " ]" >> "$KMPFILE"
+ echo "}" >> "$KMPFILE"
+ popd > /dev/null || exit
+}
+
+function link_test_keyboards() {
+ KMX_TEST_DIR=$1
+ TESTDIR=$2
+ TESTBASEDIR=$3
+
+ if [[ $(find "${KMX_TEST_DIR}/" -name k_\*.kmx 2>/dev/null | wc -l) -gt 0 ]]; then
+ mkdir -p "$(realpath --canonicalize-missing "$TESTBASEDIR")"
+ rm -f "$TESTDIR"
+ ln -sf "$(realpath "${KMX_TEST_DIR}")" "$TESTDIR"
+ else
+ echo "Can't find test kmx files in ${KMX_TEST_DIR}"
+ exit 3
+ fi
+}
+
+function setup() {
+ local DISPLAY_SERVER ENV_FILE PID_FILE TOP_SRCDIR TOP_BINDIR TESTBASEDIR TESTDIR
+ DISPLAY_SERVER=$1
+ ENV_FILE=$2
+ PID_FILE=$3
+
+ TOP_SRCDIR=${G_TEST_SRCDIR:-$(realpath "$(dirname "$0")/..")}/..
+ TOP_BINDIR=${G_TEST_BUILDDIR:-$(realpath "$(dirname "$0/..")")}/..
+ TESTBASEDIR=${XDG_DATA_HOME:-$HOME/.local/share}/keyman
+ TESTDIR=${TESTBASEDIR}/test_kmx
+
+ echo > "$ENV_FILE"
+
+ if [ -f "$PID_FILE" ]; then
+ # kill previous instances
+ "$(dirname "$0")"/teardown-tests.sh "$PID_FILE"
+ fi
+
+ echo > "$PID_FILE"
+ TEMP_DATA_DIR=$(mktemp --directory)
+ echo "rm -rf ${TEMP_DATA_DIR} || true" >> "$PID_FILE"
+
+ COMMON_ARCH_DIR=
+ [ -d "${TOP_SRCDIR}"/../../core/build/arch ] && COMMON_ARCH_DIR=${TOP_SRCDIR}/../../core/build/arch
+
+ if [ -d "${COMMON_ARCH_DIR}"/release ]; then
+ COMMON_ARCH_DIR=${COMMON_ARCH_DIR}/release
+ elif [ -d "${COMMON_ARCH_DIR}"/debug ]; then
+ COMMON_ARCH_DIR=${COMMON_ARCH_DIR}/debug
+ else
+ echo "Can't find neither ${COMMON_ARCH_DIR}/release nor ${COMMON_ARCH_DIR}/debug"
+ exit 2
+ fi
+
+ link_test_keyboards "${TOP_SRCDIR}/../../common/test/keyboards/baseline" "$TESTDIR" "$TESTBASEDIR"
+
+ generate_kmpjson "$TESTDIR"
+
+ # Start test dbus server
+ "${TOP_BINDIR}/tests/km-dbus-test-server" &> /dev/null &
+ sleep 1
+ source /tmp/km-test-server.env
+ cat /tmp/km-test-server.env >> "$ENV_FILE"
+ cat /tmp/km-test-server.env >> "$PID_FILE"
+ echo "${TOP_BINDIR}/tests/stop-test-server" >> "$PID_FILE"
+
+ if [ "$DISPLAY_SERVER" == "wayland" ]; then
+ if ! can_run_wayland; then
+ # support for --headless got added in mutter 40.x
+ echo "ERROR: mutter doesn't support running headless. Can't run Wayland tests."
+ exit 7
+ fi
+ echo "Running on Wayland:"
+ echo "Starting mutter..."
+ TMPFILE=$(mktemp)
+ # mutter-Message: 18:56:15.422: Using Wayland display name 'wayland-1'
+ mutter --wayland --headless --no-x11 --virtual-monitor 1024x768 &> "$TMPFILE" &
+ echo "kill -9 $! || true" >> "$PID_FILE"
+ sleep 1s
+ export WAYLAND_DISPLAY
+ WAYLAND_DISPLAY=$(grep "Using Wayland display" "$TMPFILE" | cut -d"'" -f2)
+ rm "$TMPFILE"
+ echo "export WAYLAND_DISPLAY=\"$WAYLAND_DISPLAY\"" >> "$ENV_FILE"
+ else
+ echo "Running on X11:"
+ echo "Starting Xvfb..."
+ Xvfb -screen 0 1024x768x24 :33 &> /dev/null &
+ echo "kill -9 $! || true" >> "$PID_FILE"
+ sleep 1
+ echo "Starting Xephyr..."
+ DISPLAY=:33 Xephyr :32 -screen 1024x768 &> /dev/null &
+ echo "kill -9 $! || true" >> "$PID_FILE"
+ sleep 1
+ echo "Starting metacity"
+ metacity --display=:32 &> /dev/null &
+ echo "kill -9 $! || true" >> "$PID_FILE"
+
+ export DISPLAY=:32
+ echo "export DISPLAY=\"$DISPLAY\"" >> "$ENV_FILE"
+ fi
+
+ # Install schema to temporary directory. This removes the build dependency on the keyman package.
+ SCHEMA_DIR=$TEMP_DATA_DIR/glib-2.0/schemas
+ export XDG_DATA_DIRS=$TEMP_DATA_DIR:${XDG_DATA_DIRS-}
+ echo "export XDG_DATA_DIRS=$XDG_DATA_DIRS" >> "$ENV_FILE"
+
+ export GSETTINGS_SCHEMA_DIR=${SCHEMA_DIR}
+ echo "export GSETTINGS_SCHEMA_DIR=\"$SCHEMA_DIR\"" >> "$ENV_FILE"
+
+ mkdir -p "$SCHEMA_DIR"
+ cp "${TOP_SRCDIR}"/../keyman-config/resources/com.keyman.gschema.xml "$SCHEMA_DIR"/
+ glib-compile-schemas "$SCHEMA_DIR"
+
+ export LD_LIBRARY_PATH=${COMMON_ARCH_DIR}/src:${LD_LIBRARY_PATH-}
+ echo "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH" >> "$ENV_FILE"
+
+ # Ubuntu 18.04 Bionic doesn't have ibus-memconf, and glib is not compiled with the keyfile
+ # backend enabled, so we just use the default backend. Otherwise we use the keyfile
+ # store which interferes less when running on a dev machine.
+ if [ -f /usr/libexec/ibus-memconf ]; then
+ export GSETTINGS_BACKEND=keyfile
+ echo "export GSETTINGS_BACKEND=\"$GSETTINGS_BACKEND\"" >> "$ENV_FILE"
+ IBUS_CONFIG=--config=/usr/libexec/ibus-memconf
+ fi
+
+ #shellcheck disable=SC2086
+ ibus-daemon ${ARG_VERBOSE-} --daemonize --panel=disable --address=unix:abstract="${TEMP_DATA_DIR}/test-ibus" ${IBUS_CONFIG-} &> /tmp/ibus-daemon.log
+ echo "kill -9 $! || true" >> "$PID_FILE"
+ sleep 1s
+
+ IBUS_ADDRESS=$(ibus address)
+ export IBUS_ADDRESS
+
+ echo "export IBUS_ADDRESS=\"$IBUS_ADDRESS\"" >> "$ENV_FILE"
+
+ echo "# DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS"
+ #shellcheck disable=SC2086
+ "${TOP_BINDIR}/src/ibus-engine-keyman" --testing ${ARG_VERBOSE-} &> /tmp/ibus-engine-keyman.log &
+ echo "kill -9 $! || true" >> "$PID_FILE"
+ sleep 1s
+}
+
+function cleanup() {
+ local PID_FILE
+ PID_FILE=$1
+
+ if [ -f "$PID_FILE" ]; then
+ echo
+ echo "# Shutting down processes..."
+ bash "$PID_FILE" > /dev/null 2>&1
+ rm "$PID_FILE"
+ echo "# Finished shutdown of processes."
+ fi
+}
diff --git a/linux/ibus-keyman/tests/scripts/test-helper.sh b/linux/ibus-keyman/tests/scripts/test-helper.sh
deleted file mode 100755
index 92c8a7e5287928c2bcc853bdb047e2ef6fbfc2f8..0000000000000000000000000000000000000000
--- a/linux/ibus-keyman/tests/scripts/test-helper.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env bash
-
-function can_run_wayland() {
- local MUTTER_VERSION
- MUTTER_VERSION=$(mutter --version | head -1 | cut -f2 -d' ' | cut -f1 -d'.')
- if (( MUTTER_VERSION < 40 )); then
- return 1
- else
- return 0
- fi
-}
diff --git a/linux/ibus-keyman/tests/testfixture.cpp b/linux/ibus-keyman/tests/testfixture.cpp
index 3e189258bdb11e19c6ba9b69aea1982473572163..84aab933c836a7fde6518be66a77ddbef1bddada 100644
--- a/linux/ibus-keyman/tests/testfixture.cpp
+++ b/linux/ibus-keyman/tests/testfixture.cpp
@@ -13,17 +13,10 @@
#include "ibusimcontext.h"
#include "keycodes.h"
#include "keymanutil.h"
+#include "KeymanSystemServiceClient.h"
#include "kmx_test_source.hpp"
#include "testmodule.h"
-#ifdef GDK_WINDOWING_X11
-#include
-#include
-#endif
-#ifdef GDK_WINDOWING_WAYLAND
-#include
-#endif
-
typedef struct {
IBusBus *bus;
GtkIMContext *context;
@@ -42,12 +35,7 @@ static gboolean use_wayland = FALSE;
static GdkWindow *window = NULL;
static GMainLoop *thread_loop = NULL;
static GTypeModule *module = NULL;
-#ifdef GDK_WINDOWING_X11
-static Display *display = NULL;
-#endif
-#ifdef GDK_WINDOWING_WAYLAND
-static GdkWaylandDisplay *wldisplay = NULL;
-#endif
+gboolean testing = TRUE;
static void
module_register(GTypeModule *module) {
@@ -69,18 +57,6 @@ ibus_keyman_tests_fixture_set_up(IBusKeymanTestsFixture *fixture, gconstpointer
window = gtk_widget_get_window(widget);
}
- GdkDisplay *gdkDisplay = gdk_display_get_default();
-#ifdef GDK_WINDOWING_X11
- if (!use_wayland && !display && GDK_IS_X11_DISPLAY(gdkDisplay)) {
- display = GDK_DISPLAY_XDISPLAY(gdkDisplay);
- }
-#endif
-#ifdef GDK_WINDOWING_WAYLAND
- if (use_wayland && !wldisplay && GDK_IS_WAYLAND_DISPLAY(gdkDisplay)) {
- wldisplay = GDK_WAYLAND_DISPLAY(gdkDisplay);
- }
-#endif
-
if (!loaded) {
ibus_init();
@@ -114,35 +90,12 @@ ibus_keyman_tests_fixture_tear_down(IBusKeymanTestsFixture *fixture, gconstpoint
static void
set_caps_lock_state(IBusKeymanTestsFixture *fixture, bool caps_lock_on) {
-#ifdef GDK_WINDOWING_X11
- if (!use_wayland && display) {
- XkbLockModifiers(display, XkbUseCoreKbd, LockMask, caps_lock_on ? LockMask : 0);
- XSync(display, False);
- }
-#endif
-#ifdef GDK_WINDOWING_WAYLAND
- if (use_wayland && wldisplay) {
- // TODO
- }
-#endif
+ set_capslock_indicator((guint32)caps_lock_on);
}
static bool
get_caps_lock_state(IBusKeymanTestsFixture *fixture) {
-#ifdef GDK_WINDOWING_X11
- if (!use_wayland && display) {
- XKeyboardState state;
- XGetKeyboardControl(display, &state);
- return state.led_mask & 1;
- }
-#endif
-#ifdef GDK_WINDOWING_WAYLAND
- if (use_wayland && wldisplay) {
- // TODO
- }
-#endif
-
- return false;
+ return get_capslock_indicator();
}
static void
@@ -493,23 +446,6 @@ main(int argc, char *argv[]) {
return 2;
}
- if (!argWayland && !argX11) {
- GdkDisplay *gdkDisplay = gdk_display_get_default();
-#ifdef GDK_WINDOWING_WAYLAND
- if (GDK_IS_WAYLAND_DISPLAY(gdkDisplay)) {
- argWayland = true;
- } else
-#endif
-#ifdef GDK_WINDOWING_X11
- if (GDK_IS_X11_DISPLAY(gdkDisplay)) {
- argX11 = true;
- } else
-#endif
- {
- g_error("Neither X11 nor Wayland display!");
- }
- }
-
use_wayland = argWayland;
int nTests = argc - iArg;
char **tests = &argv[iArg];
@@ -528,13 +464,6 @@ main(int argc, char *argv[]) {
skipReason = "mnemonic keyboards are not yet supported on Linux (#3345)";
}
- // Wayland related tests - #4273
- if (use_wayland && (
- strcmp(filename->str, "k_031___caps_lock") == 0 ||
- strcmp(filename->str, "k_032___caps_control") == 0)) {
- skipReason = "capslock related keyboards are not yet working with Wayland (#4273)";
- }
-
if (runSurroundingTextTests) {
add_test(directory, filename->str, TRUE, skipReason, use_wayland);
}
@@ -549,20 +478,6 @@ main(int argc, char *argv[]) {
// Run tests
int retVal = g_test_run();
- // Cleanup
-#ifdef GDK_WINDOWING_X11
- if (!use_wayland && display) {
- XCloseDisplay(display);
- display = NULL;
- }
-#endif
-#ifdef GDK_WINDOWING_WAYLAND
- if (use_wayland) {
- // REVIEW: do we have to call something for cleanup?
- wldisplay = NULL;
- }
-#endif
-
test_module_unuse(module);
return retVal;
}
diff --git a/linux/keyman-config/.editorconfig b/linux/keyman-config/.editorconfig
index 4b530139d7b44db0fbccb2a55ff018d9c137f63b..f65775da76c6b240b5e899aba70b3e44efb76245 100644
--- a/linux/keyman-config/.editorconfig
+++ b/linux/keyman-config/.editorconfig
@@ -7,4 +7,7 @@ indent_size = 4
indent_style = tab
[Makefile]
-indent_style = tab
\ No newline at end of file
+indent_style = tab
+
+[*.sh]
+indent_size = 2
diff --git a/linux/keyman-config/MANIFEST.in b/linux/keyman-config/MANIFEST.in
index e27020f36c9b8a46396a1ff85d8ce50bfd8e5e3f..20705c6fc3e973a6e504395b04e1eeaeeacf9ac6 100644
--- a/linux/keyman-config/MANIFEST.in
+++ b/linux/keyman-config/MANIFEST.in
@@ -2,4 +2,4 @@ recursive-include keyman_config/icons *
recursive-include icons *
include README.md
include *.bash-completion
-include *.gschema.xml
+include resources/*.gschema.xml
diff --git a/linux/keyman-config/Makefile b/linux/keyman-config/Makefile
index b18b1f133d4cd5294f4f978a1900fb72f7df59a0..f057dcad0ce8c0f81e2e82af0014c99e429a41f8 100644
--- a/linux/keyman-config/Makefile
+++ b/linux/keyman-config/Makefile
@@ -1,42 +1,19 @@
#!/usr/bin/make
-default: clean version man langtags
- python3 setup.py build
-
-langtags:
- cd buildtools && python3 ./build-langtags.py
-
-install: # run as sudo
- pip3 install qrcode sentry-sdk
- # eventually change this to: pip3 install .
- python3 setup.py install
- # install icons
- mkdir -p /usr/local/share/keyman/icons
- cp keyman_config/icons/* /usr/local/share/keyman/icons
- # install man pages
- mkdir -p /usr/local/share/man/man1
- cp ../../debian/man/*.1 /usr/local/share/man/man1
-
-install-temp:
- mkdir -p /tmp/keyman/$(shell python3 -c 'import sys;import os;pythonver="python%d.%d" % (sys.version_info[0], sys.version_info[1]);sitedir = os.path.join("lib", pythonver, "site-packages");print(sitedir)')
- # when we no longer have to support old pip version (python > 3.6) change this to:
- # pip3 install --prefix /tmp/keyman .
- PYTHONUSERBASE=/tmp/keyman python3 setup.py install --user
-
-uninstall: clean # run as sudo
- rm -rf /usr/local/share/keyman/icons
- rm -f /usr/local/share/man/man1/km-*.1
- pip3 uninstall keyman_config
- rm -f /usr/local/bin/km-config
- rm -f /usr/local/bin/km-kvk2ldml
- rm -f /usr/local/bin/km-package-get
- rm -f /usr/local/bin/km-package-install
- rm -f /usr/local/bin/km-package-list-installed
- rm -f /usr/local/bin/km-package-uninstall
+default:
+ ./build.sh clean build
+
+install:
+ ./build.sh install
+
+uninstall: # run as sudo
+ ./build.sh uninstall
clean:
- -rm -rf dist make_deb build keyman_config/version.py *.egg-info __pycache__ \
- keyman_config/standards/lang_tags_map.py
+ ./build.sh clean
+
+check:
+ ./build.sh test
devdist: version
python3 setup.py egg_info -b.`TZ=UTC git log -1 --pretty=format:%cd --date=format-local:%Y%m%d%H%M` sdist
@@ -86,6 +63,3 @@ $(MOFILES): %/LC_MESSAGES/keyman-config.mo: %.po
msgfmt -v --check --output-file=$@ $^
compile-po: $(MOFILES)
-
-check:
- ./run-tests.sh
diff --git a/linux/keyman-config/build-help.sh b/linux/keyman-config/build-help.sh
index 97f06ca3d0012649012eaa781a061f46000331ed..e05b8d284e4e90677ae22905c52de2e3fb769b9f 100755
--- a/linux/keyman-config/build-help.sh
+++ b/linux/keyman-config/build-help.sh
@@ -3,13 +3,11 @@
set -e
set -u
-## START STANDARD BUILD SCRIPT INCLUDE
-# adjust relative paths as necessary
THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
-## END STANDARD BUILD SCRIPT INCLUDE
-
THIS_DIR=$(dirname "$THIS_SCRIPT")
+cd "${THIS_DIR}"
+
function display_usage {
echo "Usage: $0 [--man] [--md] [--no-reconf]"
echo " $0 --help"
@@ -50,13 +48,13 @@ while [[ $# -gt 0 ]] ; do
shift # past the processed argument
done
-if [ -z "$generate_man" -a -z "$generate_help" ]; then
+if [ -z "$generate_man" ] && [ -z "$generate_help" ]; then
generate_man=1
generate_help=1
fi
if [ -n "$reconfigure" ]; then
- pushd $THIS_DIR/.. > /dev/null
+ pushd "$THIS_DIR/.." > /dev/null
./scripts/reconf.sh
popd > /dev/null
fi
diff --git a/linux/keyman-config/build.sh b/linux/keyman-config/build.sh
new file mode 100755
index 0000000000000000000000000000000000000000..4828dd5ec737389db387f8bf37275ed94aa7db7d
--- /dev/null
+++ b/linux/keyman-config/build.sh
@@ -0,0 +1,123 @@
+#!/usr/bin/env bash
+
+## START STANDARD BUILD SCRIPT INCLUDE
+# adjust relative paths as necessary
+THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
+. "${THIS_SCRIPT%/*}/../../resources/build/build-utils.sh"
+## END STANDARD BUILD SCRIPT INCLUDE
+
+################################ Main script ################################
+
+builder_describe \
+ "Build keyman-config." \
+ "clean" \
+ "configure" \
+ "build" \
+ "test" \
+ "install install artifacts" \
+ "uninstall uninstall artifacts" \
+
+builder_parse "$@"
+
+cd "$THIS_SCRIPT_PATH"
+
+builder_describe_outputs \
+ build "/linux/keyman-config/keyman_config/standards/lang_tags_map.py"
+
+clean_action() {
+ rm -rf dist make_deb build keyman_config/version.py ./*.egg-info __pycache__ \
+ keyman_config/standards/lang_tags_map.py
+}
+
+execute_with_temp_schema() {
+ local TEMP_DATA_DIR SCHEMA_DIR
+ TEMP_DATA_DIR=$(mktemp -d)
+ SCHEMA_DIR="${TEMP_DATA_DIR}/glib-2.0/schemas"
+ export XDG_DATA_DIRS="${TEMP_DATA_DIR}":${XDG_DATA_DIRS-}
+ export GSETTINGS_SCHEMA_DIR="${SCHEMA_DIR}"
+ mkdir -p "${SCHEMA_DIR}"
+ cp resources/com.keyman.gschema.xml "${SCHEMA_DIR}"/
+ glib-compile-schemas "${SCHEMA_DIR}"
+ "$@"
+ export XDG_DATA_DIRS=${XDG_DATA_DIRS#*:}
+ unset GSETTINGS_SCHEMA_DIR
+ rm -rf "${TEMP_DATA_DIR}"
+}
+
+build_man_and_help_pages() {
+ execute_with_temp_schema ./build-help.sh --no-reconf
+}
+
+build_action() {
+ builder_echo "Create version.py"
+ pushd keyman_config
+ sed \
+ -e "s/_VERSION_/${VERSION}/g" \
+ -e "s/_VERSIONWITHTAG_/${VERSION_WITH_TAG}/g" \
+ -e "s/_VERSIONGITTAG_/${VERSION_GIT_TAG}/g" \
+ -e "s/_MAJORVERSION_/${VERSION_MAJOR}/g" \
+ -e "s/_RELEASEVERSION_/${VERSION_RELEASE}/g" \
+ -e "s/_TIER_/${TIER}/g" \
+ -e "s/_ENVIRONMENT_/${VERSION_ENVIRONMENT}/g" \
+ -e "s/_UPLOADSENTRY_/${UPLOAD_SENTRY}/g" \
+ version.py.in > version.py
+ popd
+ pushd buildtools
+ if [ -f build-langtags.py ]; then
+ builder_echo "Create lang_tags_map.py"
+ python3 ./build-langtags.py
+ else
+ builder_echo "Skip building lang_tags_map.py during package build"
+ fi
+ popd
+ builder_echo "Building man and help pages"
+ build_man_and_help_pages
+ builder_echo "Building keyman-config"
+ python3 setup.py build
+}
+
+test_action() {
+ execute_with_temp_schema ./run-tests.sh
+}
+
+install_action() {
+ if [ -n "${SUDO_USER:-}" ]; then
+ # with sudo install into /usr/local
+ pip3 install qrcode sentry-sdk
+ # eventually change this to: pip3 install .
+ python3 setup.py install
+ # install icons
+ mkdir -p /usr/local/share/keyman/icons
+ cp keyman_config/icons/* /usr/local/share/keyman/icons
+ # install man pages
+ mkdir -p /usr/local/share/man/man1
+ cp ../../debian/man/*.1 /usr/local/share/man/man1
+ else
+ # without sudo install into /tmp/keyman (or $DESTDIR)
+ mkdir -p "/tmp/keyman/$(python3 -c 'import sys;import os;pythonver="python%d.%d" % (sys.version_info[0], sys.version_info[1]);sitedir = os.path.join("lib", pythonver, "site-packages");print(sitedir)')"
+ # when we no longer have to support old pip version (python > 3.6) change this to:
+ # pip3 install --prefix /tmp/keyman .
+ PYTHONUSERBASE=${DESTDIR:-/tmp/keyman} python3 setup.py install --user
+ fi
+}
+
+uninstall_action() {
+ # run as sudo
+ clean_action
+ rm -rf /usr/local/share/keyman/icons
+ rm -f /usr/local/share/man/man1/km-*.1
+ pip3 uninstall keyman_config
+ rm -f /usr/local/bin/km-config
+ rm -f /usr/local/bin/km-kvk2ldml
+ rm -f /usr/local/bin/km-package-get
+ rm -f /usr/local/bin/km-package-install
+ rm -f /usr/local/bin/km-package-list-installed
+ rm -f /usr/local/bin/km-package-uninstall
+}
+
+builder_run_action clean clean_action
+builder_run_action configure # nothing to do
+builder_run_action build build_action
+builder_run_action test test_action
+builder_run_action install install_action
+builder_run_action uninstall uninstall_action
diff --git a/linux/keyman-config/createkeymandirs.sh b/linux/keyman-config/createkeymandirs.sh
deleted file mode 100755
index d9befe7f5d505992f4ed0383abb2a0e587a7b5fa..0000000000000000000000000000000000000000
--- a/linux/keyman-config/createkeymandirs.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-
-sudo mkdir -p /usr/local/share/keyman
-sudo mkdir -p /usr/local/share/fonts/keyman
-sudo mkdir -p /usr/local/share/doc/keyman
-sudo chmod 00777 /usr/local/share/keyman
-sudo chmod 00777 /usr/local/share/fonts/keyman
-sudo chmod 00777 /usr/local/share/doc/keyman
diff --git a/linux/keyman-config/keyman_config/__init__.py b/linux/keyman-config/keyman_config/__init__.py
index e5cecf4cc82d6b6ae333dab67dd5aa615454b3e2..04098ade00fcbeeed91a9f7b5ee63070780d60af 100644
--- a/linux/keyman-config/keyman_config/__init__.py
+++ b/linux/keyman-config/keyman_config/__init__.py
@@ -1,20 +1,18 @@
-import getpass
import gettext
-import importlib
-import logging
-import os
-import platform
-import sys
-from .version import __version__
-from .version import __versionwithtag__
-from .version import __versiongittag__
-from .version import __majorversion__
-from .version import __releaseversion__
-from .version import __tier__
-from .version import __pkgversion__
-from .version import __environment__
-from .version import __uploadsentry__
+from keyman_config.sentry_handling import SentryErrorHandling
+
+from keyman_config.version import (
+ __version__,
+ __versionwithtag__,
+ __versiongittag__,
+ __majorversion__,
+ __releaseversion__,
+ __tier__,
+ __pkgversion__,
+ __environment__,
+ __uploadsentry__
+)
def _(txt):
@@ -24,7 +22,7 @@ def _(txt):
return translation
-def secure_lookup(data, key1, key2 = None):
+def secure_lookup(data, key1, key2=None):
"""
Return data[key1][key2] while dealing with data being None or key1 or key2 not existing
"""
@@ -38,18 +36,10 @@ def secure_lookup(data, key1, key2 = None):
return None
-def before_send(event, hint):
- if 'exc_info' in hint:
- exc_type, exc_value, tb = hint['exc_info']
- if isinstance(exc_value, KeyboardInterrupt):
- # Ignore KeyboardInterrupt exception
- return None
- return event
-
-
gettext.bindtextdomain('keyman-config', '/usr/share/locale')
gettext.textdomain('keyman-config')
+
#if __tier__ == 'alpha' or __tier__ == 'beta': // #7227 disabling:
# Alpha and beta versions will work against the staging server so that they
# can access new APIs etc that will only be available there. The staging
@@ -60,60 +50,8 @@ gettext.textdomain('keyman-config')
KeymanComUrl = 'https://keyman.com'
KeymanApiUrl = 'https://api.keyman.com'
+
# There's no staging site for downloads
KeymanDownloadsUrl = 'https://downloads.keyman.com'
-if 'unittest' in sys.modules.keys():
- print('Not reporting to Sentry', file=sys.stderr)
-elif os.environ.get('KEYMAN_NOSENTRY'):
- print('Not reporting to Sentry because KEYMAN_NOSENTRY environment variable set', file=sys.stderr)
-elif not __uploadsentry__:
- print('Not reporting to Sentry because UPLOAD_SENTRY is false (%s)' % __environment__, file=sys.stderr)
-else:
- try:
- # Try new sentry-sdk first
- sentry_sdk = importlib.import_module('sentry_sdk')
- from sentry_sdk import configure_scope, set_user
- from sentry_sdk.integrations.logging import LoggingIntegration
- HaveSentryNewSdk = True
-
- sentry_logging = LoggingIntegration(
- level=logging.INFO, # Capture info and above as breadcrumbs
- event_level=logging.CRITICAL # Send critical errors as events
- )
- SentryUrl = "https://1d0edbf2d0dc411b87119b6e92e2c357@o1005580.ingest.sentry.io/5983525"
- sentry_sdk.init(
- dsn=SentryUrl,
- environment=__environment__,
- release=__versiongittag__,
- integrations=[sentry_logging],
- before_send=before_send
- )
- set_user({'id': hash(getpass.getuser())})
- with configure_scope() as scope:
- scope.set_tag("app", os.path.basename(sys.argv[0]))
- scope.set_tag("pkgversion", __pkgversion__)
- scope.set_tag("platform", platform.platform())
- scope.set_tag("system", platform.system())
- scope.set_tag("tier", __tier__)
- except ImportError:
- try:
- # sentry-sdk is not available, so use older raven
- raven = importlib.import_module('raven')
- from raven import Client
- HaveSentryNewSdk = False
-
- # Note, legacy raven API requires secret (https://github.com/keymanapp/keyman/pull/5787#discussion_r721457909)
- SentryUrl = "https://1d0edbf2d0dc411b87119b6e92e2c357:e6d5a81ee6944fc79bd9f0cbb1f2c2a4@o1005580.ingest.sentry.io/5983525"
- client = Client(SentryUrl, environment=__environment__, release=__versiongittag__)
- client.user_context({'id': hash(getpass.getuser())})
- client.tags_context({
- 'app': os.path.basename(sys.argv[0]),
- 'pkgversion': __pkgversion__,
- 'platform': platform.platform(),
- 'system': platform.system(),
- 'tier': __tier__,
- })
- except ImportError:
- # even raven is not available. This is the case on Ubuntu 16.04. Just ignore.
- print(_('Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting.'), file=sys.stderr)
+SentryErrorHandling().initialize_sentry()
diff --git a/linux/keyman-config/keyman_config/dconf_util.py b/linux/keyman-config/keyman_config/dconf_util.py
index 09b95d1815a5f42021674cba68b40a6c2f7887fa..c28ec3fd19c5aa7b6a126c020caadb3412890f3b 100644
--- a/linux/keyman-config/keyman_config/dconf_util.py
+++ b/linux/keyman-config/keyman_config/dconf_util.py
@@ -2,25 +2,25 @@
from gi.repository import Gio
-# DConf path destkop/ibus/keyman/options
-DCONF_BASE = "com.keyman.options"
+# GSettings path destkop/ibus/keyman/options
+GSETTINGS_BASE = "com.keyman.options"
-# Utilities to get and set Keyman options in DConf:
+# Utilities to get and set Keyman options in GSettings:
# /desktop/ibus/keyman/options/packageID/keyboardID/options
def get_child_schema(info):
- settings = Gio.Settings.new(DCONF_BASE)
+ settings = Gio.Settings.new(GSETTINGS_BASE)
path = settings.get_property('path')
if not path.endswith('/'):
path += '/'
path += info['packageID'] + '/' + info['keyboardID'] + '/'
- return Gio.Settings(DCONF_BASE + '.child', path)
+ return Gio.Settings(GSETTINGS_BASE + '.child', path)
def get_option(info):
"""
- Get the Keyman keyboard options from DConf
+ Get the Keyman keyboard options from GSettings
Convert from list of comma-separated strings into dictionary
Args:
@@ -41,7 +41,7 @@ def get_option(info):
def set_option(info, options):
"""
- Store the Keyman keyboard options in DConf as a list of strings
+ Store the Keyman keyboard options in GSettings as a list of strings
Args:
info: dictionary
diff --git a/linux/keyman-config/keyman_config/get_kmp.py b/linux/keyman-config/keyman_config/get_kmp.py
index af7b34063d3336fd2c451c4ddddbdcf4073a1570..ed3f7ec8a444fdc178238f495f9ef29ca05f41f9 100755
--- a/linux/keyman-config/keyman_config/get_kmp.py
+++ b/linux/keyman-config/keyman_config/get_kmp.py
@@ -9,6 +9,7 @@ import requests
import requests_cache
from gi.repository import GObject
+from keyman_config import _
from keyman_config import KeymanApiUrl, KeymanDownloadsUrl
from keyman_config.deprecated_decorator import deprecated
@@ -20,6 +21,16 @@ class InstallLocation(GObject.GEnum):
Unknown = 99
+def get_install_area_string(area):
+ if area == InstallLocation.OS:
+ return _('System')
+ elif area == InstallLocation.Shared:
+ return _('Shared')
+ elif area == InstallLocation.User:
+ return _('User')
+ return _('Unknown')
+
+
def get_package_download_data(packageID, weekCache=False):
"""
Get package download data from keyboards download api.
diff --git a/linux/keyman-config/keyman_config/sentry_handling.py b/linux/keyman-config/keyman_config/sentry_handling.py
new file mode 100644
index 0000000000000000000000000000000000000000..f2b2f8adc3441b83ced5dc75879f06cbea06310f
--- /dev/null
+++ b/linux/keyman-config/keyman_config/sentry_handling.py
@@ -0,0 +1,152 @@
+#!/usr/bin/python3
+import getpass
+import importlib
+import logging
+import os
+import platform
+import sys
+from keyman_config.gsettings import GSettings
+from keyman_config.version import (
+ __version__,
+ __versionwithtag__,
+ __versiongittag__,
+ __majorversion__,
+ __releaseversion__,
+ __tier__,
+ __pkgversion__,
+ __environment__,
+ __uploadsentry__
+)
+
+import gi
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gio, Gtk
+
+
+class SentryErrorHandling:
+ def __init__(self) -> None:
+ self.settings = Gio.Settings.new('com.keyman.options')
+
+ def initialize_sentry(self):
+ (enabled, reason) = self.is_sentry_enabled()
+ if not enabled:
+ print(reason, file=sys.stderr)
+ logging.info(reason)
+ return (enabled, reason)
+ else:
+ try:
+ self._sentry_sdk_initialize()
+ except ImportError:
+ try:
+ self._raven_initialize()
+ except ImportError:
+ # even raven is not available. This is the case on Ubuntu 16.04. Just ignore.
+ print(_('Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting.'),
+ file=sys.stderr)
+ logging.info('Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting.')
+ return (False, _('Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting.'))
+ return (True, '')
+
+ def is_sentry_enabled(self):
+ if 'unittest' in sys.modules.keys():
+ return (False, 'Running unit tests, not reporting to Sentry')
+ elif self._get_environ_nosentry():
+ return (False, 'Not reporting to Sentry because KEYMAN_NOSENTRY environment variable set')
+ elif not __uploadsentry__:
+ return (False, f'Not reporting to Sentry because UPLOAD_SENTRY is false ({__environment__})')
+ elif not self._get_setting():
+ return (False, 'Not reporting to Sentry because disabled in GSettings')
+ return (True, 'Reporting to Sentry')
+
+ def is_sentry_disabled_by_variable(self):
+ return self._get_environ_nosentry() or not __uploadsentry__
+
+ def bind_checkbutton(self, button: Gtk.CheckButton):
+ self.settings.bind("error-reporting", button, "active", Gio.SettingsBindFlags.NO_SENSITIVITY)
+ self.settings.connect("changed::error-reporting", self._on_sentry_reporting_toggled)
+
+ def set_enabled(self, enabled):
+ assert not self.is_sentry_disabled_by_variable()
+ was_enabled = self.is_sentry_enabled()
+ self._save_setting(enabled)
+ if enabled != was_enabled:
+ self._handle_enabled(enabled)
+
+ def _get_environ_nosentry(self):
+ keyman_nosentry = os.environ.get('KEYMAN_NOSENTRY')
+ return keyman_nosentry and (int(keyman_nosentry) == 1)
+
+ def _handle_enabled(self, enabled):
+ if enabled:
+ self.initialize_sentry()
+ else:
+ self._close_sentry()
+
+ def _save_setting(self, enabled: bool):
+ self.settings.set_boolean('error-reporting', enabled)
+
+ def _get_setting(self) -> bool:
+ return self.settings.get_boolean('error-reporting')
+
+ def _on_sentry_reporting_toggled(self, settings, key):
+ self._handle_enabled(self.settings.get_boolean('error-reporting'))
+
+ def _close_sentry(self):
+ from sentry_sdk import Hub
+ logging.info("Shutting down Sentry error reporting")
+ client = Hub.current.client
+ if client is not None:
+ client.close(timeout=2.0)
+
+ def _sentry_sdk_initialize(self):
+ # Try new sentry-sdk first
+ sentry_sdk = importlib.import_module('sentry_sdk')
+ from sentry_sdk import configure_scope, set_user
+ from sentry_sdk.integrations.logging import LoggingIntegration
+
+ sentry_logging = LoggingIntegration(
+ level=logging.INFO, # Capture info and above as breadcrumbs
+ event_level=logging.CRITICAL # Send critical errors as events
+ )
+ SentryUrl = "https://1d0edbf2d0dc411b87119b6e92e2c357@o1005580.ingest.sentry.io/5983525"
+ sentry_sdk.init(
+ dsn=SentryUrl,
+ environment=__environment__,
+ release=__versiongittag__,
+ integrations=[sentry_logging],
+ before_send=self._before_send
+ )
+ set_user({'id': hash(getpass.getuser())})
+ with configure_scope() as scope:
+ scope.set_tag("app", os.path.basename(sys.argv[0]))
+ scope.set_tag("pkgversion", __pkgversion__)
+ scope.set_tag("platform", platform.platform())
+ scope.set_tag("system", platform.system())
+ scope.set_tag("tier", __tier__)
+ logging.info("Initialized Sentry error reporting")
+
+ def _raven_initialize(self):
+ # sentry-sdk is not available, so use older raven
+ raven = importlib.import_module('raven')
+ from raven import Client
+
+ # Note, legacy raven API requires secret (https://github.com/keymanapp/keyman/pull/5787#discussion_r721457909)
+ SentryUrl = "https://1d0edbf2d0dc411b87119b6e92e2c357:e6d5a81ee6944fc79bd9f0cbb1f2c2a4@o1005580.ingest.sentry.io/5983525"
+ client = Client(SentryUrl, environment=__environment__, release=__versiongittag__)
+ client.user_context({'id': hash(getpass.getuser())})
+ client.tags_context({
+ 'app': os.path.basename(sys.argv[0]),
+ 'pkgversion': __pkgversion__,
+ 'platform': platform.platform(),
+ 'system': platform.system(),
+ 'tier': __tier__,
+ })
+ logging.info("Initialized Sentry error reporting (raven)")
+
+ def _before_send(self, event, hint):
+ if 'exc_info' in hint:
+ exc_type, exc_value, tb = hint['exc_info']
+ if isinstance(exc_value, KeyboardInterrupt):
+ # Ignore KeyboardInterrupt exception
+ return None
+ return event
diff --git a/linux/keyman-config/keyman_config/view_installed.py b/linux/keyman-config/keyman_config/view_installed.py
index 01b1a59b89b3e413619c87abd56c479667abeab2..263d665d25f8ec89ef1694185015fad5e7f2d9b4 100755
--- a/linux/keyman-config/keyman_config/view_installed.py
+++ b/linux/keyman-config/keyman_config/view_installed.py
@@ -19,12 +19,13 @@ from keyman_config.accelerators import bind_accelerator, init_accel
from keyman_config.dbus_util import get_keyman_config_service
from keyman_config.downloadkeyboard import DownloadKmpWindow
from keyman_config.get_kmp import (InstallLocation, get_keyboard_dir,
- get_keyman_dir)
+ get_keyman_dir, get_install_area_string)
from keyman_config.install_window import InstallKmpWindow, find_keyman_image
from keyman_config.keyboard_details import KeyboardDetailsView
from keyman_config.kmpmetadata import get_fonts, parsemetadata
from keyman_config.list_installed_kmp import get_installed_kmp
from keyman_config.options import OptionsView
+from keyman_config.sentry_handling import SentryErrorHandling
from keyman_config.uninstall_kmp import uninstall_kmp
from keyman_config.welcome import WelcomeView
@@ -94,7 +95,7 @@ class ViewInstalledWindowBase(Gtk.Window):
self.close()
def run(self):
- self.resize(576, 324)
+ self.resize(776, 424)
self.connect("destroy", Gtk.main_quit)
self.show_all()
Gtk.main()
@@ -104,26 +105,60 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
def __init__(self):
ViewInstalledWindowBase.__init__(self)
-# window is split left/right hbox
-# right is ButtonBox
-# possibly 2 ButtonBox in a vbox
-# top one with _Remove, _About, ?_Welcome? or ?Read_Me?, _Options
-# bottom one with _Download, _Install, Re_fresh, _Close
-# left is GtkTreeView - does it need to be inside anything else apart from the hbox?
-# with liststore which defines columns
-# GdkPixbuf icon
-# gchararray name
-# gchararray version
-# gchararray packageID (hidden)
-# enum? area (user, shared, system) (icon or hidden?)
-# gchararray welcomefile (hidden) (or just use area and packageID?)
-# changing selected item in treeview changes what buttons are activated
-# on selected_item_changed signal set the data that the buttons will use in their callbacks
-# see https://developer.gnome.org/gtk3/stable/TreeWidget.html#TreeWidget
+ self.sentry = SentryErrorHandling()
+ outerHbox = Gtk.HBox()
+ sidebar = Gtk.StackSidebar()
+ stack = Gtk.Stack()
+
+ outerHbox.pack_start(sidebar, False, False, 0)
+ outerHbox.pack_end(Gtk.Separator(), False, False, 0)
+ outerHbox.pack_end(stack, True, True, 0)
+ stack.set_hexpand(True)
+ stack.set_vexpand(True)
+ sidebar.set_stack(stack)
+
+ stack.add_titled(self.add_keyboard_layouts_widget(), "KeyboardLayouts", _("Keyboard Layouts"))
+ stack.add_titled(self.add_options_widget(), "Options", _("Options"))
+
+ outmostVBox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
+ outmostVBox.pack_start(outerHbox, True, True, 0)
+
+ bbox_bottom = Gtk.ButtonBox(spacing=12, orientation=Gtk.Orientation.HORIZONTAL)
+ bbox_bottom.set_layout(Gtk.ButtonBoxStyle.START)
+
+ button = Gtk.Button.new_with_mnemonic(_("_Install keyboard..."))
+ button.set_tooltip_text(_("Install a keyboard from a file"))
+ button.connect("clicked", self.on_installfile_clicked)
+ bbox_bottom.add(button)
+
+ button = Gtk.Button.new_with_mnemonic(_("_Download keyboard..."))
+ button.set_tooltip_text(_("Download and install a keyboard from the Keyman website"))
+ button.connect("clicked", self.on_download_clicked)
+ bbox_bottom.add(button)
+
+ button = Gtk.Button.new_with_mnemonic(_("_Refresh"))
+ button.set_tooltip_text(_("Refresh keyboard list"))
+ button.connect("clicked", self.on_refresh_clicked)
+ bbox_bottom.add(button)
+
+ button = Gtk.Button.new_with_mnemonic(_("_Close"))
+ button.set_tooltip_text(_("Close window"))
+ button.connect("clicked", self.on_close_clicked)
+ bind_accelerator(self.accelerators, button, 'q')
+ bind_accelerator(self.accelerators, button, 'w')
+ bbox_bottom.add(button)
+
+ bbox_hbox = Gtk.HBox(spacing=12)
+ bbox_hbox.pack_start(bbox_bottom, True, True, 12)
+ outmostVBox.pack_end(bbox_hbox, False, True, 12)
+ self.add(outmostVBox)
+
+ def add_keyboard_layouts_widget(self):
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
- s = Gtk.ScrolledWindow()
- hbox.pack_start(s, True, True, 0)
+
+ scrolledWindow = Gtk.ScrolledWindow()
+ hbox.pack_start(scrolledWindow, True, True, 0)
self.store = Gtk.ListStore(
GdkPixbuf.Pixbuf, # icon
@@ -131,15 +166,11 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
str, # version
str, # packageID
int, # enum InstallLocation (KmpArea is GObject version)
+ str, # InstallLocation area
+ str, # Tooltip with InstallLocation path
str, # path to welcome file if it exists or None
str) # path to options file if it exists or None
- # add installed keyboards to the the store e.g.
- # treeiter = store.append([GdkPixbuf.Pixbuf.new_from_file_at_size(
- # "/usr/local/share/keyman/libtralo/libtralo.ico.png", 16, 16), \
- # "LIBTRALO", "1.6.1", \
- # "libtralo", KmpArea.SHARED, True])
-
self.refresh_installed_kmp()
self.tree = Gtk.TreeView(self.store)
@@ -155,11 +186,16 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
# i18n: column header in table displaying installed keyboards
column = Gtk.TreeViewColumn(_("Version"), renderer, text=2)
self.tree.append_column(column)
+ # i18n: column header in table displaying installed keyboards
+ column = Gtk.TreeViewColumn(_("Area"), renderer, text=5)
+ self.tree.append_column(column)
+
+ self.tree.set_tooltip_column(column=6)
select = self.tree.get_selection()
select.connect("changed", self.on_tree_selection_changed)
- s.add(self.tree)
+ scrolledWindow.add(self.tree)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
@@ -191,36 +227,34 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
bbox_top.add(self.options_button)
vbox.pack_start(bbox_top, False, False, 12)
+ hbox.pack_start(vbox, False, False, 12)
- bbox_bottom = Gtk.ButtonBox(spacing=12, orientation=Gtk.Orientation.VERTICAL)
- bbox_bottom.set_layout(Gtk.ButtonBoxStyle.END)
+ return hbox
- button = Gtk.Button.new_with_mnemonic(_("_Refresh"))
- button.set_tooltip_text(_("Refresh keyboard list"))
- button.connect("clicked", self.on_refresh_clicked)
- bbox_bottom.add(button)
+ def add_options_widget(self):
+ vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
+ label = Gtk.Label(_("General"))
+ label.set_padding(5, 5)
+ label.set_halign(Gtk.Align.START)
+ vbox.pack_start(label, False, False, 10)
- button = Gtk.Button.new_with_mnemonic(_("_Download"))
- button.set_tooltip_text(_("Download and install a keyboard from the Keyman website"))
- button.connect("clicked", self.on_download_clicked)
- bbox_bottom.add(button)
-
- button = Gtk.Button.new_with_mnemonic(_("_Install"))
- button.set_tooltip_text(_("Install a keyboard from a file"))
- button.connect("clicked", self.on_installfile_clicked)
- bbox_bottom.add(button)
+ (enabled, reason) = self.sentry.is_sentry_enabled()
+ disabledByVariable = self.sentry.is_sentry_disabled_by_variable()
- button = Gtk.Button.new_with_mnemonic(_("_Close"))
- button.set_tooltip_text(_("Close window"))
- button.connect("clicked", self.on_close_clicked)
- bind_accelerator(self.accelerators, button, 'q')
- bind_accelerator(self.accelerators, button, 'w')
- bbox_bottom.add(button)
+ self.errorReportingButton = Gtk.CheckButton(_("Automatically report errors to keyman.com"))
+ self.errorReportingButton.set_active(enabled)
+ self.errorReportingButton.set_sensitive(not disabledByVariable)
+ self.sentry.bind_checkbutton(self.errorReportingButton)
+ vbox.pack_start(self.errorReportingButton, False, False, 0)
- vbox.pack_end(bbox_bottom, False, False, 12)
+ if disabledByVariable:
+ label = Gtk.Label(reason)
+ label.set_halign(Gtk.Align.START)
+ label.set_padding(25, 0)
+ label.set_sensitive(False)
+ vbox.pack_start(label, False, False, 0)
- hbox.pack_start(vbox, False, False, 12)
- self.add(hbox)
+ return vbox
def addlistitems(self, installed_kmp, store, install_area):
for kmp in sorted(installed_kmp):
@@ -255,6 +289,8 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
kmpdata['version'],
kmpdata['packageID'],
install_area,
+ get_install_area_string(install_area),
+ path.replace(os.path.expanduser('~'), '~'),
welcome_file,
options_file])
diff --git a/linux/keyman-config/km-config.bash-completion b/linux/keyman-config/km-config.bash-completion
index b1f46c0076f7522383eb66c51342b9b380f30ed5..fd0eee394c77b5bc89154870136e539e5aeaa925 100644
--- a/linux/keyman-config/km-config.bash-completion
+++ b/linux/keyman-config/km-config.bash-completion
@@ -1,4 +1,5 @@
-#!/usr/bin/env bash
+# shellcheck disable=SC2148
+# No hashbang for bash completion scripts! They are intended to be sourced, not executed.
_km-config_completions()
{
diff --git a/linux/keyman-config/km-kvk2ldml.bash-completion b/linux/keyman-config/km-kvk2ldml.bash-completion
index 3eb2950c390659f1ce058c66b06243e42713d36d..1e8231a1a1fb37044f5fba26951212c0db7292f2 100644
--- a/linux/keyman-config/km-kvk2ldml.bash-completion
+++ b/linux/keyman-config/km-kvk2ldml.bash-completion
@@ -1,4 +1,5 @@
-#!/usr/bin/env bash
+# shellcheck disable=SC2148
+# No hashbang for bash completion scripts! They are intended to be sourced, not executed.
_km-kvk2ldml_completions()
{
diff --git a/linux/keyman-config/km-package-get.bash-completion b/linux/keyman-config/km-package-get.bash-completion
index 9bacb1b8fef29c8b7875131a0fd487a4919f0115..0fb3a4d14c76b1600d3f951ff0c44fac8af2df94 100644
--- a/linux/keyman-config/km-package-get.bash-completion
+++ b/linux/keyman-config/km-package-get.bash-completion
@@ -1,4 +1,5 @@
-#!/usr/bin/env bash
+# shellcheck disable=SC2148
+# No hashbang for bash completion scripts! They are intended to be sourced, not executed.
_km-package-get_completions()
{
diff --git a/linux/keyman-config/km-package-install.bash-completion b/linux/keyman-config/km-package-install.bash-completion
index 1a424e8ea6f80c9bb66b97923a38562b33dd573d..06bfeb6aa5cf688303550bef2f516324cf9710bf 100644
--- a/linux/keyman-config/km-package-install.bash-completion
+++ b/linux/keyman-config/km-package-install.bash-completion
@@ -1,4 +1,5 @@
-#!/usr/bin/env bash
+# shellcheck disable=SC2148
+# No hashbang for bash completion scripts! They are intended to be sourced, not executed.
_km-package-install_completions()
{
diff --git a/linux/keyman-config/km-package-list-installed.bash-completion b/linux/keyman-config/km-package-list-installed.bash-completion
index a3758b467eb8958d0af62dc48148249d9a69f0b5..672353b9a13a86838627bf067bf69af559cba584 100644
--- a/linux/keyman-config/km-package-list-installed.bash-completion
+++ b/linux/keyman-config/km-package-list-installed.bash-completion
@@ -1,4 +1,5 @@
-#!/usr/bin/env bash
+# shellcheck disable=SC2148
+# No hashbang for bash completion scripts! They are intended to be sourced, not executed.
_km-package-list-installed_completions()
{
diff --git a/linux/keyman-config/km-package-uninstall.bash-completion b/linux/keyman-config/km-package-uninstall.bash-completion
index 191e709eabaf2344951ff70f1919911f8ff1b6ed..4b81c38dacc9eaa9c0ec67e19415db9b5fb56983 100644
--- a/linux/keyman-config/km-package-uninstall.bash-completion
+++ b/linux/keyman-config/km-package-uninstall.bash-completion
@@ -1,4 +1,5 @@
-#!/usr/bin/env bash
+# shellcheck disable=SC2148
+# No hashbang for bash completion scripts! They are intended to be sourced, not executed.
_km-package-uninstall_completions()
{
diff --git a/linux/keyman-config/com.keyman.gschema.xml b/linux/keyman-config/resources/com.keyman.gschema.xml
similarity index 64%
rename from linux/keyman-config/com.keyman.gschema.xml
rename to linux/keyman-config/resources/com.keyman.gschema.xml
index 8f05a42bf9b0c70d4bc2ee9ffdb6b3ec6716c9c3..df50060d8c44eb97e2ec4e8d4848ab23c34ef665 100644
--- a/linux/keyman-config/com.keyman.gschema.xml
+++ b/linux/keyman-config/resources/com.keyman.gschema.xml
@@ -1,8 +1,12 @@
-
+
+ true
+ Automatic error reporting
+ true to enable automatic reporting of errors to Sentry
+
diff --git a/linux/debian/keyman.sharedmimeinfo b/linux/keyman-config/resources/keyman.sharedmimeinfo
similarity index 100%
rename from linux/debian/keyman.sharedmimeinfo
rename to linux/keyman-config/resources/keyman.sharedmimeinfo
diff --git a/linux/keyman-config/km-config.desktop b/linux/keyman-config/resources/km-config.desktop
similarity index 100%
rename from linux/keyman-config/km-config.desktop
rename to linux/keyman-config/resources/km-config.desktop
diff --git a/linux/keyman-config/run-tests.sh b/linux/keyman-config/run-tests.sh
index 3b8664512adc639aa376c6e6ed4b5da8e479713c..b390ce613bc589d926da09a8ca39c28ecd7c3a19 100755
--- a/linux/keyman-config/run-tests.sh
+++ b/linux/keyman-config/run-tests.sh
@@ -1,6 +1,9 @@
#!/bin/bash
PYTHONPATH=.:$PYTHONPATH
+XDG_CONFIG_HOME=$(mktemp --directory)
+export XDG_CONFIG_HOME
+
if [ -n "$TEAMCITY_VERSION" ]; then
if ! pip3 list --format=columns | grep -q teamcity-messages; then
pip3 install teamcity-messages
@@ -9,3 +12,5 @@ if [ -n "$TEAMCITY_VERSION" ]; then
else
python3 -m unittest discover -v -s tests -p test_*.py
fi
+
+rm -rf "$XDG_CONFIG_HOME"
diff --git a/linux/keyman-config/tests/test_gnome_keyboards_util.py b/linux/keyman-config/tests/test_gnome_keyboards_util.py
index b5a0cac842fff324e018f25672c1b93817ef376b..a53908cdd3296aaee7dfa26b838ac0fe29042f67 100644
--- a/linux/keyman-config/tests/test_gnome_keyboards_util.py
+++ b/linux/keyman-config/tests/test_gnome_keyboards_util.py
@@ -9,14 +9,14 @@ class GnomeKeyboardsUtilTests(unittest.TestCase):
def setUp(self):
_reset_gnome_shell()
- @patch('keyman_config.os.system')
+ @patch('os.system')
def test_IsGnomeShell_RunningGnomeShell(self, mockSystem):
# Setup
mockSystem.return_value = 0
# Execute/Verify
self.assertEqual(is_gnome_shell(), True)
- @patch('keyman_config.os.system')
+ @patch('os.system')
def test_IsGnomeShell_NotRunningGnomeShell(self, mockSystem):
# Setup
mockSystem.return_value = 1
diff --git a/linux/keyman-config/tests/test_install_kmp.py b/linux/keyman-config/tests/test_install_kmp.py
index 2f250550cd3ecef1ea5f1f1a88debe4a292c6178..d1e10bd645b6d9aaa450bc9fed3cc64883b92b31 100644
--- a/linux/keyman-config/tests/test_install_kmp.py
+++ b/linux/keyman-config/tests/test_install_kmp.py
@@ -262,13 +262,11 @@ class InstallKmpTests(unittest.TestCase):
def test_InstallKmp_FutureKeymanVersion(self):
# Setup
- workdir = tempfile.TemporaryDirectory().name
- os.makedirs(workdir)
- packagedir = tempfile.TemporaryDirectory().name
- os.makedirs(packagedir)
- self.mockGetKeyboardDir.return_value = packagedir
- kmpfile = self._createEmptyKmp(workdir)
- self._createKmpJson(packagedir, ', "fileVersion": "99.0"')
+ workdir = tempfile.TemporaryDirectory()
+ packagedir = tempfile.TemporaryDirectory()
+ self.mockGetKeyboardDir.return_value = packagedir.name
+ kmpfile = self._createEmptyKmp(workdir.name)
+ self._createKmpJson(packagedir.name, ', "fileVersion": "99.0"')
# Execute
with self.assertRaises(InstallError) as context:
@@ -278,22 +276,24 @@ class InstallKmpTests(unittest.TestCase):
self.assertTrue('foo.kmp requires Keyman 99.0 or higher' in context.exception.message)
self.mockInstallToIbus.assert_not_called()
+ # Teardown
+ workdir.cleanup()
+ packagedir.cleanup()
+
def test_InstallKmp(self):
for testcase in [
{'name': 'PreviousKeymanVersion', 'fileVersion': ', "fileVersion": "7.0"'},
- {'name': 'SameKeymanVersion', 'fileVersion': ', "fileVersion": "' + __version__ + '"'},
+ {'name': 'SameKeymanVersion', 'fileVersion': f', "fileVersion": "{__version__}"'},
{'name': 'NoFileVersion', 'fileVersion': ''}
]:
with self.subTest(msg=testcase['name'], data=testcase['fileVersion']):
# Setup
self.mockInstallToIbus.reset_mock()
- workdir = tempfile.TemporaryDirectory().name
- os.makedirs(workdir)
- packagedir = tempfile.TemporaryDirectory().name
- os.makedirs(packagedir)
- self.mockGetKeyboardDir.return_value = packagedir
- kmpfile = self._createEmptyKmp(workdir)
- self._createKmpJson(packagedir, testcase['fileVersion'])
+ workdir = tempfile.TemporaryDirectory()
+ packagedir = tempfile.TemporaryDirectory()
+ self.mockGetKeyboardDir.return_value = packagedir.name
+ kmpfile = self._createEmptyKmp(workdir.name)
+ self._createKmpJson(packagedir.name, testcase['fileVersion'])
# Execute
InstallKmp()._install_kmp(kmpfile, 'km', InstallLocation.User)
@@ -301,6 +301,10 @@ class InstallKmpTests(unittest.TestCase):
# Verify
self.mockInstallToIbus.assert_called_once()
+ # Teardown
+ workdir.cleanup()
+ packagedir.cleanup()
+
if __name__ == '__main__':
unittest.main()
diff --git a/linux/keyman-config/tests/test_package_install_completion.py b/linux/keyman-config/tests/test_package_install_completion.py
index 97238e3dc2e57051c63d085d1692018267841f71..61374a6c66cbc5756e22b0c42e42810adf378b03 100644
--- a/linux/keyman-config/tests/test_package_install_completion.py
+++ b/linux/keyman-config/tests/test_package_install_completion.py
@@ -2,7 +2,7 @@
import os
import tempfile
import unittest
-from unittest.mock import patch, ANY
+from unittest.mock import patch
from importlib.machinery import SourceFileLoader
from importlib.util import module_from_spec, spec_from_loader
@@ -10,17 +10,11 @@ from importlib.util import module_from_spec, spec_from_loader
class PackageInstallCompletionTests(unittest.TestCase):
def setUp(self):
- patcher1 = patch('keyman_config.install_kmp.extract_kmp')
- self.mockExtractKmp = patcher1.start()
- self.addCleanup(patcher1.stop)
- patcher2 = patch('keyman_config.kmpmetadata.get_metadata')
- self.mockGetMetadata = patcher2.start()
- self.addCleanup(patcher2.stop)
-
+ self.mockExtractKmp = self._setupMock('keyman_config.install_kmp.extract_kmp')
+ self.mockGetMetadata = self._setupMock('keyman_config.kmpmetadata.get_metadata')
loader = SourceFileLoader('km_package_install', os.path.join(os.path.dirname(
os.path.abspath(__file__)), '../km-package-install'))
- spec = spec_from_loader(loader.name, loader)
- if spec:
+ if spec := spec_from_loader(loader.name, loader):
self.mod = module_from_spec(spec)
loader.exec_module(self.mod)
@@ -29,32 +23,43 @@ class PackageInstallCompletionTests(unittest.TestCase):
self.cacheDir = os.path.join(self.tempDir.name, 'keyman')
os.makedirs(self.cacheDir)
+ def tearDown(self):
+ self.tempDir.cleanup()
+
+ def _setupMock(self, arg0):
+ patcher = patch(arg0)
+ result = patcher.start()
+ self.addCleanup(patcher.stop)
+ return result
+
def _list_languages_for_keyboard_impl(self, packageId):
return self.mod._list_languages_for_keyboard_impl(packageId, 'someDir')
def test_PackageCompletionNoLanguage(self):
- open(os.path.join(self.cacheDir, 'foo'), 'w')
- self.mockGetMetadata.return_value = (None, None, None, [{}], None)
- result = self._list_languages_for_keyboard_impl('foo')
- self.assertEqual(result, "")
+ with open(os.path.join(self.cacheDir, 'foo'), 'w'):
+ self.mockGetMetadata.return_value = (None, None, None, [{}], None)
+ result = self._list_languages_for_keyboard_impl('foo')
+ self.assertEqual(result, "")
def test_PackageCompletionOneLanguage(self):
- open(os.path.join(self.cacheDir, 'khmer_angkor'), 'w')
- self.mockGetMetadata.return_value = (
- None, None, None,
- [{'languages': [{'name': 'Central Khmer (Khmer, Cambodia)', 'id': 'km'}]}],
- None)
- result = self._list_languages_for_keyboard_impl('khmer_angkor')
- self.assertEqual(result, "km")
+ with open(os.path.join(self.cacheDir, 'khmer_angkor'), 'w'):
+ self.mockGetMetadata.return_value = (
+ None, None, None,
+ [{'languages': [{'name': 'Central Khmer (Khmer, Cambodia)', 'id': 'km'}]}],
+ None
+ )
+ result = self._list_languages_for_keyboard_impl('khmer_angkor')
+ self.assertEqual(result, "km")
def test_PackageCompletionMultipleLanguages(self):
- open(os.path.join(self.cacheDir, 'sil_euro_latin'), 'w')
- self.mockGetMetadata.return_value = (
- None, None, None,
- [{'languages': [
- {'name': 'English', 'id': 'en'},
- {'name': 'French', 'id': 'fr'},
- {'name': 'German', 'id': 'de'}]}],
- None)
- result = self._list_languages_for_keyboard_impl('sil_euro_latin')
- self.assertEqual(result, 'en\nfr\nde')
+ with open(os.path.join(self.cacheDir, 'sil_euro_latin'), 'w'):
+ self.mockGetMetadata.return_value = (
+ None, None, None,
+ [{'languages': [
+ {'name': 'English', 'id': 'en'},
+ {'name': 'French', 'id': 'fr'},
+ {'name': 'German', 'id': 'de'}]}],
+ None
+ )
+ result = self._list_languages_for_keyboard_impl('sil_euro_latin')
+ self.assertEqual(result, 'en\nfr\nde')
diff --git a/linux/keyman-system-service/README.md b/linux/keyman-system-service/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..358004af8fccd109d83ae9c69c79993c7982c06c
--- /dev/null
+++ b/linux/keyman-system-service/README.md
@@ -0,0 +1,28 @@
+# keyman-system-service
+
+A DBus system service that allows to access /dev/input/* devices
+to toggle capslock and perform other keyboard related actions when
+running under Wayland.
+
+See ,
+,
+,
+.
+
+## Notes
+
+- If we need to limit access to the interface to only Keyman, we can use
+ [polkit](https://www.freedesktop.org/software/polkit/docs/latest/polkit.8.html)
+ which allows to add a rule with an action that checks for the program.
+
+- to see the log file
+
+ ```bash
+ journalctl -f -u systemd-keyman
+ ```
+
+- to monitor method calls
+
+ ```bash
+ sudo busctl monitor com.keyman.SystemService1
+ ```
diff --git a/linux/keyman-system-service/build.sh b/linux/keyman-system-service/build.sh
new file mode 100755
index 0000000000000000000000000000000000000000..9b248c51130d69f2f01a3bdf0b55023f6cb30faf
--- /dev/null
+++ b/linux/keyman-system-service/build.sh
@@ -0,0 +1,66 @@
+#!/usr/bin/env bash
+
+## START STANDARD BUILD SCRIPT INCLUDE
+# adjust relative paths as necessary
+THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
+. "${THIS_SCRIPT%/*}/../../resources/build/build-utils.sh"
+## END STANDARD BUILD SCRIPT INCLUDE
+
+################################ Main script ################################
+
+builder_describe \
+ "Build keyman-system-service." \
+ ":service" \
+ "clean" \
+ "configure" \
+ "build" \
+ "test" \
+ "install install artifacts" \
+ "uninstall uninstall artifacts"
+
+builder_parse "$@"
+
+cd "$THIS_SCRIPT_PATH/"
+
+if builder_is_debug_build; then
+ MESON_TARGET=debug
+ export CPPFLAGS=-DG_MESSAGES_DEBUG
+ export CFLAGS="-O0"
+ export CXXFLAGS="-O0"
+else
+ MESON_TARGET=release
+fi
+MESON_PATH="build/$(uname -m)/$MESON_TARGET"
+
+builder_describe_outputs \
+ configure "${MESON_PATH}/build.ninja" \
+ build "${MESON_PATH}/src/keyman-system-service"
+
+builder_run_action clean rm -rf "$THIS_SCRIPT_PATH/build/"
+
+# shellcheck disable=SC2086
+builder_run_action configure meson setup "$MESON_PATH" --werror --buildtype $MESON_TARGET "${builder_extra_params[@]}"
+
+if builder_start_action build; then
+ cd "$MESON_PATH"
+ ninja
+ builder_finish_action success build
+fi
+
+if builder_start_action test; then
+ cd "$MESON_PATH"
+ meson test --print-errorlogs $builder_verbose
+ builder_finish_action success test
+fi
+
+if builder_start_action install; then
+ cd "$MESON_PATH"
+ ninja install
+ builder_finish_action success install
+fi
+
+if builder_start_action uninstall; then
+ cd "$MESON_PATH"
+ ninja uninstall
+ builder_finish_action success uninstall
+fi
diff --git a/linux/keyman-system-service/man/keyman-system-service.1 b/linux/keyman-system-service/man/keyman-system-service.1
new file mode 100644
index 0000000000000000000000000000000000000000..b506bd1607aa99442aa832d60292240f3bdae57d
--- /dev/null
+++ b/linux/keyman-system-service/man/keyman-system-service.1
@@ -0,0 +1,10 @@
+.TH KEYMAN-SYSTEM-SERVICE "1" "May 2023" "keyman-system-service" "User Commands"
+.SH NAME
+keyman-system-service \- System service for Keyman
+.SH DESCRIPTION
+\&keyman\-system\-service
+.TP
+This command should not be run directly. It will be started as a DBUS
+system service by systemd.
+.SH "SEE ALSO"
+.BR ibus-engine-keyman(1)
diff --git a/linux/keyman-system-service/meson.build b/linux/keyman-system-service/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..596ba48bcd443f4afde80d691c3ab09e23deacbe
--- /dev/null
+++ b/linux/keyman-system-service/meson.build
@@ -0,0 +1,11 @@
+project('keyman-system-service', 'c', 'cpp',
+ version: run_command('cat', '../../VERSION.md', check: true).stdout().strip(),
+ license: 'GPL-2+',
+ meson_version: '>=1.0')
+
+evdev = dependency('libevdev', version: '>= 1.9')
+systemd = dependency('libsystemd')
+
+subdir('resources')
+subdir('src')
+subdir('tests')
diff --git a/linux/keyman-system-service/resources/com.keyman.SystemService1.conf b/linux/keyman-system-service/resources/com.keyman.SystemService1.conf
new file mode 100644
index 0000000000000000000000000000000000000000..e2c564a94bc0e467c0f91c966d58c4766dde488d
--- /dev/null
+++ b/linux/keyman-system-service/resources/com.keyman.SystemService1.conf
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/linux/keyman-system-service/resources/com.keyman.SystemService1.service b/linux/keyman-system-service/resources/com.keyman.SystemService1.service
new file mode 100644
index 0000000000000000000000000000000000000000..3966fb1bbcb9003cffa49efa358eabd5ef591ff6
--- /dev/null
+++ b/linux/keyman-system-service/resources/com.keyman.SystemService1.service
@@ -0,0 +1,7 @@
+# /usr/share/dbus-1/system-services/com.keyman.SystemService1.service
+
+[D-BUS Service]
+Name=com.keyman.SystemService1
+Exec=/bin/false
+User=root
+SystemdService=systemd-keyman.service
diff --git a/linux/keyman-system-service/resources/meson.build b/linux/keyman-system-service/resources/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..c28cb81e585a540a0ae407509aec37ecfabc522b
--- /dev/null
+++ b/linux/keyman-system-service/resources/meson.build
@@ -0,0 +1,3 @@
+install_data('com.keyman.SystemService1.conf', install_dir: get_option('datadir') / 'dbus-1/system.d/')
+install_data('com.keyman.SystemService1.service', install_dir: get_option('datadir') / 'dbus-1/system-services/')
+install_data('systemd-keyman.service', install_dir: get_option('prefix') / 'lib/systemd/system/')
diff --git a/linux/keyman-system-service/resources/systemd-keyman.service b/linux/keyman-system-service/resources/systemd-keyman.service
new file mode 100644
index 0000000000000000000000000000000000000000..7cb67508a89076395ba0b1b7b9e16a3f04fad3de
--- /dev/null
+++ b/linux/keyman-system-service/resources/systemd-keyman.service
@@ -0,0 +1,51 @@
+# systemd service file
+# /usr/lib/systemd/system/systemd-keyman.service
+# See https://stackoverflow.com/a/31725112
+
+[Unit]
+Description=Keyman System Service
+
+[Service]
+Type=dbus
+BusName=com.keyman.SystemService1
+ExecStart=/usr/libexec/keyman-system-service
+Restart=on-failure
+
+# Filesystem lockdown
+ProtectSystem=strict
+ProtectKernelTunables=true
+ProtectControlGroups=true
+ReadWritePaths=/dev/input/
+PrivateTmp=true
+
+# Network
+PrivateNetwork=true
+IPAddressDeny=any
+RestrictAddressFamilies=AF_UNIX
+
+# Execute Mappings
+MemoryDenyWriteExecute=true
+
+# Modules
+ProtectKernelModules=true
+
+# Real-time
+RestrictRealtime=true
+
+# Privilege escalation
+NoNewPrivileges=true
+
+# Capabilities
+CapabilityBoundingSet=
+
+# System call interfaces
+LockPersonality=yes
+SystemCallArchitectures=native
+SystemCallFilter=@system-service
+
+# Namespaces
+PrivateUsers=yes
+RestrictNamespaces=yes
+
+# Locked memory
+LimitMEMLOCK=0
diff --git a/linux/keyman-system-service/src/KeyboardDevice.cpp b/linux/keyman-system-service/src/KeyboardDevice.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a744a96b8282e593b5175caa3e06a3e1d551241c
--- /dev/null
+++ b/linux/keyman-system-service/src/KeyboardDevice.cpp
@@ -0,0 +1,88 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include "KeyboardDevice.h"
+
+using namespace std;
+
+KeyboardDevice::KeyboardDevice()
+{
+ dev = nullptr;
+ fd = -1;
+ hasCapsLockLed = -1;
+ debug = false;
+}
+
+KeyboardDevice::~KeyboardDevice()
+{
+ if (dev) {
+ libevdev_free(dev);
+ }
+ if (fd != -1) {
+ close(fd);
+ }
+}
+
+bool KeyboardDevice::Initialize(const char* name)
+{
+ string path("/dev/input/");
+ path.append(name);
+
+ fd = open(path.c_str(), O_RDWR);
+ if (fd < 0) {
+ std::cerr << "Failed to open device " << path << ": " << strerror(errno) << std::endl;
+ return false;
+ }
+
+ int rc = libevdev_new_from_fd(fd, &dev);
+ if (rc < 0) {
+ std::cerr << "Failed to init libevdev for " << path << ": " << strerror(-rc) << std::endl;
+ close(fd);
+ fd = -1;
+ return false;
+ }
+
+ return true;
+}
+
+bool KeyboardDevice::HasCapsLockLed()
+{
+ if (hasCapsLockLed < 0) {
+ if (!libevdev_has_event_code(dev, EV_LED, LED_CAPSL)) {
+ hasCapsLockLed = 0;
+ if (debug) {
+ std::cerr << "Device '" << libevdev_get_name(dev) << "' doesn't have "
+ << libevdev_event_code_get_name(EV_LED, LED_CAPSL) << "." << std::endl;
+ }
+ } else {
+ hasCapsLockLed = 1;
+ }
+ }
+ return hasCapsLockLed == 1;
+}
+
+void KeyboardDevice::SetCapsLockLed(bool on)
+{
+ if (!HasCapsLockLed()) {
+ return;
+ }
+
+ int rc = libevdev_kernel_set_led_value(dev, LED_CAPSL, on ? LIBEVDEV_LED_ON : LIBEVDEV_LED_OFF);
+ if (rc != 0) {
+ std::cerr << "Failed to set LED " << libevdev_event_code_get_name(EV_LED, LED_CAPSL)
+ << ": " << strerror(-rc) << std::endl;
+ }
+}
+
+bool KeyboardDevice::GetCapsLockLed()
+{
+ if (!HasCapsLockLed()) {
+ return false;
+ }
+
+ int val = libevdev_get_event_value(dev, EV_LED, LED_CAPSL);
+ return val;
+}
diff --git a/linux/keyman-system-service/src/KeyboardDevice.h b/linux/keyman-system-service/src/KeyboardDevice.h
new file mode 100644
index 0000000000000000000000000000000000000000..af9ce119f339db7fb2162a2f6e4a310f9330b15d
--- /dev/null
+++ b/linux/keyman-system-service/src/KeyboardDevice.h
@@ -0,0 +1,25 @@
+#ifndef __KEYBOARDDEVICE_H__
+#define __KEYBOARDDEVICE_H__
+
+#include
+
+class KeyboardDevice
+{
+ public:
+ KeyboardDevice();
+ virtual ~KeyboardDevice();
+
+ bool Initialize(const char* name);
+ bool HasCapsLockLed();
+ void SetCapsLockLed(bool on);
+ bool GetCapsLockLed();
+ void SetDebug(bool on) { debug = on; }
+
+ private:
+ struct libevdev *dev;
+ int fd;
+ int hasCapsLockLed;
+ bool debug;
+};
+
+#endif // __KEYBOARDDEVICE_H__
diff --git a/linux/keyman-system-service/src/KeymanSystemService.cpp b/linux/keyman-system-service/src/KeymanSystemService.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..deceafd0c39193c3693c41ab54bdb10330f50107
--- /dev/null
+++ b/linux/keyman-system-service/src/KeymanSystemService.cpp
@@ -0,0 +1,195 @@
+// This file implements a service which will run on the system dbus,
+// based on the sd-bus library, see
+// https://0pointer.net/blog/the-new-sd-bus-api-of-systemd.html
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "KeymanSystemService.h"
+#include "KeyboardDevice.h"
+
+#define KEYMAN_BUS_NAME "com.keyman.SystemService1"
+#define KEYMAN_INTERFACE_NAME "com.keyman.SystemService1.System"
+#define KEYMAN_OBJECT_PATH "/com/keyman/SystemService1/System"
+
+using namespace std;
+
+static int32_t
+on_set_caps_lock_indicator(
+ sd_bus_message *msg,
+ void *user_data,
+ sd_bus_error *ret_error
+) {
+ int32_t ret;
+ uint32_t state;
+
+ *ret_error = SD_BUS_ERROR_NULL;
+
+ ret = sd_bus_message_read_basic(msg, 'b', &state);
+ if (ret < 0) {
+ syslog(LOG_USER | LOG_NOTICE, "Failed to parse parameter: %s", strerror(-ret));
+ return ret;
+ }
+
+ KeymanSystemService *service = static_cast(user_data);
+ service->SetCapsLockIndicatorOnDevices(state);
+ return sd_bus_reply_method_return(msg, "");
+}
+
+static int32_t
+on_get_caps_lock_indicator(
+ sd_bus_message *msg,
+ void *user_data,
+ sd_bus_error *ret_error
+) {
+ uint32_t state;
+
+ *ret_error = SD_BUS_ERROR_NULL;
+
+ KeymanSystemService *service = static_cast(user_data);
+ state = service->GetCapsLockIndicatorOnDevices();
+ return sd_bus_reply_method_return(msg, "b", state);
+}
+
+static const sd_bus_vtable system_service_vtable[] = {
+ SD_BUS_VTABLE_START(0),
+ SD_BUS_METHOD("SetCapsLockIndicator", "b", "", on_set_caps_lock_indicator, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("GetCapsLockIndicator", "", "b", on_get_caps_lock_indicator, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_VTABLE_END
+};
+
+KeymanSystemService::KeymanSystemService()
+{
+ int ret;
+
+ GetKbdDevices();
+
+#ifdef KEYMAN_TESTING
+ ret = sd_bus_open_user(&bus);
+#else
+ ret = sd_bus_open_system(&bus);
+#endif
+
+ if (ret < 0) {
+ syslog(LOG_USER | LOG_NOTICE, "Failed to connect to system bus: %s", strerror(-ret));
+ failed = true;
+ return;
+ }
+
+ // Install the object
+ ret = sd_bus_add_object_vtable(bus,
+ &slot,
+ KEYMAN_OBJECT_PATH,
+ KEYMAN_INTERFACE_NAME,
+ system_service_vtable,
+ this);
+ if (ret < 0) {
+ syslog(LOG_USER | LOG_NOTICE, "Failed to issue method call: %s", strerror(-ret));
+ failed = true;
+ return;
+ }
+
+ // Take a well-known service name so that clients can find us
+ ret = sd_bus_request_name(bus, KEYMAN_BUS_NAME, 0);
+ if (ret < 0) {
+ syslog(LOG_USER | LOG_NOTICE, "Failed to acquire service name: %s", strerror(-ret));
+ failed = true;
+ return;
+ }
+}
+
+KeymanSystemService::~KeymanSystemService()
+{
+ if (slot) sd_bus_slot_unref(slot);
+ if (bus) sd_bus_unref(bus);
+
+ if (kbd_devices) {
+ for (KeyboardDevice *device : *kbd_devices) {
+ delete device;
+ }
+ delete kbd_devices;
+ }
+}
+
+int KeymanSystemService::Loop()
+{
+ for (;;) {
+ // Process requests
+ int ret = sd_bus_process(bus, NULL);
+ if (ret < 0) {
+ syslog(LOG_USER | LOG_NOTICE, "Failed to process bus: %s", strerror(-ret));
+ failed = true;
+ return ret;
+ }
+ if (ret > 0) {
+ // we processed a request, try to process another one, right-away
+ continue;
+ }
+
+ // Wait for the next request to process
+ ret = sd_bus_wait(bus, (uint64_t)-1);
+ if (ret < 0) {
+ syslog(LOG_USER | LOG_NOTICE, "Failed to wait on bus: %s", strerror(-ret));
+ failed = true;
+ return ret;
+ }
+ }
+ return 0;
+}
+
+void KeymanSystemService::GetKbdDevices() {
+ kbd_devices = new std::list();
+
+ DIR *dirstream;
+ struct dirent *dir;
+ dirstream = opendir("/dev/input");
+ if (dirstream) {
+ while ((dir = readdir(dirstream)) != NULL) {
+ // we're looking for a character device like `event1`
+ if (dir->d_type == DT_CHR && strncmp(dir->d_name, "event", 5) == 0) {
+ KeyboardDevice *kbdDevice = new KeyboardDevice();
+ if (!kbdDevice->Initialize(dir->d_name) || !kbdDevice->HasCapsLockLed()) {
+ delete kbdDevice;
+ continue;
+ }
+ kbd_devices->push_back(kbdDevice);
+ }
+ }
+ closedir(dirstream);
+ }
+}
+
+// Set the CapsLock indicator on all keyboard devices.
+void
+KeymanSystemService::SetCapsLockIndicatorOnDevices(uint32_t state) {
+ for (KeyboardDevice *kbdDevice : *kbd_devices) {
+ if (!kbdDevice->HasCapsLockLed()) {
+ syslog(LOG_USER | LOG_NOTICE, "%s: No kbdDevice or no CapsLockLed", __FUNCTION__);
+ continue;
+ }
+ syslog(LOG_USER | LOG_NOTICE, "%s: Caps Lock indicator: %s", __FUNCTION__, (state != 0 ? "ON" : "OFF"));
+ kbdDevice->SetCapsLockLed(state != 0);
+ }
+}
+
+// Get the CapsLock indicator state from the list of keyboard devices.
+// This will return true if any keyboard has the CapsLock indicator lit.
+uint32_t
+KeymanSystemService::GetCapsLockIndicatorOnDevices() {
+ bool state = false;
+ for (KeyboardDevice *kbdDevice : *kbd_devices) {
+ if (!kbdDevice->HasCapsLockLed()) {
+ syslog(LOG_USER | LOG_NOTICE, "%s: No kbdDevice or no CapsLockLed", __FUNCTION__);
+ continue;
+ }
+ state = state || kbdDevice->GetCapsLockLed();
+ }
+ return state;
+}
diff --git a/linux/keyman-system-service/src/KeymanSystemService.h b/linux/keyman-system-service/src/KeymanSystemService.h
new file mode 100644
index 0000000000000000000000000000000000000000..2686bfb99f95315ac28ca022ed846e9392e0444e
--- /dev/null
+++ b/linux/keyman-system-service/src/KeymanSystemService.h
@@ -0,0 +1,33 @@
+#ifndef __KEYMANSYSTEMSERVICE_H__
+#define __KEYMANSYSTEMSERVICE_H__
+
+#include
+#include
+#include "KeyboardDevice.h"
+
+using namespace std;
+
+class KeymanSystemService {
+private:
+ std::list* kbd_devices = NULL;
+ sd_bus_slot *slot = NULL;
+ sd_bus *bus = NULL;
+ bool failed = false;
+
+ void GetKbdDevices();
+
+public:
+ KeymanSystemService();
+ ~KeymanSystemService();
+
+ bool
+ Failed() {
+ return failed;
+ }
+
+ int Loop();
+ void SetCapsLockIndicatorOnDevices(uint32_t state);
+ uint32_t GetCapsLockIndicatorOnDevices();
+};
+
+#endif // __KEYMANSYSTEMSERVICE_H__
diff --git a/linux/keyman-system-service/src/com.keyman.SystemService1.System.xml b/linux/keyman-system-service/src/com.keyman.SystemService1.System.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b75a1f23904be79d7483b5fa10cae0f03acb9b96
--- /dev/null
+++ b/linux/keyman-system-service/src/com.keyman.SystemService1.System.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/linux/keyman-system-service/src/main.cpp b/linux/keyman-system-service/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9a2bb2d0de0e11f8498c87c9882b45daf71271d5
--- /dev/null
+++ b/linux/keyman-system-service/src/main.cpp
@@ -0,0 +1,10 @@
+#include "KeymanSystemService.h"
+
+int main(int argc, char *argv[]) {
+ KeymanSystemService dbusService;
+ if (dbusService.Failed()) {
+ return 1;
+ }
+
+ return dbusService.Loop();
+}
diff --git a/linux/keyman-system-service/src/meson.build b/linux/keyman-system-service/src/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..51820ab9fa9eecf70f975c7e731b1373d34251b7
--- /dev/null
+++ b/linux/keyman-system-service/src/meson.build
@@ -0,0 +1,17 @@
+service_files = files(
+ 'KeyboardDevice.cpp',
+ 'KeymanSystemService.cpp',
+ 'main.cpp',
+)
+
+deps = [evdev, systemd]
+
+exe = executable(
+ 'keyman-system-service',
+ sources: [service_files],
+ dependencies: deps,
+ install: true,
+ install_dir: get_option('libexecdir'),
+)
+
+install_data('com.keyman.SystemService1.System.xml', install_dir: get_option('datadir') / 'dbus-1/interfaces')
diff --git a/linux/keyman-system-service/tests/KeyboardDeviceMock.cpp b/linux/keyman-system-service/tests/KeyboardDeviceMock.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dbaa6aafab99ad620c1d3566ab5c463561f653d9
--- /dev/null
+++ b/linux/keyman-system-service/tests/KeyboardDeviceMock.cpp
@@ -0,0 +1,45 @@
+// A KeyboardDevice mock.
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef KeyboardDevice
+#define KeyboardDevice KeyboardDeviceMock
+#endif
+
+#include "KeyboardDevice.h"
+
+using namespace std;
+
+KeyboardDeviceMock::KeyboardDeviceMock() {
+ dev = nullptr;
+ fd = -1;
+ hasCapsLockLed = 1;
+ debug = false;
+}
+
+KeyboardDeviceMock::~KeyboardDeviceMock() {
+}
+
+bool
+KeyboardDeviceMock::Initialize(const char* name) {
+ return true;
+}
+
+bool
+KeyboardDeviceMock::HasCapsLockLed() {
+ return true;
+}
+
+void
+KeyboardDeviceMock::SetCapsLockLed(bool on) {
+ hasCapsLockLed = on ? 1 : 0;
+}
+
+bool
+KeyboardDeviceMock::GetCapsLockLed() {
+ return hasCapsLockLed == 1;
+}
diff --git a/linux/keyman-system-service/tests/README.md b/linux/keyman-system-service/tests/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..af77363b65794c4c80ba897b042bfa55eef68bae
--- /dev/null
+++ b/linux/keyman-system-service/tests/README.md
@@ -0,0 +1,11 @@
+# keyman-system-service tests
+
+This directory defines a keyman-test-service. This is mostly identical to
+keyman-system-service. The differences are:
+
+- it runs on the session bus instead of system bus
+- KeyboardDevice (which in production interacts with evdev) is mocked
+ so that the tests don't require root permissions.
+
+The keyman-test-service gets called/used by the ibus-keyman integration
+tests.
diff --git a/linux/keyman-system-service/tests/meson.build b/linux/keyman-system-service/tests/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..f90e12d16a23a8992de761ae3aa9626fecb0f36d
--- /dev/null
+++ b/linux/keyman-system-service/tests/meson.build
@@ -0,0 +1,27 @@
+test_service_files = files(
+ '../src/main.cpp',
+ '../src/KeymanSystemService.cpp',
+ 'KeyboardDeviceMock.cpp',
+)
+
+deps = [evdev, systemd]
+
+test_c_args = [
+ '-DKEYMAN_TESTING',
+ '-DKeyboardDevice=KeyboardDeviceMock'
+]
+
+exe = executable(
+ 'keyman-test-service',
+ sources: [test_service_files],
+ c_args: test_c_args,
+ cpp_args: test_c_args,
+ dependencies: deps,
+ include_directories: [ '../src' ]
+)
+
+# we currently don't have any unit tests for keyman-system-service.
+# The keyman-test-service we build here gets used by the ibus-keyman
+# integration tests.
+
+subdir('services')
diff --git a/linux/keyman-system-service/tests/services/README.md b/linux/keyman-system-service/tests/services/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..17c6950c556659740a761d4d31f8f5cf2d76bfd7
--- /dev/null
+++ b/linux/keyman-system-service/tests/services/README.md
@@ -0,0 +1,5 @@
+# tests/services
+
+This directory contains the service file for our keyman test service as
+well as some additional files for services that are required for things
+to properly work in our test environment.
diff --git a/linux/keyman-system-service/tests/services/at-spi-dbus-bus.service.in b/linux/keyman-system-service/tests/services/at-spi-dbus-bus.service.in
new file mode 100644
index 0000000000000000000000000000000000000000..8294093a7f88a4da344a25705667c66671e9744a
--- /dev/null
+++ b/linux/keyman-system-service/tests/services/at-spi-dbus-bus.service.in
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.a11y.Bus
+Exec=/usr/libexec/at-spi-bus-launcher
diff --git a/linux/keyman-system-service/tests/services/gvfs-daemon.service.in b/linux/keyman-system-service/tests/services/gvfs-daemon.service.in
new file mode 100644
index 0000000000000000000000000000000000000000..b5357bdda3aa3766b26a86e17020ddecf468e8b2
--- /dev/null
+++ b/linux/keyman-system-service/tests/services/gvfs-daemon.service.in
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.gtk.vfs.Daemon
+Exec=/usr/libexec/gvfsd
diff --git a/linux/keyman-system-service/tests/services/keyman-test.service.in b/linux/keyman-system-service/tests/services/keyman-test.service.in
new file mode 100644
index 0000000000000000000000000000000000000000..8946119f234d18af79489daf1dc480f74881a532
--- /dev/null
+++ b/linux/keyman-system-service/tests/services/keyman-test.service.in
@@ -0,0 +1,5 @@
+# Service definition file for keyman-test-service
+
+[D-BUS Service]
+Name=com.keyman.SystemService1
+Exec=@installed_tests_dir@/keyman-test-service
diff --git a/linux/keyman-system-service/tests/services/meson.build b/linux/keyman-system-service/tests/services/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..e741aa5fbffd4f7d69f71625f5c1dedd4c40de02
--- /dev/null
+++ b/linux/keyman-system-service/tests/services/meson.build
@@ -0,0 +1,16 @@
+dbus_service_files = [
+ 'at-spi-dbus-bus.service',
+ 'gvfs-daemon.service',
+ 'keyman-test.service',
+]
+
+config_data = configuration_data()
+config_data.set('installed_tests_dir', meson.current_build_dir() / '..')
+
+foreach service_file : dbus_service_files
+ configure_file(
+ input: service_file + '.in',
+ output: service_file,
+ configuration: config_data,
+ )
+endforeach
diff --git a/linux/scripts/dist.sh b/linux/scripts/dist.sh
index 7b1be441d90374e87053c328b4d973c043bbe82a..f8d63b63e353db64aba653e209034cb467080084 100755
--- a/linux/scripts/dist.sh
+++ b/linux/scripts/dist.sh
@@ -17,7 +17,7 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
BASEDIR=$(pwd)
-if [ "$1" == "origdist" ]; then
+if [[ ! -z ${1+x} ]] && [ "$1" == "origdist" ]; then
create_origdist=1
shift
fi
@@ -33,6 +33,8 @@ dch keyman --newversion "${VERSION}" --force-bad-version --nomultimaint
dpkg-source --tar-ignore=*~ --tar-ignore=.git --tar-ignore=.gitattributes \
--tar-ignore=.gitignore --tar-ignore=experiments --tar-ignore=debian \
--tar-ignore=.github --tar-ignore=.vscode --tar-ignore=android \
+ --tar-ignore=.devcontainer \
+ --tar-ignore=artifacts \
\
--tar-ignore=common/models \
--tar-ignore=common/predictive-text \
@@ -49,11 +51,15 @@ dpkg-source --tar-ignore=*~ --tar-ignore=.git --tar-ignore=.gitattributes \
--tar-ignore=linux/keyman-config/buildtools/build-langtags.py --tar-ignore=__pycache__ \
--tar-ignore=linux/help --tar-ignore=linux/Jenkinsfile \
--tar-ignore=mac --tar-ignore=node_modules --tar-ignore=oem \
- --tar-ignore=linux/build --tar-ignore=core/build \
+ --tar-ignore=linux/build \
+ --tar-ignore=linux/builddebs \
+ --tar-ignore=linux/ibus-keyman/build \
+ --tar-ignore=linux/keyman-system-service/build \
--tar-ignore=resources/devbox --tar-ignore=resources/git-hooks \
--tar-ignore=resources/scopes \
--tar-ignore=resources/build/*.lua --tar-ignore=resources/build/jq* \
--tar-ignore=results \
+ --tar-ignore=tmp \
--tar-ignore=web --tar-ignore=windows --tar-ignore=keyman_1* \
--tar-ignore=dist --tar-ignore=.pbuilderrc --tar-ignore=VERSION -Zgzip -b .
mv ../keyman_"${VERSION}".tar.gz linux/dist/keyman-"${VERSION}".tar.gz
@@ -61,7 +67,7 @@ echo "3.0 (quilt)" > debian/source/format
cd "$BASEDIR"
# create orig.tar.gz
-if [ -n "$create_origdist" ]; then
+if [ ! -z "${create_origdist+x}" ]; then
cd dist
pkgvers="keyman-$VERSION"
tar xfz keyman-"${VERSION}".tar.gz
diff --git a/linux/scripts/install.sh b/linux/scripts/install.sh
index 40f2eb8f5b09bcd7f6571fa272d660391349ebaa..7e497232fc8d6ad7fb01bb643ae6ab5cb19b7d14 100755
--- a/linux/scripts/install.sh
+++ b/linux/scripts/install.sh
@@ -15,7 +15,7 @@ INSTALLDIR=${INSTALLDIR:-"/usr/local"}
if [[ "${SUDOINSTALL}" != "no" ]]; then
if [ "$EUID" -ne 0 ]
then
- echo "Please run 'make un/install' with sudo"
+ echo "Please run 'build.sh un/install' with sudo"
exit
fi
fi
@@ -24,7 +24,7 @@ if [ -f "/usr/share/ibus/component/keyman.xml" ] && [ "${SUDOINSTALL}" == "yes"
if grep -Fq "/usr/lib/ibus" /usr/share/ibus/component/keyman.xml
then
echo "component file is in ibus-keyman package version so move it"
- echo "run 'sudo make uninstall' to put it back"
+ echo "run 'sudo build.sh uninstall' to put it back"
mv /usr/share/ibus/component/keyman.xml /usr/share/doc/ibus-keyman/
else
echo "component file is local one so overwrite it"
@@ -37,10 +37,10 @@ cd "$BASEDIR"
cd ibus-keyman
if [[ "${SUDOINSTALL}" == "uninstall" ]]; then
- echo "doing make uninstall of ibus-keyman"
+ echo "doing build.sh uninstall of ibus-keyman"
./build.sh uninstall
else
- echo "doing make install of ibus-keyman"
+ echo "doing build.sh install of ibus-keyman"
./build.sh install
fi
cd "$BASEDIR"
@@ -49,20 +49,20 @@ cd keyman-config
echo "SUDOINSTALL: ${SUDOINSTALL}"
if [[ "${SUDOINSTALL}" == "yes" ]]; then
if [ ! -d build ]; then
- echo "keyman-config must be built before it is installed. Run 'make configure' if needed then 'make'"
+ echo "keyman-config must be built before it is installed. Run 'build.sh configure build'."
exit 1
fi
echo "doing sudo glib-compile-schemas for keyman-config"
- cp com.keyman.gschema.xml /usr/share/glib-2.0/schemas/
+ cp resources/com.keyman.gschema.xml /usr/share/glib-2.0/schemas/
glib-compile-schemas /usr/share/glib-2.0/schemas/
echo "doing sudo install of keyman-config"
- make install
+ ./build.sh install
elif [[ "${SUDOINSTALL}" == "uninstall" ]]; then
echo "doing sudo uninstall of keyman-config"
- make uninstall
+ ./build.sh uninstall
else
echo "doing /tmp install of keyman-config"
- make install-temp
+ ./build.sh install
fi
cd "$BASEDIR"
diff --git a/linux/scripts/launchpad.sh b/linux/scripts/launchpad.sh
index c16d89f7d65d6a9a2b8178bd71cc020c24ab7662..30495d2b0e1567278819415fcd9edf5a4a9de098 100755
--- a/linux/scripts/launchpad.sh
+++ b/linux/scripts/launchpad.sh
@@ -10,24 +10,20 @@
# DIST="" only upload for this distribution
# PACKAGEVERSION="" string to append to the package version. Default to "1~sil1"
-set -e
+set -eu
## START STANDARD BUILD SCRIPT INCLUDE
# adjust relative paths as necessary
THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
+# shellcheck source=resources/build/build-utils.sh
. "${THIS_SCRIPT%/*}/../../resources/build/build-utils.sh"
## END STANDARD BUILD SCRIPT INCLUDE
-. $(dirname "$THIS_SCRIPT")/package-build.inc.sh
+# shellcheck source=linux/scripts/package-build.inc.sh
+. "$(dirname "$THIS_SCRIPT")/package-build.inc.sh"
checkPrerequisites
-if [ "${UPLOAD}" == "yes" ]; then
- SIM=""
-else
- SIM="-s"
-fi
-
if [ "${TIER}" == "stable" ]; then
ppa="ppa:keymanapp/keyman"
elif [ "${TIER}" == "beta" ]; then
@@ -37,32 +33,22 @@ else
fi
echo "ppa: ${ppa}"
-if [ "${DIST:-}" != "" ]; then
- distributions="${DIST}"
-else
- distributions="focal jammy kinetic lunar"
-fi
-
-if [ "${PACKAGEVERSION:-}" != "" ]; then
- packageversion="${PACKAGEVERSION}"
-else
- packageversion="1~sil1"
-fi
-
+distributions="${DIST:-focal jammy kinetic lunar}"
+packageversion="${PACKAGEVERSION:-1~sil1}"
BASEDIR=$(pwd)
rm -rf launchpad
mkdir -p launchpad
-for proj in ${projects}; do
+for proj in ${projects:-}; do
downloadSource launchpad
- cd "${proj}-${version}"
+ cd "${proj}-${version:-}"
pwd
- cp debian/changelog ../${proj}-changelog
+ cp debian/changelog "../${proj}-changelog"
for dist in ${distributions}; do
- cp ../${proj}-changelog debian/changelog
+ cp "../${proj}-changelog" debian/changelog
dch -v "${version}-${packageversion}~${dist}" "source package for PPA"
dch -D "${dist}" -r ""
debuild -d -S -sa -Zxz
diff --git a/linux/scripts/package-build.inc.sh b/linux/scripts/package-build.inc.sh
index 7134f6719f6932335812441cb6d6015fcba5929e..6c249891c1633a3bcd5da6279f6fc13a316cc29a 100644
--- a/linux/scripts/package-build.inc.sh
+++ b/linux/scripts/package-build.inc.sh
@@ -1,14 +1,14 @@
#!/bin/bash
function checkPrerequisites() {
- if [ "${UPLOAD}" == "yes" ]; then
+ if [ "${UPLOAD:=}" == "yes" ]; then
SIM=""
else
SIM="-s"
fi
# Check the tier
- if [[ -z "${TIER}" ]]; then
+ if [[ -z "${TIER:=}" ]]; then
echo "TIER.md or \${TIER} must be set to (alpha, beta, stable) to use this script"
exit 1
fi
@@ -18,23 +18,17 @@ function checkPrerequisites() {
exit 1
fi
- if [ "${PROJECT}" != "" ]; then
- projects="${PROJECT}"
- else
- projects="keyman"
- fi
+ # shellcheck disable=SC2034
+ projects="${PROJECT:=keyman}"
}
function downloadSource() {
local packageDir
packageDir=$1
- if [ "${proj}" == "keyman" ]; then
+ if [ "${proj:=}" == "keyman" ]; then
cd "${BASEDIR}" || exit
- fi
-
- if [ "${proj}" == "keyman" ]; then
- make clean
+ ./build.sh clean
fi
# Update tier in Debian watch files (replacing any previously set tier) and remove comment
@@ -51,7 +45,7 @@ function downloadSource() {
mv "${proj}"*.asc "${BASEDIR}/${packageDir}"
rm "${proj}"*.debian.tar.xz
cd "${BASEDIR}/${packageDir}" || exit
- wget -N https://downloads.keyman.com/linux/${TIER}/${dirversion}/SHA256SUMS
+ wget -N "https://downloads.keyman.com/linux/${TIER}/${dirversion}/SHA256SUMS"
sha256sum -c --ignore-missing SHA256SUMS |grep "${proj}"
}
diff --git a/linux/scripts/reconf.sh b/linux/scripts/reconf.sh
index cd74571a4a1dc696934de83f04d395d4850cda05..4e4f5c1b115cbc37e02905dfcdc262ccb9941024 100755
--- a/linux/scripts/reconf.sh
+++ b/linux/scripts/reconf.sh
@@ -21,7 +21,7 @@ cd "$BASEDIR/ibus-keyman"
./build.sh clean configure
cd "$BASEDIR/keyman-config"
-make clean
+./build.sh clean
cd keyman_config
sed \
diff --git a/mac/Keyman4MacIM/Keyman4MacIM/am.lproj/Localizable.strings b/mac/Keyman4MacIM/Keyman4MacIM/am.lproj/Localizable.strings
index 06182ea47cbb20a18a09f6261771c207bc11f1fa..35de92b8d831632491abd14ea201191a9a9adfc9 100644
--- a/mac/Keyman4MacIM/Keyman4MacIM/am.lproj/Localizable.strings
+++ b/mac/Keyman4MacIM/Keyman4MacIM/am.lproj/Localizable.strings
@@ -68,4 +68,4 @@
"copyright-label" = "የባለቤትነት መብት፦";
/* message displayed to alert user to need grant accessibility permission */
-"privacy-alert-text" = "To function properly, Keyman requires accessibility features:\n\nGrant access in System Preferences, Security & Privacy.\nRestart your system.";
+"privacy-alert-text" = "ኪይማን በአግባቡ ለመስራት የተደራሽነት ባህሪያትን ይፈልጋል፦ \n\nበስርዓት ምርጫዎች፣ ደህንነት እና ግላዊነት ውስጥ መዳረሻ ፍቀድ። \nስርዓት እንደገና አስጀምር።";
diff --git a/mac/build.sh b/mac/build.sh
index 480cbd8587f9e35a24f5951bb57b9b59a4d0d69c..5b6a3f525b8e4e9296e4be223f9fa0df6fe521f6 100755
--- a/mac/build.sh
+++ b/mac/build.sh
@@ -132,6 +132,7 @@ QUIET=false
NOTARIZE=false
SKIP_BUILD=false
UPLOAD_SENTRY=false
+QUIET_FLAG=
# Import local environment variables for build
if [[ -f $(dirname "$THIS_SCRIPT")/localenv.sh ]]; then
@@ -259,6 +260,7 @@ displayInfo "" \
"BUILD_ACTIONS: $BUILD_ACTIONS" \
"TEST_ACTION: $TEST_ACTION" \
"UPLOAD_SENTRY: $UPLOAD_SENTRY" \
+ "QUIET_FLAG: $QUIET_FLAG" \
""
### Validate notarization environment variables ###
@@ -273,11 +275,11 @@ if $LOCALDEPLOY && ! $NOTARIZE ; then
fi
if $PREPRELEASE || $NOTARIZE ; then
- if [ ! $DO_CODESIGN ] || [ -z "${CERTIFICATE_ID}" ]; then
+ if [ ! $DO_CODESIGN ] || [ -z "${CERTIFICATE_ID+x}" ]; then
builder_die "Code signing must be configured for deployment. See build.sh -help for details."
fi
- if [ -z "${APPSTORECONNECT_PROVIDER}" ] || [ -z "${APPSTORECONNECT_USERNAME}" ] || [ -z "${APPSTORECONNECT_PASSWORD}" ]; then
+ if [ -z "${APPSTORECONNECT_PROVIDER+x}" ] || [ -z "${APPSTORECONNECT_USERNAME+x}" ] || [ -z "${APPSTORECONNECT_PASSWORD+x}" ]; then
builder_die "Appstoreconnect Apple ID credentials must be configured in environment. See build.sh -help for details."
fi
fi
@@ -388,7 +390,7 @@ if $DO_KEYMANIM ; then
ENTITLEMENTS_FILE=Keyman.entitlements
fi
- if [ -z "$DEVELOPMENT_TEAM" ]; then
+ if [ -z "${DEVELOPMENT_TEAM+x}" ]; then
DEVELOPMENT_TEAM=3YE4W86L3G
fi
@@ -411,7 +413,7 @@ if $DO_KEYMANIM ; then
if which sentry-cli >/dev/null; then
cd "$KM4MIM_BASE_PATH"
- sentry-cli upload-dif "build/${CONFIGURATION}"
+ sentry-cli upload-dif "build/$CONFIG"
else
builder_die "Error: sentry-cli not installed, download from https://github.com/getsentry/sentry-cli/releases"
fi
@@ -432,7 +434,7 @@ fi
if $PREPRELEASE || $NOTARIZE; then
builder_heading "Notarizing app"
- if [ "${CODESIGNING_SUPPRESSION}" != "" ] && [ -z "${CERTIFICATE_ID}" ]; then
+ if [ "${CODESIGNING_SUPPRESSION}" != "" ] && [ -z "${CERTIFICATE_ID+x}" ]; then
builder_die "Notarization and signed executable is required for deployment, even locally. Specify CERTIFICATE_ID environment variable for custom certificate."
else
TARGET_PATH="$KM4MIM_BASE_PATH/build/$CONFIG"
@@ -443,7 +445,7 @@ if $PREPRELEASE || $NOTARIZE; then
# Note: get-task-allow entitlement must be *off* in our release build (to do this, don't include base entitlements in project build settings)
# We may need to re-run the code signing if a custom certificate has been passed in
- if [ ! -z "${CERTIFICATE_ID}" ]; then
+ if [ ! -z "${CERTIFICATE_ID+x}" ]; then
builder_heading "Signing with custom certificate (CERTIFICATE_ID environment variable)."
codesign --force --options runtime --entitlements Keyman4MacIM/Keyman.entitlements --deep --sign "${CERTIFICATE_ID}" "$TARGET_APP_PATH"
fi
diff --git a/oem/firstvoices/ios/Cartfile b/oem/firstvoices/ios/Cartfile
index ec3127efc7f8555f418ada6a1254f76698566929..10efbc3d5a00674b34fa904f3376c63c23b95f93 100644
--- a/oem/firstvoices/ios/Cartfile
+++ b/oem/firstvoices/ios/Cartfile
@@ -1,4 +1,4 @@
-github "DaveWoodCom/XCGLogger" ~> 6.1.0
+github "keymanapp/dependency-XCGLogger" "master"
github "devicekit/DeviceKit" ~> 5.0
github "ashleymills/Reachability.swift"
-github "getsentry/sentry-cocoa" ~> 6.2.1
+github "getsentry/sentry-cocoa" ~> 8.7.0
diff --git a/oem/firstvoices/ios/Cartfile.resolved b/oem/firstvoices/ios/Cartfile.resolved
index 16cb6213b6c2f2a085fd61f59c813a6f2292ec3d..5ac3a55318988538f2f6e3ebf339ac837e43effd 100644
--- a/oem/firstvoices/ios/Cartfile.resolved
+++ b/oem/firstvoices/ios/Cartfile.resolved
@@ -1,4 +1,4 @@
-github "DaveWoodCom/XCGLogger" "6.1.0"
github "ashleymills/Reachability.swift" "v5.1.0"
github "devicekit/DeviceKit" "5.0.0"
-github "getsentry/sentry-cocoa" "6.2.1"
+github "getsentry/sentry-cocoa" "8.7.0"
+github "keymanapp/dependency-XCGLogger" "57a7b975dbb6fe4fe90cef3d1bc52b8adbd89113"
diff --git a/oem/firstvoices/ios/exportAppStore.plist b/oem/firstvoices/ios/exportAppStore.plist
index 123af31a0c437e0927eddef23f03b3a850374642..c4ac972730f0715629ebd05914f11ab9f1026ca6 100644
--- a/oem/firstvoices/ios/exportAppStore.plist
+++ b/oem/firstvoices/ios/exportAppStore.plist
@@ -7,9 +7,9 @@
teamID
D7TR486TEH
signingCertificate
- EFA9DE793B2A25F38270468AE62060CFF55CD634
+ C4726D4C8BD4C2FE38A551B84CEDB8E4B3FD12D6
installerSigningCertificate
- EFA9DE793B2A25F38270468AE62060CFF55CD634
+ C4726D4C8BD4C2FE38A551B84CEDB8E4B3FD12D6
provisioningProfiles
com.firstvoices.keyboards
diff --git a/package-lock.json b/package-lock.json
index 331c616e6d31e00c51c5c9d9e9f7a8186ccd1c44..91fce6219175c9df02c7230a940ecc14629f0ad2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,9 +11,9 @@
"core/include/ldml",
"developer/src/common/web/test-helpers",
"developer/src/kmc-analyze",
- "developer/src/kmc-keyboard",
"developer/src/kmc-kmn",
"developer/src/kmc-kmw",
+ "developer/src/kmc-ldml",
"developer/src/kmc-model",
"developer/src/kmc-model-info",
"developer/src/kmc-package",
@@ -637,9 +637,9 @@
"@keymanapp/common-types": "*",
"@keymanapp/keyman-version": "*",
"@keymanapp/kmc-analyze": "*",
- "@keymanapp/kmc-keyboard": "*",
"@keymanapp/kmc-kmn": "*",
"@keymanapp/kmc-kmw": "*",
+ "@keymanapp/kmc-ldml": "*",
"@keymanapp/kmc-model": "*",
"@keymanapp/kmc-model-info": "*",
"@keymanapp/kmc-package": "*",
@@ -900,6 +900,7 @@
},
"developer/src/kmc-keyboard": {
"name": "@keymanapp/kmc-keyboard",
+ "extraneous": true,
"license": "MIT",
"dependencies": {
"@keymanapp/keyman-version": "*",
@@ -924,34 +925,77 @@
"typescript": "^4.9.5"
}
},
- "developer/src/kmc-keyboard/node_modules/@types/mocha": {
- "version": "5.2.7",
+ "developer/src/kmc-kmn": {
+ "name": "@keymanapp/kmc-kmn",
+ "license": "MIT",
+ "dependencies": {
+ "@keymanapp/keyman-version": "*"
+ },
+ "devDependencies": {
+ "@keymanapp/developer-test-helpers": "*",
+ "@types/chai": "^4.1.7",
+ "@types/mocha": "^5.2.7",
+ "@types/node": "^10.14.6",
+ "@types/semver": "^7.3.12",
+ "@types/sinon": "^10.0.13",
+ "@types/sinon-chai": "^3.2.9",
+ "@types/xml2js": "^0.4.5",
+ "c8": "^7.12.0",
+ "chai": "^4.3.4",
+ "chalk": "^2.4.2",
+ "mocha": "^8.4.0",
+ "sinon": "^15.0.2",
+ "sinon-chai": "^3.7.0",
+ "ts-node": "^9.1.1",
+ "typescript": "^4.9.5"
+ }
+ },
+ "developer/src/kmc-kmn/node_modules/@sinonjs/commons": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz",
+ "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==",
"dev": true,
- "license": "MIT"
+ "dependencies": {
+ "type-detect": "4.0.8"
+ }
},
- "developer/src/kmc-keyboard/node_modules/@types/node": {
- "version": "10.17.60",
+ "developer/src/kmc-kmn/node_modules/@sinonjs/samsam": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-7.0.1.tgz",
+ "integrity": "sha512-zsAk2Jkiq89mhZovB2LLOdTCxJF4hqqTToGP0ASWlhp4I1hqOjcfmZGafXntCN7MDC6yySH0mFHrYtHceOeLmw==",
"dev": true,
- "license": "MIT"
+ "dependencies": {
+ "@sinonjs/commons": "^2.0.0",
+ "lodash.get": "^4.4.2",
+ "type-detect": "^4.0.8"
+ }
},
- "developer/src/kmc-keyboard/node_modules/ajv": {
- "version": "8.11.2",
- "license": "MIT",
+ "developer/src/kmc-kmn/node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz",
+ "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==",
+ "dev": true,
"dependencies": {
- "fast-deep-equal": "^3.1.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
+ "type-detect": "4.0.8"
}
},
- "developer/src/kmc-keyboard/node_modules/ansi-styles": {
+ "developer/src/kmc-kmn/node_modules/@types/mocha": {
+ "version": "5.2.7",
+ "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
+ "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==",
+ "dev": true
+ },
+ "developer/src/kmc-kmn/node_modules/@types/node": {
+ "version": "10.17.60",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz",
+ "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==",
+ "dev": true
+ },
+ "developer/src/kmc-kmn/node_modules/ansi-styles": {
"version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"color-convert": "^1.9.0"
},
@@ -959,10 +1003,11 @@
"node": ">=4"
}
},
- "developer/src/kmc-keyboard/node_modules/chalk": {
+ "developer/src/kmc-kmn/node_modules/chalk": {
"version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
@@ -972,23 +1017,32 @@
"node": ">=4"
}
},
- "developer/src/kmc-keyboard/node_modules/color-convert": {
+ "developer/src/kmc-kmn/node_modules/color-convert": {
"version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
- "license": "MIT",
"dependencies": {
"color-name": "1.1.3"
}
},
- "developer/src/kmc-keyboard/node_modules/color-name": {
+ "developer/src/kmc-kmn/node_modules/color-name": {
"version": "1.1.3",
- "dev": true,
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true
},
- "developer/src/kmc-keyboard/node_modules/js-yaml": {
+ "developer/src/kmc-kmn/node_modules/isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==",
+ "dev": true
+ },
+ "developer/src/kmc-kmn/node_modules/js-yaml": {
"version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz",
+ "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==",
"dev": true,
- "license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
@@ -996,14 +1050,11 @@
"js-yaml": "bin/js-yaml.js"
}
},
- "developer/src/kmc-keyboard/node_modules/json-schema-traverse": {
- "version": "1.0.0",
- "license": "MIT"
- },
- "developer/src/kmc-keyboard/node_modules/minimatch": {
+ "developer/src/kmc-kmn/node_modules/minimatch": {
"version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
- "license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@@ -1011,10 +1062,11 @@
"node": "*"
}
},
- "developer/src/kmc-keyboard/node_modules/mocha": {
+ "developer/src/kmc-kmn/node_modules/mocha": {
"version": "8.4.0",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz",
+ "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"@ungap/promise-all-settled": "1.1.2",
"ansi-colors": "4.1.1",
@@ -1054,10 +1106,11 @@
"url": "https://opencollective.com/mochajs"
}
},
- "developer/src/kmc-keyboard/node_modules/mocha/node_modules/escape-string-regexp": {
+ "developer/src/kmc-kmn/node_modules/mocha/node_modules/escape-string-regexp": {
"version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=10"
},
@@ -1065,10 +1118,11 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "developer/src/kmc-keyboard/node_modules/mocha/node_modules/supports-color": {
+ "developer/src/kmc-kmn/node_modules/mocha/node_modules/supports-color": {
"version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dev": true,
- "license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -1079,15 +1133,87 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
- "developer/src/kmc-keyboard/node_modules/ms": {
+ "developer/src/kmc-kmn/node_modules/ms": {
"version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ },
+ "developer/src/kmc-kmn/node_modules/nise": {
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.4.tgz",
+ "integrity": "sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==",
"dev": true,
- "license": "MIT"
+ "dependencies": {
+ "@sinonjs/commons": "^2.0.0",
+ "@sinonjs/fake-timers": "^10.0.2",
+ "@sinonjs/text-encoding": "^0.7.1",
+ "just-extend": "^4.0.2",
+ "path-to-regexp": "^1.7.0"
+ }
+ },
+ "developer/src/kmc-kmn/node_modules/nise/node_modules/@sinonjs/commons": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz",
+ "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==",
+ "dev": true,
+ "dependencies": {
+ "type-detect": "4.0.8"
+ }
+ },
+ "developer/src/kmc-kmn/node_modules/path-to-regexp": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
+ "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
+ "dev": true,
+ "dependencies": {
+ "isarray": "0.0.1"
+ }
+ },
+ "developer/src/kmc-kmn/node_modules/sinon": {
+ "version": "15.0.2",
+ "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.0.2.tgz",
+ "integrity": "sha512-PCVP63XZkg0/LOqQH5rEU4LILuvTFMb5tNxTHfs6VUMNnZz2XrnGSTZbAGITjzwQWbl/Bl/8hi4G3zZWjyBwHg==",
+ "dev": true,
+ "dependencies": {
+ "@sinonjs/commons": "^3.0.0",
+ "@sinonjs/fake-timers": "^10.0.2",
+ "@sinonjs/samsam": "^7.0.1",
+ "diff": "^5.1.0",
+ "nise": "^5.1.4",
+ "supports-color": "^7.2.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/sinon"
+ }
},
- "developer/src/kmc-keyboard/node_modules/supports-color": {
+ "developer/src/kmc-kmn/node_modules/sinon/node_modules/diff": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz",
+ "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "developer/src/kmc-kmn/node_modules/sinon/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "developer/src/kmc-kmn/node_modules/supports-color": {
"version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
- "license": "MIT",
"dependencies": {
"has-flag": "^3.0.0"
},
@@ -1095,15 +1221,16 @@
"node": ">=4"
}
},
- "developer/src/kmc-keyboard/node_modules/supports-color/node_modules/has-flag": {
+ "developer/src/kmc-kmn/node_modules/supports-color/node_modules/has-flag": {
"version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=4"
}
},
- "developer/src/kmc-keyboard/node_modules/ts-node": {
+ "developer/src/kmc-kmn/node_modules/ts-node": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz",
"integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==",
@@ -1129,7 +1256,7 @@
"typescript": ">=2.7"
}
},
- "developer/src/kmc-keyboard/node_modules/ts-node/node_modules/diff": {
+ "developer/src/kmc-kmn/node_modules/ts-node/node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
@@ -1138,73 +1265,59 @@
"node": ">=0.3.1"
}
},
- "developer/src/kmc-kmn": {
- "name": "@keymanapp/kmc-kmn",
+ "developer/src/kmc-kmw": {
+ "name": "@keymanapp/kmc-kmw",
"license": "MIT",
"dependencies": {
- "@keymanapp/keyman-version": "*"
+ "@keymanapp/common-types": "*",
+ "@keymanapp/kmc-kmn": "*",
+ "ajv": "^8.11.0",
+ "restructure": "git+https://github.com/keymanapp/dependency-restructure.git#49d129cf0916d082a7278bb09296fb89cecfcc50",
+ "semver": "^7.3.7",
+ "xml2js": "git+https://github.com/keymanapp/dependency-node-xml2js#535fe732dc408d697e0f847c944cc45f0baf0829"
},
"devDependencies": {
- "@keymanapp/developer-test-helpers": "*",
"@types/chai": "^4.1.7",
"@types/mocha": "^5.2.7",
"@types/node": "^10.14.6",
"@types/semver": "^7.3.12",
- "@types/sinon": "^10.0.13",
- "@types/sinon-chai": "^3.2.9",
"@types/xml2js": "^0.4.5",
"c8": "^7.12.0",
"chai": "^4.3.4",
"chalk": "^2.4.2",
"mocha": "^8.4.0",
- "sinon": "^15.0.2",
- "sinon-chai": "^3.7.0",
"ts-node": "^9.1.1",
"typescript": "^4.9.5"
}
},
- "developer/src/kmc-kmn/node_modules/@sinonjs/commons": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz",
- "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==",
- "dev": true,
- "dependencies": {
- "type-detect": "4.0.8"
- }
- },
- "developer/src/kmc-kmn/node_modules/@sinonjs/samsam": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-7.0.1.tgz",
- "integrity": "sha512-zsAk2Jkiq89mhZovB2LLOdTCxJF4hqqTToGP0ASWlhp4I1hqOjcfmZGafXntCN7MDC6yySH0mFHrYtHceOeLmw==",
- "dev": true,
- "dependencies": {
- "@sinonjs/commons": "^2.0.0",
- "lodash.get": "^4.4.2",
- "type-detect": "^4.0.8"
- }
- },
- "developer/src/kmc-kmn/node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz",
- "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==",
- "dev": true,
- "dependencies": {
- "type-detect": "4.0.8"
- }
- },
- "developer/src/kmc-kmn/node_modules/@types/mocha": {
+ "developer/src/kmc-kmw/node_modules/@types/mocha": {
"version": "5.2.7",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
"integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==",
"dev": true
},
- "developer/src/kmc-kmn/node_modules/@types/node": {
+ "developer/src/kmc-kmw/node_modules/@types/node": {
"version": "10.17.60",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz",
"integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==",
"dev": true
},
- "developer/src/kmc-kmn/node_modules/ansi-styles": {
+ "developer/src/kmc-kmw/node_modules/ajv": {
+ "version": "8.12.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+ "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "developer/src/kmc-kmw/node_modules/ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
@@ -1216,7 +1329,7 @@
"node": ">=4"
}
},
- "developer/src/kmc-kmn/node_modules/chalk": {
+ "developer/src/kmc-kmw/node_modules/chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
@@ -1230,7 +1343,7 @@
"node": ">=4"
}
},
- "developer/src/kmc-kmn/node_modules/color-convert": {
+ "developer/src/kmc-kmw/node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
@@ -1239,19 +1352,13 @@
"color-name": "1.1.3"
}
},
- "developer/src/kmc-kmn/node_modules/color-name": {
+ "developer/src/kmc-kmw/node_modules/color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
"dev": true
},
- "developer/src/kmc-kmn/node_modules/isarray": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
- "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==",
- "dev": true
- },
- "developer/src/kmc-kmn/node_modules/js-yaml": {
+ "developer/src/kmc-kmw/node_modules/js-yaml": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz",
"integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==",
@@ -1263,7 +1370,12 @@
"js-yaml": "bin/js-yaml.js"
}
},
- "developer/src/kmc-kmn/node_modules/minimatch": {
+ "developer/src/kmc-kmw/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
+ },
+ "developer/src/kmc-kmw/node_modules/minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
@@ -1275,7 +1387,7 @@
"node": "*"
}
},
- "developer/src/kmc-kmn/node_modules/mocha": {
+ "developer/src/kmc-kmw/node_modules/mocha": {
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz",
"integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==",
@@ -1319,7 +1431,7 @@
"url": "https://opencollective.com/mochajs"
}
},
- "developer/src/kmc-kmn/node_modules/mocha/node_modules/escape-string-regexp": {
+ "developer/src/kmc-kmw/node_modules/mocha/node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
@@ -1331,7 +1443,7 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "developer/src/kmc-kmn/node_modules/mocha/node_modules/supports-color": {
+ "developer/src/kmc-kmw/node_modules/mocha/node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
@@ -1346,83 +1458,13 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
- "developer/src/kmc-kmn/node_modules/ms": {
+ "developer/src/kmc-kmw/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
},
- "developer/src/kmc-kmn/node_modules/nise": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.4.tgz",
- "integrity": "sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==",
- "dev": true,
- "dependencies": {
- "@sinonjs/commons": "^2.0.0",
- "@sinonjs/fake-timers": "^10.0.2",
- "@sinonjs/text-encoding": "^0.7.1",
- "just-extend": "^4.0.2",
- "path-to-regexp": "^1.7.0"
- }
- },
- "developer/src/kmc-kmn/node_modules/nise/node_modules/@sinonjs/commons": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz",
- "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==",
- "dev": true,
- "dependencies": {
- "type-detect": "4.0.8"
- }
- },
- "developer/src/kmc-kmn/node_modules/path-to-regexp": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
- "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
- "dev": true,
- "dependencies": {
- "isarray": "0.0.1"
- }
- },
- "developer/src/kmc-kmn/node_modules/sinon": {
- "version": "15.0.2",
- "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.0.2.tgz",
- "integrity": "sha512-PCVP63XZkg0/LOqQH5rEU4LILuvTFMb5tNxTHfs6VUMNnZz2XrnGSTZbAGITjzwQWbl/Bl/8hi4G3zZWjyBwHg==",
- "dev": true,
- "dependencies": {
- "@sinonjs/commons": "^3.0.0",
- "@sinonjs/fake-timers": "^10.0.2",
- "@sinonjs/samsam": "^7.0.1",
- "diff": "^5.1.0",
- "nise": "^5.1.4",
- "supports-color": "^7.2.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/sinon"
- }
- },
- "developer/src/kmc-kmn/node_modules/sinon/node_modules/diff": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz",
- "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==",
- "dev": true,
- "engines": {
- "node": ">=0.3.1"
- }
- },
- "developer/src/kmc-kmn/node_modules/sinon/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "developer/src/kmc-kmn/node_modules/supports-color": {
+ "developer/src/kmc-kmw/node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
@@ -1434,7 +1476,7 @@
"node": ">=4"
}
},
- "developer/src/kmc-kmn/node_modules/supports-color/node_modules/has-flag": {
+ "developer/src/kmc-kmw/node_modules/supports-color/node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
@@ -1443,7 +1485,7 @@
"node": ">=4"
}
},
- "developer/src/kmc-kmn/node_modules/ts-node": {
+ "developer/src/kmc-kmw/node_modules/ts-node": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz",
"integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==",
@@ -1469,7 +1511,7 @@
"typescript": ">=2.7"
}
},
- "developer/src/kmc-kmn/node_modules/ts-node/node_modules/diff": {
+ "developer/src/kmc-kmw/node_modules/ts-node/node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
@@ -1478,18 +1520,19 @@
"node": ">=0.3.1"
}
},
- "developer/src/kmc-kmw": {
- "name": "@keymanapp/kmc-kmw",
+ "developer/src/kmc-ldml": {
+ "name": "@keymanapp/kmc-ldml",
"license": "MIT",
"dependencies": {
- "@keymanapp/common-types": "*",
- "@keymanapp/kmc-kmn": "*",
+ "@keymanapp/keyman-version": "*",
+ "@keymanapp/ldml-keyboard-constants": "*",
"ajv": "^8.11.0",
"restructure": "git+https://github.com/keymanapp/dependency-restructure.git#49d129cf0916d082a7278bb09296fb89cecfcc50",
"semver": "^7.3.7",
"xml2js": "git+https://github.com/keymanapp/dependency-node-xml2js#535fe732dc408d697e0f847c944cc45f0baf0829"
},
"devDependencies": {
+ "@keymanapp/developer-test-helpers": "*",
"@types/chai": "^4.1.7",
"@types/mocha": "^5.2.7",
"@types/node": "^10.14.6",
@@ -1503,19 +1546,19 @@
"typescript": "^4.9.5"
}
},
- "developer/src/kmc-kmw/node_modules/@types/mocha": {
+ "developer/src/kmc-ldml/node_modules/@types/mocha": {
"version": "5.2.7",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
"integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==",
"dev": true
},
- "developer/src/kmc-kmw/node_modules/@types/node": {
+ "developer/src/kmc-ldml/node_modules/@types/node": {
"version": "10.17.60",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz",
"integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==",
"dev": true
},
- "developer/src/kmc-kmw/node_modules/ajv": {
+ "developer/src/kmc-ldml/node_modules/ajv": {
"version": "8.12.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
@@ -1530,7 +1573,7 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
- "developer/src/kmc-kmw/node_modules/ansi-styles": {
+ "developer/src/kmc-ldml/node_modules/ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
@@ -1542,7 +1585,7 @@
"node": ">=4"
}
},
- "developer/src/kmc-kmw/node_modules/chalk": {
+ "developer/src/kmc-ldml/node_modules/chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
@@ -1556,7 +1599,7 @@
"node": ">=4"
}
},
- "developer/src/kmc-kmw/node_modules/color-convert": {
+ "developer/src/kmc-ldml/node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
@@ -1565,13 +1608,13 @@
"color-name": "1.1.3"
}
},
- "developer/src/kmc-kmw/node_modules/color-name": {
+ "developer/src/kmc-ldml/node_modules/color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
"dev": true
},
- "developer/src/kmc-kmw/node_modules/js-yaml": {
+ "developer/src/kmc-ldml/node_modules/js-yaml": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz",
"integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==",
@@ -1583,12 +1626,12 @@
"js-yaml": "bin/js-yaml.js"
}
},
- "developer/src/kmc-kmw/node_modules/json-schema-traverse": {
+ "developer/src/kmc-ldml/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
},
- "developer/src/kmc-kmw/node_modules/minimatch": {
+ "developer/src/kmc-ldml/node_modules/minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
@@ -1600,7 +1643,7 @@
"node": "*"
}
},
- "developer/src/kmc-kmw/node_modules/mocha": {
+ "developer/src/kmc-ldml/node_modules/mocha": {
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz",
"integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==",
@@ -1644,7 +1687,7 @@
"url": "https://opencollective.com/mochajs"
}
},
- "developer/src/kmc-kmw/node_modules/mocha/node_modules/escape-string-regexp": {
+ "developer/src/kmc-ldml/node_modules/mocha/node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
@@ -1656,7 +1699,7 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "developer/src/kmc-kmw/node_modules/mocha/node_modules/supports-color": {
+ "developer/src/kmc-ldml/node_modules/mocha/node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
@@ -1671,13 +1714,13 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
- "developer/src/kmc-kmw/node_modules/ms": {
+ "developer/src/kmc-ldml/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
},
- "developer/src/kmc-kmw/node_modules/supports-color": {
+ "developer/src/kmc-ldml/node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
@@ -1689,7 +1732,7 @@
"node": ">=4"
}
},
- "developer/src/kmc-kmw/node_modules/supports-color/node_modules/has-flag": {
+ "developer/src/kmc-ldml/node_modules/supports-color/node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
@@ -1698,7 +1741,7 @@
"node": ">=4"
}
},
- "developer/src/kmc-kmw/node_modules/ts-node": {
+ "developer/src/kmc-ldml/node_modules/ts-node": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz",
"integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==",
@@ -1724,7 +1767,7 @@
"typescript": ">=2.7"
}
},
- "developer/src/kmc-kmw/node_modules/ts-node/node_modules/diff": {
+ "developer/src/kmc-ldml/node_modules/ts-node/node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
@@ -1761,8 +1804,7 @@
"name": "@keymanapp/kmc-model-info",
"license": "MIT",
"dependencies": {
- "@keymanapp/keyman-version": "*",
- "@keymanapp/kmc-package": "*",
+ "@keymanapp/common-types": "*",
"@keymanapp/models-types": "*"
},
"devDependencies": {
@@ -2763,10 +2805,6 @@
"resolved": "developer/src/kmc-analyze",
"link": true
},
- "node_modules/@keymanapp/kmc-keyboard": {
- "resolved": "developer/src/kmc-keyboard",
- "link": true
- },
"node_modules/@keymanapp/kmc-kmn": {
"resolved": "developer/src/kmc-kmn",
"link": true
@@ -2775,6 +2813,10 @@
"resolved": "developer/src/kmc-kmw",
"link": true
},
+ "node_modules/@keymanapp/kmc-ldml": {
+ "resolved": "developer/src/kmc-ldml",
+ "link": true
+ },
"node_modules/@keymanapp/kmc-model": {
"resolved": "developer/src/kmc-model",
"link": true
diff --git a/package.json b/package.json
index 6a13ed2685cb47f2b98e241dde59f81846275f6e..f832cea04a0f5570f6bdbd0e66efbdcb23823a72 100644
--- a/package.json
+++ b/package.json
@@ -21,9 +21,9 @@
"core/include/ldml",
"developer/src/common/web/test-helpers",
"developer/src/kmc-analyze",
- "developer/src/kmc-keyboard",
"developer/src/kmc-kmn",
"developer/src/kmc-kmw",
+ "developer/src/kmc-ldml",
"developer/src/kmc-model",
"developer/src/kmc-model-info",
"developer/src/kmc-package",
diff --git a/resources/build/build-utils-ci.inc.sh b/resources/build/build-utils-ci.inc.sh
index de36ae9e9b606556869c22f2f7492240825070f7..cab449a4636d59e5f9a388bfad84601d165e0956 100644
--- a/resources/build/build-utils-ci.inc.sh
+++ b/resources/build/build-utils-ci.inc.sh
@@ -100,18 +100,7 @@ function _builder_publish_npm_package() {
dry_run=--dry-run
fi
- # We use --no-git-tag-version because our CI system controls version numbering
- # and already tags releases. We also want to have the version of this match
- # the release of Keyman Developer -- these two versions should be in sync.
- # Because this is a large repo with multiple projects and build systems, it's
- # better for us that individual build systems don't take too much ownership of
- # git tagging. :)
- npm version --allow-same-version --no-git-tag-version --no-commit-hooks "$VERSION_WITH_TAG"
-
- # Update all @keymanapp/* [*]dependencies in package.json to the current
- # version-with-tag, so that the published version has precise dependencies,
- # and we don't accidentally end up with either older or newer deps here
- _builder_npm_set_dependency_version
+ _builder_write_npm_version
# Note: In either case, npm publish MUST be given --access public to publish a
# package in the @keymanapp scope on the public npm package index.
@@ -128,18 +117,33 @@ function _builder_publish_npm_package() {
fi
}
-# Updates all @keymanapp/* [*]dependencies in package.json to the current
-# version-with-tag, so that the published version has precise dependencies, and
-# we don't accidentally end up with either older or newer deps. This overwrites
-# the local package.json, so it does need to be restored afterwards
-function _builder_npm_set_dependency_version() {
- cat package.json | "$JQ" --arg VERSION_WITH_TAG "$VERSION_WITH_TAG" \
- '
- . +
- (try { dependencies: (.dependencies | to_entries | . + map(select(.key | match("@keymanapp/.*")) .value |= $VERSION_WITH_TAG) | from_entries) } catch {}) +
- (try { devDependencies: (.devDependencies | to_entries | . + map(select(.key | match("@keymanapp/.*")) .value |= $VERSION_WITH_TAG) | from_entries) } catch {}) +
- (try { bundleDependencies: (.bundleDependencies | to_entries | . + map(select(.key | match("@keymanapp/.*")) .value |= $VERSION_WITH_TAG) | from_entries) } catch {}) +
- (try { optionalDependencies: (.optionalDependencies | to_entries | . + map(select(.key | match("@keymanapp/.*")) .value |= $VERSION_WITH_TAG) | from_entries) } catch {})
- ' > package1.json
- mv -f package1.json package.json
+function _builder_write_npm_version() {
+ # We use --no-git-tag-version because our CI system controls version numbering
+ # and already tags releases. We also want to have the version of this match
+ # the release of Keyman Developer -- these two versions should be in sync.
+ # Because this is a large repo with multiple projects and build systems, it's
+ # better for us that individual build systems don't take too much ownership of
+ # git tagging. :)
+ if ! "$JQ" -e '.version' package.json > /dev/null; then
+ pushd "$KEYMAN_ROOT" > /dev/null
+ npm version --allow-same-version --no-git-tag-version --no-commit-hooks --workspaces "$VERSION_WITH_TAG"
+ popd > /dev/null
+ fi
+
+ # Updates all @keymanapp/* [*]dependencies in all package.jsons to the current
+ # version-with-tag, so that the published version has precise dependencies, and
+ # we don't accidentally end up with either older or newer deps. This overwrites
+ # the local package.json files, so they do need to be restored afterwards
+ find "$KEYMAN_ROOT" -name "package.json" -not -path '*/node_modules/*' -print0 | \
+ while IFS= read -r -d '' line; do
+ cat "$line" | "$JQ" --arg VERSION_WITH_TAG "$VERSION_WITH_TAG" \
+ '
+ . +
+ (try { dependencies: (.dependencies | to_entries | . + map(select(.key | match("@keymanapp/.*")) .value |= $VERSION_WITH_TAG) | from_entries) } catch {}) +
+ (try { devDependencies: (.devDependencies | to_entries | . + map(select(.key | match("@keymanapp/.*")) .value |= $VERSION_WITH_TAG) | from_entries) } catch {}) +
+ (try { bundleDependencies: (.bundleDependencies | to_entries | . + map(select(.key | match("@keymanapp/.*")) .value |= $VERSION_WITH_TAG) | from_entries) } catch {}) +
+ (try { optionalDependencies: (.optionalDependencies | to_entries | . + map(select(.key | match("@keymanapp/.*")) .value |= $VERSION_WITH_TAG) | from_entries) } catch {})
+ ' > "${line}_"
+ mv -f "${line}_" "$line"
+ done
}
\ No newline at end of file
diff --git a/resources/build/build-utils.md b/resources/build/build-utils.md
index f6be8b3fc73a0fa4bba3bbe97f373ba503b21054..6c27e5e8a4bd9b3e7980d2f6278c0690f0f527dd 100644
--- a/resources/build/build-utils.md
+++ b/resources/build/build-utils.md
@@ -267,7 +267,7 @@ fi
Each step is run separately, is started with [`builder_start_action`], and
finishes with [`builder_finish_action`]. If a build step is complex, it may be
worthwhile splitting it into a separate function or even a separate script
-include.
+include. See also [`builder_run_action`].
Use the longer form of `if ...; then` rather than the shorter `[ ... ] && `
pattern, for consistency and readability.
@@ -303,10 +303,10 @@ have described outputs for them, and the outputs do not exist, and the
dependency is required for one of the targets specified on the command line.
The build order of dependencies is determined by the order in which
-`builder_start_action` is called in the script for each action.
+[`builder_start_action`] is called in the script for each action.
You can also define your own internal dependencies with
-`builder_describe_internal_dependency`. This allows you to define dependencies
+[`builder_describe_internal_dependency`]. This allows you to define dependencies
across targets. Use this judiciously; for example, Keyman Core uses this to
build both x86_64 and arm64 targets, and test only the appropriate architecture
on macOS.
@@ -343,7 +343,7 @@ npm test -- $builder_debug
## `builder_describe` function
Describes a build script, defines available parameters and their meanings. Use
-together with `builder_parse` to process input parameters.
+together with [`builder_parse`] to process input parameters.
### Usage
@@ -391,7 +391,7 @@ builder_describe "Sample script" :engine ":proxy the proxy module"
```
There are several predefined targets. These will not be available to users of
-your script unless you include them in the `builder_describe` call, but when
+your script unless you include them in the [`builder_describe`] call, but when
used, they have default descriptions, which can be used instead of adding your
own in the call:
* `:project`: `"this project"`
@@ -515,15 +515,46 @@ builder_describe_internal_dependency \
```
**Note:** actions and targets must be fully specified, and this _must_ be called
-before either builder_describe_outputs or builder_parse in order for
+before either [`builder_describe_outputs`] or [`builder_parse`] in order for
dependencies to be resolved.
--------------------------------------------------------------------------------
+## `builder_describe_outputs` function
+
+Defines an output file or folder expected to be present after successful
+completion of an action for a target. Used to skip actions for dependency
+builds. If `:target` is not provided, assumes `:project`.
+
+Relative paths are relative to script folder; absolute paths are relative to
+repository root, not filesystem root.
+
+### Usage
+
+```bash
+ builder_describe_outputs action:target filename [...]
+```
+
+### Parameters
+
+* 1: `action[:target]` action and/or target associated with file
+* 2: `filename` name of file or folder to check
+* 3+: ... repeat previous arguments for additional outputs
+
+### Example
+
+```bash
+ builder_describe_outputs \
+ "configure" "/node_modules" \
+ "build" "build/index.js"
+```
+
+--------------------------------------------------------------------------------
+
## `builder_display_usage` function
Prints the help for the script, constructed from the [`builder_describe`]
-parameters, so must be called after `builder_describe`.
+parameters, so must be called after [`builder_describe`].
### Usage
@@ -600,7 +631,7 @@ white for top-level builds and child builds.
## `builder_echo_debug` function
-Wraps the `builder_echo` command with debug mode and a `[DEBUG]` prefix.
+Wraps the [`builder_echo`] command with debug mode and a `[DEBUG]` prefix.
### Usage
@@ -666,6 +697,7 @@ fi
These last two parameters can optionally be space separated.
### Description
+
In normal circumstances, `builder_finish_action` will then print a corresponding
message:
@@ -752,7 +784,7 @@ fi
### Description
The `--debug` standard option is currently handled differently to other options.
-It should never be declared in `builder_describe`, because it is always
+It should never be declared in [`builder_describe`], because it is always
available anyway.
`--debug` is automatically passed to child scripts and dependency scripts.
@@ -779,6 +811,46 @@ correct quoting and escaping.
--------------------------------------------------------------------------------
+## `builder_run_action` function
+
+Wraps [`builder_start_action'] and [`builder_finish`] commands in a shorthand
+style for single-command actions. Can be used together with a local function for
+multi-command actions. Do be aware that this pseudo-closure style cannot be
+mixed with operators such as `<`, `>`, `&&`, `;`, `()` and so on.
+
+### Usage
+
+```bash
+ builder_run_action action[:target] command [command-params...]
+```
+
+### Parameters
+
+* 1: `action[:target]` name of action, and optionally also target, if target
+ excluded starts for all defined targets
+* 2: command command to run if action is started
+* 3...: command-params parameters for command
+
+### Example
+
+The following example shows a sensible pattern to use when you have a single
+multi-command action and other single-command actions. If most of your actions
+are multi-command, you may choose to use this approach, or stick with the
+longhand form.
+
+```bash
+ function do_build() {
+ mkdir -p build/cjs-src
+ npm run build
+ }
+
+ builder_run_action clean rm -rf ./build/ ./tsconfig.tsbuildinfo
+ builder_run_action configure verify_npm_setup
+ builder_run_action build do_build
+```
+
+--------------------------------------------------------------------------------
+
## `builder_run_child_actions` function
Executes the specified actions on or all child targets, or on the specified
@@ -937,6 +1009,8 @@ Note: it is recommended that you use `$(builder_term text)` instead of
[standard builder parameters]: #standard-builder-parameters
[`builder_describe`]: #builderdescribe-function
+[`builder_describe_outputs`]: #builderdescribeoutputs-function
+[`builder_describe_internal_dependency`]: #builderdescribeinternaldependency-function
[`builder_display_usage`]: #builderdisplayusage-function
[`$builder_extra_params`]: #builderextraparams-variable
[`builder_finish_action`]: #builderfinishaction-function
@@ -947,8 +1021,9 @@ Note: it is recommended that you use `$(builder_term text)` instead of
[`builder_use_color`]: #builderusecolor-function
[`$builder_verbose`]: #builderverbose-variable
[formatting variables]: #formatting-variables
+[`builder_run_action`]: #builderrunaction-function
[`builder_run_child_actions`]: #builderrunchildactions-function
[`builder_echo`]: #builderecho-function
[`builder_die`]: #builderdie-function
[`builder_echo_debug`]: #builderechodebug-function
-[`builder_is_debug_build`]: #builderisdebugbuild-function
+[`builder_is_debug_build`]: #builderisdebugbuild-function
\ No newline at end of file
diff --git a/resources/build/build-utils.sh b/resources/build/build-utils.sh
index 3cff571b218d5dd7eb9d33cca72a2e3aabe8dc2f..7ae8db2ae1e90a292f1675cd94001b2391d61181 100755
--- a/resources/build/build-utils.sh
+++ b/resources/build/build-utils.sh
@@ -30,7 +30,7 @@
#
# Exit on command failure and when using unset variables:
-# TODO #8693: set -eu
+set -eu
#
# Prevents 'clear' on exit of mingw64 bash shell
@@ -293,7 +293,7 @@ set_keyman_standard_build_path() {
# For CI compatbility of building Keyman for Android 16.0 with OpenJDK 8,
# this overrides JAVA_HOME for the builder script to use OpenJDK 11.
set_java_home() {
- if [[ ! -z {$JAVA_HOME_11+x} ]]; then
+ if [[ ! -z ${JAVA_HOME_11+x} ]]; then
builder_echo "Setting JAVA_HOME to JAVA_HOME_11 ($JAVA_HOME_11)"
export JAVA_HOME="${JAVA_HOME_11}"
fi
diff --git a/resources/builder.inc.sh b/resources/builder.inc.sh
index 385d03816f0a9c23cc178bc3b8c0e19301921928..f9440ae83eb36f3f293a56efaee5de96bccce8ce 100755
--- a/resources/builder.inc.sh
+++ b/resources/builder.inc.sh
@@ -359,7 +359,7 @@ _builder_failure_trap() {
# finishes.
#
_builder_cleanup_deps() {
- if ! builder_is_dep_build && [[ ! -z ${_builder_deps_built+x} ]]; then
+ if ! builder_is_dep_build && ! builder_is_child_build && [[ ! -z ${_builder_deps_built+x} ]]; then
if $_builder_debug_internal; then
builder_echo_debug "Dependencies that were built:"
cat "$_builder_deps_built"
@@ -523,6 +523,48 @@ builder_has_action() {
fi
}
+#
+# Wraps builder_start_action and builder_finish action for single-command
+# actions. Can be used together with a local function for multi-command actions.
+# Do be aware that this pseudo-closure style cannot be mixed with operators such
+# as `<`, `>`, `&&`, `;`, `()` and so on.
+#
+# ### Usage
+#
+# ```bash
+# builder_run_action action[:target] command [command-params...]
+# ```
+#
+# ### Parameters
+#
+# * 1: `action[:target]` name of action, and optionally also target, if target
+# excluded starts for all defined targets
+# * 2: command command to run if action is started
+# * 3...: command-params parameters for command
+#
+# ### Example
+#
+# ```bash
+# function do_build() {
+# mkdir -p build/cjs-src
+# npm run build
+# }
+#
+# builder_run_action clean rm -rf ./build/ ./tsconfig.tsbuildinfo
+# builder_run_action configure verify_npm_setup
+# builder_run_action build do_build
+# ```
+#
+function builder_run_action() {
+ local action=$1
+ shift
+ if builder_start_action $action; then
+ ($@)
+ builder_finish_action success $action
+ fi
+ return 0
+}
+
#
# Returns `0` if the user has asked to perform action on target on the command
# line, and then starts the action. Should be paired with
@@ -1690,6 +1732,7 @@ builder_has_dependencies() {
builder_has_module_been_built() {
local module="$1"
+
if [[ -z ${_builder_deps_built+x} ]]; then
# not in a builder context, so we assume a build is needed
return 1
diff --git a/resources/locate_emscripten.inc.sh b/resources/locate_emscripten.inc.sh
new file mode 100644
index 0000000000000000000000000000000000000000..a58b384089e30cc3faece91ee9476b11e0f6d485
--- /dev/null
+++ b/resources/locate_emscripten.inc.sh
@@ -0,0 +1,30 @@
+# shellcheck shell=bash
+# no hashbang for .inc.sh
+
+#
+# We don't want to rely on emcc.py being on the path, because Emscripten puts far
+# too many things onto the path (in particular for us, node).
+#
+# The following comment suggests that we don't need emcc.py on the path.
+# https://github.com/emscripten-core/emscripten/issues/4848#issuecomment-1097357775
+#
+# So we try and locate emcc.py in common locations ourselves. The search pattern
+# is:
+#
+# 1. Look for $EMSCRIPTEN_BASE (our primary emscripten variable), which should
+# point to the folder that emcc.py is located in
+# 2. Look for $EMCC which should point to the emcc.py executable
+# 3. Look for emcc.py on the path
+#
+locate_emscripten() {
+ if [[ -z ${EMSCRIPTEN_BASE+x} ]]; then
+ if [[ -z ${EMCC+x} ]]; then
+ local EMCC=`which emcc.py`
+ [[ -z $EMCC ]] && builder_die "locate_emscripten: Could not locate emscripten (emcc.py) on the path or with \$EMCC or \$EMSCRIPTEN_BASE"
+ fi
+ [[ -x $EMCC ]] || builder_die "locate_emscripten: Variable EMCC ($EMCC) does not point to a valid executable emcc.py"
+ EMSCRIPTEN_BASE="$(dirname "$EMCC")"
+ fi
+
+ [[ -x ${EMSCRIPTEN_BASE}/emcc.py ]] || builder_die "locate_emscripten: Variable EMSCRIPTEN_BASE ($EMSCRIPTEN_BASE) does not point to emcc.py's folder"
+}
\ No newline at end of file
diff --git a/tsconfig.esm.json b/tsconfig.esm.json
index f7c3999a4a4d5efcfb78a2947f940084364c8026..ddab85239860824c6ae3d640351d3e4086e4138f 100644
--- a/tsconfig.esm.json
+++ b/tsconfig.esm.json
@@ -12,12 +12,14 @@
{ "path": "./developer/src/kmc/tsconfig.json" },
- { "path": "./developer/src/kmc-keyboard/test/tsconfig.json" },
- { "path": "./developer/src/kmc-keyboard/tsconfig.json" },
+ // { "path": "./developer/src/kmc-analyze/test/tsconfig.json" },
+ { "path": "./developer/src/kmc-analyze/tsconfig.json" },
{ "path": "./developer/src/kmc-kmn/test/tsconfig.json" },
{ "path": "./developer/src/kmc-kmn/tsconfig.json" },
{ "path": "./developer/src/kmc-kmw/test/tsconfig.json" },
{ "path": "./developer/src/kmc-kmw/tsconfig.json" },
+ { "path": "./developer/src/kmc-ldml/test/tsconfig.json" },
+ { "path": "./developer/src/kmc-ldml/tsconfig.json" },
{ "path": "./developer/src/kmc-model/test/tsconfig.json" },
{ "path": "./developer/src/kmc-model/tsconfig.json" },
//{ "path": "./developer/src/kmc-model-info/test/tsconfig.json" },
diff --git a/windows/src/desktop/kmshell/locale/am-ET/strings.xml b/windows/src/desktop/kmshell/locale/am-ET/strings.xml
index 141ba5da55e5a856754c9acd319029547cf54392..20e21edee605f16cbe39b675397755799ad3e357 100644
--- a/windows/src/desktop/kmshell/locale/am-ET/strings.xml
+++ b/windows/src/desktop/kmshell/locale/am-ET/strings.xml
@@ -46,6 +46,10 @@
ይቅር
+
+ ቋንቋ ይጨምሩ ወይም ያጥፉ...
+
+
የፊደል ገበታ ሰሌዳውን ለመምረጥ ይህንን ምስል ይጫኑ
@@ -64,6 +68,18 @@
እርዳታ
+
+
+
+ ያጥፉ
+
+
+
+ ያንቁ
+
+
+
+ እንዳይሰራ ያድርጉ
@@ -174,6 +190,10 @@
ቋንቋ ይጨምሩ
+
+ ቋንቋ ይጨምሩ ወይም ያጥፉ
+
+
የስክሪን ላይ የፊደል ገበታ፦
@@ -223,7 +243,7 @@
- የፊደል ገበታ ሰሌዳ አማራጮች
+ የፊደል ገበታ ሰሌዳ አማራጮች...
@@ -341,7 +361,7 @@
- (ባዶ ነው)
+ (አማራጭ ሆትኪዪ የለም)
diff --git a/windows/src/desktop/setup/locale/am-ET/strings.xml b/windows/src/desktop/setup/locale/am-ET/strings.xml
index 1c4f4252d9e83752e0ab45334b23a0a88fc57d57..b67dc6851a1bf57b7359bf83b897df6ed81eb49d 100644
--- a/windows/src/desktop/setup/locale/am-ET/strings.xml
+++ b/windows/src/desktop/setup/locale/am-ET/strings.xml
@@ -72,9 +72,7 @@
%0:s በማውረድ ላይ
%0:s በማውረድ ላይ
- $APPNAME ማዋቀር ተጨማሪ አጋዥ ሪሶርሶችን ለማውረድ ከkeyman.com ጋር መገናኘት አልቻለም።
-
-እባክዎን የኢንተርኔት ኮኔክሽን መኖሩን ያረጋግጡ እና በፋየርዎልዎ ቅንብሮች ውስጥ በይነመረብን ለመድረስ ለ $APPNAME ማዋቀር ፈቃድ ይስጡ።
-
-ከቅንብር ለመውጣት (Abort)ን ይምረጡ፣ እንደገና ሪሶርሶቹን ለማውረድ እንደገና ይሞክሩ፣ ወይም ከኢንተርኔት ውጭ ለመቀጠል ችላ ይበሉት።
+ $APPNAME ማቀነባበሪያው ተጨማሪ አጋዥ ሪሶርሶችን ለማውረድ ከkeyman.com ጋር መገናኘት አልቻለም።
+ እባክዎን የኢንተርኔት ኮኔክሽን መኖሩን ያረጋግጡ እና በፋየርዎልዎ ቅንብሮች ውስጥ በይነመረብን ለመድረስ ለ $APPNAME ማቀነባበሪያውን ፈቃድ ይስጡ።
+ ከማቀነባበሪያው ለመውጣት (Abort) ን ይምረጡ፣ እንደገና ሪሶርሶቹን ለማውረድ ይሞክሩ፣ ወይም ከኢንተርኔት ውጭ ለመቀጠል ይሞክሩ።
diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp
index 190cf53e79eff5ab23de777e4c8524e9a715ae98..e29e504b2a1ce49568438f1bdf9dc789eae7675d 100644
--- a/windows/src/engine/keyman32/K32_load.cpp
+++ b/windows/src/engine/keyman32/K32_load.cpp
@@ -45,12 +45,6 @@ BOOL GetKeyboardFileName(LPSTR kbname, LPSTR buf, int nbuf)
{
PKEYMAN64THREADDATA _td = ThreadGlobals();
if(!_td) return FALSE;
- if(_td->ForceFileName[0])
- {
- strncpy_s(buf, nbuf, _td->ForceFileName, nbuf - 1);
- buf[nbuf-1] = 0;
- return TRUE;
- }
int n = 0;
RegistryReadOnly *reg = Reg_GetKeymanInstalledKeyboard(kbname);
@@ -75,9 +69,9 @@ BOOL GetKeyboardFileName(LPSTR kbname, LPSTR buf, int nbuf)
return n;
}
-BOOL LoadlpKeyboardCore(int i)
+BOOL LoadlpKeyboard(int i)
{
- SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: Enter ---");
+ SendDebugMessageFormat(0, sdmLoad, 0, "%s: Enter ---", __FUNCTION__);
PKEYMAN64THREADDATA _td = ThreadGlobals();
if (!_td) return FALSE;
@@ -85,7 +79,7 @@ BOOL LoadlpKeyboardCore(int i)
if (_td->lpActiveKeyboard == &_td->lpKeyboards[i]) _td->lpActiveKeyboard = NULL; // I822 TSF not working
if (_td->lpKeyboards[i].lpCoreKeyboardState) {
- SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: a keyboard km_kbp_state exits without matching keyboard - disposing of state");
+ SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboard: a keyboard km_kbp_state exits without matching keyboard - disposing of state");
km_kbp_state_dispose(_td->lpKeyboards[i].lpCoreKeyboardState);
_td->lpKeyboards[i].lpCoreKeyboardState = NULL;
}
@@ -95,7 +89,7 @@ BOOL LoadlpKeyboardCore(int i)
PWCHAR keyboardPath = strtowstr(buf);
km_kbp_status err_status = km_kbp_keyboard_load(keyboardPath, &_td->lpKeyboards[i].lpCoreKeyboard);
if (err_status != KM_KBP_STATUS_OK) {
- SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: km_kbp_keyboard_load failed for %ls with error status [%d]", keyboardPath, err_status);
+ SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboard: km_kbp_keyboard_load failed for %ls with error status [%d]", keyboardPath, err_status);
delete keyboardPath;
return FALSE;
}
@@ -104,7 +98,7 @@ BOOL LoadlpKeyboardCore(int i)
km_kbp_option_item *core_environment = nullptr;
if(!SetupCoreEnvironment(&core_environment)) {
- SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: Unable to set environment options for keyboard %ls", keyboardPath);
+ SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboard: Unable to set environment options for keyboard %ls", keyboardPath);
return FALSE;
}
@@ -114,7 +108,7 @@ BOOL LoadlpKeyboardCore(int i)
if (err_status != KM_KBP_STATUS_OK) {
SendDebugMessageFormat(
- 0, sdmLoad, 0, "LoadlpKeyboardCore: km_kbp_state_create failed with error status [%d]", err_status);
+ 0, sdmLoad, 0, "LoadlpKeyboard: km_kbp_state_create failed with error status [%d]", err_status);
// Dispose of the keyboard to leave us in a consistent state
ReleaseKeyboardMemoryCore(&_td->lpKeyboards[i].lpCoreKeyboard);
return FALSE;
@@ -122,38 +116,15 @@ BOOL LoadlpKeyboardCore(int i)
// Register callback?
err_status = km_kbp_keyboard_get_imx_list(_td->lpKeyboards[i].lpCoreKeyboard, &_td->lpKeyboards[i].lpIMXList);
if (err_status != KM_KBP_STATUS_OK) {
- SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: km_kbp_keyboard_get_imx_list failed with error status [%d]", err_status);
+ SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboard: km_kbp_keyboard_get_imx_list failed with error status [%d]", err_status);
// Dispose of the keyboard to leave us in a consistent state
ReleaseKeyboardMemoryCore(&_td->lpKeyboards[i].lpCoreKeyboard);
return FALSE;
}
- LoadDLLsCore(&_td->lpKeyboards[i]);
-
- LoadKeyboardOptionsREGCore(&_td->lpKeyboards[i], _td->lpKeyboards[i].lpCoreKeyboardState);
-
- return TRUE;
-}
-
-BOOL LoadlpKeyboard(int i)
-{
- if (Globals::get_CoreIntegration())
- {
- return LoadlpKeyboardCore(i);
- }
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td) return FALSE;
- if(_td->lpKeyboards[i].Keyboard) return TRUE;
- if(_td->lpActiveKeyboard == &_td->lpKeyboards[i]) _td->lpActiveKeyboard = NULL; // I822 TSF not working
-
- char buf[256];
- if(!GetKeyboardFileName(_td->lpKeyboards[i].Name, buf, 255)) return FALSE;
-
- if(!LoadKeyboard(buf, &_td->lpKeyboards[i].Keyboard)) return FALSE; // I5136
-
LoadDLLs(&_td->lpKeyboards[i]);
- LoadKeyboardOptions(&_td->lpKeyboards[i]);
+ LoadKeyboardOptionsRegistrytoCore(&_td->lpKeyboards[i], _td->lpKeyboards[i].lpCoreKeyboardState);
return TRUE;
}
diff --git a/windows/src/engine/keyman32/addins.cpp b/windows/src/engine/keyman32/addins.cpp
deleted file mode 100644
index 6c7f5d0f285842d9a47753bc56081219c6fbd662..0000000000000000000000000000000000000000
--- a/windows/src/engine/keyman32/addins.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- Name: addins
- Copyright: Copyright (C) SIL International.
- Documentation:
- Description:
- Create Date: 14 Jun 2008
-
- Modified Date: 14 May 2010
- Authors: mcdurdin
- Related Files:
- Dependencies:
-
- Bugs:
- Todo:
- Notes:
- History: 14 Jun 2008 - mcdurdin - I1488 - Fix registry handle leak
- 11 Mar 2009 - mcdurdin - I1894 - Fix threading bugs introduced in I1888
- 11 Dec 2009 - mcdurdin - I934 - x64 - Initial version
- 12 Mar 2010 - mcdurdin - I934 - x64 - Complete
- 12 Mar 2010 - mcdurdin - I2229 - Remove hints and warnings
- 04 May 2010 - mcdurdin - I2351 - Robustness - verify _td return value
- 14 May 2010 - mcdurdin - I2374 - Fix crash in some situations
-*/
-
-#include "pch.h"
-
-void Addin_Release()
-{
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td) return;
-
- //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Release: ENTER [%d]", nAddins);
- if(_td->Addins)
- {
- for(int i = 0; i < _td->nAddins; i++)
- if(_td->Addins[i].hAddin)
- {
- if(_td->Addins[i].Uninitialise) (*_td->Addins[i].Uninitialise)();
- FreeLibrary(_td->Addins[i].hAddin);
- }
- delete[] _td->Addins;
- }
- _td->Addins = NULL;
- _td->nAddins = 0;
- _td->CurrentAddin = -1;
- //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Release: EXIT");
-}
-
-void ReadAddins(HKEY hkey)
-{
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td) return;
-
- //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: ReadAddins: ENTER");
- RegistryReadOnly *reg = new RegistryReadOnly(hkey);
- if(reg->OpenKeyReadOnly(hkey == HKEY_CURRENT_USER ? REGSZ_KeymanAddinsCU : REGSZ_KeymanAddinsLM))
- {
- int n = _td->nAddins;
- char buf[128];
- while(reg->GetValueNames(buf, 128, n))
- {
- Addin *a = new Addin[n+1];
- if(_td->Addins)
- {
- memcpy(a, _td->Addins, n * sizeof(Addin));
- delete[] _td->Addins;
- }
- _td->Addins = a;
- _td->Addins[n].hAddin = 0;
- _td->Addins[n].FocusChanged = NULL;
- _td->Addins[n].Initialise = NULL;
- _td->Addins[n].OutputBackspace = NULL;
- _td->Addins[n].OutputChar = NULL;
- _td->Addins[n].Uninitialise = NULL;
- _td->Addins[n].ShouldProcess = NULL;
- strcpy(_td->Addins[n].ClassName, buf);
- reg->ReadString(buf, _td->Addins[n].AddinName, 260);
- _td->Addins[n].Application[0] = 0;
- n++;
- }
- _td->nAddins = n;
- }
- delete reg;
- //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: ReadAddins: EXIT");
-}
-
-void Addin_Refresh()
-{
- //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Refresh: ENTER");
- Addin_Release();
- ReadAddins(HKEY_CURRENT_USER);
- ReadAddins(HKEY_LOCAL_MACHINE);
- //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Refresh: EXIT");
-}
-
-BOOL LoadAddin()
-{
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td) return FALSE;
- if(_td->CurrentAddin == -1) return FALSE;
-
- Addin *a = &_td->Addins[_td->CurrentAddin];
- if(!a->hAddin)
- {
- //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: ENTER");
- a->hAddin = LoadLibrary(a->AddinName);
- if(!a->hAddin)
- {
- a->hAddin = 0;
- a->ClassName[0] = 0; // prevent add-in attempting to load again
- _td->CurrenthWnd = 0;
- _td->CurrentAddin = -1;
- //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: EXIT - FALSE - LoadLibrary");
- return FALSE;
- }
- a->OutputBackspace = (PKeymanOutputBackspace) GetProcAddress(a->hAddin, "KeymanOutputBackspace");
- a->OutputChar = (PKeymanOutputChar) GetProcAddress(a->hAddin, "KeymanOutputChar");
- a->FocusChanged = (PKeymanFocusChanged) GetProcAddress(a->hAddin, "KeymanFocusChanged");
- a->ShouldProcess = (PKeymanShouldProcess) GetProcAddress(a->hAddin, "KeymanShouldProcess");
- a->Initialise = (PKeymanInit) GetProcAddress(a->hAddin, "KeymanInitialise");
- a->Uninitialise = (PKeymanInit) GetProcAddress(a->hAddin, "KeymanUninitialise");
-
- if(a->Initialise && !(*a->Initialise)())
- {
- FreeLibrary(a->hAddin);
- a->hAddin = 0;
- a->ClassName[0] = 0;
- _td->CurrenthWnd = 0;
- _td->CurrentAddin = -1;
- //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: EXIT - FALSE - Initialise");
- return FALSE;
- }
- //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: EXIT - TRUE - Loaded");
- }
- return TRUE;
-}
-
-BOOL Addin_ShouldProcessUnichar(HWND hwnd)
-{
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td) return FALSE;
-
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: ENTER");
- _td->CurrenthWnd = hwnd;
- GetClassName(hwnd, _td->CurrentClassName, 128);
- if(_td->CurrentAddin >= 0 && !_strcmpi(_td->CurrentClassName, _td->Addins[_td->CurrentAddin].ClassName))
- {
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: EXIT - TRUE - CurrentAddin okay");
- return TRUE;
- }
-
- for(int i = 0; i < _td->nAddins; i++)
- if(!_strcmpi(_td->CurrentClassName, _td->Addins[i].ClassName))
- {
- _td->CurrentAddin = i;
- if(!LoadAddin())
- {
- _td->CurrentAddin = -1;
- _td->Addins[i].ClassName[0] = 0; // prevent add-in attempting to load again
- }
- else if(_td->Addins[i].ShouldProcess && !(*_td->Addins[i].ShouldProcess)(hwnd))
- _td->CurrentAddin = -1;
- else
- {
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: EXIT - TRUE - FoundAddin");
- return TRUE;
- }
- }
- _td->CurrentAddin = -1;
- _td->CurrenthWnd = 0;
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: EXIT - FALSE");
- return FALSE;
-}
-
-BOOL Addin_ProcessUnichar(HWND hwnd, DWORD chr)
-{
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td) return FALSE;
-
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: ENTER");
- if(_td->CurrenthWnd != hwnd)
- if(!Addin_ShouldProcessUnichar(hwnd))
- {
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT - FALSE - Addin_ShouldProcessUnichar");
- return FALSE;
- }
-
- if(!LoadAddin())
- {
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT - FALSE - !LoadAddin)");
- return FALSE;
- }
- if(!_td->Addins[_td->CurrentAddin].OutputChar)
- {
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT - FALSE !OutputChar");
- return FALSE;
- }
-
- BOOL b = (*_td->Addins[_td->CurrentAddin].OutputChar)(hwnd, chr);
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT (b) == %d", b);
- return b;
-}
-
-BOOL Addin_ProcessBackspace(HWND hwnd)
-{
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td) return FALSE;
-
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: ENTER");
- if(_td->CurrenthWnd != hwnd)
- if(!Addin_ShouldProcessUnichar(hwnd))
- {
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - !ShouldProcess");
- return FALSE;
- }
-
- if(!LoadAddin())
- {
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - !LoadAddin");
- return FALSE;
- }
- if(!_td->Addins[_td->CurrentAddin].OutputBackspace)
- {
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - !OutputBackspace");
- return FALSE;
- }
-
- BOOL b = (*_td->Addins[_td->CurrentAddin].OutputBackspace)(hwnd);
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - (b) = %d", b);
- return b;
-}
-
-void Addin_FocusChanged(HWND hwnd)
-{
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td) return;
-
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: ENTER");
-
- if(_td->CurrenthWnd != hwnd)
- if(!Addin_ShouldProcessUnichar(hwnd))
- {
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT - !ShouldProcess");
- return;
- }
-
- if(!LoadAddin())
- {
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT - !LoadAddin");
- return;
- }
-
- // Addin variables must be valid now
-
- if(!_td->Addins[_td->CurrentAddin].FocusChanged)
- {
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT - !FocusChanged");
- return;
- }
-
- (*_td->Addins[_td->CurrentAddin].FocusChanged)();
- //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT");
-}
diff --git a/windows/src/engine/keyman32/addins.h b/windows/src/engine/keyman32/addins.h
deleted file mode 100644
index 71aa006e59c41ab2ec71517b3e24e76dc16e2e36..0000000000000000000000000000000000000000
--- a/windows/src/engine/keyman32/addins.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- Name: addins
- Copyright: Copyright (C) SIL International.
- Documentation:
- Description:
- Create Date: 11 Dec 2009
-
- Modified Date: 11 Dec 2009
- Authors: mcdurdin
- Related Files:
- Dependencies:
-
- Bugs:
- Todo:
- Notes:
- History: 11 Dec 2009 - mcdurdin - I934 - x64 - Initial version
-*/
-void Addin_Release();
-void Addin_Refresh();
-BOOL Addin_ShouldProcessUnichar(HWND hwnd);
-BOOL Addin_ProcessUnichar(HWND hwnd, DWORD chr);
-BOOL Addin_ProcessBackspace(HWND hwnd);
-void Addin_FocusChanged(HWND hwnd);
diff --git a/windows/src/engine/keyman32/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp
index 23240b2a067b5d517653b3b1da6f678cb7b5344f..34f3afc867f5c243898a0c0452cc2e89479859c6 100644
--- a/windows/src/engine/keyman32/appint/aiTIP.cpp
+++ b/windows/src/engine/keyman32/appint/aiTIP.cpp
@@ -126,7 +126,6 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM
BOOL isUp = keyFlags & KF_UP ? TRUE : FALSE;
BOOL extended = keyFlags & KF_EXTENDED ? TRUE : FALSE;
BYTE scan = keyFlags & 0xFF;
- BOOL isUsingCoreProcessor = Globals::get_CoreIntegration();
SendDebugMessageFormat(0, sdmAIDefault, 0, "TIPProcessKey: Enter VirtualKey=%s lParam=%x IsUp=%d Extended=%d Updateable=%d Preserved=%d", Debug_VirtualKey((WORD) wParam), lParam, isUp, extended, Updateable, Preserved);
@@ -163,72 +162,31 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM
// core processor. The core processor has the keyboard Caps Lock stores and will
// queue an action 'KM_KBP_IT_CAPSLOCK'. In processing the action the Windows engine will synthesise keystrokes
// to ensure caps lock is in the correct state.
- if (isUsingCoreProcessor) {
- if (!Preserved) {
- switch (wParam) {
- case VK_MENU:
- case VK_CONTROL:
- ProcessModifierChange((UINT)wParam, isUp, extended);
- return FALSE;
- case VK_NUMLOCK:
+ if (!Preserved) {
+ switch (wParam) {
+ case VK_MENU:
+ case VK_CONTROL:
+ ProcessModifierChange((UINT)wParam, isUp, extended);
+ return FALSE;
+ case VK_NUMLOCK:
+ if (!isUp)
+ ProcessToggleChange((UINT)wParam); // I4793
+ return FALSE;
+ case VK_CAPITAL:
if (!isUp)
- ProcessToggleChange((UINT)wParam); // I4793
- return FALSE;
- case VK_CAPITAL:
- if (!isUp)
- ProcessToggleChange((UINT)wParam); // I4793
- break;
- case VK_SHIFT:
- ProcessModifierChange((UINT)wParam, isUp, extended);
+ ProcessToggleChange((UINT)wParam); // I4793
break;
- }
- } else {
- // Mask out Ctrl, Shift and Alt and include new modifiers // I4548
- DWORD NewShiftState = TSFShiftToShift(lParam); // I3588
- SendDebugMessageFormat(
- 0, sdmGlobal, 0, "TIPProcessKey: TSFShiftToShift start with %x, include %x", LocalShiftState, NewShiftState);
- *Globals::ShiftState() = (LocalShiftState & K_NOTMODIFIERFLAG) | NewShiftState; // I3588
- }
- } else { // using windows processor TODO: #5442 Remove this else block
- if (!Preserved) {
- switch (wParam) {
- case VK_CAPITAL:
- if (!isUp)
- ProcessToggleChange((UINT)wParam); // I4793
- if (!Updateable) {
- // We only want to process the Caps Lock key event once --
- // in the first pass (!Updateable).
- KeyCapsLockPress(isUp); // I4548
- }
- return FALSE;
- case VK_SHIFT:
- if (!Updateable) {
- // We only want to process the Shift key event once --
- // in the first pass (!Updateable).
- KeyShiftPress(isUp); // I4548
- }
- // Fall through
- case VK_MENU:
- case VK_CONTROL:
- ProcessModifierChange((UINT)wParam, isUp, extended);
- return FALSE;
- case VK_NUMLOCK:
- if (!isUp)
- ProcessToggleChange((UINT)wParam); // I4793
- return FALSE;
- }
- // This would only get here if none of the above cases matched why not use default in the switch?
- if (isUp) {
- return FALSE; // return value ignored in this case; we only needed it for testing anyway
- }
- } else {
- // Mask out Ctrl, Shift and Alt and include new modifiers // I4548
- DWORD NewShiftState = TSFShiftToShift(lParam); // I3588
- SendDebugMessageFormat(
- 0, sdmGlobal, 0, "TIPProcessKey: TSFShiftToShift start with %x, include %x", LocalShiftState, NewShiftState);
- *Globals::ShiftState() = (LocalShiftState & K_NOTMODIFIERFLAG) | NewShiftState; // I3588
+ case VK_SHIFT:
+ ProcessModifierChange((UINT)wParam, isUp, extended);
+ break;
}
- } // TODO: #5442 Remove this else block ^^
+ } else {
+ // Mask out Ctrl, Shift and Alt and include new modifiers // I4548
+ DWORD NewShiftState = TSFShiftToShift(lParam); // I3588
+ SendDebugMessageFormat(
+ 0, sdmGlobal, 0, "TIPProcessKey: TSFShiftToShift start with %x, include %x", LocalShiftState, NewShiftState);
+ *Globals::ShiftState() = (LocalShiftState & K_NOTMODIFIERFLAG) | NewShiftState; // I3588
+ }
_td->TIPFUpdateable = Updateable;
_td->TIPFPreserved = Preserved; // I4290
@@ -239,16 +197,7 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM
_td->state.vkey = (WORD) wParam;
_td->state.isDown = !isUp;
- if (isUsingCoreProcessor) {
- _td->state.lpCoreKb = _td->lpActiveKeyboard->lpCoreKeyboard;
-
- } else {
- _td->state.lpkb = _td->lpActiveKeyboard->Keyboard;
- _td->state.startgroup = &_td->state.lpkb->dpGroupArray[_td->state.lpkb->StartGroup[BEGIN_UNICODE]];
- _td->state.NoMatches = TRUE;
- _td->state.LoopTimes = 0;
- _td->state.StopOutput = FALSE;
- }
+ _td->state.lpCoreKb = _td->lpActiveKeyboard->lpCoreKeyboard;
_td->state.windowunicode = TRUE;
@@ -257,30 +206,8 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM
_td->TIPProcessOutput = outfunc;
_td->TIPGetContext = ctfunc;
- AppContextWithStores *savedContext = NULL; // I4370 // I4978
-
- if (!Updateable) {
- // The core processor km_kbp_process_event is only called once per key stroke
- // therefore there is no need to preserve context and keyboard actions
- if (!isUsingCoreProcessor) {
- savedContext = new AppContextWithStores(_td->lpActiveKeyboard->Keyboard->cxStoreArray); // I4370 // I4978
- _td->app->SaveContext(savedContext);
- }
- }
-
BOOL res = ProcessHook();
- if (!Updateable) {
- if (!isUsingCoreProcessor) {
- if (res) { // I4585 // I4370
- // Reset the context if match found
- _td->app->RestoreContext(savedContext);
- delete savedContext;
- savedContext = NULL;
- }
- }
- }
-
_td->TIPProcessOutput = NULL;
_td->TIPGetContext = NULL;
@@ -439,65 +366,6 @@ void AITIP::ReadContext() {
}
}
-AppContextWithStores::AppContextWithStores(int nKeyboardOptions) : AppContext() { // I4978
- this->nKeyboardOptions = nKeyboardOptions;
- KeyboardOptions = new INTKEYBOARDOPTIONS[nKeyboardOptions];
- memset(KeyboardOptions, 0, sizeof(INTKEYBOARDOPTIONS) * nKeyboardOptions);
-}
-
-AppContextWithStores::~AppContextWithStores() { // I4978
- for(DWORD i = 0; i < nKeyboardOptions; i++) {
- if(KeyboardOptions[i].Value) delete KeyboardOptions[i].Value;
- }
- delete KeyboardOptions;
-}
-
-void AITIP::SaveContext(AppContextWithStores *savedContext) { // I4370 // I4978
- savedContext->CopyFrom(context);
-
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td || !_td->lpActiveKeyboard || !_td->lpActiveKeyboard->Keyboard) return;
-
- assert(savedContext->nKeyboardOptions == _td->lpActiveKeyboard->Keyboard->cxStoreArray);
-
- for(DWORD i = 0; i < savedContext->nKeyboardOptions; i++) { // I4978
- if(_td->lpActiveKeyboard->KeyboardOptions[i].Value != NULL) {
- savedContext->KeyboardOptions[i].Value = new WCHAR[wcslen(_td->lpActiveKeyboard->KeyboardOptions[i].Value)+1];
- wcscpy_s(savedContext->KeyboardOptions[i].Value, wcslen(_td->lpActiveKeyboard->KeyboardOptions[i].Value)+1, _td->lpActiveKeyboard->KeyboardOptions[i].Value);
- }
- }
-}
-
-void AITIP::RestoreContext(AppContextWithStores *savedContext) { // I4370 // I4978
- context->CopyFrom(savedContext);
-
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td || !_td->lpActiveKeyboard || !_td->lpActiveKeyboard->Keyboard) return;
- LPINTKEYBOARDINFO kp = _td->lpActiveKeyboard;
-
- assert(savedContext->nKeyboardOptions == kp->Keyboard->cxStoreArray);
-
- for(DWORD i = 0; i < savedContext->nKeyboardOptions; i++) { // I4978
- if(kp->KeyboardOptions[i].Value == NULL && savedContext->KeyboardOptions[i].Value != NULL) {
- // Restore the previously saved value as it was reset
- kp->KeyboardOptions[i].OriginalStore = kp->Keyboard->dpStoreArray[i].dpString;
- kp->Keyboard->dpStoreArray[i].dpString = kp->KeyboardOptions[i].Value = savedContext->KeyboardOptions[i].Value;
- savedContext->KeyboardOptions[i].Value = NULL;
- } else if(kp->KeyboardOptions[i].Value != NULL && savedContext->KeyboardOptions[i].Value == NULL) {
- // Clear the newly saved value back to the default
- delete kp->KeyboardOptions[i].Value;
- kp->KeyboardOptions[i].Value = NULL;
- kp->Keyboard->dpStoreArray[i].dpString = kp->KeyboardOptions[i].OriginalStore;
- } else if(kp->KeyboardOptions[i].Value != NULL && savedContext->KeyboardOptions[i].Value != NULL &&
- wcscmp(kp->KeyboardOptions[i].Value, savedContext->KeyboardOptions[i].Value) != 0) {
- // Restore the previously saved value as it was changed
- delete kp->KeyboardOptions[i].Value;
- kp->Keyboard->dpStoreArray[i].dpString = kp->KeyboardOptions[i].Value = savedContext->KeyboardOptions[i].Value;
- savedContext->KeyboardOptions[i].Value = NULL;
- }
- }
-}
-
void AITIP::CopyContext(AppContext *savedContext) {
savedContext->CopyFrom(context);
}
@@ -722,49 +590,3 @@ void FillStoreOffsets(AIDEBUGINFO *di)
}
di->StoreOffsets[n] = 0xFFFF;
}
-
-BOOL AITIP::QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY Rule, PWSTR fcontext, PWSTR foutput, DWORD_PTR dwExtraFlags)
-{
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td) return TRUE;
- if(!_td->ForceFileName[0]) return TRUE;
-
- SendDebugMessageFormat(0, sdmAIDefault, 0, "AIDebugger::QueueDebugInformation ItemType=%d", ItemType);
- AIDEBUGINFO di;
- di.cbSize = sizeof(AIDEBUGINFO);
- di.ItemType = ItemType; // int
- di.Context = fcontext; // PWSTR
- di.Rule = Rule; // LPKEY
- di.Group = Group; // LPGROUP
- di.Output = foutput; // PWSTR
- di.Flags = dwExtraFlags; // DWORD
-
- if(di.Rule) FillStoreOffsets(&di);
-
- // data required
- // keystroke
- // context for rule
- // if rule, then output of rule
- // match positions for all stores in rule
-
- if(DebugControlled())
- SendMessage(GetDebugControlWindow(), WM_KEYMANDEBUG_RULEMATCH, ItemType, (LPARAM) &di);
-
- return TRUE;
-}
-
-typedef BOOL(WINAPI *PREFRESHPRESERVEDKEYSFUNC)(BOOL Activating);
-
-void RefreshPreservedKeys(BOOL Activating) {
-#ifdef _WIN64
- HMODULE hModule = GetModuleHandle("kmtip64");
-#else
- HMODULE hModule = GetModuleHandle("kmtip");
-#endif
- if (hModule != NULL) {
- PREFRESHPRESERVEDKEYSFUNC pRefreshPreservedKeys = (PREFRESHPRESERVEDKEYSFUNC)GetProcAddress(hModule, "RefreshPreservedKeys");
- if (pRefreshPreservedKeys) {
- pRefreshPreservedKeys(Activating);
- }
- }
-}
diff --git a/windows/src/engine/keyman32/appint/aiTIP.h b/windows/src/engine/keyman32/appint/aiTIP.h
index 7ff5aff4ef2c29164363ed6860f370a65cdcea20..3c6fd9b6980b7bcf139b77dac28cace83bf134bc 100644
--- a/windows/src/engine/keyman32/appint/aiTIP.h
+++ b/windows/src/engine/keyman32/appint/aiTIP.h
@@ -71,11 +71,6 @@ public:
BOOL DebugControlled();
- // TODO: 5442 This would be better to called SaveContextWithStores or SaveContextWithKbdOptions
- // Will be removed with 5442 when removing window core
- void SaveContext(AppContextWithStores *savedContext); // I4370 // I4978
- void RestoreContext(AppContextWithStores *savedContext); // I4370 // I4978
-
/**
* Copy the member context
*
@@ -106,7 +101,6 @@ public:
/* Queue and sending functions */
virtual BOOL SendActions(); // I4196
- virtual BOOL QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY Rule, PWSTR fcontext, PWSTR foutput, DWORD_PTR dwExtraFlags);
/* TIP interactions */
diff --git a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp
index 19da87a543581223b8aaf860cda5116bdbbfc28e..a6b540fd47a1c4a9d09ee7c5cca65388ae263b7d 100644
--- a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp
+++ b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp
@@ -1,18 +1,18 @@
/*
Name: AIWin2000Unicode
Copyright: Copyright (C) SIL International.
- Documentation:
- Description:
+ Documentation:
+ Description:
Create Date: 22 Jan 2007
Modified Date: 9 Aug 2015
Authors: mcdurdin
- Related Files:
- Dependencies:
+ Related Files:
+ Dependencies:
- Bugs:
- Todo:
- Notes:
+ Bugs:
+ Todo:
+ Notes:
History: 22 Jan 2007 - mcdurdin - Fix for K_NPENTER
13 Jul 2007 - mcdurdin - I934 - Prep fox x64
23 Aug 2007 - mcdurdin - I719 - Fix Alt+LeftShift and Word interactions
@@ -43,12 +43,6 @@
#include "pch.h" // I4128 // I4287
#include "serialkeyeventclient.h"
-#define KEYMAN_MOREPOST "WM_KMMOREPOST"
-
-#ifndef WM_UNICHAR
-#define WM_UNICHAR 0x0109
-#define UNICODE_NOCHAR 0xFFFF
-#endif
AIWin2000Unicode::AIWin2000Unicode()
{
@@ -70,13 +64,13 @@ BOOL AIWin2000Unicode::CanHandleWindow(HWND ahwnd)
}
BOOL AIWin2000Unicode::HandleWindow(HWND ahwnd)
-{
+{
if(hwnd != ahwnd)
{
- hwnd = ahwnd;
+ hwnd = ahwnd;
context->Reset();
}
- return TRUE;
+ return TRUE;
}
BOOL AIWin2000Unicode::IsWindowHandled(HWND ahwnd)
@@ -84,11 +78,11 @@ BOOL AIWin2000Unicode::IsWindowHandled(HWND ahwnd)
return (hwnd == ahwnd);
}
-BOOL AIWin2000Unicode::IsUnicode()
-{
+BOOL AIWin2000Unicode::IsUnicode()
+{
BOOL Result = IsWindowUnicode(hwnd);
SendDebugMessageFormat(0, sdmAIDefault, 0, "IsWindowUnicode=%s", Result ? "Yes" : "No");
- return Result;
+ return Result;
}
/* Context functions */
@@ -96,7 +90,7 @@ BOOL AIWin2000Unicode::IsUnicode()
void AIWin2000Unicode::ReadContext()
{
}
-
+
void AIWin2000Unicode::AddContext(WCHAR ch) //I2436
{
context->Add(ch);
@@ -121,7 +115,7 @@ void AIWin2000Unicode::SetContext(const WCHAR* buf)
{
return context->Set(buf);
}
-
+
BYTE SavedKbdState[256];
BOOL AIWin2000Unicode::SendActions() // I4196
@@ -137,7 +131,7 @@ BOOL AIWin2000Unicode::QueueAction(int ItemType, DWORD dwData)
int result = AppIntegration::QueueAction(ItemType, dwData);
//SendDebugMessageFormat(hwnd, sdmAIDefault, 0, "App::QueueAction ItemType=%d dwData=%x", ItemType, dwData);
-
+
switch(ItemType)
{
case QIT_VKEYDOWN:
@@ -166,27 +160,16 @@ BOOL AIWin2000Unicode::QueueAction(int ItemType, DWORD dwData)
return result;
}
-BOOL AIWin2000Unicode::QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY Rule, PWSTR fcontext, PWSTR foutput, DWORD_PTR dwExtraFlags)
-{
- UNREFERENCED_PARAMETER(ItemType);
- UNREFERENCED_PARAMETER(Group);
- UNREFERENCED_PARAMETER(Rule);
- UNREFERENCED_PARAMETER(fcontext);
- UNREFERENCED_PARAMETER(foutput);
- UNREFERENCED_PARAMETER(dwExtraFlags);
- return TRUE;
-}
-
// I1512 - SendInput with VK_PACKET for greater robustness
BOOL AIWin2000Unicode::PostKeys()
-{
+{
PKEYMAN64THREADDATA _td = ThreadGlobals();
if(!_td) {
return FALSE;
}
- if(QueueSize == 0)
+ if(QueueSize == 0)
{
return TRUE;
}
@@ -208,7 +191,7 @@ BOOL AIWin2000Unicode::PostKeys()
switch(Queue[n].ItemType) {
case QIT_VKEYDOWN:
if((Queue[n].dwData & QVK_KEYMASK) == 0x05) Queue[n].dwData = (Queue[n].dwData & QVK_FLAGMASK) | VK_RETURN; // I649 // I3438
-
+
/* 6.0.153.0: Fix repeat state for virtual keys */
if((Queue[n].dwData & QVK_KEYMASK) <= VK__MAX) // I3438
@@ -277,7 +260,6 @@ BOOL AIWin2000Unicode::PostKeys()
break;
case QIT_BACK:
if(Queue[n].dwData & BK_DEADKEY) break;
- if(Addin_ProcessBackspace(hwnd)) break;
pInputs[i].type = INPUT_KEYBOARD;
pInputs[i].ki.wVk = VK_BACK;
diff --git a/windows/src/engine/keyman32/appint/aiWin2000Unicode.h b/windows/src/engine/keyman32/appint/aiWin2000Unicode.h
index 73db7ac9073ceeefdbd138777f3a8ebf120122fd..1ee49ed001fef8fbb4dce79565beb835832f9800 100644
--- a/windows/src/engine/keyman32/appint/aiWin2000Unicode.h
+++ b/windows/src/engine/keyman32/appint/aiWin2000Unicode.h
@@ -1,18 +1,18 @@
/*
Name: aiWin2000Unicode
Copyright: Copyright (C) SIL International.
- Documentation:
- Description:
+ Documentation:
+ Description:
Create Date: 27 Jan 2009
Modified Date: 23 Jun 2014
Authors: mcdurdin
- Related Files:
- Dependencies:
+ Related Files:
+ Dependencies:
- Bugs:
- Todo:
- Notes:
+ Bugs:
+ Todo:
+ Notes:
History: 27 Jan 2009 - mcdurdin - I1797 - Add fallback for AIWin2000 app integration
11 Dec 2009 - mcdurdin - I934 - x64 - Initial version
24 Jun 2010 - mcdurdin - I2436 - Add space to context for AIWin2000Unicode when not matched
@@ -43,7 +43,7 @@ public:
virtual BOOL QueueAction(int ItemType, DWORD dwData);
/* Information functions */
-
+
virtual BOOL CanHandleWindow(HWND ahwnd);
virtual BOOL IsWindowHandled(HWND ahwnd);
virtual BOOL HandleWindow(HWND ahwnd);
@@ -59,9 +59,8 @@ public:
virtual void SetContext(const WCHAR* buf);
/* Queue and sending functions */
-
+
virtual BOOL SendActions(); // I4196
- virtual BOOL QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY Rule, PWSTR fcontext, PWSTR foutput, DWORD_PTR dwExtraFlags);
};
#endif
diff --git a/windows/src/engine/keyman32/appint/appint.h b/windows/src/engine/keyman32/appint/appint.h
index 3e9a4dfb4d49ed3993d173d1c508bd60ff60739f..6fe7ca7e201ef5016613ee292e3f86033ac2f643 100644
--- a/windows/src/engine/keyman32/appint/appint.h
+++ b/windows/src/engine/keyman32/appint/appint.h
@@ -43,22 +43,6 @@ typedef struct
#define QIT_CAPSLOCK 8
#define QIT_INVALIDATECONTEXT 9
-// QueueDebugInformation ItemTypes
-#define QID_BEGIN_UNICODE 0
-#define QID_BEGIN_ANSI 1
-#define QID_GROUP_ENTER 2
-#define QID_GROUP_EXIT 3
-#define QID_RULE_ENTER 4
-#define QID_RULE_EXIT 5
-#define QID_MATCH_ENTER 6
-#define QID_MATCH_EXIT 7
-#define QID_NOMATCH_ENTER 8
-#define QID_NOMATCH_EXIT 9
-#define QID_END 10
-
-#define QID_FLAG_RECURSIVE_OVERFLOW 0x0001
-#define QID_FLAG_NOMATCH 0x0002
-
#define QVK_EXTENDED 0x00010000 // Flag for QIT_VKEYDOWN to indicate an extended key
#define QVK_KEYMASK 0x0000FFFF
#define QVK_FLAGMASK 0xFFFF0000
@@ -178,15 +162,6 @@ public:
};
-class AppContextWithStores : public AppContext // I4978
-{
-public:
- AppContextWithStores(int nKeyboardOptions);
- ~AppContextWithStores();
- DWORD nKeyboardOptions;
- LPINTKEYBOARDOPTIONS KeyboardOptions;
-};
-
class AppIntegration:public AppActionQueue
{
protected:
@@ -214,7 +189,6 @@ public:
/* Queue and sending functions */
- virtual BOOL QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY Rule, PWSTR fcontext, PWSTR foutput, DWORD_PTR dwExtraFlags) = 0;
void SetCurrentShiftState(int ShiftFlags) { FShiftFlags = ShiftFlags; }
virtual BOOL SendActions() = 0; // I4196
};
diff --git a/windows/src/engine/keyman32/calldll.cpp b/windows/src/engine/keyman32/calldll.cpp
index 142db01747c644393d556d31100d1ec2bb3a636d..f0c623373c2e7bd1e20577f32826e31cd5092960 100644
--- a/windows/src/engine/keyman32/calldll.cpp
+++ b/windows/src/engine/keyman32/calldll.cpp
@@ -93,34 +93,6 @@ static LPIMDLL AddIMDLL(LPINTKEYBOARDINFO lpkbi, LPSTR kbdpath, LPSTR dllfilenam
return imd;
}
-/* Add a dll hook function to the list of hook functions associated with a single dll */
-
-static BOOL AddIMDLLHook(LPIMDLL imd, LPSTR funcname, DWORD storeno, PWCHAR *dpString)
-{
- //SendDebugMessageFormat(0, sdmKeyboard, 0, "AddIMDLLHook: Enter");
- /* Get the procedure address for the function */
-
- IMDLLHOOKProc dhp = (IMDLLHOOKProc) GetProcAddress(imd->hModule, funcname);
- if(!dhp) return FALSE;
-
- /* Add the function to the list of functions in the DLL */
-
- LPIMDLLHOOK hooks = new IMDLLHOOK[imd->nHooks+1];
- if(imd->nHooks > 0)
- {
- memcpy(hooks, imd->Hooks, sizeof(IMDLLHOOK) * imd->nHooks);
- delete imd->Hooks;
- }
- imd->Hooks = hooks;
- strncpy(imd->Hooks[imd->nHooks].name, funcname, 31);
- imd->Hooks[imd->nHooks].name[31] = 0;
- imd->Hooks[imd->nHooks].storeno = storeno;
- imd->Hooks[imd->nHooks].function = dhp;
- *dpString = (PWCHAR) &imd->Hooks[imd->nHooks++];
- //SendDebugMessageFormat(0, sdmKeyboard, 0, "AddIMDLLHook: Exit");
- return TRUE;
-}
-
static km_kbp_action_item*
kmnToCoreActionItem(int ItemType, DWORD dwData, WORD wVkey) {
@@ -232,55 +204,6 @@ BOOL CallbackDLLs(LPINTKEYBOARDINFO lpkbi, PSTR cmd)
return TRUE;
}
-/* Load the dlls associated with a keyboard */
-
-BOOL LoadDLLs(LPINTKEYBOARDINFO lpkbi)
-{
- char fullname[_MAX_PATH];
- //SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Enter");
-
- if(lpkbi->nIMDLLs > 0) if(!UnloadDLLs(lpkbi)) return FALSE;
-
- if (!GetKeyboardFileName(lpkbi->Name, fullname, _MAX_PATH)) {
- SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Filename not found[%s]", lpkbi->Name);
- return FALSE;
- }
-
- if (!lpkbi->Keyboard) {
- SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Keyboard is null");
- return FALSE;
- }
- for(DWORD i = 0; i < lpkbi->Keyboard->cxStoreArray; i++)
- {
- LPSTORE s = &lpkbi->Keyboard->dpStoreArray[i];
- if(s->dwSystemID == TSS_CALLDEFINITION)
- {
- /* Break the store string into components */
-
- PCHAR p = wstrtostr(s->dpString), q, r, context;
-
- q = strtok_s(p, ":", &context);
- r = strtok_s(NULL, ":", &context);
-
- if(!q || !r)
- {
- s->dwSystemID = TSS_CALLDEFINITION_LOADFAILED;
- delete[] p;
- continue;
- }
-
- LPIMDLL imd = AddIMDLL(lpkbi, fullname, q);
- if(imd && AddIMDLLHook(imd, r, i, &s->dpString)) s->dwSystemID = TSS_CALLDEFINITION;
- else s->dwSystemID = TSS_CALLDEFINITION_LOADFAILED;
-
- delete[] p;
- }
- }
-
- //SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Exit");
- return TRUE;
-}
-
// Both Core and Window keyboard processor can use this function
BOOL UnloadDLLs(LPINTKEYBOARDINFO lpkbi)
{
@@ -302,7 +225,7 @@ BOOL UnloadDLLs(LPINTKEYBOARDINFO lpkbi)
lpkbi->IMDLLs = NULL;
lpkbi->nIMDLLs = 0;
- if (Globals::get_CoreIntegration() && lpkbi->lpCoreKeyboardState) {
+ if (lpkbi->lpCoreKeyboardState) {
km_kbp_state_imx_deregister_callback(lpkbi->lpCoreKeyboardState);
}
return TRUE;
@@ -330,26 +253,6 @@ BOOL DeactivateDLLs(LPINTKEYBOARDINFO lpkbi)
return TRUE;
}
-void CallDLL(LPINTKEYBOARDINFO lpkbi, DWORD storenum)
-{
- //SendDebugMessageFormat(0, sdmKeyboard, 0, "CallDll: Enter");
- if (!lpkbi->Keyboard) return;
- if(storenum >= lpkbi->Keyboard->cxStoreArray) return;
-
- LPSTORE s = &lpkbi->Keyboard->dpStoreArray[storenum];
- if(s->dwSystemID != TSS_CALLDEFINITION) return;
- if(s->dpString == NULL) return;
- LPIMDLLHOOK imdh = (LPIMDLLHOOK) s->dpString;
-
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td) return;
-
- if(_td->TIPFUpdateable) { // I4452
- (*imdh->function)(_td->state.msg.hwnd, _td->state.vkey, _td->state.charCode, Globals::get_ShiftState());
- }
- //SendDebugMessageFormat(0, sdmKeyboard, 0, "CallDll: Exit");
-}
-
// The callback function called by the Core Keyboardprocessor
extern "C" uint8_t IM_CallBackCore(km_kbp_state *km_state, uint32_t UniqueStoreNo, void *callbackObject) {
//SendDebugMessageFormat(0, sdmKeyboard, 0, "IM_CallBackCore: Enter");
@@ -402,90 +305,84 @@ extern "C" BOOL _declspec(dllexport) WINAPI KMSetOutput(PWSTR buf, DWORD backlen
if (!_td->app)
return FALSE;
- if (!Globals::get_CoreIntegration()) { // TODO: 5442 Remove If and fix indent
- while (backlen-- > 0)
- _td->app->QueueAction(QIT_BACK, BK_DEFAULT);
- while (*buf)
- _td->app->QueueAction(QIT_CHAR, *buf++);
- return TRUE;
- } else {
- if (!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) {
- SendDebugMessageFormat(0, sdmKeyboard, 0, "KMSetOutputCore: no active state");
- return FALSE;
- }
- DWORD numActions = backlen + (DWORD)wcslen(buf);
- DWORD idx = 0;
- km_kbp_action_item *actionItems = new km_kbp_action_item[numActions + 1];
-
- // The actions sent to the core processor need to set the expected_type
- // correctly. To do this need to check the context as we process the
- // backspaces.
- km_kbp_context_item *citems = nullptr;
- if (KM_KBP_STATUS_OK != kbp_state_get_intermediate_context(_td->lpActiveKeyboard->lpCoreKeyboardState, &citems)) {
- delete[] actionItems;
- return FALSE;
- }
- DWORD context_length = (DWORD)km_kbp_context_item_list_size(citems);
- WCHAR *contextString = new WCHAR[(context_length * 3) + 1]; // *3 if every context item was a deadkey
- if (!ContextItemToAppContext(citems, contextString, context_length)) {
- km_kbp_context_items_dispose(citems);
- delete[] contextString;
- delete[] actionItems;
- return FALSE;
- }
+ if (!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) {
+ SendDebugMessageFormat(0, sdmKeyboard, 0, "KMSetOutputCore: no active state");
+ return FALSE;
+ }
+ DWORD numActions = backlen + (DWORD)wcslen(buf);
+ DWORD idx = 0;
+ km_kbp_action_item *actionItems = new km_kbp_action_item[numActions + 1];
+
+ // The actions sent to the core processor need to set the expected_type
+ // correctly. To do this need to check the context as we process the
+ // backspaces.
+ km_kbp_context_item *citems = nullptr;
+ if (KM_KBP_STATUS_OK != kbp_state_get_intermediate_context(_td->lpActiveKeyboard->lpCoreKeyboardState, &citems)) {
+ delete[] actionItems;
+ return FALSE;
+ }
+
+ DWORD context_length = (DWORD)km_kbp_context_item_list_size(citems);
+ WCHAR *contextString = new WCHAR[(context_length * 3) + 1]; // *3 if every context item was a deadkey
+ if (!ContextItemToAppContext(citems, contextString, context_length)) {
km_kbp_context_items_dispose(citems);
- AppContext context;
- context.Set(contextString);
delete[] contextString;
-
- while (backlen-- > 0) {
- actionItems[idx].type = KM_KBP_IT_BACK;
- WCHAR *CodeUnitPtr;
- const int DeadKeyLength = 3;
- const int SurrogateLength = 2;
- const int SingleCharLength = 1;
- if (context.CharIsDeadkey()) {
- CodeUnitPtr = context.BufMax(DeadKeyLength);
- CodeUnitPtr += 2;
- actionItems[idx].backspace.expected_type = KM_KBP_BT_MARKER;
- actionItems[idx].backspace.expected_value = (uintptr_t)*CodeUnitPtr;
- } else if (context.CharIsSurrogatePair()) {
- CodeUnitPtr = context.BufMax(SurrogateLength);
- actionItems[idx].backspace.expected_type = KM_KBP_BT_CHAR;
- actionItems[idx].backspace.expected_value = (DWORD)Uni_SurrogateToUTF32(*CodeUnitPtr, *(CodeUnitPtr + 1));
- } else if (!context.IsEmpty()) {
- CodeUnitPtr = context.BufMax(SingleCharLength);
- actionItems[idx].backspace.expected_type = KM_KBP_BT_CHAR;
- actionItems[idx].backspace.expected_value = (DWORD)*CodeUnitPtr;
- } else {
- actionItems[idx].backspace.expected_type = KM_KBP_BT_UNKNOWN;
- actionItems[idx].backspace.expected_value = 0;
- }
- context.Delete();
- idx++;
+ delete[] actionItems;
+ return FALSE;
+ }
+ km_kbp_context_items_dispose(citems);
+ AppContext context;
+ context.Set(contextString);
+ delete[] contextString;
+
+ while (backlen-- > 0) {
+ actionItems[idx].type = KM_KBP_IT_BACK;
+ WCHAR *CodeUnitPtr;
+ const int DeadKeyLength = 3;
+ const int SurrogateLength = 2;
+ const int SingleCharLength = 1;
+ if (context.CharIsDeadkey()) {
+ CodeUnitPtr = context.BufMax(DeadKeyLength);
+ CodeUnitPtr += 2;
+ actionItems[idx].backspace.expected_type = KM_KBP_BT_MARKER;
+ actionItems[idx].backspace.expected_value = (uintptr_t)*CodeUnitPtr;
+ } else if (context.CharIsSurrogatePair()) {
+ CodeUnitPtr = context.BufMax(SurrogateLength);
+ actionItems[idx].backspace.expected_type = KM_KBP_BT_CHAR;
+ actionItems[idx].backspace.expected_value = (DWORD)Uni_SurrogateToUTF32(*CodeUnitPtr, *(CodeUnitPtr + 1));
+ } else if (!context.IsEmpty()) {
+ CodeUnitPtr = context.BufMax(SingleCharLength);
+ actionItems[idx].backspace.expected_type = KM_KBP_BT_CHAR;
+ actionItems[idx].backspace.expected_value = (DWORD)*CodeUnitPtr;
+ } else {
+ actionItems[idx].backspace.expected_type = KM_KBP_BT_UNKNOWN;
+ actionItems[idx].backspace.expected_value = 0;
}
+ context.Delete();
+ idx++;
+ }
- while (*buf) {
- actionItems[idx].type = KM_KBP_IT_CHAR;
- if (Uni_IsSurrogate1(*buf) && Uni_IsSurrogate2(*(buf + 1))) {
- actionItems[idx].character = Uni_SurrogateToUTF32(*buf, *(buf + 1));
- buf++;
- } else {
- actionItems[idx].character = (DWORD)(*buf);
- }
+ while (*buf) {
+ actionItems[idx].type = KM_KBP_IT_CHAR;
+ if (Uni_IsSurrogate1(*buf) && Uni_IsSurrogate2(*(buf + 1))) {
+ actionItems[idx].character = Uni_SurrogateToUTF32(*buf, *(buf + 1));
buf++;
- idx++;
- }
- actionItems[idx].type = KM_KBP_IT_END;
- if (KM_KBP_STATUS_OK != km_kbp_state_queue_action_items(_td->lpActiveKeyboard->lpCoreKeyboardState, actionItems)) {
- delete[] actionItems;
- return FALSE;
+ } else {
+ actionItems[idx].character = (DWORD)(*buf);
}
+ buf++;
+ idx++;
+ }
+ actionItems[idx].type = KM_KBP_IT_END;
+ if (KM_KBP_STATUS_OK != km_kbp_state_queue_action_items(_td->lpActiveKeyboard->lpCoreKeyboardState, actionItems)) {
delete[] actionItems;
- //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMSetOutputCore: Exit");
- return TRUE;
+ return FALSE;
}
+ delete[] actionItems;
+ //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMSetOutputCore: Exit");
+ return TRUE;
+
}
extern "C" BOOL _declspec(dllexport) WINAPI KMQueueAction(int ItemType, DWORD dwData) {
@@ -496,61 +393,53 @@ extern "C" BOOL _declspec(dllexport) WINAPI KMQueueAction(int ItemType, DWORD dw
if (!_td->app)
return FALSE;
- if (!Globals::get_CoreIntegration()) {
- return _td->app->QueueAction(ItemType, dwData); // TODO: 5442 Remove
- } else {
- if (!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) {
- return FALSE;
- }
+ if (!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) {
+ return FALSE;
+ }
- km_kbp_action_item *actionItem = kmnToCoreActionItem(ItemType, dwData, _td->state.vkey);
- km_kbp_status_codes error_status =
- (km_kbp_status_codes)km_kbp_state_queue_action_items(_td->lpActiveKeyboard->lpCoreKeyboardState, actionItem);
- if (error_status != KM_KBP_STATUS_OK) {
- delete[] actionItem;
- SendDebugMessageFormat(0, sdmKeyboard, 0, "KMQueueAction: Error core queue_action_items error status:[%lu]",error_status);
- return FALSE;
- }
+ km_kbp_action_item *actionItem = kmnToCoreActionItem(ItemType, dwData, _td->state.vkey);
+ km_kbp_status_codes error_status =
+ (km_kbp_status_codes)km_kbp_state_queue_action_items(_td->lpActiveKeyboard->lpCoreKeyboardState, actionItem);
+ if (error_status != KM_KBP_STATUS_OK) {
delete[] actionItem;
- //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMQueueActionCore: Exit");
- return TRUE;
+ SendDebugMessageFormat(0, sdmKeyboard, 0, "KMQueueAction: Error core queue_action_items error status:[%lu]",error_status);
+ return FALSE;
}
+ delete[] actionItem;
+ //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMQueueActionCore: Exit");
+ return TRUE;
+
}
extern "C" BOOL _declspec(dllexport) WINAPI KMGetContext(PWSTR buf, DWORD len)
{
//SendDebugMessageFormat(0, sdmKeyboard, 0, "KMGetContext: Enter");
PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td) return FALSE;
- if(!_td->app) return FALSE;
- // TODO: 5442 KMGetContext is already public call (even though it is pointer) Rather then making a new KMGetContextCore
- // This has been modified to check for core processor once we move to core processor the old Windows Platmform calling of
- // ContextBuff can be removed
- //
- if(!Globals::get_CoreIntegration()){
- PWSTR q = _td->app->ContextBufMax(len);
- if (!q)
- return FALSE; // context buf does not exist
-
- wcscpy_s(buf, len + 1, q); // I3091
- return TRUE;
- } else {
- if (!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) {
- return FALSE;
- }
- km_kbp_context_item *citems = nullptr;
- if (KM_KBP_STATUS_OK != kbp_state_get_intermediate_context(_td->lpActiveKeyboard->lpCoreKeyboardState, &citems)) {
- return FALSE;
- }
+ if(!_td) {
+ return FALSE;
+ }
+
+ if(!_td->app) {
+ return FALSE;
+ }
- if (!ContextItemToAppContext(citems, buf, len)) {
- km_kbp_context_items_dispose(citems);
+ if (!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) {
+ return FALSE;
+ }
+
+ km_kbp_context_item *citems = nullptr;
+ if (KM_KBP_STATUS_OK != kbp_state_get_intermediate_context(_td->lpActiveKeyboard->lpCoreKeyboardState, &citems)) {
return FALSE;
- }
+ }
+
+ if (!ContextItemToAppContext(citems, buf, len)) {
km_kbp_context_items_dispose(citems);
- //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMGetContext: Exit");
- return TRUE;
+ return FALSE;
}
+ km_kbp_context_items_dispose(citems);
+ //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMGetContext: Exit");
+ return TRUE;
+
}
extern "C" BOOL _declspec(dllexport) WINAPI KMDisplayIM(HWND hwnd, BOOL FShowAlways)
@@ -650,8 +539,8 @@ BOOL IsIMWindow(HWND hwnd)
/* Add a dll hook function to the list of hook functions associated with a single dll */
static BOOL
-AddIMDLLHookCore(LPIMDLL imd, LPSTR funcname, DWORD storeno) {
- //SendDebugMessageFormat(0, sdmKeyboard, 0, "AddIMDLLHookCore: Enter");
+AddIMDLLHook(LPIMDLL imd, LPSTR funcname, DWORD storeno) {
+ //SendDebugMessageFormat(0, sdmKeyboard, 0, "AddIMDLLHook: Enter");
/* Get the procedure address for the function */
IMDLLHOOKProc dhp = (IMDLLHOOKProc)GetProcAddress(imd->hModule, funcname);
if (!dhp)
@@ -670,15 +559,15 @@ AddIMDLLHookCore(LPIMDLL imd, LPSTR funcname, DWORD storeno) {
imd->Hooks[imd->nHooks].storeno = storeno;
imd->Hooks[imd->nHooks].function = dhp;
imd->nHooks++;
- //SendDebugMessageFormat(0, sdmKeyboard, 0, "AddIMDLLHookCore: Exit");
+ //SendDebugMessageFormat(0, sdmKeyboard, 0, "AddIMDLLHook: Exit");
return TRUE;
}
/* Load the dlls associated with a keyboard */
BOOL
-LoadDLLsCore(LPINTKEYBOARDINFO lpkbi) {
+LoadDLLs(LPINTKEYBOARDINFO lpkbi) {
char fullname[_MAX_PATH];
- //SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLsCore: Enter");
+ //SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Enter");
if (lpkbi->nIMDLLs > 0)
if (!UnloadDLLs(lpkbi))
@@ -694,11 +583,11 @@ LoadDLLsCore(LPINTKEYBOARDINFO lpkbi) {
BOOL result = false;
for (; imx_list->library_name; ++imx_list) {
LPIMDLL imd = AddIMDLL(lpkbi, fullname, wstrtostr(reinterpret_cast(imx_list->library_name)));
- if (imd && AddIMDLLHookCore(imd, wstrtostr(reinterpret_cast(imx_list->function_name)), imx_list->imx_id)) {
+ if (imd && AddIMDLLHook(imd, wstrtostr(reinterpret_cast(imx_list->function_name)), imx_list->imx_id)) {
result = TRUE;
}
else {
- SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLsCore: Error Loading Library name [%s], Function name [%s]",
+ SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Error Loading Library name [%s], Function name [%s]",
wstrtostr(reinterpret_cast(imx_list->library_name)),
wstrtostr(reinterpret_cast(imx_list->function_name)));
}
@@ -707,7 +596,7 @@ LoadDLLsCore(LPINTKEYBOARDINFO lpkbi) {
if (result) {
km_kbp_state_imx_register_callback(lpkbi->lpCoreKeyboardState, IM_CallBackCore, (void *)lpkbi);
}
- //SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLsCore: Exit");
+ //SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Exit");
return TRUE;
}
diff --git a/windows/src/engine/keyman32/calldll.h b/windows/src/engine/keyman32/calldll.h
index 9eb1a7ade4144e0240bad642b711e0c30740e723..6e719bde9ac29a7edf212018d5e12b766c4fb77e 100644
--- a/windows/src/engine/keyman32/calldll.h
+++ b/windows/src/engine/keyman32/calldll.h
@@ -19,24 +19,19 @@
#ifndef __CALLDLL_H
#define __CALLDLL_H
-BOOL LoadDLLs(LPINTKEYBOARDINFO lpkbi);
-BOOL UnloadDLLs(LPINTKEYBOARDINFO lpkbi);
-BOOL DeactivateDLLs(LPINTKEYBOARDINFO lpkbi);
-BOOL ActivateDLLs(LPINTKEYBOARDINFO lpkbi);
-
-// TODO: 5444 This will become the only LoadDLLs function
/**
* Load the all the dlls used by the current keyboard
* @param lpkbi The keyboard for which to load the dlls
* @return BOOL True on success
*/
-BOOL LoadDLLsCore(LPINTKEYBOARDINFO lpkbi);
+BOOL LoadDLLs(LPINTKEYBOARDINFO lpkbi);
+BOOL UnloadDLLs(LPINTKEYBOARDINFO lpkbi);
+BOOL DeactivateDLLs(LPINTKEYBOARDINFO lpkbi);
+BOOL ActivateDLLs(LPINTKEYBOARDINFO lpkbi);
BOOL IsIMWindow(HWND hwnd);
-void CallDLL(LPINTKEYBOARDINFO lpkbi, DWORD storenum);
-
// Callback function used by the core processor to call out to 3rd Party Library functions
extern "C" uint8_t IM_CallBackCore(km_kbp_state *km_state, uint32_t UniqueStoreNo, void *callbackObject);
diff --git a/windows/src/engine/keyman32/capsstate.cpp b/windows/src/engine/keyman32/capsstate.cpp
index c9d283cde40db020413c10e186119cdef47e049b..4f9b466e9ee85e2a73a4041613c0842c6c1c06b7 100644
--- a/windows/src/engine/keyman32/capsstate.cpp
+++ b/windows/src/engine/keyman32/capsstate.cpp
@@ -29,73 +29,3 @@
BOOL IsCapsLockOn(void) {
return GetKeyState(VK_CAPITAL) & 1;
}
-
-void ResetCapsLock(void)
-{
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if (!_td) return;
- if (!_td->lpActiveKeyboard) return;
- if (!_td->lpActiveKeyboard->Keyboard) return;
-
- SendDebugMessageFormat(0, sdmGlobal, 0, "ResetCapsLock: enter");
-
- if (_td->lpActiveKeyboard->Keyboard->dwFlags & KF_CAPSALWAYSOFF)
- {
- SendDebugMessageFormat(0, sdmGlobal, 0, "ResetCapsLock: caps lock should be always off");
- if (IsCapsLockOn())
- {
- SendDebugMessageFormat(0, sdmGlobal, 0, "ResetCapsLock: caps lock is on, switching off caps lock");
- keybd_event(VK_CAPITAL, 0x3A, 0, 0);
- keybd_event(VK_CAPITAL, 0x3A, 0 | KEYEVENTF_KEYUP, 0);
- }
- }
- SendDebugMessageFormat(0, sdmGlobal, 0, "ResetCapsLock: exit");
-}
-
-
-void KeyCapsLockPress(BOOL FIsUp) // I3284 - void // I3529
-{
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if (!_td) return;
- if (!_td->lpActiveKeyboard) return; // pass through to window
- if (!_td->lpActiveKeyboard->Keyboard) return;
-
- if (_td->lpActiveKeyboard->Keyboard->dwFlags & KF_CAPSONONLY)
- {
- SendDebugMessageFormat(0, sdmAIDefault, 0, "KeyCapsLockPress: KF_CAPSONONLY: FIsUp=%d CapsState=%d", FIsUp, IsCapsLockOn());
- if (FIsUp && !IsCapsLockOn()) // I267 - 24/11/2006 invert GetKeyState test
- {
- keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, 0, 0);
- keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, KEYEVENTF_KEYUP, 0);
- }
- }
- else if (_td->lpActiveKeyboard->Keyboard->dwFlags & KF_CAPSALWAYSOFF)
- {
- SendDebugMessageFormat(0, sdmAIDefault, 0, "KeyCapsLockPress: KF_CAPSALWAYSOFF: FIsUp=%d CapsState=%d", FIsUp, IsCapsLockOn());
- if (!FIsUp && IsCapsLockOn())
- { // I267 - 24/11/2006 invert GetKeyState test
- keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, KEYEVENTF_KEYUP, 0);
- keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, 0, 0);
- }
- }
-}
-
-
-void KeyShiftPress(BOOL FIsUp) // I3284 - void // I3529
-{
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if (!_td) return;
- if (!_td->lpActiveKeyboard) return; // pass through to window
- if (!_td->lpActiveKeyboard->Keyboard) return;
-
- if (_td->lpActiveKeyboard->Keyboard->dwFlags & KF_SHIFTFREESCAPS)
- {
- SendDebugMessageFormat(0, sdmAIDefault, 0, "KeyShiftPress: KF_SHIFTFREESCAPS: FIsUp=%d CapsState=%d", FIsUp, IsCapsLockOn());
- if (!FIsUp && IsCapsLockOn())
- {
- keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, 0, 0);
- keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, KEYEVENTF_KEYUP, 0);
- }
- }
-}
-
diff --git a/windows/src/engine/keyman32/capsstate.h b/windows/src/engine/keyman32/capsstate.h
index aeb3e2900065fd6a7ece9a27f3a921ec0f5edcd5..d28ba9c0db99f240744e273b4b919cf4ead96aee 100644
--- a/windows/src/engine/keyman32/capsstate.h
+++ b/windows/src/engine/keyman32/capsstate.h
@@ -20,8 +20,5 @@
#define __CAPSSTATE_H
BOOL IsCapsLockOn(void);
-void ResetCapsLock(void);
-void KeyCapsLockPress(BOOL FIsUp);
-void KeyShiftPress(BOOL FIsUp);
#endif
diff --git a/windows/src/engine/keyman32/globals.h b/windows/src/engine/keyman32/globals.h
index 6e840fce99b7c1a6d6e9e1205a51076e2e6e2f8d..320ef811de4d0af5a08a8ce43232f2e781a85b5a 100644
--- a/windows/src/engine/keyman32/globals.h
+++ b/windows/src/engine/keyman32/globals.h
@@ -151,7 +151,6 @@ public:
static BOOL get_debug_KeymanLog();
static BOOL get_debug_ToConsole();
- static BOOL get_CoreIntegration();
static void LoadDebugSettings();
};
@@ -216,8 +215,6 @@ typedef struct tagKEYMAN64THREADDATA
FInitialised,
FInitialising;
- char ForceFileName[MAX_PATH];
-
DWORD ActiveKeymanID;
/* TIP Globals */
diff --git a/windows/src/engine/keyman32/glossary.cpp b/windows/src/engine/keyman32/glossary.cpp
index 2954638c1925ee01bb14d75fddcc96dee6e06124..7a6aecddc06998ef337a80a5bd3f0860a4f644c7 100644
--- a/windows/src/engine/keyman32/glossary.cpp
+++ b/windows/src/engine/keyman32/glossary.cpp
@@ -1,18 +1,18 @@
/*
Name: glossary
Copyright: Copyright (C) SIL International.
- Documentation:
- Description:
+ Documentation:
+ Description:
Create Date: 20 Jul 2008
Modified Date: 28 May 2014
Authors: mcdurdin
- Related Files:
- Dependencies:
+ Related Files:
+ Dependencies:
- Bugs:
- Todo:
- Notes:
+ Bugs:
+ Todo:
+ Notes:
History: 20 Jul 2008 - mcdurdin - I1498 - Fix keyboard switching for Shadow keyboards on Vista+
20 Jul 2008 - mcdurdin - I1546 - Fix language switch with ids >= x80000000
20 Jul 2008 - mcdurdin - I1545 - Fix registry leak
@@ -38,9 +38,9 @@ BOOL HKLIsIME(HKL hkl) // I1498 - fix keyboard switching for shadow keyboards o
if( (GetVersion() & 0xFF) >= 6 ) return FALSE;
if( (GetVersion() & 0x8000000) == 0x8000000 || (GetVersion() & 0xFF) == 4 )
r = GetSystemMetrics(SM_DBCSENABLED);
- else
+ else
r = GetSystemMetrics(SM_IMMENABLED);
-
+
return r && ImmIsIME(hkl);
}
#pragma warning(default: 4996)
@@ -99,12 +99,12 @@ DWORD HKLToKeyboardID(HKL hkl)
return (DWORD) LOWORD(hkl);
}
- for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS;
- len = 16, i++, n=0)
+ for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS;
+ len = 16, i++, n=0)
{
RegOpenKeyEx(hkey, str, NULL, KEY_READ, &hsubkey);
len = 16;
- if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS)
+ if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS)
{
n = strtoul(str2, NULL, 16); // I1546
if(n == LayoutID)
@@ -120,7 +120,7 @@ DWORD HKLToKeyboardID(HKL hkl)
}
RegCloseKey(hkey);
-
+
//SendDebugMessageFormat(0, sdmGlobal, 0, "HKLToKeyboardID: fails[2], return LOWORD(hkl)=%x", LOWORD(hkl));
return (DWORD) LOWORD(hkl); // should never happen
}
@@ -143,11 +143,11 @@ WORD HKLToLayoutNumber(HKL hkl)
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSZ_SystemKeyboardLayouts, NULL, KEY_READ, &hkey) != ERROR_SUCCESS)
return 0;
- for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS; len = 16, i++, n=0)
+ for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS; len = 16, i++, n=0)
{
RegOpenKeyEx(hkey, str, NULL, KEY_READ, &hsubkey);
len = 16;
- if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS)
+ if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS)
{
if(strtoul(str2, NULL, 16) == LayoutID) break; // strtoul - I1546
}
@@ -166,37 +166,3 @@ WORD HKLToLayoutID(HKL hkl)
return HIWORD(hkl) & 0x0FFF;
}
-
-DWORD EthnologueCodeToKeymanID(DWORD EthCode)
-{
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td) return KEYMANID_NONKEYMAN;
-
- for(int i = 0; i < _td->nKeyboards; i++)
- {
- if(!_td->lpKeyboards[i].Keyboard && !LoadlpKeyboard(i))
- {
- SendDebugMessageFormat(0,sdmGlobal,0,
- "EthnologueCodeToKeymanID: Unable to load keyboard %s", _td->lpKeyboards[i].Name);
- return KEYMANID_NONKEYMAN;
- }
-
- PWSTR ps = GetSystemStore(_td->lpKeyboards[i].Keyboard, TSS_ETHNOLOGUECODE);
- if(ps)
- {
- SendDebugMessageFormat(0,sdmGlobal,0,"EthnologueCodeToKeymanID: %s %ws %x", _td->lpKeyboards[i].Name, ps, EthnologueStringCodeToDWord(ps));
- if(EthnologueStringCodeToDWord(ps) == EthCode) return _td->lpKeyboards[i].KeymanID;
- }
- }
-
- return KEYMANID_NONKEYMAN;
-}
-
-DWORD EthnologueStringCodeToDWord(PWSTR EthCode)
-{
- if(wcslen(EthCode) < 3 || wcslen(EthCode) > 4) return (DWORD)-1;
- return (LOBYTE(EthCode[0])) |
- (LOBYTE(EthCode[1]) << 8) |
- (LOBYTE(EthCode[2]) << 16) |
- (LOBYTE(EthCode[3]) << 24);
-}
diff --git a/windows/src/engine/keyman32/k32_globals.cpp b/windows/src/engine/keyman32/k32_globals.cpp
index 054945b8129a72cf7479097c551f820fd477cc5b..989a787f95951a3652624d4f502d3a530e65d448 100644
--- a/windows/src/engine/keyman32/k32_globals.cpp
+++ b/windows/src/engine/keyman32/k32_globals.cpp
@@ -288,9 +288,6 @@ static BOOL
f_debug_KeymanLog = FALSE,
f_debug_ToConsole = FALSE;
-static BOOL
- f_CoreIntegration = TRUE;
-
#pragma data_seg()
/***************************************************************************/
@@ -365,8 +362,6 @@ BOOL Globals::get_MnemonicDeadkeyConversionMode() { return f_MnemonicDeadkeyConv
BOOL Globals::get_debug_KeymanLog() { return f_debug_KeymanLog; }
BOOL Globals::get_debug_ToConsole() { return f_debug_ToConsole; }
-BOOL Globals::get_CoreIntegration() { return f_CoreIntegration; }
-
void Globals::SetBaseKeyboardName(wchar_t *baseKeyboardName, wchar_t *baseKeyboardNameAlt) { // I4583
wcscpy_s(f_BaseKeyboardName, baseKeyboardName);
wcscpy_s(f_BaseKeyboardNameAlt, baseKeyboardNameAlt);
@@ -385,9 +380,6 @@ void Globals::SetBaseKeyboardFlags(char *baseKeyboard, BOOL simulateAltGr, BOOL
be changed until Keyman is restarted.
*/
BOOL Globals::InitSettings() {
- /* Check for common core vs windows core */
- f_CoreIntegration = Reg_GetDebugFlag(REGSZ_Flag_UseKeymanCore, TRUE);
- SendDebugMessageFormat(0, sdmAIDefault, 0, "Globals::InitSettings - Coreintegration set in '" REGSZ_Flag_UseKeymanCore "' to %x", f_CoreIntegration);
f_vk_prefix = _VK_PREFIX_DEFAULT;
RegistryReadOnly reg(HKEY_LOCAL_MACHINE);
if (reg.OpenKeyReadOnly(REGSZ_KeymanLM) &&
diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp
index 3e5edcff5bcb18307c7d9ff446fa2d2fadfeb53b..96deb57590dac21770303edbbfe91447e93da434 100644
--- a/windows/src/engine/keyman32/keyboardoptions.cpp
+++ b/windows/src/engine/keyman32/keyboardoptions.cpp
@@ -19,10 +19,8 @@
*/
#include "pch.h"
-void IntSaveKeyboardOption(LPCSTR key, LPINTKEYBOARDINFO kp, int nStoreToSave);
-BOOL IntLoadKeyboardOptions(LPCSTR key, LPINTKEYBOARDINFO kp);
-BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* const state);
-void IntSaveKeyboardOptionREGCore(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value);
+BOOL IntLoadKeyboardOptionsRegistrytoCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* const state);
+void IntSaveKeyboardOptionCoretoRegistry(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value);
static km_kbp_cp* CloneKMKBPCP(const km_kbp_cp* cp) {
LPCWSTR buf = reinterpret_cast(cp);
@@ -37,123 +35,12 @@ static km_kbp_cp* CloneKMKBPCPFromWSTR(LPWSTR buf) {
return clone;
}
-void LoadKeyboardOptions(LPINTKEYBOARDINFO kp)
-{ // I3594
- IntLoadKeyboardOptions(REGSZ_KeyboardOptions, kp);
-}
-
-void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp)
-{
- if(!DebugAssert(!Globals::get_CoreIntegration(), "LoadSharedKeyboardOptions: Error called in core integration mode")) {
- return;
- }
- // Called when another thread changes keyboard options and we are sharing keyboard settings
- assert(kp != NULL);
- assert(kp->Keyboard != NULL);
-
- if(kp->KeyboardOptions != NULL) FreeKeyboardOptions(kp);
-
- IntLoadKeyboardOptions(REGSZ_SharedKeyboardOptions, kp);
-}
-
-void FreeKeyboardOptions(LPINTKEYBOARDINFO kp)
-{
- // This is a cleanup routine; we don't want to precondition all calls to it
- // so we do not assert
- if (kp == NULL || kp->Keyboard == NULL || kp->KeyboardOptions == NULL)
- return;
-
- for(DWORD i = 0; i < kp->Keyboard->cxStoreArray; i++)
- if(kp->KeyboardOptions[i].Value)
- {
- kp->Keyboard->dpStoreArray[i].dpString = kp->KeyboardOptions[i].OriginalStore;
- delete kp->KeyboardOptions[i].Value;
- }
- delete kp->KeyboardOptions;
- kp->KeyboardOptions = NULL;
-}
-
-void SetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSet, int nStoreToRead)
-{
- if (!DebugAssert(!Globals::get_CoreIntegration(), "SetKeyboardOption: Error called in core integration mode")) {
- return;
- }
- assert(kp != NULL);
- assert(kp->Keyboard != NULL);
- assert(kp->KeyboardOptions != NULL);
- assert(nStoreToSet >= 0);
- assert(nStoreToSet < (int) kp->Keyboard->cxStoreArray);
- assert(nStoreToRead >= 0);
- assert(nStoreToRead < (int) kp->Keyboard->cxStoreArray);
-
- LPSTORE sp = &kp->Keyboard->dpStoreArray[nStoreToRead];
- if(kp->KeyboardOptions[nStoreToSet].Value)
- {
- delete kp->KeyboardOptions[nStoreToSet].Value;
- }
- else
- {
- kp->KeyboardOptions[nStoreToSet].OriginalStore = kp->Keyboard->dpStoreArray[nStoreToSet].dpString;
- }
-
- kp->KeyboardOptions[nStoreToSet].Value = new WCHAR[wcslen(sp->dpString)+1];
- wcscpy_s(kp->KeyboardOptions[nStoreToSet].Value, wcslen(sp->dpString)+1, sp->dpString);
- kp->Keyboard->dpStoreArray[nStoreToSet].dpString = kp->KeyboardOptions[nStoreToSet].Value;
-}
-
-void ResetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToReset)
+void SaveKeyboardOptionCoretoRegistry(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value)
{
- if (!DebugAssert(!Globals::get_CoreIntegration(), "ResetKeyboardOption: Error called in core integration mode")) {
- return;
- }
- assert(kp != NULL);
- assert(kp->Keyboard != NULL);
- assert(kp->KeyboardOptions != NULL);
- assert(nStoreToReset >= 0);
- assert(nStoreToReset < (int) kp->Keyboard->cxStoreArray);
-
- if(kp->KeyboardOptions[nStoreToReset].Value)
- {
- kp->Keyboard->dpStoreArray[nStoreToReset].dpString = kp->KeyboardOptions[nStoreToReset].OriginalStore;
- delete kp->KeyboardOptions[nStoreToReset].Value;
- kp->KeyboardOptions[nStoreToReset].Value = NULL;
-
- if(kp->Keyboard->dpStoreArray[nStoreToReset].dpName == NULL) return;
-
- RegistryReadOnly r(HKEY_CURRENT_USER);
- if(r.OpenKeyReadOnly(REGSZ_KeymanActiveKeyboards) && r.OpenKeyReadOnly(kp->Name) && r.OpenKeyReadOnly(REGSZ_KeyboardOptions))
- {
- if(r.ValueExists(kp->Keyboard->dpStoreArray[nStoreToReset].dpName))
- {
- WCHAR val[256];
- if(!r.ReadString(kp->Keyboard->dpStoreArray[nStoreToReset].dpName, val, sizeof(val) / sizeof(val[0]))) return;
- if(!val[0]) return;
- val[255] = 0;
- kp->KeyboardOptions[nStoreToReset].Value = new WCHAR[wcslen(val)+1];
- wcscpy_s(kp->KeyboardOptions[nStoreToReset].Value, wcslen(val)+1, val);
-
- kp->KeyboardOptions[nStoreToReset].OriginalStore = kp->Keyboard->dpStoreArray[nStoreToReset].dpString;
- kp->Keyboard->dpStoreArray[nStoreToReset].dpString = kp->KeyboardOptions[nStoreToReset].Value;
- }
- }
- }
+ IntSaveKeyboardOptionCoretoRegistry(REGSZ_KeyboardOptions, kp, key, value);
}
-
-void SaveKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSave)
-{
- if (!DebugAssert(!Globals::get_CoreIntegration(), "SaveKeyboardOption: Error called in core integration mode")) {
- return;
- }
- IntSaveKeyboardOption(REGSZ_KeyboardOptions, kp, nStoreToSave);
-}
-
-void SaveKeyboardOptionREGCore(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value)
-{
- IntSaveKeyboardOptionREGCore(REGSZ_KeyboardOptions, kp, key, value);
-}
-
-void IntSaveKeyboardOptionREGCore(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value)
+void IntSaveKeyboardOptionCoretoRegistry(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value)
{
assert(REGKey != NULL);
assert(kp != NULL);
@@ -167,73 +54,13 @@ void IntSaveKeyboardOptionREGCore(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR k
}
}
-BOOL IntLoadKeyboardOptions(LPCSTR key, LPINTKEYBOARDINFO kp)
-{
- assert(key != NULL);
- assert(kp != NULL);
- assert(kp->Keyboard != NULL);
- assert(kp->KeyboardOptions == NULL);
-
- kp->KeyboardOptions = new INTKEYBOARDOPTIONS[kp->Keyboard->cxStoreArray];
- memset(kp->KeyboardOptions, 0, sizeof(INTKEYBOARDOPTIONS) * kp->Keyboard->cxStoreArray);
- RegistryReadOnly r(HKEY_CURRENT_USER);
- if(r.OpenKeyReadOnly(REGSZ_KeymanActiveKeyboards) && r.OpenKeyReadOnly(kp->Name) && r.OpenKeyReadOnly(key))
- {
- WCHAR buf[256];
- int n = 0;
- while(r.GetValueNames(buf, sizeof(buf) / sizeof(buf[0]), n))
- {
- buf[255] = 0;
- WCHAR val[256];
- if(r.ReadString(buf, val, sizeof(val) / sizeof(val[0])) && val[0])
- {
- val[255] = 0;
- for(DWORD i = 0; i < kp->Keyboard->cxStoreArray; i++)
- {
- if(kp->Keyboard->dpStoreArray[i].dpName != NULL && _wcsicmp(kp->Keyboard->dpStoreArray[i].dpName, buf) == 0)
- {
- kp->KeyboardOptions[i].Value = new WCHAR[wcslen(val)+1];
- wcscpy_s(kp->KeyboardOptions[i].Value, wcslen(val)+1, val);
-
- kp->KeyboardOptions[i].OriginalStore = kp->Keyboard->dpStoreArray[i].dpString;
- kp->Keyboard->dpStoreArray[i].dpString = kp->KeyboardOptions[i].Value;
-
- break;
- }
- }
- }
- n++;
- }
- return TRUE;
- }
- return FALSE;
-}
-
-void IntSaveKeyboardOption(LPCSTR key, LPINTKEYBOARDINFO kp, int nStoreToSave)
+void LoadKeyboardOptionsRegistrytoCore(LPINTKEYBOARDINFO kp, km_kbp_state* const state)
{
- assert(key != NULL);
- assert(kp != NULL);
- assert(kp->Keyboard != NULL);
- assert(kp->KeyboardOptions != NULL);
- assert(nStoreToSave >= 0);
- assert(nStoreToSave < (int) kp->Keyboard->cxStoreArray);
-
- if(kp->Keyboard->dpStoreArray[nStoreToSave].dpName == NULL) return;
-
- RegistryFullAccess r(HKEY_CURRENT_USER);
- if(r.OpenKey(REGSZ_KeymanActiveKeyboards, TRUE) && r.OpenKey(kp->Name, TRUE) && r.OpenKey(key, TRUE))
- {
- r.WriteString(kp->Keyboard->dpStoreArray[nStoreToSave].dpName, kp->Keyboard->dpStoreArray[nStoreToSave].dpString);
- }
+ SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadKeyboardOptionsRegistrytoCore: Enter");
+ IntLoadKeyboardOptionsRegistrytoCore(REGSZ_KeyboardOptions, kp, state);
}
-void LoadKeyboardOptionsREGCore(LPINTKEYBOARDINFO kp, km_kbp_state* const state)
-{
- SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadKeyboardOptionsREGCore: Enter");
- IntLoadKeyboardOptionsCore(REGSZ_KeyboardOptions, kp, state);
-}
-
-BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* const state)
+BOOL IntLoadKeyboardOptionsRegistrytoCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* const state)
{
assert(key != NULL);
assert(kp != NULL);
@@ -243,7 +70,7 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state*
km_kbp_status err_status = km_kbp_keyboard_get_attrs(kp->lpCoreKeyboard, &keyboardAttrs);
if (err_status != KM_KBP_STATUS_OK) {
SendDebugMessageFormat(
- 0, sdmKeyboard, 0, "LoadKeyboardOptionsREGCore: km_kbp_keyboard_get_attrs failed with error status [%d]", err_status);
+ 0, sdmKeyboard, 0, "LoadKeyboardOptionsRegistrytoCore: km_kbp_keyboard_get_attrs failed with error status [%d]", err_status);
return FALSE;
}
@@ -275,7 +102,7 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state*
err_status = km_kbp_state_options_update(state, keyboardOpts);
if (err_status != KM_KBP_STATUS_OK) {
SendDebugMessageFormat(
- 0, sdmKeyboard, 0, "LoadKeyboardOptionsREGCore: km_kbp_state_options_update failed with error status [%d]", err_status);
+ 0, sdmKeyboard, 0, "LoadKeyboardOptionsRegistrytoCore: km_kbp_state_options_update failed with error status [%d]", err_status);
}
for (int i = 0; i < n; i++) {
delete[] keyboardOpts[i].value;
@@ -283,89 +110,3 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state*
delete[] keyboardOpts;
return TRUE;
}
-
-BOOL
-UpdateKeyboardOptionsCore(
- km_kbp_state* const lpCoreKeyboardState,
- km_kbp_option_item *lpCoreKeyboardOptions) {
-
- int listSize = (int)km_kbp_options_list_size(lpCoreKeyboardOptions);
- // Create a option list based on this size look up each key and store the return value in it.
- // then at the end return this options list.
- BOOL changed = FALSE;
- km_kbp_cp const* retValue = nullptr;
- for (int i = 0; i < listSize; i++) {
- km_kbp_status err_status = km_kbp_state_option_lookup(lpCoreKeyboardState, lpCoreKeyboardOptions[i].scope, lpCoreKeyboardOptions[i].key,
- &retValue);
- if (err_status != KM_KBP_STATUS_OK) {
- SendDebugMessageFormat(
- 0, sdmKeyboard, 0, "UpdateKeyboardOptionsCore: km_kbp_state_option_lookup failed with error status [%d]", err_status);
- continue;
- }
- // compare to see if changed
- if (wcscmp(reinterpret_cast(retValue), reinterpret_cast(lpCoreKeyboardOptions[i].value)) != 0) {
- delete lpCoreKeyboardOptions[i].value;
- lpCoreKeyboardOptions[i].value = CloneKMKBPCP(retValue);
- changed = TRUE;
- }
- }
- return changed;
-}
-
-km_kbp_option_item*
-SaveKeyboardOptionsCore(LPINTKEYBOARDINFO kp) {
-
- // Get the list of default options to determine size of list
- const km_kbp_keyboard_attrs* keyboardAttrs;
- km_kbp_status err_status = km_kbp_keyboard_get_attrs(kp->lpCoreKeyboard, &keyboardAttrs);
- if (err_status != KM_KBP_STATUS_OK) {
- SendDebugMessageFormat(
- 0, sdmKeyboard, 0, "SaveKeyboardOptionsCore: km_kbp_keyboard_get_attrs failed with error status [%d]", err_status);
- return nullptr;
- }
- int listSize = (int)km_kbp_options_list_size(keyboardAttrs->default_options);
- km_kbp_option_item* savedKeyboardOpts = new km_kbp_option_item[listSize + 1];
- km_kbp_cp const* retValue = nullptr;
-
- km_kbp_option_item const* kbDefaultOpts = keyboardAttrs->default_options;
- for (int i = 0; i < listSize; i++, ++kbDefaultOpts) {
- if (kbDefaultOpts->scope != KM_KBP_OPT_KEYBOARD)
- continue;
- err_status =
- km_kbp_state_option_lookup(kp->lpCoreKeyboardState, KM_KBP_OPT_KEYBOARD, kbDefaultOpts->key, &retValue);
- if (err_status != KM_KBP_STATUS_OK) {
- SendDebugMessageFormat(
- 0, sdmKeyboard, 0, "SaveKeyboardOptionsCore: km_kbp_state_option_lookup failed with error status [%d]", err_status);
- continue;
- }
- savedKeyboardOpts[i].key = CloneKMKBPCP(kbDefaultOpts->key);
- savedKeyboardOpts[i].value = CloneKMKBPCP(retValue);
- savedKeyboardOpts[i].scope = KM_KBP_OPT_KEYBOARD;
- }
- savedKeyboardOpts[listSize] = KM_KBP_OPTIONS_END;
- return savedKeyboardOpts;
-}
-
-BOOL
-RestoreKeyboardOptionsCore(
- km_kbp_state* const lpCoreKeyboardState,
- km_kbp_option_item* lpCoreKeyboardOptions) {
- km_kbp_status err_status = km_kbp_state_options_update(lpCoreKeyboardState, lpCoreKeyboardOptions);
- if (err_status != KM_KBP_STATUS_OK) {
- SendDebugMessageFormat(
- 0, sdmKeyboard, 0, "RestoreKeyboardOptionsCore: km_kbp_state_options_update failed with error status [%d]", err_status);
- return FALSE;
- }
- return TRUE;
-}
-
-void
-DisposeKeyboardOptionsCore(km_kbp_option_item** lpCoreKeyboardOptions) {
- size_t listSize = km_kbp_options_list_size(*lpCoreKeyboardOptions);
- for (int i = 0; i < (int)listSize; i++) {
- delete[] (*lpCoreKeyboardOptions)[i].key;
- delete[] (*lpCoreKeyboardOptions)[i].value;
- }
- delete[] *lpCoreKeyboardOptions;
- *lpCoreKeyboardOptions = NULL;
-}
diff --git a/windows/src/engine/keyman32/keyboardoptions.h b/windows/src/engine/keyman32/keyboardoptions.h
index cef9ae6df1bf34a24b12546c098f2b9bc4122a2f..f55b0bcc77d5f7ebd5ea0952fccec67e6eb0d8c9 100644
--- a/windows/src/engine/keyman32/keyboardoptions.h
+++ b/windows/src/engine/keyman32/keyboardoptions.h
@@ -16,44 +16,6 @@
History: 25 May 2010 - mcdurdin - I1632 - Keyboard Options
*/
-void LoadKeyboardOptions(LPINTKEYBOARDINFO kp);
-void FreeKeyboardOptions(LPINTKEYBOARDINFO kp);
-void SetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSet, int nStoreToRead);
-void ResetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToReset);
-void SaveKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSave);
-void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp);
-/**
- * Updates the supplied Keyboard processor options list from the keyboard processor pointed
- * to by the state pointer.
- *
- * @param lpCoreKeyboardState The core keyboardprocessor state which has the source options
- * @param[in,out] lpCoreKeyboardOptions The core keyboard options to be updated
- * @return BOOL True if one or more options were updated
- */
-BOOL UpdateKeyboardOptionsCore(km_kbp_state* const lpCoreKeyboardState, km_kbp_option_item *lpCoreKeyboardOptions);
-
-/**
- * Returns a copy of the core keyboard processors current keyboard options
- * The caller is responsible for freeing the returned km_kbp_option_item's list.
- *
- * @param kp A pointer to the keyboard info object that contains the
- * keyboardprocessor state and keyboard for the source options list.
- *
- * @return km_kbp_option_item* The copy of the options list or NULL if copy failed
- */
-km_kbp_option_item* SaveKeyboardOptionsCore(LPINTKEYBOARDINFO kp);
-
-/**
- * Restore the core keyboard processor options to the supplied keyboard
- * list of `km_kbp_option_item`s
- *
- * @param lpCoreKeyboardState The state pointer for the keyboard processor
- * @param lpCoreKeyboardOptions The list of `km_kbp_option_item`s to restore
- *
- * return BOOL TRUE when the call to update keyboard processor was successful
- */
-BOOL RestoreKeyboardOptionsCore(km_kbp_state* const lpCoreKeyboardState, km_kbp_option_item* lpCoreKeyboardOptions);
-
/* Common core integration functions */
/**
@@ -62,7 +24,7 @@ BOOL RestoreKeyboardOptionsCore(km_kbp_state* const lpCoreKeyboardState, km_kbp_
* @param kp keyboard info object with options to be updated
* @param state core keyboard state used to update keyboard options
*/
-void LoadKeyboardOptionsREGCore(LPINTKEYBOARDINFO kp, km_kbp_state* state);
+void LoadKeyboardOptionsRegistrytoCore(LPINTKEYBOARDINFO kp, km_kbp_state* state);
/**
* Saves the keyboard option to the windows registry
@@ -71,12 +33,6 @@ void LoadKeyboardOptionsREGCore(LPINTKEYBOARDINFO kp, km_kbp_state* state);
* @param key keyboard key to save
* @param value keyboard option value to save
*/
-void SaveKeyboardOptionREGCore(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value);
+void SaveKeyboardOptionCoretoRegistry(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value);
+
-/**
- * Free the allocated resources belonging to a key_kbp_option_items object
- * that was created on the heap most likely using SaveKeyboardOptionREGCore
- *
- * @param lpCoreKeyboardOptions keyboard options items to be freed
- */
-void DisposeKeyboardOptionsCore(km_kbp_option_item** lpCoreKeyboardOptions);
diff --git a/windows/src/engine/keyman32/keyman-engine.vcxproj b/windows/src/engine/keyman32/keyman-engine.vcxproj
index 6869117fd9a41e685be646f78c54b05608259191..d2e78ef7e4fba2a9e0adc19dde994e1dbcc74d6a 100644
--- a/windows/src/engine/keyman32/keyman-engine.vcxproj
+++ b/windows/src/engine/keyman32/keyman-engine.vcxproj
@@ -59,7 +59,7 @@
$(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\src;$(ProjectDir)..\..\..\..\core\build\rust\x86\$(Configuration);$(LibraryPath)
- $(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\include;$(IncludePath)
+ $(ProjectDir)..\..\..\..\common\include;$(ProjectDir)..\..\..\..\core\include;$(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\include;$(IncludePath)
@@ -186,12 +186,6 @@
-
- %(AdditionalIncludeDirectories)
- %(PreprocessorDefinitions)
- %(AdditionalIncludeDirectories)
- %(PreprocessorDefinitions)
-
%(AdditionalIncludeDirectories)
%(PreprocessorDefinitions)
@@ -403,4 +397,4 @@
-
\ No newline at end of file
+
diff --git a/windows/src/engine/keyman32/keyman-engine.vcxproj.filters b/windows/src/engine/keyman32/keyman-engine.vcxproj.filters
index 7cd4d906d1b5e2a358e7ada4eb3fdb55a6dd4e7c..c0eab08097cded066cd712f162636ef4f54b389f 100644
--- a/windows/src/engine/keyman32/keyman-engine.vcxproj.filters
+++ b/windows/src/engine/keyman32/keyman-engine.vcxproj.filters
@@ -15,9 +15,6 @@
-
- Source Files
-
Source Files
diff --git a/windows/src/engine/keyman32/keyman32.cpp b/windows/src/engine/keyman32/keyman32.cpp
index ee6cd754b822b955afd021863820ec25e0cf34ab..86eda219a232766e6074c7df61e507b8794f68e7 100644
--- a/windows/src/engine/keyman32/keyman32.cpp
+++ b/windows/src/engine/keyman32/keyman32.cpp
@@ -492,7 +492,6 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_Exit(void)
*Globals::Keyman_Shutdown() = TRUE;
ReleaseKeyboards(TRUE);
- Addin_Release();
if(!Globals::get_Keyman_Initialised())
{
@@ -529,138 +528,6 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_RestartEngine()
return TRUE;
}
-/*******************************************************************************************/
-/* */
-/* Keyman Keyboard Override Functions */
-/* */
-/*******************************************************************************************/
-
-extern "C" BOOL _declspec(dllexport) WINAPI Keyman_StopForcingKeyboard();
-
-void RefreshPreservedKeys(BOOL Activating);
-
-extern "C" BOOL _declspec(dllexport) WINAPI Keyman_ForceKeyboard(PCSTR FileName)
-{
- SendDebugMessageFormat(0,sdmGlobal,0,"Keyman_ForceKeyboard: ENTER %s", FileName);
-
- Keyman_StopForcingKeyboard(); // 7.0.219.0
-
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td) return FALSE;
-
- strncpy(_td->ForceFileName, FileName, MAX_PATH - 1);
- _td->ForceFileName[MAX_PATH-1] = 0;
-
- if(_td->lpActiveKeyboard)
- {
- DeactivateDLLs(_td->lpActiveKeyboard);
- }
-
- _td->lpActiveKeyboard = new INTKEYBOARDINFO;
- memset(_td->lpActiveKeyboard, 0, sizeof(INTKEYBOARDINFO)); // I2437 - Crash unloading keyboard due to keyboard options not init
- /*_td->lpActiveKeyboard->KeymanID = 0;
- _td->lpActiveKeyboard->nIMDLLs = 0;
- _td->lpActiveKeyboard->IMDLLs = NULL;
- _td->lpActiveKeyboard->KeyboardOptions = NULL;*/
- _splitpath_s(FileName, NULL, 0, NULL, 0, _td->lpActiveKeyboard->Name, sizeof(_td->lpActiveKeyboard->Name), NULL, 0);
- // TODO: 5442 - remove if/ else as there will no longer be the old LoadKeyboard option
- if (Globals::get_CoreIntegration()) {
- PWCHAR keyboardPath = strtowstr(_td->ForceFileName);
- km_kbp_status err_status = km_kbp_keyboard_load(keyboardPath, &_td->lpActiveKeyboard->lpCoreKeyboard);
- if (err_status != KM_KBP_STATUS_OK) {
- SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: km_kbp_keyboard_load failed for %ls with error status [%d]", keyboardPath, err_status); // TODO: 5442 - remove word Core
- delete keyboardPath;
- return FALSE;
- }
- delete keyboardPath;
- SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: %s OK", FileName); // TODO: 5442 - remove word Core
-
- km_kbp_option_item *core_environment = nullptr;
-
- if(!SetupCoreEnvironment(&core_environment)) {
- SendDebugMessageFormat(0, sdmLoad, 0, "Keyman_ForceKeyboard Core: Unable to set environment options for keyboard %s", FileName); // TODO: 5442 - remove word Core
- return FALSE;
- }
-
- err_status =
- km_kbp_state_create(_td->lpActiveKeyboard->lpCoreKeyboard, core_environment, &_td->lpActiveKeyboard->lpCoreKeyboardState);
-
- DeleteCoreEnvironment(core_environment);
-
- if (err_status != KM_KBP_STATUS_OK) {
- SendDebugMessageFormat(
- 0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: km_kbp_state_create failed with error status [%d]", err_status);
- // Dispose of the keyboard to leave us in a consitent state
- ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard);
- return FALSE;
- }
-
- ResetCapsLock();
- err_status = km_kbp_keyboard_get_imx_list(_td->lpActiveKeyboard->lpCoreKeyboard, &_td->lpActiveKeyboard->lpIMXList);
- if (err_status != KM_KBP_STATUS_OK) {
- SendDebugMessageFormat(0, sdmLoad, 0, "Keyman_ForceKeyboard Core: km_kbp_keyboard_get_imx_list failed with error status [%d]", err_status);
- // Dispose of the keyboard to leave us in a consistent state
- ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard);
- return FALSE;
- }
-
- LoadDLLsCore(_td->lpActiveKeyboard);
- ActivateDLLs(_td->lpActiveKeyboard);
- LoadKeyboardOptionsREGCore(_td->lpActiveKeyboard, _td->lpActiveKeyboard->lpCoreKeyboardState);
- RefreshPreservedKeys(TRUE);
- return TRUE;
- } else {
- if (LoadKeyboard(_td->ForceFileName, &_td->lpActiveKeyboard->Keyboard)) {
- SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard: %s OK", FileName);
- ResetCapsLock();
- LoadDLLs(_td->lpActiveKeyboard);
- ActivateDLLs(_td->lpActiveKeyboard);
- LoadKeyboardOptions(_td->lpActiveKeyboard); // I2437 - Crash unloading keyboard due to keyboard options not set
- RefreshPreservedKeys(TRUE);
- return TRUE;
- }
- }
- SendDebugMessageFormat(0,sdmGlobal,0,"Keyman_ForceKeyboard: %s FAIL", FileName);
-
- delete _td->lpActiveKeyboard;
- _td->lpActiveKeyboard = NULL;
-
- _td->ForceFileName[0] = 0;
- return FALSE;
-}
-
-extern "C" BOOL _declspec(dllexport) WINAPI Keyman_StopForcingKeyboard()
-{
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td)
- {
- SetLastError(ERROR_KEYMAN_THREAD_DATA_NOT_READY); // I3173 // I3525
- return FALSE;
- }
-
- if(!_td->lpActiveKeyboard)
- {
- SetLastError(ERROR_KEYMAN_KEYBOARD_NOT_ACTIVE); // I3173 // I3525
- return FALSE;
- }
- SendDebugMessageFormat(0,sdmGlobal,0,"Keyman_StopForcingKeyboard");
- if(_td->ForceFileName[0])
- {
- SendDebugMessageFormat(0,sdmGlobal,0,"Keyman_StopForcingKeyboard: Stopping forcing");
- if(!DeactivateDLLs(_td->lpActiveKeyboard)) return FALSE; // I3173 // I3525
- if(!UnloadDLLs(_td->lpActiveKeyboard)) return FALSE; // I3173 // I3525
- _td->ForceFileName[0] = 0;
- FreeKeyboardOptions(_td->lpActiveKeyboard);
- ReleaseKeyboardMemory(_td->lpActiveKeyboard->Keyboard);
- ReleaseStateMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboardState);
- ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard);
- RefreshPreservedKeys(FALSE);
- delete _td->lpActiveKeyboard;
- _td->lpActiveKeyboard = NULL;
- }
- return TRUE;
-}
-
//---------------------------------------------------------------------------------------------------------
//
// Utility guff functions
@@ -936,8 +803,6 @@ void RefreshKeyboards(BOOL Initialising)
// Can happen when multiple top-level windows for one process
- Addin_Refresh();
-
SendDebugMessageFormat(0,sdmGlobal,0,"---ENTER RefreshKeyboards---");
//FInRefreshKeyboards = TRUE;
@@ -1006,8 +871,6 @@ void RefreshKeyboards(BOOL Initialising)
RefreshKeyboardProfiles(kp, FALSE); // Read standard profiles
RefreshKeyboardProfiles(kp, TRUE); // Read transient profiles
- kp->Keyboard = NULL;
-
SendDebugMessageFormat(0,sdmGlobal,0,"RefreshKeyboards: Added keyboard %s, %d",
kp->Name, kp->KeymanID);
i++;
@@ -1035,13 +898,15 @@ void ReleaseKeyboards(BOOL Lock)
if(!_td || !_td->lpKeyboards) return;
- if(Lock) if(_td->lpActiveKeyboard && !_td->ForceFileName[0]) DeactivateDLLs(_td->lpActiveKeyboard);
+ if(Lock) {
+ if(_td->lpActiveKeyboard) {
+ DeactivateDLLs(_td->lpActiveKeyboard);
+ }
+ }
for(int i = 0; i < _td->nKeyboards; i++)
{
if(Lock) UnloadDLLs(&_td->lpKeyboards[i]);
- FreeKeyboardOptions(&_td->lpKeyboards[i]);
- ReleaseKeyboardMemory(_td->lpKeyboards[i].Keyboard);
ReleaseStateMemoryCore(&_td->lpKeyboards[i].lpCoreKeyboardState);
ReleaseKeyboardMemoryCore(&_td->lpKeyboards[i].lpCoreKeyboard);
if(_td->lpKeyboards[i].Profiles) delete _td->lpKeyboards[i].Profiles; // I3581
@@ -1051,7 +916,6 @@ void ReleaseKeyboards(BOOL Lock)
delete _td->lpKeyboards;
_td->lpKeyboards = NULL;
- if(!_td->ForceFileName[0]) _td->lpActiveKeyboard = NULL;
}
/**
diff --git a/windows/src/engine/keyman32/keyman32.def b/windows/src/engine/keyman32/keyman32.def
index 84f0f24a91645bdf94c3fd1bcbee4b44f748372a..2fa0e767c550182fe27330d3bd30e6e3608e4c47 100644
--- a/windows/src/engine/keyman32/keyman32.def
+++ b/windows/src/engine/keyman32/keyman32.def
@@ -4,8 +4,6 @@ EXPORTS
Keyman_GetInitialised
Keyman_Initialise
Keyman_Exit
- Keyman_ForceKeyboard
- Keyman_StopForcingKeyboard
Keyman_GetLastActiveWindow
Keyman_GetLastFocusWindow
KMSetOutput
diff --git a/windows/src/engine/keyman32/keyman32.vcxproj b/windows/src/engine/keyman32/keyman32.vcxproj
index 0d78d2c2927fbd6d0f84100989fcb86badaebd2b..670df3c1d4197ec0a592a1aad3beff1d9e3dff6a 100644
--- a/windows/src/engine/keyman32/keyman32.vcxproj
+++ b/windows/src/engine/keyman32/keyman32.vcxproj
@@ -176,12 +176,6 @@
-
- %(AdditionalIncludeDirectories)
- %(PreprocessorDefinitions)
- %(AdditionalIncludeDirectories)
- %(PreprocessorDefinitions)
-
%(AdditionalIncludeDirectories)
%(PreprocessorDefinitions)
@@ -362,7 +356,6 @@
-
diff --git a/windows/src/engine/keyman32/keyman32.vcxproj.filters b/windows/src/engine/keyman32/keyman32.vcxproj.filters
index 8995c39a9308cfa03547f0b363de6eb9c2fc2e3f..dcf5f5d4c51c8069ebd39adeccb31c9307fb323c 100644
--- a/windows/src/engine/keyman32/keyman32.vcxproj.filters
+++ b/windows/src/engine/keyman32/keyman32.vcxproj.filters
@@ -15,9 +15,6 @@
-
- Source Files
-
Source Files
@@ -162,9 +159,6 @@
-
- Header Files
-
Header Files
diff --git a/windows/src/engine/keyman32/keymanengine.h b/windows/src/engine/keyman32/keymanengine.h
index d56bcc1e3e14be8d34899c478ee3ccd934616487..f40aeaf3728ef1f2f09dba9305c4aab675d719dc 100644
--- a/windows/src/engine/keyman32/keymanengine.h
+++ b/windows/src/engine/keyman32/keymanengine.h
@@ -81,11 +81,9 @@ typedef struct tagINTKEYBOARDINFO
DWORD __filler_Hotkey;
DWORD __filler; // makes same as KEYBOARDINFO // I4462
char Name[256];
- LPKEYBOARD Keyboard;
DWORD nIMDLLs;
LPIMDLL IMDLLs;
int __filler2; // makes same as KEYBOARDINFO
- LPINTKEYBOARDOPTIONS KeyboardOptions;
int nProfiles;
LPINTKEYBOARDPROFILE Profiles;
km_kbp_keyboard* lpCoreKeyboard;
@@ -105,17 +103,11 @@ typedef struct tagKMSTATE
{
BOOL NoMatches;
MSG msg;
- // TODO: 5442 will remove these once windows core is deprecated
- BOOL StopOutput;
- int LoopTimes;
- // TODO: 5442
WORD vkey; // I934
WCHAR charCode; // I4582
BOOL windowunicode; // I4287
BOOL isDown;
- LPKEYBOARD lpkb;
km_kbp_keyboard* lpCoreKb; // future use with IMDLL
- LPGROUP startgroup; // TODO: 5442 will remove this once windows core is deprecated
} KMSTATE;
// I3616
@@ -129,7 +121,6 @@ LRESULT CALLBACK kmnLowLevelKeyboardProc( // I4124
_In_ LPARAM lParam
);
-BOOL ReleaseKeyboardMemory(LPKEYBOARD kbd);
BOOL ReleaseStateMemoryCore(km_kbp_state** state);
BOOL ReleaseKeyboardMemoryCore(km_kbp_keyboard** kbd);
@@ -230,8 +221,6 @@ DWORD HKLToKeyboardID(HKL hkl);
WORD HKLToLanguageID(HKL hkl);
WORD HKLToLayoutNumber(HKL hkl);
WORD HKLToLayoutID(HKL hkl);
-DWORD EthnologueCodeToKeymanID(DWORD EthCode);
-DWORD EthnologueStringCodeToDWord(PWSTR EthCode);
PWSTR GetSystemStore(LPKEYBOARD kb, DWORD SystemID);
@@ -254,7 +243,6 @@ void keybd_shift(LPINPUT pInputs, int* n, BOOL isReset, LPBYTE const kbd);
#include "keystate.h"
#include "calldll.h"
-#include "addins.h"
#include "keymancontrol.h"
#include "keyboardoptions.h"
#include "kmprocessactions.h"
diff --git a/windows/src/engine/keyman32/kmhook_getmessage.cpp b/windows/src/engine/keyman32/kmhook_getmessage.cpp
index f6a56340f93e258059f436e092a4a2d5b37b0b45..562c455abb3cc53bbf6368915ed905150cb3ea32 100644
--- a/windows/src/engine/keyman32/kmhook_getmessage.cpp
+++ b/windows/src/engine/keyman32/kmhook_getmessage.cpp
@@ -248,19 +248,6 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam)
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
- /*
- Handle WM_UNICHAR messages for RichEdit control -- should we test RichEdit version?
- */
-
- if(mp->message == WM_UNICHAR && Addin_ShouldProcessUnichar(mp->hwnd))
- {
- if(Addin_ProcessUnichar(mp->hwnd, (DWORD) mp->wParam))
- {
- mp->message = 0;
- return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
- }
- }
-
/*
Handle wm_keyman_control_internal messages
*/
@@ -271,7 +258,6 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam)
if(_td->lpActiveKeyboard)
{
- _td->state.lpkb = _td->lpActiveKeyboard->Keyboard;
_td->state.lpCoreKb = _td->lpActiveKeyboard->lpCoreKeyboard;
}
// I4412
@@ -297,20 +283,17 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(_td->app)
{
- BOOL isUsingCoreProcessor = Globals::get_CoreIntegration();
-
- if (isUsingCoreProcessor) {
- // Call the core keyboard processor to process the queued actions
- if (!_td->lpActiveKeyboard) {
- return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
- }
- if (KM_KBP_STATUS_OK != km_kbp_process_queued_actions(_td->lpActiveKeyboard->lpCoreKeyboardState)) {
- SendDebugMessageFormat(0, sdmGlobal, 0, "_kmnGetMessageProc wm_keymanim_close process event fail");
- return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
- }
- BOOL emitKeyStroke;
- ProcessActions(&emitKeyStroke);
+ // Call the core keyboard processor to process the queued actions
+ if (!_td->lpActiveKeyboard) {
+ return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
+ if (KM_KBP_STATUS_OK != km_kbp_process_queued_actions(_td->lpActiveKeyboard->lpCoreKeyboardState)) {
+ SendDebugMessageFormat(0, sdmGlobal, 0, "_kmnGetMessageProc wm_keymanim_close process event fail");
+ return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
+ }
+ BOOL emitKeyStroke;
+ ProcessActions(&emitKeyStroke);
+
_td->app->SetCurrentShiftState(Globals::get_ShiftState());
_td->app->SendActions();
}
@@ -372,7 +355,6 @@ void ProcessWMKeyman(HWND hwnd, WPARAM wParam, LPARAM lParam)
hwnd = GetFocus();
if(_td->lpActiveKeyboard) {
- _td->state.lpkb = _td->lpActiveKeyboard->Keyboard;
_td->state.lpCoreKb = _td->lpActiveKeyboard->lpCoreKeyboard;
}
@@ -384,7 +366,6 @@ void ProcessWMKeyman(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
if(_td->app) _td->app->ResetQueue();
GetCapsAndNumlockState();
- Addin_FocusChanged(hwnd);
UpdateActiveWindows();
}
}
diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp
index 7faac081c279526359bd4a2ba918bfd953f11bf6..64a6a48e98d3f2b5d8bdd2c5dceaf1907c16da22 100644
--- a/windows/src/engine/keyman32/kmprocess.cpp
+++ b/windows/src/engine/keyman32/kmprocess.cpp
@@ -119,7 +119,6 @@ Process_Event_Core(PKEYMAN64THREADDATA _td) {
return TRUE;
}
-
/*
* BOOL ProcessHook();
*
@@ -138,10 +137,7 @@ BOOL ProcessHook()
PKEYMAN64THREADDATA _td = ThreadGlobals();
if(!_td) return FALSE;
- LPGROUP gp = _td->state.startgroup;
-
fOutputKeystroke = FALSE; // TODO: 5442 no longer needs to be global once we use core processor
- BOOL isUsingCoreProcessor = Globals::get_CoreIntegration();
//
// If we are running in the debugger, don't do a second run through
//
@@ -160,44 +156,28 @@ BOOL ProcessHook()
Debug_VirtualKey(_td->state.vkey), getcontext_debug());
}
- AIDEBUGKEYINFO keyinfo;
- keyinfo.shiftFlags = Globals::get_ShiftState();
- keyinfo.VirtualKey = _td->state.vkey;
- keyinfo.Character = _td->state.charCode;
- keyinfo.DeadKeyCharacter = 0; // I4582
- keyinfo.IsUp = !_td->state.isDown;
- if(_td->app->IsUnicode())
- _td->app->QueueDebugInformation(QID_BEGIN_UNICODE, NULL, NULL, NULL, NULL, (DWORD_PTR) &keyinfo);
- else
- _td->app->QueueDebugInformation(QID_BEGIN_ANSI, NULL, NULL, NULL, NULL, (DWORD_PTR) &keyinfo);
}
- if (isUsingCoreProcessor) { // TODO: 5442 Note: Nested if will be reduced once using core only
- // For applications not using the TSF kmtip calls this function twice for each keystroke,
- // first to determine if we are doing processing work (TIPFUpdateable == FALSE),
- // if we say yes it will call a second time to actually do the work.
- // We call the core process event only once and use the core's queued actions
- // on the second pass.
- // For the TSF in most cases kmtip (except OnPreservedKey) will not call the non-updateable test parse.
- // Therfore the core process event will need to be called before processing the actions.
-
- // CoreProcessEventRun would be a sufficient test however testing TIPFUpdateable defines
- // the status of the keystroke processing more precisely.
- if (!_td->TIPFUpdateable || !_td->CoreProcessEventRun) {
- if (!Process_Event_Core(_td)) {
- return FALSE;
- }
- }
-
- if (!_td->TIPFUpdateable) {
- ProcessActionsNonUpdatableParse(&fOutputKeystroke);
- } else {
- ProcessActions(&fOutputKeystroke);
+ // For applications not using the TSF kmtip calls this function twice for each keystroke,
+ // first to determine if we are doing processing work (TIPFUpdateable == FALSE),
+ // if we say yes it will call a second time to actually do the work.
+ // We call the core process event only once and use the core's queued actions
+ // on the second pass.
+ // For the TSF in most cases kmtip (except OnPreservedKey) will not call the non-updateable test parse.
+ // Therfore the core process event will need to be called before processing the actions.
+
+ // CoreProcessEventRun would be a sufficient test however testing TIPFUpdateable defines
+ // the status of the keystroke processing more precisely.
+ if (!_td->TIPFUpdateable || !_td->CoreProcessEventRun) {
+ if (!Process_Event_Core(_td)) {
+ return FALSE;
}
-
}
- else {
- ProcessGroup(gp); // TODO: 5442 remove
+
+ if (!_td->TIPFUpdateable) {
+ ProcessActionsNonUpdatableParse(&fOutputKeystroke);
+ } else {
+ ProcessActions(&fOutputKeystroke);
}
if (fOutputKeystroke && !_td->app->IsQueueEmpty()) {
@@ -256,671 +236,9 @@ BOOL ProcessHook()
// PWSTR contextBuf = _td->app->ContextBufMax(MAXCONTEXT);
// SendDebugMessageFormat(0, sdmAIDefault, 0, "Kmprocess::ProcessHook After cxt=%s", Debug_UnicodeString(contextBuf, 1));
- _td->app->QueueDebugInformation(QID_END, NULL, NULL, NULL, NULL, 0);
return !fOutputKeystroke;
}
-/*
-* PRIVATE BOOL ProcessGroup(LPGROUP gp);
-*
-* Parameters: gp Pointer to group to process inside
-*
-* Returns: TRUE if messages are to be sent,
-* and FALSE if no messages are to be sent.
-*
-* Called by: ProcessHook, recursive inside groups
-*
-* ProcessKey is where the keystroke conversion and output takes place. This routine
-* has a lot of crucial code in it!
-*/
-
-BOOL ProcessGroup(LPGROUP gp)
-{
- if (!DebugAssert(!Globals::get_CoreIntegration(), "KMPROCESS:ProcessGroup: Error called in core integration mode")) {
- return FALSE;
- }
- DWORD i;
- LPKEY kkp = NULL;
- PWSTR p;
- int sdmfI;
-
- /*
- If the number of nested groups goes higher than 50, then break out - this is
- a limitation of stack size. This is basically a catch-all for freaky apps that
- cause message loopbacks and nasty things like that. Okay, it's really a catch all
- for bugs! This means the user's system shouldn't hang.
- */
-
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td) return FALSE;
-
- _td->app->QueueDebugInformation(QID_GROUP_ENTER, gp, NULL, NULL, NULL, 0);
-
- sdmfI = -1;
-
- for(i = 0; i < _td->state.lpkb->cxGroupArray; i++)
- if(gp == &_td->state.lpkb->dpGroupArray[i])
- {
- if(_td->state.msg.message == wm_keymankeydown && ShouldDebug(sdmKeyboard))
- SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, "Entering group %d of %d, context '%s'", i+1, _td->state.lpkb->cxGroupArray, getcontext_debug());
- sdmfI = i;
- break;
- }
-
- if(++_td->state.LoopTimes > 50)
- {
- if(_td->state.msg.message == wm_keymankeydown) SendDebugMessage(_td->state.msg.hwnd, sdmKeyboard, 0, "Aborting output: state.LoopTimes exceeded.");
- _td->state.StopOutput = TRUE;
- _td->app->QueueDebugInformation(QID_GROUP_EXIT, gp, NULL, NULL, NULL, QID_FLAG_RECURSIVE_OVERFLOW);
- return FALSE;
- }
-
- _td->state.NoMatches = TRUE;
-
- /*
- The rule matching loop.
-
- This loop iterates through all the rules in the group that is currently being
- processed. Each rule in a group can be of three different types:
- 1. A virtual key rule, where the key to be matched is a virtual key
- 2. A normal key rule (WM_CHAR), where the key to be matched is an Ascii char.
- 3. A rule in a keyless group, where only the context is matched.
-
- The loop goes through and checks the rules like that. This loop could be optimized
- with standard searching techniques - the ContextMatch may be difficult.
- */
-
- if(ShouldDebug(sdmKeyboard))
- SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, "state.vkey: %s shiftFlags: %x; charCode: %X",
- Debug_VirtualKey(_td->state.vkey), Globals::get_ShiftState(), _td->state.charCode); // I4582
-
- if(gp)
- {
- for(kkp = gp->dpKeyArray, i=0; i < gp->cxKeyArray; i++, kkp++)
- {
- if(!ContextMatch(kkp)) continue;
- if(!gp->fUsingKeys)
- {
- if(kkp->dpContext[0] != 0) break; else continue;
- }
-
- //if(kkp->Key == state.vkey)
- //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, 0, "kkp->Key: %d kkp->ShiftFlags: %x",
- // kkp->Key, kkp->ShiftFlags);
-
- /* Keyman 6.0: support Virtual Characters */
- if(IsEquivalentShift(kkp->ShiftFlags, Globals::get_ShiftState()))
- {
- if(kkp->Key > VK__MAX && kkp->Key == _td->state.vkey) break; // I3438 // I4582
- else if(kkp->Key == _td->state.vkey) break; // I4169
- }
- else if(kkp->ShiftFlags == 0 && kkp->Key == _td->state.charCode && _td->state.charCode != 0) break;
- }
- }
-
- if(!gp || i == gp->cxKeyArray)
- {
- /*
- No rule was found that corresponded to the current state of the context and
- keyboard. NoMatch should be checked for everything except virtual keys; and
- context should also be kept.
-
- If the message was a virtual key, then just return without checking NoMatch.
- NoMatch shouldn't be used for virtual keys because it will mean that no key
- can ever get through that isn't matched - including arrows, func. keys, etc !!
- Context is not kept for virtual keys being output.
- */
-
- if(_td->state.msg.message == wm_keymankeydown && ShouldDebug(sdmKeyboard)) SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0,
- "No match was found in group %d of %d", sdmfI, _td->state.lpkb->cxGroupArray);
-
- if(!gp || (_td->state.charCode == 0 && gp->fUsingKeys)) // I4585
- // 7.0.241.0: I1133 - Fix mismatched parentheses on state.charCode - ie. we don't want to output this letter if !gp->fUsingKeys
- {
- BOOL fIsBackspace = _td->state.vkey == VK_BACK && (Globals::get_ShiftState() & (LCTRLFLAG|RCTRLFLAG|LALTFLAG|RALTFLAG)) == 0; // I4128
-
- if(/*_td->app->DebugControlled() &&*/ fIsBackspace) { // I4838 // I4933
- if(_td->state.msg.message == wm_keymankeydown) { // I4933
- if(!_td->app->IsLegacy()) { // I4933
- PWCHAR pdeletecontext = _td->app->ContextBuf(1); // I4933
- if(!pdeletecontext || *pdeletecontext == 0) { // I4933
- _td->app->ResetContext(); // I4933
- fOutputKeystroke = TRUE; // I4933
- return FALSE; // I4933
- }
- if (Uni_IsSurrogate1(*pdeletecontext) && Uni_IsSurrogate2(*(pdeletecontext+1))) {
- // 2 backspaces to delete both parts of surrogate pair
- // This only needs to be done for TSF-aware apps as legacy apps
- // will receive a BKSP WM_KEYDOWN event which results in deleting
- // both parts in one action
- _td->app->QueueAction(QIT_BACK, BK_BACKSPACE | BK_SURROGATE);
- }
- else {
- _td->app->QueueAction(QIT_BACK, BK_BACKSPACE);
- }
- }
- else {
- _td->app->QueueAction(QIT_BACK, BK_BACKSPACE); // I4933
- }
- }
- } else if( (!_td->app->IsLegacy() || !fIsBackspace) && !_td->TIPFPreserved) { // I4024 // I4128 // I4287 // I4290
- SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, " ... IsLegacy = FALSE; IsTIP = TRUE"); // I4128
- if(_td->state.charCode == 0) _td->app->ResetContext(); // I3573 // I3577 // I4585
- fOutputKeystroke = TRUE;
- return FALSE;
- }
- //fOutputKeystroke = TRUE; return FALSE; // Don't swallow keystroke // I3577
- ///SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, " ... IsLegacy = TRUE; IsTIP = TRUE");
-
- /*
- If the key is not a character key (white keys), or not processing, then we must init the stack -
- unknown keys do things like moving position in the context, so must clear.
- */
- if(fIsBackspace) // I4128
- {
- /*
- Must have special handling for VK_BACK: delete a character from the context stack
- This only fires if the keyboard has no rule for backspace.
- */
- }
- else
- {
- //app->NoSetShift = FALSE;
-
- DWORD dw = _td->state.vkey;
- if(dw == 0x05) dw = VK_RETURN; // I649 - VK_ENTER and K_NPENTER
-
- if(_td->state.msg.lParam & (1<<24)) dw |= QVK_EXTENDED; // Extended key flag // I3438
-
- if(_td->state.charCode == 0) {
- _td->app->ResetContext();
- }
-
- if(_td->TIPFPreserved) { // I4290
- if(_td->state.charCode != 0) {
- _td->app->QueueAction(QIT_CHAR, _td->state.charCode);
- }
- } else {
- if(_td->state.msg.message == wm_keymankeydown)
- {
- _td->app->QueueAction(QIT_VSHIFTDOWN, Globals::get_ShiftState()); // 15/05/2001 - fixing I201 -- enabled line
- _td->app->QueueAction(QIT_VKEYDOWN, dw);
- }
-
- if(_td->state.msg.message == wm_keymankeyup) {
- _td->app->QueueAction(QIT_VKEYUP, dw);
- _td->app->QueueAction(QIT_VSHIFTUP, Globals::get_ShiftState());
- }
- }
- }
- }
- else if (gp->dpNoMatch != NULL && *gp->dpNoMatch != 0 && _td->state.msg.message != wm_keymankeyup)
- {
- /* NoMatch rule found, and is a character key */
- _td->app->QueueDebugInformation(QID_NOMATCH_ENTER, gp, NULL, NULL, gp->dpNoMatch, 0);
- PostString(gp->dpNoMatch, &_td->state.msg, _td->state.lpkb, NULL);
- _td->app->QueueDebugInformation(QID_NOMATCH_EXIT, gp, NULL, NULL, gp->dpNoMatch, 0);
- }
- else if (_td->state.charCode != 0 && _td->state.charCode != 0xFFFF && _td->state.msg.message != wm_keymankeyup && gp->fUsingKeys)
- {
- /* No rule found, is a character key */
- // 7.0.239.0: I994 - Workaround output order issues - we will use the TSF to output all characters...
- // if(app->Type1() == AIType_TIP) { fOutputKeystroke = TRUE; return FALSE; } // Don't swallow keystroke
-
- _td->app->QueueAction(QIT_CHAR, _td->state.charCode);
- }
-
- _td->app->QueueDebugInformation(QID_GROUP_EXIT, gp, NULL, NULL, NULL, QID_FLAG_NOMATCH);
- return TRUE;
- }
-
- if(_td->state.msg.message == wm_keymankeyup)
- return TRUE;
-
- SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, "match found in rule %d", i);
-
- _td->state.NoMatches = FALSE;
-
- /*
- Save the context that will be used for output when the 'context' keyword is used.
- For each deadkey, we need to add 2 characters; look in related stores as well...
- */
-
- assert(kkp != NULL);
-
- _td->miniContextIfLen = xstrlen(kkp->dpContext) - xstrlen_ignoreifopt(kkp->dpContext);
-
- // 11 Aug 2003 - I25(v6) - mcdurdin - CODE_NUL context support
- if(*kkp->dpContext == UC_SENTINEL && *(kkp->dpContext+1) == CODE_NUL)
- wcsncpy_s(_td->miniContext, GLOBAL_ContextStackSize, _td->app->ContextBuf(xstrlen_ignoreifopt(kkp->dpContext)-1), GLOBAL_ContextStackSize); // I3162 // I3536
- else
- wcsncpy_s(_td->miniContext, GLOBAL_ContextStackSize, _td->app->ContextBuf(xstrlen_ignoreifopt(kkp->dpContext)), GLOBAL_ContextStackSize); // I3162 // I3536
-
- _td->miniContext[GLOBAL_ContextStackSize-1] = 0;
-
- _td->app->QueueDebugInformation(QID_RULE_ENTER, gp, kkp, _td->miniContext, NULL, 0);
-
- /*
- The next section includes several optimizations that make the code a little harder
- to read, but are probably worth it in the time that they save.
-
- If the output string doesn't have a "context" byte at the start, post backspaces
- to erase the appropriate number of characters in the application. If it does have
- a "context" byte at the start, then the string won't change, and no backspaces are
- necessary. You could go one step further with this optimization, in PostAllKeys,
- by comparing the starts of the strings to see what is same, and not backspacing
- that, but it is probably not necessary.
- */
-
- p = kkp->dpOutput;
- if(*p != UC_SENTINEL || *(p+1) != CODE_CONTEXT) {
- for(PWSTR mcp = decxstr(wcschr(_td->miniContext, 0), _td->miniContext); mcp != NULL; mcp = decxstr(mcp, _td->miniContext)) {
- if (*mcp == UC_SENTINEL) {
- switch (*(mcp + 1)) {
- case CODE_DEADKEY: _td->app->QueueAction(QIT_BACK, BK_DEADKEY); break;
- case CODE_NUL: break; // 11 Aug 2003 - I25(v6) - mcdurdin - CODE_NUL context support
- }
- }
- else if (Uni_IsSurrogate1(*mcp) && Uni_IsSurrogate2(*(mcp + 1))) {
- // 2 backspaces to delete both parts of surrogate pair
- // This only needs to be done for TSF-aware apps as legacy apps
- // will receive a BKSP WM_KEYDOWN event which results in deleting
- // both parts in one action
- _td->app->QueueAction(QIT_BACK, BK_SURROGATE);
- }
- else {
- _td->app->QueueAction(QIT_BACK, 0);
- }
- }
- }
- else {
- // otherwise, the "context" entry has to be jumped over
- p += 2;
- }
-
- /* Use PostString to post the rest of the output string. */
-
- if(PostString(p, &_td->state.msg, _td->state.lpkb, NULL) == psrCheckMatches)
- {
- _td->app->QueueDebugInformation(QID_RULE_EXIT, gp, kkp, _td->miniContext, NULL, 0);
-
- if(gp->dpMatch && *gp->dpMatch)
- {
- _td->app->QueueDebugInformation(QID_MATCH_ENTER, gp, NULL, NULL, gp->dpMatch, 0);
- PostString(gp->dpMatch, &_td->state.msg, _td->state.lpkb, NULL);
- _td->app->QueueDebugInformation(QID_MATCH_EXIT, gp, NULL, NULL, gp->dpMatch, 0);
- }
- }
- else
- _td->app->QueueDebugInformation(QID_RULE_EXIT, gp, kkp, _td->miniContext, NULL, 0);
- _td->app->QueueDebugInformation(QID_GROUP_EXIT, gp, NULL, NULL, NULL, 0);
-
- return TRUE;
-}
-
-/*
-* int PostString( LPSTR str, BOOL *useMode, LPMSG mp,
-* LPKEYBOARD lpkb );
-*
-* Parameters: str Pointer to string to send
-* useMode Pointer to BOOL about whether a "use" command was found
-* mp Pointer to MSG structure to copy in outputting messages
-* lpkb Pointer to global keyboard structure
-*
-* Returns: 0 to continue, 1 and 2 to return.
-*
-* Called by: ProcessKey
-*
-* PostString posts a string of "context", "index", "beep", characters and virtual keys
-* to the active application, via the Keyman PostKey buffer.
-*/
-
-int PostString(PWSTR str, LPMSG mp, LPKEYBOARD lpkb, PWSTR endstr)
-{
- if (!DebugAssert(!Globals::get_CoreIntegration(), "KKMPROCESS:PostString: Error called in core integration mode")) {
- return FALSE;
- }
- PWSTR p, q, temp;
- LPSTORE s;
- int n1, n2;
- int i, n, shift;
- BOOL FoundUse = FALSE;
-
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td) return FALSE;
-
- // TODO: Refactor to use incxstr
- for(p = str; *p && (p < endstr || !endstr); p++)
- {
- if(*p == UC_SENTINEL)
- switch(*(++p))
- {
- case CODE_EXTENDED: // Start of a virtual key section w/shift codes
- p++;
-
- shift = *p; //(*p<<8) | *(p+1);
- _td->app->QueueAction(QIT_VSHIFTDOWN, shift);
-
- p++;
-
- _td->app->QueueAction(QIT_VKEYDOWN, *p);
- _td->app->QueueAction(QIT_VKEYUP, *p);
-
- _td->app->QueueAction(QIT_VSHIFTUP, shift);
-
- p++; // CODE_EXTENDEDEND
- ////// CODE_EXTENDEDEND will be incremented by loop
-
- //app->QueueAction(QIT_VSHIFTUP, shift);
- break;
-
- case CODE_DEADKEY: // A deadkey to be output
- p++;
- _td->app->QueueAction(QIT_DEADKEY, *p);
- break;
- case CODE_BEEP: // Sound an 'iconasterisk' beep
- _td->app->QueueAction(QIT_BELL, 0);
- break;
- case CODE_CONTEXT: // copy the context to the output
- PostString(_td->miniContext, mp, lpkb, wcschr(_td->miniContext, 0));
- break;
- case CODE_CONTEXTEX:
- p++;
- for(q = _td->miniContext, i = _td->miniContextIfLen; *q && i < *p-1; i++, q=incxstr(q));
- if(*q) {
- temp = incxstr(q);
- PostString(q, mp, lpkb, temp);
- }
- break;
- case CODE_RETURN: // stop processing and start PostAllKeys
- _td->state.StopOutput = TRUE;
- return psrPostMessages;
-
- case CODE_CALL:
- p++;
- CallDLL(_td->lpActiveKeyboard, *p-1);
- if(_td->state.StopOutput) return psrPostMessages;
- FoundUse = TRUE;
- break;
- case CODE_USE: // use another group
- p++;
- ProcessGroup(&lpkb->dpGroupArray[*p-1]);
- if(_td->state.StopOutput) return psrPostMessages;
- FoundUse = TRUE;
- break;
- case CODE_CLEARCONTEXT:
- _td->app->ResetContext();
- _td->app->ReadContext();
- break;
- case CODE_INDEX:
- p++;
- s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[*p - 1];
- p++;
-
- n = _td->IndexStack[*p - 1];
- for(temp = s->dpString; *temp && n > 0; temp = incxstr(temp), n--);
- PostString(temp, mp, lpkb, incxstr(temp));
- break;
- case CODE_SETOPT:
- p++;
- n1 = *p - 1;
- p++;
- n2 = *p - 1;
- SetKeyboardOption(_td->lpActiveKeyboard, n1, n2);
- break;
- case CODE_RESETOPT:
- p++;
- n1 = *p - 1;
- ResetKeyboardOption(_td->lpActiveKeyboard, n1);
- break;
- case CODE_SAVEOPT:
- p++;
- n1 = *p - 1;
- SaveKeyboardOption(_td->lpActiveKeyboard, n1);
- break;
- case CODE_IFSYSTEMSTORE:
- p+=3;
- break;
- case CODE_SETSYSTEMSTORE:
- p+=2;
- break;
- }
- else
- _td->app->QueueAction(QIT_CHAR, *p);
- }
- return FoundUse ? psrPostMessages : psrCheckMatches;
-}
-
-
-BOOL IsMatchingBaseLayout(PWCHAR layoutName) // I3432
-{
- BOOL bEqual = _wcsicmp(layoutName, Globals::get_BaseKeyboardName()) == 0 || // I4583
- _wcsicmp(layoutName, Globals::get_BaseKeyboardNameAlt()) == 0; // I4583
-
- return bEqual;
-}
-
-BOOL IsMatchingPlatformString(PWCHAR platform) // I3432
-{
- return
- _wcsicmp(platform, L"windows") == 0 ||
- _wcsicmp(platform, L"desktop") == 0 ||
- _wcsicmp(platform, L"hardware") == 0 ||
- _wcsicmp(platform, L"native") == 0;
-}
-
-BOOL IsMatchingPlatform(LPSTORE s) // I3432
-{
- PWCHAR t = new WCHAR[wcslen(s->dpString)+1];
- wcscpy_s(t, wcslen(s->dpString)+1, s->dpString);
- PWCHAR context = NULL;
- PWCHAR platform = wcstok_s(t, L" ", &context);
- while(platform != NULL)
- {
- if(!IsMatchingPlatformString(platform))
- {
- s->dwSystemID = TSS_PLATFORM_NOMATCH;
- delete[] t;
- return FALSE;
- }
- platform = wcstok_s(NULL, L" ", &context);
- }
-
- s->dwSystemID = TSS_PLATFORM_MATCH;
- delete[] t;
- return TRUE;
-}
-
-/*
-* BOOL ContextMatch( LPKEY kkp );
-*
-* Parameters: kkp Rule to compare
-*
-* Returns: 0 on OK, 1 on not equal
-*
-* Called by: ProcessKey
-*
-* ContextMatch compares the context of a rule with the current context.
-*/
-
-BOOL ContextMatch(LPKEY kkp)
-{
- if (!DebugAssert(!Globals::get_CoreIntegration(), "KMPROCESS:ContextMatch: Error called in core integration mode")) {
- return FALSE;
- }
- WORD /*i,*/ n;
- PWSTR p, q, qbuf, temp;
- LPWORD indexp;
- LPSTORE s, t;
- BOOL bEqual;
-
- //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: ENTER [%d]", kkp->Line);
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td) return FALSE;
-
- memset(_td->IndexStack, 0, GLOBAL_ContextStackSize*sizeof(WORD)); // I3158 // I3524
-
- p = kkp->dpContext;
-
- if(*p == 0)
- {
- //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT TRUE -> no rule context");
- return TRUE;
- }
-
- /* 11 Aug 2003 - I25(v6) - mcdurdin - test for CODE_NUL */
-
- if(*p == UC_SENTINEL && *(p+1) == CODE_NUL)
- {
- // If context buf is longer than the context, then obviously not start of doc.
- if(_td->app->ContextBuf(xstrlen_ignoreifopt(p))) return FALSE; // I2484 - Fix bug with if() following nul in same statement
- p = incxstr(p);
- if(*p == 0) return TRUE;
- }
-
- for(PWCHAR pp = p; pp && *pp; pp = incxstr(pp))
- {
- if(*pp == UC_SENTINEL && *(pp+1) == CODE_IFOPT)
- {
- s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(pp+2))-1]; // I2590
- t = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(pp+4))-1]; // I2590
-
- bEqual = wcscmp(s->dpString, t->dpString) == 0;
- if(*(pp+3) == 1 && bEqual) return FALSE; // I2590
- if(*(pp+3) == 2 && !bEqual) return FALSE; // I2590
- }
- else if(*pp == UC_SENTINEL && *(pp+1) == CODE_IFSYSTEMSTORE) // I3432
- {
- DWORD dwSystemID = *(pp+2)-1;
- t = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(pp+4))-1]; // I2590
- switch(dwSystemID)
- {
- case TSS_PLATFORM_MATCH: // Cached platform result - a matching platform
- bEqual = TRUE;
- break;
- case TSS_PLATFORM_NOMATCH: // Cached platform result - not a matching platform
- bEqual = FALSE;
- break;
- case TSS_PLATFORM:
- bEqual = IsMatchingPlatform(t);
- break;
- case TSS_BASELAYOUT:
- bEqual = IsMatchingBaseLayout(t->dpString);
- break;
- default:
- {
- PWCHAR ss = GetSystemStore(_td->lpActiveKeyboard->Keyboard, dwSystemID);
- if(ss == NULL) return FALSE;
- bEqual = wcscmp(ss, t->dpString) == 0;
- }
- }
-
- if(*(pp+3) == 1 && bEqual) return FALSE; // I2590
- if(*(pp+3) == 2 && !bEqual) return FALSE; // I2590
- }
- }
-
- q = qbuf = _td->app->ContextBuf(xstrlen_ignoreifopt(p));
- if(!q)
- {
- //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT FALSE -> context too short");
- return FALSE; // context buf is too short!
- }
- indexp = _td->IndexStack;
-
- //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: [%d] Rule: %s", kkp->Line, format_unicode_debug(kkp->dpContext));
- //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: [%d] Test: %s", kkp->Line, format_unicode_debug(q));
-
- for(; *p && *q; p = incxstr(p))
- {
- //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: p:%x q:%x", *p, *q);
- *indexp = 0;
-
- if(*p == UC_SENTINEL)
- {
- switch(*(p+1))
- {
- case CODE_DEADKEY:
- if(*q != UC_SENTINEL || *(q+1) != CODE_DEADKEY || *(q+2) != *(p+2))
- {
- // SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT FALSE -> deadkeys don't match %x %x %x != %x %x %x",
- // *p, *(p+1), *(p+2), *q, *(q+1), *(q+2));
- return FALSE;
- }
- break;
- case CODE_ANY:
- s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(p+2))-1];
-
- temp = xstrchr(s->dpString, q);
-
- /*SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard ,kkp->Line, "ContextMatch: CODE_ANY [%x %x %x %x %x %x %x %x %x %x] [%x %x %x] %d",
- s->dpString[0], s->dpString[1], s->dpString[2],
- s->dpString[3], s->dpString[4], s->dpString[5],
- s->dpString[6], s->dpString[7], s->dpString[8],
- s->dpString[9],
- q[0], q[1], q[2],
- (temp ? (INT_PTR)(temp-s->dpString) : 0));*/
-
- if(temp != NULL) // I1622
- *indexp = (WORD) xstrpos(temp, s->dpString);
-
- //if((temp = xstrchr(s->dpString, GetSuppChar(q))) != NULL)
- // *indexp = xstrpos(temp, s->dpString);
- else
- return FALSE;
- break;
- case CODE_NOTANY:
- s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(p+2))-1];
-
- if((temp = xstrchr(s->dpString, q)) != NULL) // I1622
- return FALSE;
-
- //if((temp = xstrchr(s->dpString, GetSuppChar(q))) != NULL)
- // return FALSE;
- break;
- case CODE_INDEX:
- s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(p+2))-1];
- *indexp = n = _td->IndexStack[(*(p+3))-1];
-
- for(temp = s->dpString; *temp && n > 0; temp = incxstr(temp), n--);
- if(n != 0) return FALSE;
- if(xchrcmp(temp, q) != 0) return FALSE;
- ////if(GetSuppChar(temp) != GetSuppChar(q)) return FALSE; // I1622
- break;
- case CODE_CONTEXTEX:
- // only the nth character
- for(n = *(p+2) - 1, temp = qbuf; temp < q && n > 0; n--, temp = incxstr(temp));
- if(n == 0)
- if(xchrcmp(temp, q) != 0) return FALSE;
- //if(GetSuppChar(temp) != GetSuppChar(q)) return FALSE;
- break;
- case CODE_IFOPT:
- case CODE_IFSYSTEMSTORE: // I3432
- indexp++;
- continue; // don't increment q
- default:
- return FALSE;
- }
- }
- else if(xchrcmp(p, q) != 0) //GetSuppChar(p) != GetSuppChar(q))
- {
- //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: [%d] FAIL: %s", kkp->Line, format_unicode_debug(p));
- //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: [%d] FAIL: %s", kkp->Line, format_unicode_debug(q));
- //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT FALSE -> chrs don't match");
- return FALSE;
- }
- indexp++;
- q = incxstr(q);
- }
-
- while(*p == UC_SENTINEL && (*(p+1) == CODE_IFOPT || *(p+1) == CODE_IFSYSTEMSTORE)) p = incxstr(p); // already tested // I3432
-
- //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT %s -> END OF FUNCTION",
- // *p == *q ? "TRUE" : "FALSE");
- return *p == *q; /*at least one must ==0 at this point*/
-}
-
-
PWSTR strtowstr(PSTR in)
{
PWSTR result;
@@ -933,7 +251,6 @@ PWSTR strtowstr(PSTR in)
return result;
}
-
PSTR wstrtostr(PCWSTR in)
{
PSTR result;
diff --git a/windows/src/engine/keyman32/kmprocessactions.cpp b/windows/src/engine/keyman32/kmprocessactions.cpp
index 1e07523925079b9b1426d769c2a74b8bc48dee2d..8855ad7e15ed4e4dd2603180991fb29b3810e60b 100644
--- a/windows/src/engine/keyman32/kmprocessactions.cpp
+++ b/windows/src/engine/keyman32/kmprocessactions.cpp
@@ -71,7 +71,7 @@ static BOOL processPersistOpt(
SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessHook: Saving option to registry for keyboard [%s].", activeKeyboard->Name);
LPWSTR value = new WCHAR[sizeof(actionItem->option->value) + 1];
wcscpy_s(value, sizeof(actionItem->option->value) + 1, reinterpret_cast(actionItem->option->value));
- SaveKeyboardOptionREGCore(activeKeyboard, reinterpret_cast(actionItem->option->key), value);
+ SaveKeyboardOptionCoretoRegistry(activeKeyboard, reinterpret_cast(actionItem->option->key), value);
}
}
return TRUE;
diff --git a/windows/src/engine/keyman32/preservedkeymap.cpp b/windows/src/engine/keyman32/preservedkeymap.cpp
index cd13a82f8c885a95f3a91a87f08e62c46984e8c6..1fd803838d7aa250eee4a84789b752cf4835b55e 100644
--- a/windows/src/engine/keyman32/preservedkeymap.cpp
+++ b/windows/src/engine/keyman32/preservedkeymap.cpp
@@ -37,12 +37,11 @@ struct PreservedKey
class PreservedKeyMap
{
public:
- BOOL MapKeyboard(KEYBOARD *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys);
/**
* Updates a map of preserved keys (with GUID) that are used in keyboard rules.
* Passing in NULL for pPreservedKeys will cause cPreservedKeys to be set to the number
- * of preserved keys needed for the supplied pKeyboard; this should be used in creating
- * pPreservedKeys list to sufficient size. When pPreservedKeys list is passed the
+ * of preserved keys needed for the supplied pKeyboard; this should be used in creating
+ * pPreservedKeys list to sufficient size. When pPreservedKeys list is passed the
* cPreservedKeys will be the actual count of the number of unique pPreservedKeys
*
* @param pKeyboard the keyboard for which the rules will be extracted from
@@ -50,14 +49,13 @@ public:
* @param cPreservedKeys number of preserved keys in pPreservedKeys - or the size pPreservedKeys needs to be
* @return BOOL return TRUE on success
*/
- BOOL MapKeyboardCore(km_kbp_keyboard *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys);
+ BOOL MapKeyboard(km_kbp_keyboard *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys);
private:
BOOL m_BaseKeyboardUsesAltGr; // I4592
UINT ShiftToTSFShift(UINT ShiftFlags);
BOOL MapUSCharToVK(UINT *puKey, UINT *puShiftFlags);
- BOOL MapKeyRule(KEY *pKey, TF_PRESERVEDKEY *pPreservedKey);
- BOOL MapKeyRuleCore(km_kbp_keyboard_key *pKeyRule, TF_PRESERVEDKEY *pPreservedKey);
+ BOOL MapKeyRule(km_kbp_keyboard_key *pKeyRule, TF_PRESERVEDKEY *pPreservedKey);
BOOL IsMatchingKey(PreservedKey *pKey, PreservedKey *pKeys, size_t cKeys);
};
@@ -199,45 +197,8 @@ UINT PreservedKeyMap::ShiftToTSFShift(UINT ShiftFlags)
return res;
}
-BOOL PreservedKeyMap::MapKeyRule(KEY *pKey, TF_PRESERVEDKEY *pPreservedKey)
-{
- UINT ShiftFlags;
- UINT Key;
-
- Key = pKey->Key;
- ShiftFlags = pKey->ShiftFlags;
-
- if(Key == VK_BACK || Key == VK_RETURN || Key == VK_TAB) // I4575
- {
- //
- // We never map backspace, return or tab because these are the only supported virtual key outputs,
- // and result in recursion. Sadly, this is an imperfect solution forced upon us by preserved key
- // limitations.
- //
- // Other virtual key output will be blocked with this version.
- return FALSE;
- }
-
- if (Key > 255) {
- //
- // Touch-defined keys have a value > 255, but these should never be preserved
- //
- return FALSE;
- }
-
- if(ShiftFlags == 0)
- {
- if(!MapUSCharToVK(&Key, &ShiftFlags)) return FALSE;
- }
-
- pPreservedKey->uVKey = (UINT) USVKToScanCodeToLayoutVK( (WORD) Key); // I3762
- pPreservedKey->uModifiers = ShiftToTSFShift(ShiftFlags);
-
- return TRUE;
-}
-
BOOL
-PreservedKeyMap::MapKeyRuleCore(km_kbp_keyboard_key *pKeyRule, TF_PRESERVEDKEY *pPreservedKey) {
+PreservedKeyMap::MapKeyRule(km_kbp_keyboard_key *pKeyRule, TF_PRESERVEDKEY *pPreservedKey) {
UINT ShiftFlags;
UINT Key;
@@ -280,94 +241,8 @@ BOOL PreservedKeyMap::IsMatchingKey(PreservedKey *pKey, PreservedKey *pKeys, siz
return FALSE;
}
-// TODO: 5442 - Remove once core processor verfied
-BOOL PreservedKeyMap::MapKeyboard(KEYBOARD *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys)
-{
- size_t cKeys = 0, n;
- DWORD i, j;
- GROUP *pGroup;
-
- m_BaseKeyboardUsesAltGr = KeyboardGivesCtrlRAltForRAlt(); // I4592
-
- // This is not the same as m_BaseKeyboardUsesAltGr -- we are turning
- // the simulation back on after (possibly) turning it off, for a
- // consistent experience. TODO: determine if m_BaseKeyboardUseAltGr
- // is still needed given we always use kbdus as base for Keyman 10+
- BOOL bSimulateAltGr = Globals::get_SimulateAltGr();
-
- // We only want to translate RALT and RALT+SHIFT for Ctrl+Alt rules.
- // So we exclude all our other favourite modifier keys.
- const UINT RALT_MATCHING_MASK = TF_MOD_CONTROL | TF_MOD_ALT | TF_MOD_LCONTROL | TF_MOD_RCONTROL | TF_MOD_LALT | TF_MOD_RALT;
-
- for(i = 0; i < pKeyboard->cxGroupArray; i++)
- {
- if(pKeyboard->dpGroupArray[i].fUsingKeys)
- {
- cKeys += pKeyboard->dpGroupArray[i].cxKeyArray;
- }
- }
-
- if(cKeys == 0)
- {
- return FALSE;
- }
-
- if (bSimulateAltGr)
- {
- // We might need twice as many preserved keys to map both LCtrl+LAlt+x and RAlt+x
- cKeys *= 2;
- }
-
- if(pPreservedKeys == NULL)
- {
- *cPreservedKeys = cKeys;
- return TRUE;
- }
-
- if(*cPreservedKeys < cKeys)
- {
- return FALSE;
- }
-
- PreservedKey *pKeys = *pPreservedKeys;
-
- for(n = i = 0; i < pKeyboard->cxGroupArray; i++)
- {
- pGroup = &pKeyboard->dpGroupArray[i];
- if(pGroup->fUsingKeys)
- {
- for(j = 0; j < pGroup->cxKeyArray; j++)
- {
- // If we have a key rule for the key, we should preserve it
- if(MapKeyRule(&pGroup->dpKeyArray[j], &pKeys[n].key))
- {
- // Don't attempt to add the same preserved key twice. Bad things happen
- if(!IsMatchingKey(&pKeys[n], pKeys, n))
- {
- CoCreateGuid(&pKeys[n].guid);
- n++;
-
- if (bSimulateAltGr && (pKeys[n-1].key.uModifiers & RALT_MATCHING_MASK) == TF_MOD_RALT)
- {
- // Do this for RALT and RALT+SHIFT only, so we've tested against that mask
- // Copy the key and fix modifiers
- pKeys[n].key = pKeys[n - 1].key;
- pKeys[n].key.uModifiers = (pKeys[n].key.uModifiers & ~TF_MOD_RALT) | TF_MOD_LCONTROL | TF_MOD_LALT;
- CoCreateGuid(&pKeys[n].guid);
- n++;
- }
- }
- }
- }
- }
- }
-
- *cPreservedKeys = n; // return actual count of allocated keys, usually smaller than allocated count
- return TRUE;
-}
-
BOOL
-PreservedKeyMap::MapKeyboardCore(km_kbp_keyboard *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys) {
+PreservedKeyMap::MapKeyboard(km_kbp_keyboard *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys) {
size_t cKeys = 0, cRules = 0, n = 0;
DWORD i;
@@ -422,7 +297,7 @@ PreservedKeyMap::MapKeyboardCore(km_kbp_keyboard *pKeyboard, PreservedKey **pPre
for (i = 0; i < cRules; i++) {
// If we have a key rule for the key, we should preserve it
- if (MapKeyRuleCore(&kb_key_list[i], &pKeys[n].key)) {
+ if (MapKeyRule(&kb_key_list[i], &pKeys[n].key)) {
// Don't attempt to add the same preserved key twice. Bad things happen
if (!IsMatchingKey(&pKeys[n], pKeys, n)) {
CoCreateGuid(&pKeys[n].guid);
@@ -457,23 +332,14 @@ extern "C" __declspec(dllexport) BOOL WINAPI GetKeyboardPreservedKeys(PreservedK
if (!_td) {
return FALSE;
}
+
if (!_td->lpActiveKeyboard) {
return FALSE;
}
- // It could be an active core keyboard
- if (Globals::get_CoreIntegration()) {
- if (!_td->lpActiveKeyboard->lpCoreKeyboard) {
- return FALSE;
- }
- // use api to get key rules
- return pkm.MapKeyboardCore(_td->lpActiveKeyboard->lpCoreKeyboard, pPreservedKeys, cPreservedKeys);
-
- } else { // TODO: 5442 Remove else
- if (!_td->lpActiveKeyboard->Keyboard) {
- return FALSE;
- }
- return pkm.MapKeyboard(_td->lpActiveKeyboard->Keyboard, pPreservedKeys, cPreservedKeys);
+ if (!_td->lpActiveKeyboard->lpCoreKeyboard) {
+ return FALSE;
}
-
+ // use api to get key rules
+ return pkm.MapKeyboard(_td->lpActiveKeyboard->lpCoreKeyboard, pPreservedKeys, cPreservedKeys);
}
diff --git a/windows/src/engine/keyman32/selectkeyboard.cpp b/windows/src/engine/keyman32/selectkeyboard.cpp
index ae6f366f3fa39be1181908fed1d3097f2a035816..0ca9e2e65f77ae37750053cefaac2c35549da108 100644
--- a/windows/src/engine/keyman32/selectkeyboard.cpp
+++ b/windows/src/engine/keyman32/selectkeyboard.cpp
@@ -53,7 +53,7 @@
// I3594 // I4220
-BOOL SelectKeyboardCore(DWORD KeymanID)
+BOOL SelectKeyboard(DWORD KeymanID)
{
int i;
HWND hwnd = GetFocus();
@@ -71,14 +71,9 @@ BOOL SelectKeyboardCore(DWORD KeymanID)
__try
{
- if (_td->ForceFileName[0])
- {
- SendDebugMessageFormat(hwnd, sdmGlobal, 0, "SelectKeyboard: Ignored due to ForceFile");
- return FALSE; // Keyboard file is force-loaded
- }
KMHideIM();
-
+
if (_td->lpActiveKeyboard) DeactivateDLLs(_td->lpActiveKeyboard);
_td->lpActiveKeyboard = NULL;
_td->ActiveKeymanID = KEYMANID_NONKEYMAN;
@@ -101,12 +96,13 @@ BOOL SelectKeyboardCore(DWORD KeymanID)
SendDebugMessageFormat(hwnd, sdmGlobal, 0, "SelectKeyboardCore: NewKeymanID: %x", _td->ActiveKeymanID);
if (_td->app) _td->app->ResetContext();
- ResetCapsLock();
+
+ // TODO: #5822 tell the core with km_kbp_event so it can reset the capslock state
SelectApplicationIntegration(); // I4287
if (_td->app && !_td->app->IsWindowHandled(hwnd)) _td->app->HandleWindow(hwnd);
_td->state.windowunicode = !_td->app || _td->app->IsUnicode();
-
+
ActivateDLLs(_td->lpActiveKeyboard);
return TRUE;
@@ -130,88 +126,6 @@ BOOL SelectKeyboardCore(DWORD KeymanID)
return TRUE;
}
-BOOL SelectKeyboard(DWORD KeymanID)
-{
- if (Globals::get_CoreIntegration())
- {
- return SelectKeyboardCore(KeymanID);
- }
- int i;
- HWND hwnd = GetFocus();
-
- PKEYMAN64THREADDATA _td = ThreadGlobals();
- if(!_td) return FALSE;
-
- SendDebugMessageFormat(hwnd,sdmGlobal,0,"ENTER SelectKeyboard-------------------------------------------");
- SendDebugMessageFormat(hwnd,sdmGlobal,0,"ENTER SelectKeyboard: Current:(HKL=%x KeymanID=%x %s) New:(ID=%x)", //lpActiveKeyboard=%s ActiveKeymanID: %x sk: %x KeymanID: %d",
- GetKeyboardLayout(0),
- _td->ActiveKeymanID,
- _td->lpActiveKeyboard == NULL ? "NULL" : _td->lpActiveKeyboard->Name,
- //_td->NextKeyboardLayout,
- KeymanID);
-
- __try
- {
- if(_td->ForceFileName[0])
- {
- SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: Ignored due to ForceFile");
- return FALSE; // Keyboard file is force-loaded
- }
-
- KMHideIM();
-
- if(_td->lpActiveKeyboard) DeactivateDLLs(_td->lpActiveKeyboard);
- _td->lpActiveKeyboard = NULL;
- _td->ActiveKeymanID = KEYMANID_NONKEYMAN;
-
- //SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: nKeyboards=%d", nKeyboards);
-
- for(i = 0; i < _td->nKeyboards; i++)
- {
- if(_td->lpKeyboards[i].KeymanID == KeymanID)
- {
- if(!_td->lpKeyboards[i].Keyboard && !LoadlpKeyboard(i))
- {
- SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: Unable to load");
- return TRUE;
- }
-
- _td->lpActiveKeyboard = &_td->lpKeyboards[i];
- _td->ActiveKeymanID = _td->lpActiveKeyboard->KeymanID;
-
- SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: NewKeymanID: %x", _td->ActiveKeymanID);
-
- if(_td->app) _td->app->ResetContext();
- ResetCapsLock();
-
- SelectApplicationIntegration(); // I4287
- if(_td->app && !_td->app->IsWindowHandled(hwnd)) _td->app->HandleWindow(hwnd);
- _td->state.windowunicode = !_td->app || _td->app->IsUnicode();
-
- ActivateDLLs(_td->lpActiveKeyboard);
-
- return TRUE;
- }
- }
-
- if(IsFocusedThread())
- {
- SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: Keyboard Not Found");
- }
- }
- __finally
- {
- SendDebugMessageFormat(hwnd,sdmGlobal,0,"EXIT SelectKeyboard: Current:(HKL=%x KeymanID=%x %s) New:(ID=%x)", //lpActiveKeyboard=%s ActiveKeymanID: %x sk: %x KeymanID: %d",
- GetKeyboardLayout(0),
- _td->ActiveKeymanID,
- _td->lpActiveKeyboard == NULL ? "NULL" : _td->lpActiveKeyboard->Name,
- KeymanID);
- SendDebugMessageFormat(hwnd,sdmGlobal,0,"EXIT SelectKeyboard-------------------------------------------");
- }
- return TRUE;
-}
-
-
BOOL SelectKeyboardTSF(DWORD dwIdentity, BOOL foreground) // I3933 // I3949 // I4271
{
if (!foreground && IsFocusedThread()) {
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 4a16621ee881fcec9fe8aa592edc8d51b5739c3a..795f89fe447c7029fcafc802afaeb648f6aac7be 100644
--- a/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp
+++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp
@@ -5,77 +5,6 @@
#include
#include
-// Test UpdateKeyboardOptionsCore, also uses SaveKeyboardOptionsCore
-TEST(KEYBOARDOPTIONS, UpdateKeyboardOptionsCore) {
- LPINTKEYBOARDINFO kp = new INTKEYBOARDINFO;
- memset(kp, 0, sizeof(INTKEYBOARDINFO));
-
- km_kbp_option_item test_env_opts[] = {
- {u"__test_point", u"not tiggered", KM_KBP_OPT_KEYBOARD}, {u"hello", u"-", KM_KBP_OPT_ENVIRONMENT}, KM_KBP_OPTIONS_END};
-
- km_kbp_path_name dummyPath = L"dummyActions.mock";
- EXPECT_EQ(km_kbp_keyboard_load(dummyPath, &kp->lpCoreKeyboard), KM_KBP_STATUS_OK);
- EXPECT_EQ(km_kbp_state_create(kp->lpCoreKeyboard, test_env_opts, &kp->lpCoreKeyboardState), KM_KBP_STATUS_OK);
-
- kp->lpCoreKeyboardOptions = SaveKeyboardOptionsCore(kp);
- // No Change
- EXPECT_FALSE(UpdateKeyboardOptionsCore(kp->lpCoreKeyboardState, kp->lpCoreKeyboardOptions));
- std::u16string value = kp->lpCoreKeyboardOptions[0].value;
- std::u16string expectedValue = u"not tiggered";
- EXPECT_TRUE(value == expectedValue);
-
- km_kbp_option_item update_key_opts[] = {{u"__test_point", u"triggered", KM_KBP_OPT_KEYBOARD}, KM_KBP_OPTIONS_END};
- EXPECT_EQ(km_kbp_state_options_update(kp->lpCoreKeyboardState, update_key_opts), KM_KBP_STATUS_OK);
- // Change value to triggered
- EXPECT_TRUE(UpdateKeyboardOptionsCore(kp->lpCoreKeyboardState, kp->lpCoreKeyboardOptions));
- value = kp->lpCoreKeyboardOptions[0].value;
- expectedValue = u"triggered";
- EXPECT_TRUE(value == expectedValue);
- DisposeKeyboardOptionsCore(&kp->lpCoreKeyboardOptions);
- ReleaseStateMemoryCore(&kp->lpCoreKeyboardState);
- ReleaseKeyboardMemoryCore(&kp->lpCoreKeyboard);
- delete kp;
-
-}
-
-// Test SaveKeyboardOptionsCore and RestoreKeyboardOptionsCORE
-TEST(KEYBOARDOPTIONS, SaveRestoreKeyboardOptionsCore) {
-
- LPINTKEYBOARDINFO kp = new INTKEYBOARDINFO;
- memset(kp, 0, sizeof(INTKEYBOARDINFO));
-
- km_kbp_option_item test_env_opts[] = {
- {u"__test_point", u"not tiggered", KM_KBP_OPT_KEYBOARD}, {u"hello", u"-", KM_KBP_OPT_ENVIRONMENT}, KM_KBP_OPTIONS_END};
- km_kbp_path_name dummyPath = L"dummyActions.mock";
- EXPECT_EQ(km_kbp_keyboard_load(dummyPath, &kp->lpCoreKeyboard), KM_KBP_STATUS_OK);
- EXPECT_EQ(km_kbp_state_create(kp->lpCoreKeyboard, test_env_opts, &kp->lpCoreKeyboardState), KM_KBP_STATUS_OK);
-
- km_kbp_option_item *SavedKBDOptions = SaveKeyboardOptionsCore(kp);
-
- std::u16string value = SavedKBDOptions[0].value;
- std::u16string expectedValue = u"not tiggered";
- km_kbp_option_item update_key_opts[] = {{u"__test_point", u"triggered", KM_KBP_OPT_KEYBOARD}, KM_KBP_OPTIONS_END};
- EXPECT_EQ(km_kbp_state_options_update(kp->lpCoreKeyboardState, update_key_opts), KM_KBP_STATUS_OK);
-
- km_kbp_option_item *NewKBDOptions = SaveKeyboardOptionsCore(kp);
- value = NewKBDOptions[0].value;
- expectedValue = u"triggered";
- EXPECT_TRUE(value == expectedValue);
- km_kbp_cp const *retValue = nullptr;
- EXPECT_TRUE(RestoreKeyboardOptionsCore(kp->lpCoreKeyboardState, SavedKBDOptions));
- EXPECT_EQ(km_kbp_state_option_lookup(kp->lpCoreKeyboardState, KM_KBP_OPT_KEYBOARD, test_env_opts[0].key, &retValue), KM_KBP_STATUS_OK);
-
- value = retValue;
- expectedValue = u"not tiggered";
- EXPECT_TRUE(value == expectedValue);
-
- DisposeKeyboardOptionsCore(&NewKBDOptions);
- DisposeKeyboardOptionsCore(&SavedKBDOptions);
-
- ReleaseStateMemoryCore(&kp->lpCoreKeyboardState);
- ReleaseKeyboardMemoryCore(&kp->lpCoreKeyboard);
- delete kp;
-}
// Test SetupCoreEnvironment and also test km_kbp_state_options_update
TEST(KEYBOARDOPTIONS, SetupCoreEnvironment) {
diff --git a/windows/src/engine/keyman64/keyman64.vcxproj b/windows/src/engine/keyman64/keyman64.vcxproj
index d70c0872eddcfa111f582c87c43c021ccb7c9c63..15546caef5b0022e0d61e337ed041c3e481ab053 100644
--- a/windows/src/engine/keyman64/keyman64.vcxproj
+++ b/windows/src/engine/keyman64/keyman64.vcxproj
@@ -177,7 +177,6 @@
-
@@ -279,7 +278,6 @@
-
diff --git a/windows/src/engine/keyman64/keyman64.vcxproj.filters b/windows/src/engine/keyman64/keyman64.vcxproj.filters
index 0b53bd96cbaf397e58d5a3bc208a73496baabbd9..cd8aeefb322143e5ecef53a8b55e11e15c3d6c88 100644
--- a/windows/src/engine/keyman64/keyman64.vcxproj.filters
+++ b/windows/src/engine/keyman64/keyman64.vcxproj.filters
@@ -2,7 +2,6 @@
-
@@ -41,7 +40,6 @@
-
diff --git a/windows/src/engine/kmtip/keys.cpp b/windows/src/engine/kmtip/keys.cpp
index d5d4882ca586f84ed8c590b727b4cc0159f6bfa1..9f1552f4e30e4883a347ac8426c84720624b5bdc 100644
--- a/windows/src/engine/kmtip/keys.cpp
+++ b/windows/src/engine/kmtip/keys.cpp
@@ -362,36 +362,3 @@ STDMETHODIMP CKMTipTextService::OnPreservedKey(ITfContext *pContext, REFGUID rgu
*pfEaten = FALSE;
return S_OK;
}
-
-BOOL CKMTipTextService::DoRefreshPreservedKeys(BOOL Activating) {
- LogEnter();
- ITfKeystrokeMgr *pKeystrokeMgr;
- HRESULT hr = S_OK;
-
- Log(L"CKMTipTextService::DoRefreshPreservedKeys");
-
- if (!_pThreadMgr) {
- return FALSE;
- }
-
- if (_pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr, (void **)&pKeystrokeMgr) != S_OK) {
- return FALSE;
- }
-
- _UnpreserveAltKeys(pKeystrokeMgr);
- if (Activating) {
- hr = _PreserveAltKeys(pKeystrokeMgr); // I3588
- }
-
- pKeystrokeMgr->Release();
-
- return (hr == S_OK);
-}
-
-__declspec(dllexport) BOOL WINAPI RefreshPreservedKeys(BOOL Activating) {
- LogEnter();
- if (CKMTipTextService::ThreadThis) {
- return CKMTipTextService::ThreadThis->DoRefreshPreservedKeys(Activating);
- }
- return FALSE;
-}
diff --git a/windows/src/engine/kmtip/kmtip.def b/windows/src/engine/kmtip/kmtip.def
index 64c10743c23a56877be1792f37de6210798adb23..854f6b6ca5042a89711519a42e0b9b330eb7a98c 100644
--- a/windows/src/engine/kmtip/kmtip.def
+++ b/windows/src/engine/kmtip/kmtip.def
@@ -5,5 +5,4 @@ EXPORTS
DllCanUnloadNow PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
- RefreshPreservedKeys
Keyman_Diagnostic
diff --git a/windows/src/engine/kmtip/kmtip.h b/windows/src/engine/kmtip/kmtip.h
index aabe098b8b6bb11877d2aeffd95df5fe92b2a601..3ab425891df64c53f02cf7379495a65f57aa3bef 100644
--- a/windows/src/engine/kmtip/kmtip.h
+++ b/windows/src/engine/kmtip/kmtip.h
@@ -1,18 +1,18 @@
/*
Name: kmtip
Copyright: Copyright (C) SIL International.
- Documentation:
+ Documentation:
Description: CKMTipTextService declaration.
Create Date: 7 Sep 2009
Modified Date: 27 Jan 2015
Authors: mcdurdin
- Related Files:
- Dependencies:
+ Related Files:
+ Dependencies:
- Bugs:
- Todo:
- Notes:
+ Bugs:
+ Todo:
+ Notes:
History: 07 Sep 2009 - mcdurdin - I2095 - TSF addin is not threadsafe
01 May 2014 - mcdurdin - I4216 - V9.0 - Keyman TIP should use ITfTextInputProcessorEx
16 Jun 2014 - mcdurdin - I4274 - V9.0 - kmtip does not work if already active before KM starts
@@ -88,8 +88,6 @@ public:
BOOL TIPNotifyActivate(GUID *guidProfile);
- BOOL DoRefreshPreservedKeys(BOOL Activating);
-
static __declspec(thread) CKMTipTextService *ThreadThis;
private:
@@ -107,7 +105,7 @@ private:
void _UninitKeyman();
void _TryAndStartKeyman();
-
+
HRESULT _UnpreserveAltKeys(ITfKeystrokeMgr *pKeystrokeMgr);
// Keyman interfaces
diff --git a/windows/src/global/delphi/general/keyman32_int.pas b/windows/src/global/delphi/general/keyman32_int.pas
deleted file mode 100644
index decebd7bdb754dc5b4fee74fb73e0602ab9a2d96..0000000000000000000000000000000000000000
--- a/windows/src/global/delphi/general/keyman32_int.pas
+++ /dev/null
@@ -1,184 +0,0 @@
-(*
- Name: keyman32_int
- Copyright: Copyright (C) SIL International.
- Documentation:
- Description:
- Create Date: 1 Aug 2006
-
- Modified Date: 17 Aug 2012
- Authors: mcdurdin
- Related Files:
- Dependencies:
-
- Bugs:
- Todo:
- Notes:
- History: 01 Aug 2006 - mcdurdin - Add GetKeymanInstallPath function
- 14 Sep 2006 - mcdurdin - Retrieve Debug_Keyman32 path if assigned
- 18 Mar 2011 - mcdurdin - I2825 - Debug_Keyman32 override not working correctly
- 03 May 2011 - mcdurdin - I2890 - Record diagnostic data when encountering registry errors
- 17 Aug 2012 - mcdurdin - I3310 - V9.0 - Unicode in Delphi fixes
-*)
-unit keyman32_int;
-
-interface
-
-uses Windows, SysUtils, Forms, ErrorControlledRegistry, RegistryKeys; //, util;
-
-function Keyman_Initialise(Handle: HWND; FSingleApp: Boolean): Boolean;
-function Keyman_Exit: Boolean;
-function Keyman_ForceKeyboard(const s: string): Boolean;
-function Keyman_StopForcingKeyboard: Boolean;
-
-implementation
-
-uses DebugPaths, Dialogs, KLog;
-
-type TKeyman_ForceKeyboard = function (s: PAnsiChar): Boolean; stdcall; // I3310
-type TKeyman_StopForcingKeyboard = function: Boolean; stdcall;
-type TKeyman_Initialise = function(h: THandle; FSingleApp: LongBool): Boolean; stdcall;
-type TKeyman_Exit = function: Boolean; stdcall;
-
-var
- FInitKeyman: Boolean = False;
- FKeyman32Path: string = '';
-
-function GetKeymanInstallPath: string;
-var
- RootPath: string;
-begin
- RootPath := '';
- with TRegistryErrorControlled.Create do // I2890
- try
- RootKey := HKEY_LOCAL_MACHINE;
- if OpenKeyReadOnly(SRegKey_KeymanEngine_LM) and ValueExists(SRegValue_RootPath) then
- RootPath := ReadString(SRegValue_RootPath);
- finally
- Free;
- end;
-
- RootPath := GetDebugPath('Debug_Keyman32Path', RootPath); // I2825
-
- if RootPath = '' then
- begin
- RootPath := ExtractFilePath(ParamStr(0));
- end;
-
- Result := IncludeTrailingPathDelimiter(RootPath);
-
- if not FileExists(Result + 'keyman32.dll') then
- raise Exception.Create( 'The executable keyman32.dll could not '+
- 'be found. You should reinstall.');
-end;
-
-function Keyman_Initialise(Handle: HWND; FSingleApp: Boolean): Boolean;
-var
- hkeyman: THandle;
- FLoad: Boolean;
- ki: TKeyman_Initialise;
- s: string;
-begin
- Result := False;
- FLoad := False;
- hkeyman := GetModuleHandle('keyman32.dll');
- if hkeyman = 0 then
- begin
- s := GetKeymanInstallPath;
- hkeyman := LoadLibrary(PChar(s+'keyman32.dll'));
- if hkeyman = 0 then
- begin
- KL.LogError('Keyman_Initialise: Unable to load '+s+'keyman32.dll: '+SysErrorMessage(GetLastError));
- Exit;
- end;
- KL.Log('Keyman_Initialise: Loaded keyman32.dll');
- FLoad := True;
- end
- else
- KL.Log('Keyman_Initialise: Found keyman32.dll already loaded');
- ki := TKeyman_Initialise(GetProcAddress(hkeyman, 'Keyman_Initialise'));
- if not Assigned(@ki) then
- begin
- KL.LogError('Keyman_Initialise: Unable to find Keyman_Initialise in '+s+'keyman32.dll: '+SysErrorMessage(GetLastError));
- if FLoad then FreeLibrary(hkeyman);
- Exit;
- end;
- if not ki(Handle, FSingleApp) then
- begin
- KL.LogError('Keyman_Initialise: Call to Keyman_Initialise in '+s+'keyman32.dll failed: '+SysErrorMessage(GetLastError));
- if FLoad then FreeLibrary(hkeyman);
- Exit;
- end;
-
- KL.Log('Keyman_Initialise: Loaded successfully');
- FInitKeyman := True;
- Result := True;
-end;
-
-function Keyman_Exit: Boolean;
-var
- hkeyman: THandle;
- ke: TKeyman_Exit;
-begin
- if not FInitKeyman then
- begin
- Result := True;
- Exit;
- end;
- Result := False;
- hkeyman := GetModuleHandle('keyman32.dll');
- if hkeyman = 0 then Exit;
- ke := TKeyman_Exit(GetProcAddress(hkeyman, 'Keyman_Exit'));
- if not Assigned(@ke) then Exit;
- if not ke then Exit;
- if FInitKeyman then FreeLibrary(hkeyman);
- FInitKeyman := False;
- Result := True;
-end;
-
-function Keyman_ForceKeyboard(const s: string): Boolean;
-var
- hkeyman: THandle;
- fk: TKeyman_ForceKeyboard;
-begin
- Result := False;
- hkeyman := GetModuleHandle('keyman32.dll');
- if hkeyman = 0 then
- begin
- KL.Log('Keyman_ForceKeyboard: Attempting to load keyman32.dll');
- if not Keyman_Initialise(Application.MainForm.Handle, True) then
- begin
- KL.LogError('Keyman_ForceKeyboard: Unable to load keyman32.dll');
- Exit;
- end;
- hkeyman := GetModuleHandle('keyman32.dll');
- if hkeyman = 0 then Exit;
- end;
- fk := TKeyman_ForceKeyboard(GetProcAddress(hkeyman, 'Keyman_ForceKeyboard'));
- if(Assigned(@fk)) then
- begin
- Result := fk(PAnsiChar(AnsiString(s))); // todo: k9: unicode // I3310
- if not Result then KL.LogError('Keyman_ForceKeyboard in keyman32.dll failed: '+s)
- else KL.Log('Keyman_ForceKeyboard: success');
- end
- else
- KL.LogError('Keyman_ForceKeyboard: failed to find Keyman_ForceKeyboard in keyman32.dll');
-end;
-
-function Keyman_StopForcingKeyboard: Boolean;
-var
- hkeyman: THandle;
- sfk: TKeyman_StopForcingKeyboard;
-begin
- Result := False;
- hkeyman := GetModuleHandle('keyman32.dll');
- if hkeyman = 0 then Exit;
- sfk := TKeyman_StopForcingKeyboard(GetProcAddress(hkeyman, 'Keyman_StopForcingKeyboard'));
- if(Assigned(@sfk)) then
- Result := sfk;
-end;
-
-initialization
-finalization
- Keyman_Exit;
-end.
-
diff --git a/windows/src/support/Makefile b/windows/src/support/Makefile
index 7f624d29f41a45544cbd88e8f5f07b8fc82696d2..56609e21e48831b4ab4ce85a28a353e6089537fb 100644
--- a/windows/src/support/Makefile
+++ b/windows/src/support/Makefile
@@ -3,9 +3,9 @@
#
!ifdef NODELPHI
-TARGETS=etl2log
+TARGETS=etl2log texteditor
!else
-TARGETS=oskbulkrenderer etl2log
+TARGETS=oskbulkrenderer etl2log texteditor
!endif
CLEANS=clean-support
@@ -21,6 +21,10 @@ etl2log: .virtual
cd $(ROOT)\src\support\etl2log
$(MAKE) $(TARGET)
+texteditor: .virtual
+ cd $(ROOT)\src\support\texteditor
+ $(MAKE) $(TARGET)
+
# ----------------------------------------------------------------------
clean-support:
diff --git a/windows/src/support/texteditor/Makefile b/windows/src/support/texteditor/Makefile
index a9fa1b1cd225a6f04c29a2e23ecedc7b2ac336f7..473bf57598e68dac99e4a5bab9602ee9724802bf 100644
--- a/windows/src/support/texteditor/Makefile
+++ b/windows/src/support/texteditor/Makefile
@@ -8,9 +8,9 @@ build:
$(MSBUILD) editor.vcxproj $(MSBUILD_BUILD) /p:Platform=x86
$(MSBUILD) editor.vcxproj $(MSBUILD_BUILD) /p:Platform=x64
$(COPY) $(WIN32_TARGET_PATH)\editor32.exe $(PROGRAM)\support
- $(COPY) $(WIN32_TARGET_PATH)\editor32.pdb $(PROGRAM)\support
+ $(COPY) $(WIN32_TARGET_PATH)\editor32.pdb $(DEBUGPATH)\support
$(COPY) $(X64_TARGET_PATH)\editor64.exe $(PROGRAM)\support
- $(COPY) $(X64_TARGET_PATH)\editor64.pdb $(PROGRAM)\support
+ $(COPY) $(X64_TARGET_PATH)\editor64.pdb $(DEBUGPATH)\support
clean: def-clean
$(MSBUILD) $(MSBUILD_CLEAN) editor.sln
@@ -23,6 +23,12 @@ install:
$(COPY) $(PROGRAM)\support\editor32.exe "$(INSTALLPATH_KEYMANENGINE)"
$(COPY) $(PROGRAM)\support\editor64.exe "$(INSTALLPATH_KEYMANENGINE)"
+wrap-symbols:
+ $(SYMSTORE) $(PROGRAM)\support\editor32.exe /t keyman-windows
+ $(SYMSTORE) $(PROGRAM)\support\editor64.exe /t keyman-windows
+ $(SYMSTORE) $(DEBUGPATH)\support\editor32.pdb /t keyman-windows
+ $(SYMSTORE) $(DEBUGPATH)\support\editor64.pdb /t keyman-windows
+
!include ..\..\Target.mak
# ----------------------------------------------------------------------