From 65335ecaf5057c234816c8fcd1c9aa4f8b2955ed Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Fri, 24 Jul 2026 12:07:22 +1000 Subject: [PATCH 01/26] fix(windows): initial commit --- windows/src/desktop/kmshell/main/UfrmMain.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/windows/src/desktop/kmshell/main/UfrmMain.pas b/windows/src/desktop/kmshell/main/UfrmMain.pas index 6a631fb546..a469db480c 100644 --- a/windows/src/desktop/kmshell/main/UfrmMain.pas +++ b/windows/src/desktop/kmshell/main/UfrmMain.pas @@ -661,6 +661,8 @@ end; procedure TfrmMain.Options_BaseKeyboard; // I4169 begin + // TODO change this dialog to run as current user and elevate on "ok" button:wq + WaitForElevatedConfiguration(Handle, '-basekeyboard'); // Refresh will be triggered by elevated process end; From 92643e35692c0678153472cb6a33a11427a1c288 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Wed, 29 Jul 2026 14:47:00 +1000 Subject: [PATCH 02/26] fix(windows): handle basekeyboard change non-admin user --- .../desktop/kmshell/main/UfrmBaseKeyboard.pas | 135 ++++++++++++++++-- windows/src/desktop/kmshell/main/UfrmMain.pas | 11 +- windows/src/desktop/kmshell/main/initprog.pas | 16 ++- .../com/keyboards/keymankeyboardinstalled.pas | 6 +- .../kmcomapi/com/options/keymanoptions.pas | 24 ++-- .../processes/keyboard/kpinstallkeyboard.pas | 5 +- .../keyboard/kprecompilemnemonickeyboard.pas | 10 +- .../kmcomapi/util/internalinterfaces.pas | 2 +- 8 files changed, 174 insertions(+), 35 deletions(-) diff --git a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas index 40a65e31ce..b3f60a5067 100644 --- a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas @@ -11,13 +11,16 @@ type TfrmBaseKeyboard = class(TfrmWebContainer) procedure TntFormCreate(Sender: TObject); private + FBaseKeyboardID: Integer; procedure Footer_Cancel; procedure Footer_OK(params: TStringList); protected procedure FireCommand(const command: WideString; params: TStringList); override; end; -function ConfigureBaseKeyboard: Boolean; +function ConfigureBaseKeyboard(out BaseKeyboardID: Integer): Boolean; +function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolean; +function MCompileBaseKeyboard(const BaseKeyboardIDText: string): Boolean; implementation @@ -25,15 +28,18 @@ implementation uses BaseKeyboards, - kmint; + ErrorControlledRegistry, + RegistryKeys, + keymanapi_TLB, + kmint, + utilkmshell; -function ConfigureBaseKeyboard: Boolean; -begin - with TfrmBaseKeyboard.Create(nil) do +function ConfigureBaseKeyboard(out BaseKeyboardID: Integer): Boolean; +begin with TfrmBaseKeyboard.Create(nil) do try Result := ShowModal = mrOk; if Result then - kmcom.Apply; + BaseKeyboardID := FBaseKeyboardID; finally Free; end; @@ -65,9 +71,122 @@ var v: Integer; begin if not TryStrToInt('$'+params.Values['id'], v) then Exit; - kmcom.Options['koBaseLayout'].Value := v; - kmcom.Options.Apply; + FBaseKeyboardID := v; ModalResult := mrOk; end; +function MCompileBaseKeyboard(const BaseKeyboardIDText: string): Boolean; +var + BaseKeyboardID: Integer; + PreviousBaseKeyboardID: Integer; + PreviousBaseKeyboardValue: string; + PreviousBaseKeyboardValueExists: Boolean; + + procedure SavePreviousRegistryBaseKeyboardValue; + var + Reg: TRegistryErrorControlled; + begin + PreviousBaseKeyboardValueExists := False; + PreviousBaseKeyboardValue := ''; + + Reg := TRegistryErrorControlled.Create; + try + if Reg.OpenKeyReadOnly(SRegKey_KeymanEngine_CU) and Reg.ValueExists(SRegValue_UnderlyingLayout) then + begin + PreviousBaseKeyboardValueExists := True; + PreviousBaseKeyboardValue := Reg.ReadString(SRegValue_UnderlyingLayout); + end; + finally + Reg.Free; + end; + end; + + procedure RestorePreviousBaseKeyboardValue; + var + Reg: TRegistryErrorControlled; + begin + Reg := TRegistryErrorControlled.Create; + try + if Reg.OpenKey(SRegKey_KeymanEngine_CU, True) then + if PreviousBaseKeyboardValueExists then + Reg.WriteString(SRegValue_UnderlyingLayout, PreviousBaseKeyboardValue) + else if Reg.ValueExists(SRegValue_UnderlyingLayout) then + Reg.DeleteValue(SRegValue_UnderlyingLayout); + finally + Reg.Free; + end; + end; + + procedure ForceBaseLayoutChange; + var + Reg: TRegistryErrorControlled; + begin + // This is hacky, maybe just remove the registry value, however that + // would not force a recompile if the was the default base layout. + // Options.Apply re-compiles only when it observes a changed base layout. + // The caller may be repairing missing files for the already-selected layout. + Reg := TRegistryErrorControlled.Create; + try + if Reg.OpenKey(SRegKey_KeymanEngine_CU, True) then + Reg.WriteString(SRegValue_UnderlyingLayout, '00000000'); + finally + Reg.Free; + end; + end; + +begin + Result := False; + if not TryStrToInt('$' + BaseKeyboardIDText, BaseKeyboardID) or + not kmcom.SystemInfo.IsAdministrator then + Exit; + + SavePreviousRegistryBaseKeyboardValue; + PreviousBaseKeyboardID := kmcom.Options['koBaseLayout'].Value; + kmcom.Options['koBaseLayout'].Value := BaseKeyboardID; + try + if PreviousBaseKeyboardID = BaseKeyboardID then + ForceBaseLayoutChange; + kmcom.Options.Apply; + Result := True; + finally + kmcom.Options['koBaseLayout'].Value := PreviousBaseKeyboardID; + RestorePreviousBaseKeyboardValue; + end; +end; + +function BaseKeyboardNeedsMCompile(BaseKeyboardID: Integer): Boolean; +var + I: Integer; + Keyboard: IKeymanKeyboardInstalled; + BaseFileName: string; + BaseKeyboardIDHex: string; +begin + BaseKeyboardIDHex := IntToHex(BaseKeyboardID, 8); + for I := 0 to kmcom.Keyboards.Count - 1 do + begin + Keyboard := kmcom.Keyboards.Items[I]; + BaseFileName := Keyboard.Filename; + if FileExists(BaseFileName) and + (not FileExists(ChangeFileExt(BaseFileName, '') + '-' + BaseKeyboardIDHex + '.kmx') or + not FileExists(ChangeFileExt(BaseFileName, '') + '-' + BaseKeyboardIDHex + '-d.kmx')) then + Exit(True); + end; + Result := False; +end; + +function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolean; +var + MCompileResult: Boolean; +begin + MCompileResult := True; + Result := False; + if BaseKeyboardNeedsMCompile(BaseKeyboardID) and not kmcom.SystemInfo.IsAdministrator then + MCompileResult := WaitForElevatedConfiguration(WindowHandle, '-mcompile ' + IntToHex(BaseKeyboardID, 8)) = 0; + if not MCompileResult then + Exit; + kmcom.Options['koBaseLayout'].Value := BaseKeyboardID; + kmcom.Options.Apply; // This will trigger a recompile if needed + Result := True; +end; + end. diff --git a/windows/src/desktop/kmshell/main/UfrmMain.pas b/windows/src/desktop/kmshell/main/UfrmMain.pas index a469db480c..a556019abd 100644 --- a/windows/src/desktop/kmshell/main/UfrmMain.pas +++ b/windows/src/desktop/kmshell/main/UfrmMain.pas @@ -197,6 +197,7 @@ uses Keyman.Configuration.UI.UfrmStartInstall, RegistryKeys, SupportXMLRenderer, + UfrmBaseKeyboard, UfrmChangeHotkey, UfrmHTML, UfrmInstallKeyboardFromWeb, @@ -660,11 +661,15 @@ end; ------------------------------------------------------------------------------} procedure TfrmMain.Options_BaseKeyboard; // I4169 +var + BaseKeyboardID: Integer; begin - // TODO change this dialog to run as current user and elevate on "ok" button:wq + if ConfigureBaseKeyboard(BaseKeyboardID) then + begin + SetBaseKeyboard(Handle, BaseKeyboardID) + // Refresh will be triggered by elevated process + end; - WaitForElevatedConfiguration(Handle, '-basekeyboard'); - // Refresh will be triggered by elevated process end; procedure TfrmMain.Options_SettingsManager; diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas index 359130f27e..8ea4331995 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -90,6 +90,7 @@ type fmKeyboardWelcome, // I2569 fmKeyboardPrint, // I2329 fmBaseKeyboard, // I4169 + fmMCompile, fmUpgradeMnemonicLayout, // I4553 fmRepair, fmKeepInTouch, @@ -262,6 +263,13 @@ begin else if s = '-bd' then FMode := fmBackgroundDownload else if s = '-an' then FMode := fmApplyInstallNow else if s = '-basekeyboard' then FMode := fmBaseKeyboard // I4169 + else if s = '-mcompile' then + begin + FMode := fmMCompile; + Inc(i); + if i > ParamCount then Exit; + FQuery := ParamStr(i); + end else if s = '-nowelcome' then FNoWelcome := True else if s = '-kw' then FMode := fmKeyboardWelcome // I2569 else if s = '-kp' then FMode := fmKeyboardPrint // I2329 @@ -393,6 +401,7 @@ var kdl: IKeymanDefaultLanguage; FIcon: string; FMutex: TKeymanMutex; // I2720 + BaseKeyboardID: Integer; function FirstKeyboardFileName: WideString; begin if KeyboardFileNames.Count = 0 @@ -540,7 +549,12 @@ begin end; fmBaseKeyboard: // I4169 - if ConfigureBaseKeyboard + if ConfigureBaseKeyboard(BaseKeyboardID) and SetBaseKeyboard(0, BaseKeyboardID) + then ExitCode := 0 + else ExitCode := 1; + + fmMCompile: + if MCompileBaseKeyboard(FQuery) then ExitCode := 0 else ExitCode := 1; diff --git a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas index 051d399b6e..91ecaa9b5f 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas @@ -109,7 +109,7 @@ type { IIntKeymanKeyboardInstalled } function RegKeyboard: TRegKeyboard; procedure ClearVisualKeyboard; - procedure UpdateBaseLayout; // I4169 + procedure UpdateBaseLayout(BaseKeyboardID: Integer); // I4169 procedure RefreshInstallation; public @@ -151,12 +151,12 @@ begin end; end; -procedure TKeymanKeyboardInstalled.UpdateBaseLayout; // I4169 +procedure TKeymanKeyboardInstalled.UpdateBaseLayout(BaseKeyboardID: Integer); // I4169 begin if FRegKeyboard.MnemonicLayout and FileExists(FRegKeyboard.KeymanFile) then // I4615 with TKPRecompileMnemonicKeyboard.Create(Context) do try - Execute(FRegKeyboard.KeymanFile, FRegKeyboard.PackageName); + Execute(FRegKeyboard.KeymanFile, FRegKeyboard.PackageName, BaseKeyboardID); finally Free; end; diff --git a/windows/src/engine/kmcomapi/com/options/keymanoptions.pas b/windows/src/engine/kmcomapi/com/options/keymanoptions.pas index 7bea91450b..8635a74808 100644 --- a/windows/src/engine/kmcomapi/com/options/keymanoptions.pas +++ b/windows/src/engine/kmcomapi/com/options/keymanoptions.pas @@ -1,18 +1,18 @@ (* Name: keymanoptions Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 20 Jun 2006 Modified Date: 6 Feb 2015 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 20 Jun 2006 - mcdurdin - Initial version 01 Aug 2006 - mcdurdin - Add AutoRefershKeyman call 12 Aug 2008 - mcdurdin - Avoid crash with missing options @@ -67,6 +67,7 @@ uses ErrorControlledRegistry, RegistryKeys, Glossary, + isadmin, Keyman.System.BaseKeyboard, KeymanOptionNames, keymanerrorcodes; @@ -112,7 +113,9 @@ end; procedure TKeymanOptions.Apply; var - I, FOldBaseLayout: Integer; + I: Integer; + FOldBaseLayout: Integer; + FNewBaseLayout: Integer; begin with TRegistryErrorControlled.Create do // I3717 try @@ -130,9 +133,10 @@ begin FInternalOptions.Save(Context); - if FOldBaseLayout <> Get_Items('koBaseLayout').Value then + FNewBaseLayout := Get_Items('koBaseLayout').Value; + if IsAdministrator and (FOldBaseLayout <> FNewBaseLayout) then for I := 0 to Context.Keyboards.Count - 1 do // I4169 - (Context.Keyboards.Items[I] as IIntKeymanKeyboardInstalled).UpdateBaseLayout; + (Context.Keyboards.Items[I] as IIntKeymanKeyboardInstalled).UpdateBaseLayout(FNewBaseLayout); Context.Control.AutoApplyKeyman; end; diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas index 26c92faa90..1df237b0c6 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas @@ -125,6 +125,7 @@ var FExitCode: Integer; FKVKName: WideString; FCreatedIcon: Boolean; + BaseKeyboardID: Integer; begin KL.MethodEnter(Self, 'Execute', [FileName,PackageID,ikPartOfPackage in FInstallOptions ,Force]); try @@ -248,9 +249,11 @@ begin // Recompile a mnemonic layout to the user's selected base layout if ki.MnemonicLayout then // I4169 begin + with Context as TKeymanContext do + BaseKeyboardID := (Options as IKeymanOptions).Items['koBaseLayout'].Value; with TKPRecompileMnemonicKeyboard.Create(Context) do try - Execute(FDestFileName, PackageID); + Execute(FDestFileName, PackageID, BaseKeyboardID); finally Free; end; diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas b/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas index 30d0c275cc..7a4d5a2b39 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas @@ -27,7 +27,7 @@ uses type TKPRecompileMnemonicKeyboard = class(TKPBase) - procedure Execute(const FileName: string; const PackageName: string); + procedure Execute(const FileName: string; const PackageName: string; BaseKeyboardID: Cardinal); end; implementation @@ -42,10 +42,8 @@ uses Winapi.Windows, errorcontrolledregistry, - keymancontext, keymanerrorcodes, KeymanPaths, - keymanapi_TLB, RegistryKeys, utilexecute, utilkeyman, @@ -67,7 +65,7 @@ begin Result := ''; end; -procedure TKPRecompileMnemonicKeyboard.Execute(const FileName,PackageName: string); +procedure TKPRecompileMnemonicKeyboard.Execute(const FileName,PackageName: string; BaseKeyboardID: Cardinal); var FDestPath, FDestFileName: string; FBaseKeyboardIDHex: string; @@ -76,7 +74,6 @@ var FExitCode: Integer; FMCompilePath: string; FBaseKeyboardFileName: string; - BaseKeyboardID: Cardinal; FDestDeadkeyFileName: string; FCommand: string; begin @@ -84,9 +81,6 @@ begin then FDestPath := GetPackageInstallPath(PackageName) // I3581 else FDestPath := GetKeyboardInstallPath(FileName); // I3581 - with Context as TKeymanContext do - BaseKeyboardID := (Options as IKeymanOptions).Items['koBaseLayout'].Value; - FBaseKeyboardIDHex := IntToHex(BaseKeyboardID, 8); FBaseFileName := FDestPath + '\' + ExtractFileName(FileName); // I3581 FDestFileName := ChangeFileExt(FBaseFileName, '') + '-'+FBaseKeyboardIDHex + '.kmx'; diff --git a/windows/src/engine/kmcomapi/util/internalinterfaces.pas b/windows/src/engine/kmcomapi/util/internalinterfaces.pas index 1759468e00..11093ac89a 100644 --- a/windows/src/engine/kmcomapi/util/internalinterfaces.pas +++ b/windows/src/engine/kmcomapi/util/internalinterfaces.pas @@ -67,7 +67,7 @@ type ['{4876E6DF-C557-46E2-84F4-787BE5F55DDA}'] function RegKeyboard: TRegKeyboard; procedure ClearVisualKeyboard; - procedure UpdateBaseLayout; // I4169 + procedure UpdateBaseLayout(BaseKeyboardID: Cardinal); // I4169 procedure RefreshInstallation; end; From 2f4c428b13bbb5215745df9454b6f5c4a3beb851 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Wed, 29 Jul 2026 15:03:57 +1000 Subject: [PATCH 03/26] fix(windows): restore UpdateBaseLayout interface The original change, changed the InKeymanKyboardInstalled UpdateBaseLayout inteface and it didn't need to. This change restores it. --- .../com/keyboards/keymankeyboardinstalled.pas | 9 +++++++-- .../engine/kmcomapi/com/options/keymanoptions.pas | 2 +- .../keyboard/kprecompilemnemonickeyboard.pas | 14 +++++++------- .../engine/kmcomapi/util/internalinterfaces.pas | 2 +- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas index 91ecaa9b5f..52fd698435 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas @@ -109,7 +109,7 @@ type { IIntKeymanKeyboardInstalled } function RegKeyboard: TRegKeyboard; procedure ClearVisualKeyboard; - procedure UpdateBaseLayout(BaseKeyboardID: Integer); // I4169 + procedure UpdateBaseLayout; // I4169 procedure RefreshInstallation; public @@ -151,15 +151,20 @@ begin end; end; -procedure TKeymanKeyboardInstalled.UpdateBaseLayout(BaseKeyboardID: Integer); // I4169 +procedure TKeymanKeyboardInstalled.UpdateBaseLayout; // I4169 +var + BaseKeyboardID: Integer; begin if FRegKeyboard.MnemonicLayout and FileExists(FRegKeyboard.KeymanFile) then // I4615 + begin + BaseKeyboardID := (Context.Options as IKeymanOptions).Items['koBaseLayout'].Value; with TKPRecompileMnemonicKeyboard.Create(Context) do try Execute(FRegKeyboard.KeymanFile, FRegKeyboard.PackageName, BaseKeyboardID); finally Free; end; + end; end; function TKeymanKeyboardInstalled.Get_Copyright: WideString; diff --git a/windows/src/engine/kmcomapi/com/options/keymanoptions.pas b/windows/src/engine/kmcomapi/com/options/keymanoptions.pas index 8635a74808..a60c5da041 100644 --- a/windows/src/engine/kmcomapi/com/options/keymanoptions.pas +++ b/windows/src/engine/kmcomapi/com/options/keymanoptions.pas @@ -136,7 +136,7 @@ begin FNewBaseLayout := Get_Items('koBaseLayout').Value; if IsAdministrator and (FOldBaseLayout <> FNewBaseLayout) then for I := 0 to Context.Keyboards.Count - 1 do // I4169 - (Context.Keyboards.Items[I] as IIntKeymanKeyboardInstalled).UpdateBaseLayout(FNewBaseLayout); + (Context.Keyboards.Items[I] as IIntKeymanKeyboardInstalled).UpdateBaseLayout; Context.Control.AutoApplyKeyman; end; diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas b/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas index 7a4d5a2b39..3d806afda2 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas @@ -1,18 +1,18 @@ (* Name: kprecompilemnemonickeyboard Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 24 Apr 2014 Modified Date: 13 Mar 2015 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 24 Apr 2014 - mcdurdin - I4174 - V9 - mcompile logs should be stored in diag folder 06 Feb 2015 - mcdurdin - I4552 - V9.0 - Add mnemonic recompile option to ignore deadkeys 13 Mar 2015 - mcdurdin - I4615 - CrashID:kmshell.exe_9.0.481.0_2C6795CE_EOleException diff --git a/windows/src/engine/kmcomapi/util/internalinterfaces.pas b/windows/src/engine/kmcomapi/util/internalinterfaces.pas index 11093ac89a..1759468e00 100644 --- a/windows/src/engine/kmcomapi/util/internalinterfaces.pas +++ b/windows/src/engine/kmcomapi/util/internalinterfaces.pas @@ -67,7 +67,7 @@ type ['{4876E6DF-C557-46E2-84F4-787BE5F55DDA}'] function RegKeyboard: TRegKeyboard; procedure ClearVisualKeyboard; - procedure UpdateBaseLayout(BaseKeyboardID: Cardinal); // I4169 + procedure UpdateBaseLayout; // I4169 procedure RefreshInstallation; end; From 27970c671e4bc45c3b24da667d8824b071547fb0 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Mon, 3 Aug 2026 15:22:21 +1000 Subject: [PATCH 04/26] fix(windows): refresh UI after basekbd change --- windows/src/desktop/kmshell/main/UfrmMain.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/src/desktop/kmshell/main/UfrmMain.pas b/windows/src/desktop/kmshell/main/UfrmMain.pas index a556019abd..4ee970cca5 100644 --- a/windows/src/desktop/kmshell/main/UfrmMain.pas +++ b/windows/src/desktop/kmshell/main/UfrmMain.pas @@ -666,8 +666,8 @@ var begin if ConfigureBaseKeyboard(BaseKeyboardID) then begin - SetBaseKeyboard(Handle, BaseKeyboardID) - // Refresh will be triggered by elevated process + SetBaseKeyboard(Handle, BaseKeyboardID); + DoRefresh; end; end; From 62dd0de7868abe931d01428034fc43deabd8ba7f Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Fri, 21 Aug 2026 13:53:26 +1000 Subject: [PATCH 05/26] fix(windows): add compile for base keyoard to api What we was needed was the ability to recompile installed keyboards against a basekeyboard id. MCompileForBaseKeyboard which will take the base keyboard id. This allows the call to be done elevated and seperates out the actuall selecting the base keyboard. --- .../desktop/kmshell/main/UfrmBaseKeyboard.pas | 97 +++++-------------- windows/src/desktop/kmshell/main/initprog.pas | 8 +- .../com/keyboards/keymankeyboardinstalled.pas | 22 ++++- .../kmcomapi/com/options/keymanoptions.pas | 24 ----- windows/src/engine/kmcomapi/keymanapi_TLB.pas | 10 ++ windows/src/engine/kmcomapi/kmcomapi.ridl | 14 +++ 6 files changed, 74 insertions(+), 101 deletions(-) diff --git a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas index b3f60a5067..e9ce67d5e3 100644 --- a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas @@ -21,6 +21,7 @@ type function ConfigureBaseKeyboard(out BaseKeyboardID: Integer): Boolean; function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolean; function MCompileBaseKeyboard(const BaseKeyboardIDText: string): Boolean; +function CompileForBaseKeyboard(BaseKeyboardID: Integer): Boolean; implementation @@ -78,80 +79,12 @@ end; function MCompileBaseKeyboard(const BaseKeyboardIDText: string): Boolean; var BaseKeyboardID: Integer; - PreviousBaseKeyboardID: Integer; - PreviousBaseKeyboardValue: string; - PreviousBaseKeyboardValueExists: Boolean; - - procedure SavePreviousRegistryBaseKeyboardValue; - var - Reg: TRegistryErrorControlled; - begin - PreviousBaseKeyboardValueExists := False; - PreviousBaseKeyboardValue := ''; - - Reg := TRegistryErrorControlled.Create; - try - if Reg.OpenKeyReadOnly(SRegKey_KeymanEngine_CU) and Reg.ValueExists(SRegValue_UnderlyingLayout) then - begin - PreviousBaseKeyboardValueExists := True; - PreviousBaseKeyboardValue := Reg.ReadString(SRegValue_UnderlyingLayout); - end; - finally - Reg.Free; - end; - end; - - procedure RestorePreviousBaseKeyboardValue; - var - Reg: TRegistryErrorControlled; - begin - Reg := TRegistryErrorControlled.Create; - try - if Reg.OpenKey(SRegKey_KeymanEngine_CU, True) then - if PreviousBaseKeyboardValueExists then - Reg.WriteString(SRegValue_UnderlyingLayout, PreviousBaseKeyboardValue) - else if Reg.ValueExists(SRegValue_UnderlyingLayout) then - Reg.DeleteValue(SRegValue_UnderlyingLayout); - finally - Reg.Free; - end; - end; - - procedure ForceBaseLayoutChange; - var - Reg: TRegistryErrorControlled; - begin - // This is hacky, maybe just remove the registry value, however that - // would not force a recompile if the was the default base layout. - // Options.Apply re-compiles only when it observes a changed base layout. - // The caller may be repairing missing files for the already-selected layout. - Reg := TRegistryErrorControlled.Create; - try - if Reg.OpenKey(SRegKey_KeymanEngine_CU, True) then - Reg.WriteString(SRegValue_UnderlyingLayout, '00000000'); - finally - Reg.Free; - end; - end; - begin Result := False; if not TryStrToInt('$' + BaseKeyboardIDText, BaseKeyboardID) or not kmcom.SystemInfo.IsAdministrator then Exit; - - SavePreviousRegistryBaseKeyboardValue; - PreviousBaseKeyboardID := kmcom.Options['koBaseLayout'].Value; - kmcom.Options['koBaseLayout'].Value := BaseKeyboardID; - try - if PreviousBaseKeyboardID = BaseKeyboardID then - ForceBaseLayoutChange; - kmcom.Options.Apply; - Result := True; - finally - kmcom.Options['koBaseLayout'].Value := PreviousBaseKeyboardID; - RestorePreviousBaseKeyboardValue; - end; + Result := CompileForBaseKeyboard(BaseKeyboardID); end; function BaseKeyboardNeedsMCompile(BaseKeyboardID: Integer): Boolean; @@ -180,13 +113,33 @@ var begin MCompileResult := True; Result := False; - if BaseKeyboardNeedsMCompile(BaseKeyboardID) and not kmcom.SystemInfo.IsAdministrator then - MCompileResult := WaitForElevatedConfiguration(WindowHandle, '-mcompile ' + IntToHex(BaseKeyboardID, 8)) = 0; + if BaseKeyboardNeedsMCompile(BaseKeyboardID) then + begin + if not kmcom.SystemInfo.IsAdministrator then + begin + MCompileResult := WaitForElevatedConfiguration(WindowHandle, '-mcompilekbds ' + IntToHex(BaseKeyboardID, 8)) = 0; + end + else + MCompileResult := CompileForBaseKeyboard(BaseKeyboardID); + end; if not MCompileResult then Exit; + kmcom.Options['koBaseLayout'].Value := BaseKeyboardID; - kmcom.Options.Apply; // This will trigger a recompile if needed + kmcom.Options.Apply; Result := True; end; +function CompileForBaseKeyboard(BaseKeyboardID: Integer): Boolean; +var + i: Integer; + kbd: IKeymanKeyboardInstalled; +begin + for i := 0 to kmcom.Keyboards.Count - 1 do + begin + kbd := kmcom.Keyboards[i]; + (kbd as IKeymanKeyboardInstalled2).MCompileForBaseKeyboard(BaseKeyboardID); + end; +end; + end. diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas index 3444e7ce53..f9b5f9ac9b 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -90,7 +90,7 @@ type fmKeyboardWelcome, // I2569 fmKeyboardPrint, // I2329 fmBaseKeyboard, // I4169 - fmMCompile, + fmMCompileKbds, fmUpgradeMnemonicLayout, // I4553 fmRepair, fmKeepInTouch, @@ -263,9 +263,9 @@ begin else if s = '-bd' then FMode := fmBackgroundDownload else if s = '-an' then FMode := fmApplyInstallNow else if s = '-basekeyboard' then FMode := fmBaseKeyboard // I4169 - else if s = '-mcompile' then + else if s = '-mcompilekbds' then begin - FMode := fmMCompile; + FMode := fmMCompileKbds; Inc(i); if i > ParamCount then Exit; FQuery := ParamStr(i); @@ -553,7 +553,7 @@ begin then ExitCode := 0 else ExitCode := 1; - fmMCompile: + fmMCompileKbds: if MCompileBaseKeyboard(FQuery) then ExitCode := 0 else ExitCode := 1; diff --git a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas index 52fd698435..01b03ae3fc 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas @@ -63,7 +63,8 @@ type TKeymanKeyboardInstalled = class( // I3581 TKeymanKeyboard, IIntKeymanKeyboardInstalled, - IKeymanKeyboardInstalled) + IKeymanKeyboardInstalled, + IKeymanKeyboardInstalled2) private FRegKeyboard: TRegKeyboard; FVisualKeyboard: IKeymanVisualKeyboard; @@ -112,6 +113,9 @@ type procedure UpdateBaseLayout; // I4169 procedure RefreshInstallation; + { IKeymanKeyboardInstalled2 } + procedure MCompileForBaseKeyboard(KLID: Integer); safecall; + public constructor Create(AContext: TKeymanContext; const Name: string); destructor Destroy; override; @@ -476,5 +480,21 @@ begin Result := FRegKeyboard; end; +{ IKeymanKeyboardInstalled2 } +procedure TKeymanKeyboardInstalled.MCompileForBaseKeyboard(KLID: Integer); safecall; +var + RecompileMnemonicKeyboard: TKPRecompileMnemonicKeyboard; +begin + if FRegKeyboard.MnemonicLayout and FileExists(FRegKeyboard.KeymanFile) then + begin + RecompileMnemonicKeyboard := TKPRecompileMnemonicKeyboard.Create(Context); + try + RecompileMnemonicKeyboard.Execute(FRegKeyboard.KeymanFile, FRegKeyboard.PackageName, KLID); + finally + RecompileMnemonicKeyboard.Free; + end; + end; +end; + end. diff --git a/windows/src/engine/kmcomapi/com/options/keymanoptions.pas b/windows/src/engine/kmcomapi/com/options/keymanoptions.pas index a60c5da041..1848428033 100644 --- a/windows/src/engine/kmcomapi/com/options/keymanoptions.pas +++ b/windows/src/engine/kmcomapi/com/options/keymanoptions.pas @@ -112,32 +112,8 @@ begin end; procedure TKeymanOptions.Apply; -var - I: Integer; - FOldBaseLayout: Integer; - FNewBaseLayout: Integer; begin - with TRegistryErrorControlled.Create do // I3717 - try - if OpenKey(SRegKey_KeymanEngine_CU, True) then - begin - if ValueExists(SRegValue_UnderlyingLayout) - then FOldBaseLayout := StrToIntDef('$'+ReadString(SRegValue_UnderlyingLayout),0) // I3759 - else FOldBaseLayout := TBaseKeyboard.GetDefaultBaseLayoutID; - end - else - FOldBaseLayout := TBaseKeyboard.GetDefaultBaseLayoutID; - finally - Free; - end; - FInternalOptions.Save(Context); - - FNewBaseLayout := Get_Items('koBaseLayout').Value; - if IsAdministrator and (FOldBaseLayout <> FNewBaseLayout) then - for I := 0 to Context.Keyboards.Count - 1 do // I4169 - (Context.Keyboards.Items[I] as IIntKeymanKeyboardInstalled).UpdateBaseLayout; - Context.Control.AutoApplyKeyman; end; diff --git a/windows/src/engine/kmcomapi/keymanapi_TLB.pas b/windows/src/engine/kmcomapi/keymanapi_TLB.pas index 3ceb5b15cd..786ce6c9b2 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -1569,6 +1569,16 @@ type procedure RefreshInstalledKeyboards; safecall; end; +// *********************************************************************// +// Interface: IKeymanKeyboardInstalled2 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {3086C85C-932A-4726-BF76-2D74DD133AC9} +// *********************************************************************// + IKeymanKeyboardInstalled2 = interface(IKeymanKeyboardInstalled) + ['{3086C85C-932A-4726-BF76-2D74DD133AC9}'] + procedure MCompileForBaseKeyboard(KLID: Integer); safecall; + end; + // *********************************************************************// // DispIntf: IKeymanKeyboardsInstalled2Disp // Flags: (4416) Dual OleAutomation Dispatchable diff --git a/windows/src/engine/kmcomapi/kmcomapi.ridl b/windows/src/engine/kmcomapi/kmcomapi.ridl index ac20310a87..9eb63fbd68 100644 --- a/windows/src/engine/kmcomapi/kmcomapi.ridl +++ b/windows/src/engine/kmcomapi/kmcomapi.ridl @@ -60,6 +60,7 @@ library keymanapi interface IKeymanKeyboardLanguagesInstalled; interface IKeymanKeyboardLanguagesFile; interface IKeymanKeyboardsInstalled2; + interface IKeymanKeyboardInstalled2; interface IKeymanPackagesInstalled2; interface IKeymanKeyboardFile2; interface IKeymanPackageFile2; @@ -936,6 +937,19 @@ library keymanapi HRESULT _stdcall RefreshInstalledKeyboards(void); }; + [ + uuid(3086C85C-932A-4726-BF76-2D74DD133AC9), + version(19.0), + helpstring("https://help.keyman.com/developer/engine/windows/19.0/api/IKeymanKeyboardInstalled2"), + dual, + oleautomation + ] + interface IKeymanKeyboardInstalled2: IKeymanKeyboardInstalled + { + [id(0x00000120)] + HRESULT _stdcall MCompileForBaseKeyboard(long KLID); + }; + [ uuid(F23B9848-2AEF-4A2B-BC3A-292E3A00D691), version(14.0), From 82fb40002b980a243edd7a9c647f7d3ca585c422 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Mon, 31 Aug 2026 15:34:45 +1000 Subject: [PATCH 06/26] fix(windows): pass basekeyboardid to installation api The updates all the apis so that the basekeyboardid or klid can be passed in as an argument. This in needed so that elevated process required to compile the keyboard has the call users keyboard base id. --- .../Keyman.Configuration.UI.InstallFile.pas | 30 +++++----- ...Configuration.UI.KeymanProtocolHandler.pas | 12 ++-- .../kmshell/install/UfrmInstallKeyboard.pas | 17 ++++-- .../install/UfrmInstallKeyboardFromWeb.pas | 6 +- windows/src/desktop/kmshell/main/initprog.pas | 15 ++--- .../com/keyboards/keymankeyboardfile.pas | 23 +++++++- .../keyboards/keymankeyboardsinstalled.pas | 22 ++++++- .../com/packages/keymanpackagefile.pas | 43 ++++++++++---- .../com/packages/keymanpackagesinstalled.pas | 30 +++++++++- windows/src/engine/kmcomapi/keymanapi_TLB.pas | 42 ++++++++++++++ windows/src/engine/kmcomapi/kmcomapi.ridl | 58 +++++++++++++++++++ .../processes/keyboard/kpinstallkeyboard.pas | 23 +++++--- .../processes/package/kpinstallpackage.pas | 12 ++-- 13 files changed, 264 insertions(+), 69 deletions(-) diff --git a/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.InstallFile.pas b/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.InstallFile.pas index c6ee3564ae..3cc8dcc901 100644 --- a/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.InstallFile.pas +++ b/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.InstallFile.pas @@ -18,9 +18,9 @@ type FPackage: IKeymanPackageInstalled; const BCP47: string); static; public class function BrowseAndInstallKeyboardFromFile(Owner: TComponent): Boolean; static; - class function Execute(KeyboardFileNames: TStrings; const FirstKeyboardFileName: string; FSilent, FNoWelcome: Boolean; const LogFile: string): Boolean; overload; static; - class function Execute(Owner: TComponent; const FileName: string; ASilent, ANoWelcome: Boolean; const LogFile, BCP47: string): Boolean; overload; static; - class function Execute(Owner: TComponent; const FileNames: TStrings; ASilent: Boolean): Boolean; overload; static; + class function Execute(KeyboardFileNames: TStrings; const FirstKeyboardFileName: string; FSilent, FNoWelcome: Boolean; const LogFile: string; BaseKeyboardID: Integer): Boolean; overload; static; + class function Execute(Owner: TComponent; const FileName: string; ASilent, ANoWelcome: Boolean; const LogFile, BCP47: string; BaseKeyboardID: Integer): Boolean; overload; static; + class function Execute(Owner: TComponent; const FileNames: TStrings; ASilent: Boolean; BaseKeyboardID: Integer): Boolean; overload; static; end; implementation @@ -35,29 +35,30 @@ uses Keyman.Configuration.UI.KeymanProtocolHandler, Keyman.Configuration.UI.MitigationForWin10_1803, kmint, + KeymanOptionNames, UfrmHTML, UfrmInstallKeyboard; class function TInstallFile.Execute(KeyboardFileNames: TStrings; const FirstKeyboardFileName: string; FSilent, FNoWelcome: Boolean; - const LogFile: string): Boolean; + const LogFile: string; BaseKeyboardID: Integer): Boolean; begin if TKeymanProtocolHandler.CanHandle(FirstKeyboardFileName) then begin - Result := TKeymanProtocolHandler.Handle(nil, FirstKeyboardFileName, FSilent, FNoWelcome, LogFile); + Result := TKeymanProtocolHandler.Handle(nil, FirstKeyboardFileName, FSilent, FNoWelcome, LogFile, BaseKeyboardID); end else if (KeyboardFileNames.Count > 1) or (Pos('=', FirstKeyboardFileName) > 0) then begin - Result := TInstallFile.Execute(nil, KeyboardFileNames, FSilent) + Result := TInstallFile.Execute(nil, KeyboardFileNames, FSilent, BaseKeyboardID) end // TODO: support bare package ids from command line (if it does not include a file extension, assume it is a .kmp and try and download it) // else if IsNotPackageOrKeyboardFile then else begin - Result := TInstallFile.Execute(nil, FirstKeyboardFileName, FSilent, FNoWelcome, LogFile, ''); + Result := TInstallFile.Execute(nil, FirstKeyboardFileName, FSilent, FNoWelcome, LogFile, '', BaseKeyboardID); end; end; -class function TInstallFile.Execute(Owner: TComponent; const FileName: string; ASilent, ANoWelcome: Boolean; const LogFile, BCP47: string): Boolean; +class function TInstallFile.Execute(Owner: TComponent; const FileName: string; ASilent, ANoWelcome: Boolean; const LogFile, BCP47: string; BaseKeyboardID: Integer): Boolean; var n: Integer; InstalledKeyboards: array of IKeymanKeyboardInstalled; @@ -77,7 +78,7 @@ begin begin if ASilent then begin - InstallKeyboard(LogFile, BCP47); + InstallKeyboard(LogFile, BCP47, BaseKeyboardID); Result := True; end else @@ -139,7 +140,7 @@ end; /// This is the handler for the `-i` parameter, e.g. /// kmshell -i khmer_angkor.kmp c:\temp\sil_euro_latin.kmp=fr /// -class function TInstallFile.Execute(Owner: TComponent; const FileNames: TStrings; ASilent: Boolean): Boolean; +class function TInstallFile.Execute(Owner: TComponent; const FileNames: TStrings; ASilent: Boolean; BaseKeyboardID: Integer): Boolean; var i, j: Integer; FPackage: IKeymanPackageInstalled; @@ -170,7 +171,7 @@ begin end; if IsPackage then begin - FPackage := (kmcom.Packages as IKeymanPackagesInstalled2).Install2(FileName, True); + FPackage := (kmcom.Packages as IKeymanPackagesInstalled3).Install3(FileName, True, BaseKeyboardID); if Length(FilenameBCP47) > 1 then RegisterKeyboardPackageLanguage(FPackage, FilenameBCP47[1]) else RegisterKeyboardPackageLanguage(FPackage, ''); @@ -178,7 +179,7 @@ begin end else begin - FKeyboard := (kmcom.Keyboards as IKeymanKeyboardsInstalled2).Install2(FileName, True); + FKeyboard := (kmcom.Keyboards as IKeymanKeyboardsInstalled3).Install3(FileName, True, BaseKeyboardID); if (Length(FilenameBCP47) > 1) and (Trim(FilenameBCP47[1]) <> '') then BCP47Tag := FilenameBCP47[1] else BCP47Tag := TTIPMaintenance.GetFirstLanguage(FKeyboard); @@ -209,6 +210,7 @@ end; class function TInstallFile.BrowseAndInstallKeyboardFromFile(Owner: TComponent): Boolean; var dlgOpen: TOpenDialog; + BaseKeyboardID : Integer; begin dlgOpen := TOpenDialog.Create(nil); try @@ -216,9 +218,9 @@ begin 'Keyman files (*.kmx, *.kxx, *.kmp)|*.kmx;*.kxx;*.kmp|Keyman keyboards (*.kmx,*.kxx)' + '|*.kmx;*.kxx|Keyman packages (*.kmp)|*.kmp|All files (*.*)|*.*'; dlgOpen.Title := 'Install Keyman Keyboard'; - + BaseKeyboardID := kmcom.Options[KeymanOptionName(koBaseLayout)].Value; if dlgOpen.Execute then - Result := Execute(Owner, dlgOpen.FileName, False, False, '', '') + Result := Execute(Owner, dlgOpen.FileName, False, False, '', '', BaseKeyboardID) else Result := False; finally diff --git a/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.KeymanProtocolHandler.pas b/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.KeymanProtocolHandler.pas index 6f13f6777b..60ac8ae43c 100644 --- a/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.KeymanProtocolHandler.pas +++ b/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.KeymanProtocolHandler.pas @@ -17,13 +17,13 @@ type FDownloadURL: string; frmDownloadProgress: TfrmDownloadProgress; function DoHandle(Owner: TComponent; const url: string; ASilent, - ANoWelcome: Boolean; const ALogFile: string): Boolean; + ANoWelcome: Boolean; const ALogFile: string; BaseKeyboardID: Integer): Boolean; procedure DoDownload(AOwner: TfrmDownloadProgress; var Result: Boolean); procedure HttpReceiveData(const Sender: TObject; AContentLength, AReadCount: Int64; var Abort: Boolean); public class function CanHandle(const url: string): Boolean; static; - class function Handle(Owner: TComponent; const url: string; ASilent, ANoWelcome: Boolean; const ALogFile: string): Boolean; static; + class function Handle(Owner: TComponent; const url: string; ASilent, ANoWelcome: Boolean; const ALogFile: string; BaseKeyboardID: Integer): Boolean; static; end; implementation @@ -51,13 +51,13 @@ end; class function TKeymanProtocolHandler.Handle(Owner: TComponent; const url: string; ASilent, ANoWelcome: Boolean; - const ALogFile: string): Boolean; + const ALogFile: string; BaseKeyboardID: Integer): Boolean; var h: TKeymanProtocolHandler; begin h := TKeymanProtocolHandler.Create; try - Result := h.DoHandle(Owner, url, ASilent, ANoWelcome, ALogFile); + Result := h.DoHandle(Owner, url, ASilent, ANoWelcome, ALogFile, BaseKeyboardID); finally h.Free; end; @@ -65,7 +65,7 @@ end; function TKeymanProtocolHandler.DoHandle(Owner: TComponent; const url: string; ASilent, ANoWelcome: Boolean; - const ALogFile: string): Boolean; + const ALogFile: string; BaseKeyboardID: Integer): Boolean; var FTempDir: string; PackageID, BCP47: string; @@ -98,7 +98,7 @@ begin end; // TODO: this makes a circular dependency, refactor it out! - Result := TInstallFile.Execute(nil, FDownloadFilename, False, False, '', BCP47); + Result := TInstallFile.Execute(nil, FDownloadFilename, False, False, '', BCP47, BaseKeyboardID); finally if FileExists(FDownloadFilename) then diff --git a/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas b/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas index 6d79811a80..775aa1ca2e 100644 --- a/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas +++ b/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas @@ -74,6 +74,7 @@ uses Vcl.StdCtrls, keymanapi_TLB, + KeymanOptionNames, UfrmKeymanBase, UfrmWebContainer; @@ -102,7 +103,7 @@ type protected procedure FireCommand(const command: WideString; params: TStringList); override; public - procedure InstallKeyboard(const ALogFile, BCP47Tag: string); + procedure InstallKeyboard(const ALogFile, BCP47Tag: string; BaseKeyboardID: Integer); property DefaultBCP47Tag: string read FDefaultBCP47Tag write SetDefaultBCP47Tag; property InstallFile: string read FInstallFile write SetInstallFile; property Silent: Boolean read FSilent write FSilent; @@ -271,6 +272,7 @@ end; procedure TfrmInstallKeyboard.FireCommand(const command: WideString; params: TStringList); var BCP47Tag: string; + BaseKeyboardID :Integer; begin BCP47Tag := ''; if (command = 'keyboard_install') and kmcom.SystemInfo.IsAdministrator then // I4172 @@ -283,7 +285,8 @@ begin Manager.Title := 'Installing Keyboard'; Manager.CanCancel := False; Manager.UpdateProgress('Installing Keyboard', 0, 0); - InstallKeyboard('', BCP47Tag); + BaseKeyboardID := kmcom.Options[KeymanOptionName(koBaseLayout)].Value; + InstallKeyboard('', BCP47Tag, BaseKeyboardID); Result := True; end ); @@ -299,6 +302,7 @@ begin var t: TTempFile; ExecParams: string; + BaseKeyboardString :string; begin KL.MethodEnter(Self, '"keyboard_install"', [params.Text]); try @@ -306,8 +310,9 @@ begin Manager.CanCancel := False; Manager.UpdateProgress('Installing Keyboard', 0, 0); t := TTempFileManager.Get('.log'); + BaseKeyboardString := IntToHex(kmcom.Options[KeymanOptionName(koBaseLayout)].Value, 8); try - ExecParams := '-log "'+t.Name+'" -s -i "'+FInstallFile+'='+BCP47Tag+'"'+ + ExecParams := '-log "'+t.Name+'" -bkd "'+BaseKeyboardString+'" -s -i "'+FInstallFile+'='+BCP47Tag+'"'+ ' -nowelcome '+TTIPMaintenance.GetUserDefaultLangParameterString; KL.Log('Calling elevated kmshell %s', [ExecParams]); if WaitForElevatedConfiguration(GetForegroundWindow, ExecParams) = 0 then @@ -358,7 +363,7 @@ end; ------------------------------------------------------------------------------} // TODO: move this to TInstallFile -procedure TfrmInstallKeyboard.InstallKeyboard(const ALogFile, BCP47Tag: string); +procedure TfrmInstallKeyboard.InstallKeyboard(const ALogFile, BCP47Tag: string; BaseKeyboardID: Integer); var i: Integer; kbd: IKeymanKeyboardInstalled; @@ -400,7 +405,7 @@ begin kbd := nil; kmcom.Keyboards.Apply; kmcom.Keyboards.Refresh; - FInstalledKeyboard := (FKeyboard as IKeymanKeyboardFile2).Install2(True); + FInstalledKeyboard := (FKeyboard as IKeymanKeyboardFile3).Install3(True, BaseKeyboardID); if not InstallTipForKeyboard(BCP47Tag) then begin // TODO can we return a failure code? @@ -461,7 +466,7 @@ begin kmcom.Keyboards.Apply; kmcom.Keyboards.Refresh; // I2169 - (FPackage as IKeymanPackageFile2).Install2(True); + (FPackage as IKeymanPackageFile3).Install3(True, BaseKeyboardID); kmcom.Refresh; diff --git a/windows/src/desktop/kmshell/install/UfrmInstallKeyboardFromWeb.pas b/windows/src/desktop/kmshell/install/UfrmInstallKeyboardFromWeb.pas index aff3251037..ed236d489d 100644 --- a/windows/src/desktop/kmshell/install/UfrmInstallKeyboardFromWeb.pas +++ b/windows/src/desktop/kmshell/install/UfrmInstallKeyboardFromWeb.pas @@ -87,6 +87,7 @@ uses Keyman.Configuration.UI.InstallFile, Keyman.System.LocaleStrings, kmint, + KeymanOptionNames, MessageIdentifierConsts, Upload_Settings, utilfiletypes, @@ -213,6 +214,7 @@ end; procedure TfrmInstallKeyboardFromWeb.DownloadAndInstallPackage(const PackageID, BCP47: string); var FTempDir: string; + BaseKeyboardID: Integer; begin FTempDir := IncludeTrailingPathDelimiter(CreateTempPath); // I1679 try @@ -230,8 +232,8 @@ begin finally frmDownloadProgress.Free; end; - - if TInstallFile.Execute(Self, FDownloadFilename, False, False, '', BCP47) then + BaseKeyboardID := kmcom.Options[KeymanOptionName(koBaseLayout)].Value; + if TInstallFile.Execute(Self, FDownloadFilename, False, False, '', BCP47, BaseKeyboardID) then ModalResult := mrOk; finally diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas index f9b5f9ac9b..0f0cc6f367 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -206,7 +206,7 @@ end; function Init(var FMode: TKMShellMode; KeyboardFileNames: TStrings; var FSilent, FForce, FNoWelcome: Boolean; var FLogFile, FQuery: string; var FDisablePackages, FDefaultUILanguage: string; var FStartWithConfiguration: Boolean; - var FParentWindow: THandle; var FDefaultBCP47: string; var FDefaultLangID: Integer): Boolean; + var FParentWindow: THandle; var FDefaultBCP47: string; var FDefaultLangID, FBaseKeyboard: Integer): Boolean; var s: string; i: Integer; @@ -263,6 +263,7 @@ begin else if s = '-bd' then FMode := fmBackgroundDownload else if s = '-an' then FMode := fmApplyInstallNow else if s = '-basekeyboard' then FMode := fmBaseKeyboard // I4169 + else if s = 'bkd' then begin Inc(i); FBaseKeyboard := ParamStr(i); end else if s = '-mcompilekbds' then begin FMode := fmMCompileKbds; @@ -329,7 +330,7 @@ end; procedure RunKMCOM(FMode: TKMShellMode; KeyboardFileNames: TStrings; FSilent, FForce, FNoWelcome: Boolean; FLogFile, FQuery: string; FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; FParentWindow: THandle; - const FDefaultBCP47: string; FDefaultLangID: Integer); forward; + const FDefaultBCP47: string; FDefaultLangID, FBaseKeyboard: Integer); forward; procedure Run; var @@ -340,7 +341,7 @@ var FForce: Boolean; FParentWindow: THandle; FLogFile: string; - FDefaultLangID: Integer; + FDefaultLangID, FBaseKeyboard: Integer; FDefaultBCP47, FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; begin @@ -349,7 +350,7 @@ begin KeyboardFileNames := TStringList.Create; try FParentWindow := 0; - if not Init(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow, FDefaultBCP47, FDefaultLangID) then + if not Init(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow, FDefaultBCP47, FDefaultLangID, FBaseKeyboard) then begin //TODO: TUtilExecute.Shell(PChar('hh.exe mk:@MSITStore:'+ExtractFilePath(KMShellExe)+'keyman.chm::/context/keyman_usage.html'), SW_SHOWNORMAL); Exit; @@ -357,7 +358,7 @@ begin if not LoadKMCOM then Exit; try - RunKMCOM(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow, FDefaultBCP47, FDefaultLangID); + RunKMCOM(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow, FDefaultBCP47, FDefaultLangID, FBaseKeyboard); finally kmcom := nil; end; @@ -396,7 +397,7 @@ end; procedure RunKMCOM(FMode: TKMShellMode; KeyboardFileNames: TStrings; FSilent, FForce, FNoWelcome: Boolean; FLogFile, FQuery: string; FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; - FParentWindow: THandle; const FDefaultBCP47: string; FDefaultLangID: Integer); + FParentWindow: THandle; const FDefaultBCP47: string; FDefaultLangID, FBaseKeyboard: Integer); var kdl: IKeymanDefaultLanguage; FIcon: string; @@ -559,7 +560,7 @@ begin else ExitCode := 1; fmInstall: - if TInstallFile.Execute(KeyboardFileNames, FirstKeyboardFileName, FSilent, FNoWelcome, FLogFile) + if TInstallFile.Execute(KeyboardFileNames, FirstKeyboardFileName, FSilent, FNoWelcome, FLogFile, FBaseKeyboard) then ExitCode := 0 else ExitCode := 1; diff --git a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas index 5ea1e74265..b7255869b7 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas @@ -37,7 +37,7 @@ uses keymankeyboard, keymancontext, Classes, PackageInfo, keymankeyboardlanguagesfile; type - TKeymanKeyboardFile = class(TKeymanKeyboard, IKeymanKeyboardFile, IKeymanKeyboardFile2) + TKeymanKeyboardFile = class(TKeymanKeyboard, IKeymanKeyboardFile, IKeymanKeyboardFile2, IKeymanKeyboardFile3) private FFileName: WideString; FError: Boolean; @@ -52,6 +52,7 @@ type { IKeymanKeyboardFile } procedure Install(Force: WordBool); safecall; function Install2(Force: WordBool): IKeymanKeyboardInstalled; safecall; + function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; safecall; { IKeymanKeyboard } function Get_Copyright: WideString; override; safecall; @@ -252,7 +253,7 @@ procedure TKeymanKeyboardFile.Install(Force: WordBool); begin with TKPInstallKeyboard.Create(Context) do try - Execute(FFileName, '', [ikLegacyRegisterAndInstallProfiles], nil, Force); + Execute(FFileName, '', [ikLegacyRegisterAndInstallProfiles], nil, Force, 0); finally Free; end; @@ -264,7 +265,23 @@ var begin with TKPInstallKeyboard.Create(Context) do try - Execute(FFileName, '', [], nil, Force); + Execute(FFileName, '', [], nil, Force, 0); + finally + Free; + end; + + kki := Context.Keyboards as IKeymanKeyboardsInstalled; + kki.Refresh; + Result := kki.Items[FFileName]; +end; + +function TKeymanKeyboardFile.Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; +var + kki: IKeymanKeyboardsInstalled; +begin + with TKPInstallKeyboard.Create(Context) do + try + Execute(FFileName, '', [], nil, Force, BaseKeyboardID); finally Free; end; diff --git a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardsinstalled.pas b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardsinstalled.pas index f5f8b74448..b37e0dfce0 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardsinstalled.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardsinstalled.pas @@ -37,7 +37,8 @@ uses keymanerrorcodes, keymankeyboardinstalled, keymankeyboard, internalinterfaces; type - TKeymanKeyboardsInstalled = class(TKeymanAutoCollectionObject, IKeymanKeyboardsInstalled, IKeymanKeyboardsInstalled2, IIntKeymanKeyboardsInstalled) // I4376 + TKeymanKeyboardsInstalled = class(TKeymanAutoCollectionObject, IKeymanKeyboardsInstalled, + IKeymanKeyboardsInstalled2, IIntKeymanKeyboardsInstalled, IKeymanKeyboardsInstalled3) // I4376 private FKeyboards: TKeyboardList; procedure TriggerWindowsLanguageSync; @@ -55,6 +56,7 @@ type procedure Install(const Filename: WideString; Force: WordBool); safecall; procedure Apply; safecall; function Install2(const Filename: WideString; Force: WordBool): IKeymanKeyboardInstalled; safecall; + function Install3(const Filename: WideString; Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; safecall; procedure RefreshInstalledKeyboards; safecall; { IIntKeymanKeyboardsInstalled } @@ -101,7 +103,7 @@ procedure TKeymanKeyboardsInstalled.Install(const Filename: WideString; Force: W begin with TKPInstallKeyboard.Create(Context) do try - Execute(FileName, '', [ikLegacyRegisterAndInstallProfiles], nil, Force); + Execute(FileName, '', [ikLegacyRegisterAndInstallProfiles], nil, Force, 0); finally Free; end; @@ -112,7 +114,21 @@ function TKeymanKeyboardsInstalled.Install2(const Filename: WideString; begin with TKPInstallKeyboard.Create(Context) do try - Execute(FileName, '', [], nil, Force); + Execute(FileName, '', [], nil, Force, 0); + finally + Free; + end; + + DoRefresh; + Result := Get_Items(FileName); +end; + +function TKeymanKeyboardsInstalled.Install3(const Filename: WideString; + Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; +begin + with TKPInstallKeyboard.Create(Context) do + try + Execute(FileName, '', [], nil, Force, BaseKeyboardID); finally Free; end; diff --git a/windows/src/engine/kmcomapi/com/packages/keymanpackagefile.pas b/windows/src/engine/kmcomapi/com/packages/keymanpackagefile.pas index 14b207e229..28ef2d064a 100644 --- a/windows/src/engine/kmcomapi/com/packages/keymanpackagefile.pas +++ b/windows/src/engine/kmcomapi/com/packages/keymanpackagefile.pas @@ -1,18 +1,18 @@ (* Name: keymanpackagefile Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 20 Jun 2006 Modified Date: 29 Mar 2010 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 20 Jun 2006 - mcdurdin - Initial version 01 Aug 2006 - mcdurdin - Avoid processmessages in unzip 04 Dec 2006 - mcdurdin - Add Serialize function, support ShortcutRootPath in installation @@ -37,7 +37,7 @@ uses keymanpackagecontentfiles, StdVcl, kmpinffile, KeymanContext, Graphics, Classes, internalinterfaces; type - TKeymanPackageFile = class(TKeymanAutoObject, IKeymanPackage, IKeymanPackageFile, IKeymanPackageFile2) + TKeymanPackageFile = class(TKeymanAutoObject, IKeymanPackage, IKeymanPackageFile, IKeymanPackageFile2, IKeymanPackageFile3) private FSourcePath: string; FSubFiles: IKeymanPackageContentFiles; @@ -74,6 +74,7 @@ type { IKeymanPackageFile } procedure Install(Force: WordBool); safecall; function Install2(Force: WordBool): IKeymanPackageInstalled; safecall; + function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; safecall; public constructor Create(AContext: TKeymanContext; const Filename: Widestring); destructor Destroy; override; @@ -175,7 +176,7 @@ begin o := [ipLegacyRegisterAndInstallProfiles]; if Force then Include(o, ipForce); - Execute(FFileName, o); + Execute(FFileName, o, 0); finally Free; end; @@ -191,7 +192,27 @@ begin o := []; if Force then Include(o, ipForce); - Execute(FFileName, o); + Execute(FFileName, o, 0); + finally + Free; + end; + + kpi := Context.Packages as IKeymanPackagesInstalled; + kpi.Refresh; + Result := kpi.Items[FFileName]; +end; + +function TKeymanPackageFile.Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; +var + o: TKPInstallPackageOptions; + kpi: IKeymanPackagesInstalled; +begin + with TKPInstallPackage.Create(Context) do + try + o := []; + if Force then + Include(o, ipForce); + Execute(FFileName, o, BaseKeyboardID); finally Free; end; @@ -211,7 +232,7 @@ var begin if not FileExists(FFileName) then raise Exception.Create('File '+FFileName+' does not exist.'); - + if GetTempPath(260, buf) = 0 then raise Exception.Create('Unable to get temporary path: ' + IntToHex(GetLastError, 8) + ' ' + SysErrorMessage(GetLastError)); FTempOutPath := buf; diff --git a/windows/src/engine/kmcomapi/com/packages/keymanpackagesinstalled.pas b/windows/src/engine/kmcomapi/com/packages/keymanpackagesinstalled.pas index 9dd9f1a52a..821a38bdc5 100644 --- a/windows/src/engine/kmcomapi/com/packages/keymanpackagesinstalled.pas +++ b/windows/src/engine/kmcomapi/com/packages/keymanpackagesinstalled.pas @@ -38,7 +38,8 @@ type property Items[Index: Integer]: IIntKeymanPackageInstalled read GetItem write SetItem; default; end; - TKeymanPackagesInstalled = class(TKeymanAutoCollectionObject, IKeymanPackagesInstalled, IKeymanPackagesInstalled2) + TKeymanPackagesInstalled = class(TKeymanAutoCollectionObject, + IKeymanPackagesInstalled, IKeymanPackagesInstalled2, IKeymanPackagesInstalled3) private FPackages: TPackageList; protected @@ -51,6 +52,7 @@ type function IndexOf(const ID: WideString): Integer; safecall; procedure Install(const Filename: WideString; Force: WordBool); safecall; function Install2(const Filename: WideString; Force: WordBool): IKeymanPackageInstalled; safecall; + function Install3(const Filename: WideString; Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; safecall; public constructor Create(AContext: TKeymanContext); destructor Destroy; override; @@ -118,7 +120,7 @@ begin o := [ipLegacyRegisterAndInstallProfiles]; if Force then Include(o, ipForce); - Execute(Filename, o); + Execute(Filename, o, 0); finally Free; end; @@ -136,7 +138,29 @@ begin o := []; if Force then Include(o, ipForce); - Execute(Filename, o); + Execute(Filename, o, 0); + finally + Free; + end; + + DoRefresh; + Result := Get_Items(Filename); + + KL.MethodExit(Self, 'Install2'); +end; + +function TKeymanPackagesInstalled.Install3(const Filename: WideString; + Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; +var + o: TKPInstallPackageOptions; +begin + KL.MethodEnter(Self, 'Install2', [Filename, Force]); + with TKPInstallPackage.Create(Context) do + try + o := []; + if Force then + Include(o, ipForce); + Execute(Filename, o, BaseKeyboardID); finally Free; end; diff --git a/windows/src/engine/kmcomapi/keymanapi_TLB.pas b/windows/src/engine/kmcomapi/keymanapi_TLB.pas index 786ce6c9b2..7246c9173f 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -1569,6 +1569,17 @@ type procedure RefreshInstalledKeyboards; safecall; end; +// *********************************************************************// +// Interface: IKeymanKeyboardsInstalled3 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641} +// *********************************************************************// + IKeymanKeyboardsInstalled3 = interface(IKeymanKeyboardsInstalled) + ['{B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641}'] + function Install3(const Filename: WideString; Force: WordBool; BasePackageID: Integer): IKeymanKeyboardInstalled; safecall; + procedure RefreshInstalledKeyboards; safecall; + end; + // *********************************************************************// // Interface: IKeymanKeyboardInstalled2 // Flags: (4416) Dual OleAutomation Dispatchable @@ -1610,6 +1621,16 @@ type function Install2(const Filename: WideString; Force: WordBool): IKeymanPackageInstalled; safecall; end; +// *********************************************************************// +// Interface: IKeymanPackagesInstalled3 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458} +// *********************************************************************// + IKeymanPackagesInstalled3 = interface(IKeymanPackagesInstalled) + ['{3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458}'] + function Install3(const Filename: WideString; Force: WordBool; BasePackageID: Integer): IKeymanPackageInstalled; safecall; + end; + // *********************************************************************// // DispIntf: IKeymanPackagesInstalled2Disp // Flags: (4416) Dual OleAutomation Dispatchable @@ -1639,6 +1660,16 @@ type function Install2(Force: WordBool): IKeymanKeyboardInstalled; safecall; end; +// *********************************************************************// +// Interface: IKeymanKeyboardFile3 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {EDE4326B-51F4-42D5-8251-B20B71993EC8} +// *********************************************************************// + IKeymanKeyboardFile3 = interface(IKeymanKeyboardFile) + ['{8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4}'] + function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; safecall; + end; + // *********************************************************************// // DispIntf: IKeymanKeyboardFile2Disp // Flags: (4416) Dual OleAutomation Dispatchable @@ -1677,6 +1708,17 @@ type function Install2(Force: WordBool): IKeymanPackageInstalled; safecall; end; +// *********************************************************************// +// Interface: IKeymanPackageFile3 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7} +// *********************************************************************// + IKeymanPackageFile3 = interface(IKeymanPackageFile) + ['{C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7}'] + function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; safecall; + end; + + // *********************************************************************// // DispIntf: IKeymanPackageFile2Disp // Flags: (4416) Dual OleAutomation Dispatchable diff --git a/windows/src/engine/kmcomapi/kmcomapi.ridl b/windows/src/engine/kmcomapi/kmcomapi.ridl index 9eb63fbd68..91f49822b5 100644 --- a/windows/src/engine/kmcomapi/kmcomapi.ridl +++ b/windows/src/engine/kmcomapi/kmcomapi.ridl @@ -66,6 +66,10 @@ library keymanapi interface IKeymanPackageFile2; interface IKeymanKeyboardLanguageInstalled2; interface IKeymanKeyboardLanguagesInstalled2; + interface IKeymanKeyboardFile3; + interface IKeymanPackageFile3; + interface IKeymanKeyboardsInstalled3; + interface IKeymanPackagesInstalled3; interface IKeymanBCP47Canonicalization; interface IKeymanDefaultLanguage; @@ -976,6 +980,60 @@ library keymanapi HRESULT _stdcall Install2([in] VARIANT_BOOL Force, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); }; + [ + uuid(8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4), + version(19.0), + helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanKeyboardFile3"), + dual, + oleautomation + ] + interface IKeymanKeyboardFile3: IKeymanKeyboardFile + { + [id(0x00000121)] + HRESULT _stdcall Install3([in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); + }; + + [ + uuid(C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7), + version(19.0), + helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanPackageFile3"), + dual, + oleautomation + ] + + interface IKeymanPackageFile3: IKeymanPackageFile + { + [id(0x00000124)] + HRESULT _stdcall Install3([in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanPackageFile** Package); + }; + + + [ + uuid(B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641), + version(19.0), + helpstring("https://help.keyman.com/developer/engine/windows/19.0/api/IKeymanKeyboardInstalled2\3"), + dual, + oleautomation + ] + interface IKeymanKeyboardsInstalled3: IKeymanKeyboardsInstalled + { + [id(0x00000122)] + HRESULT _stdcall Install3([in] BSTR Filename, [in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); + }; + + [ + uuid(3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458), + version(19.0), + helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanPackagesInstalled3"), + dual, + oleautomation + ] + interface IKeymanPackagesInstalled3: IKeymanPackagesInstalled + { + [id(0x00000123)] + HRESULT _stdcall Install3([in] BSTR Filename, [in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanPackageInstalled** PackageResult); + }; + [ uuid(9B43B6BC-C622-47EF-915E-6780CF53BAAA), version(14.0), diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas index 1df237b0c6..6d3bd1f3ed 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas @@ -64,7 +64,7 @@ type ikLegacyRegisterAndInstallProfiles); TKPInstallKeyboard = class(TKPBase) - procedure Execute(const FileName, PackageID: string; FInstallOptions: TKPInstallKeyboardOptions; Languages: TPackageKeyboardLanguageList; Force: Boolean); + procedure Execute(const FileName: string; const PackageID: string; FInstallOptions: TKPInstallKeyboardOptions; Languages: TPackageKeyboardLanguageList; Force: Boolean; BaseKeyboardID: Integer); procedure RegisterProfiles(const FileName, PackageID: string; FInstallOptions: TKPInstallKeyboardOptions; PackageLanguageMetadata: TPackageKeyboardLanguageList); private procedure LegacyRegisterAndInstallLanguageProfile(Langs: array of Integer; @@ -112,7 +112,7 @@ uses utiltsf, keymanapi_TLB; -procedure TKPInstallKeyboard.Execute(const FileName, PackageID: string; FInstallOptions: TKPInstallKeyboardOptions; Languages: TPackageKeyboardLanguageList; Force: Boolean); +procedure TKPInstallKeyboard.Execute(const FileName: string; const PackageID: string; FInstallOptions: TKPInstallKeyboardOptions; Languages: TPackageKeyboardLanguageList; Force: Boolean; BaseKeyboardID: Integer); var ki: TKeyboardInfo; FDestPath: string; @@ -125,7 +125,9 @@ var FExitCode: Integer; FKVKName: WideString; FCreatedIcon: Boolean; - BaseKeyboardID: Integer; + ElevatedBaseKeyboardID: Integer; + KeymanContext: TKeymanContext; + RecompileMnemonicKeyboard: TKPRecompileMnemonicKeyboard; begin KL.MethodEnter(Self, 'Execute', [FileName,PackageID,ikPartOfPackage in FInstallOptions ,Force]); try @@ -246,14 +248,19 @@ begin KL.Log(FLogText); end; - // Recompile a mnemonic layout to the user's selected base layout + // Recompile a mnemonic layout to the user's selected base layout. If + // the baselayout has not been passed through (=0) then use the current + // process configured value which is likely the Admin user if ki.MnemonicLayout then // I4169 begin - with Context as TKeymanContext do - BaseKeyboardID := (Options as IKeymanOptions).Items['koBaseLayout'].Value; - with TKPRecompileMnemonicKeyboard.Create(Context) do + KeymanContext := Context as TKeymanContext; + ElevatedBaseKeyboardID := (KeymanContext.Options as IKeymanOptions).Items['koBaseLayout'].Value; + RecompileMnemonicKeyboard := TKPRecompileMnemonicKeyboard.Create(Context); try - Execute(FDestFileName, PackageID, BaseKeyboardID); + if (BaseKeyboardID = 0) then + RecompileMnemonicKeyboard.Execute(FDestFileName, PackageID, ElevatedBaseKeyboardID) + else + RecompileMnemonicKeyboard.Execute(FDestFileName, PackageID, BaseKeyboardID); finally Free; end; diff --git a/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas b/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas index 98edfbf3fb..4ab33cdfee 100644 --- a/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas +++ b/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas @@ -50,7 +50,7 @@ type TKPInstallPackage = class(TKPBase) public - procedure Execute(const FileName: string; Options: TKPInstallPackageOptions); + procedure Execute(const FileName: string; Options: TKPInstallPackageOptions; BaseKeyboardID: Integer); end; implementation @@ -85,7 +85,7 @@ uses { TKPInstallPackage } -procedure TKPInstallPackage.Execute(const FileName: string; Options: TKPInstallPackageOptions); +procedure TKPInstallPackage.Execute(const FileName: string; Options: TKPInstallPackageOptions; BaseKeyboardID: Integer); function GetHHIcon: string; var buf: array[0..260] of char; @@ -112,7 +112,7 @@ var FErrorValue: Cardinal; FSrcFileName: string; - procedure InstallKeyboard(FileName: string); + procedure InstallKeyboard(FileName: string; BaseKeyboardID: Integer); var FOptions: TKPInstallKeyboardOptions; kbd: TPackageKeyboard; @@ -132,7 +132,7 @@ var with TKPInstallKeyboard.Create(Context) do try - Execute(FileName, PackageName, FOptions, FLanguages, ipForce in Options); + Execute(FileName, PackageName, FOptions, FLanguages, ipForce in Options, BaseKeyboardID); finally Free; end; @@ -253,12 +253,12 @@ begin begin case inf.Files[i].FileType of ftKeymanFile: - InstallKeyboard(dest + inf.Files[i].FileName); + InstallKeyboard(dest + inf.Files[i].FileName, BaseKeyboardID); ftPackageFile: with TKPInstallPackage.Create(Context) do try - Execute(dest + inf.Files[i].FileName, Options); + Execute(dest + inf.Files[i].FileName, Options, BaseKeyboardID); finally Free; end; From 155b8e15edab819bde11b564423a950366a05812 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Tue, 1 Sep 2026 15:53:48 +1000 Subject: [PATCH 07/26] fix(windows): strtoint for command line basekeyboardid Also rebuild kmcomapi_TLB.pas --- windows/src/desktop/kmshell/main/initprog.pas | 2 +- windows/src/engine/kmcomapi/keymanapi_TLB.pas | 251 ++++++++++++++---- windows/src/engine/kmcomapi/kmcomapi.ridl | 108 ++++---- 3 files changed, 252 insertions(+), 109 deletions(-) diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas index 0f0cc6f367..b1afe4e10f 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -263,7 +263,7 @@ begin else if s = '-bd' then FMode := fmBackgroundDownload else if s = '-an' then FMode := fmApplyInstallNow else if s = '-basekeyboard' then FMode := fmBaseKeyboard // I4169 - else if s = 'bkd' then begin Inc(i); FBaseKeyboard := ParamStr(i); end + else if s = 'bkd' then begin Inc(i); FBaseKeyboard := StrToInt('$' + ParamStr(i)); end else if s = '-mcompilekbds' then begin FMode := fmMCompileKbds; diff --git a/windows/src/engine/kmcomapi/keymanapi_TLB.pas b/windows/src/engine/kmcomapi/keymanapi_TLB.pas index 7246c9173f..3c436dc5d9 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -12,7 +12,7 @@ unit keymanapi_TLB; // ************************************************************************ // // $Rev: 52393 $ -// File generated on 16/09/2021 6:54:44 PM from Type Library described below. +// File generated on 31/08/2026 5:28:13 PM from Type Library described below. // ************************************************************************ // // Type Lib: C:\Projects\keyman\app\windows\src\engine\kmcomapi\kmcomapi (1) @@ -87,11 +87,16 @@ const IID_IKeymanKeyboardLanguagesInstalled: TGUID = '{7DC22BC0-85BB-45C0-8EDB-A2F4BD1D500B}'; IID_IKeymanKeyboardLanguagesFile: TGUID = '{5F90BCDA-F1C1-433A-8FD0-B498299D3C30}'; IID_IKeymanKeyboardsInstalled2: TGUID = '{EA57C94F-C140-485E-941A-3F1D5A229024}'; + IID_IKeymanKeyboardInstalled2: TGUID = '{3086C85C-932A-4726-BF76-2D74DD133AC9}'; IID_IKeymanPackagesInstalled2: TGUID = '{F23B9848-2AEF-4A2B-BC3A-292E3A00D691}'; IID_IKeymanKeyboardFile2: TGUID = '{EDE4326B-51F4-42D5-8251-B20B71993EC8}'; IID_IKeymanPackageFile2: TGUID = '{9B43B6BC-C622-47EF-915E-6780CF53BAAA}'; IID_IKeymanKeyboardLanguageInstalled2: TGUID = '{414C26E6-BFAC-4A70-9EA1-E525BA9BBA7E}'; IID_IKeymanKeyboardLanguagesInstalled2: TGUID = '{628FF2E6-B490-462E-8FC7-7AE53B9D392C}'; + IID_IKeymanKeyboardFile3: TGUID = '{8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4}'; + IID_IKeymanPackageFile3: TGUID = '{C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7}'; + IID_IKeymanKeyboardsInstalled3: TGUID = '{B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641}'; + IID_IKeymanPackagesInstalled3: TGUID = '{3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458}'; CLASS_Keyman: TGUID = '{CF46549D-4D2D-4679-A2E1-23A815F172F8}'; IID_IKeymanDefaultLanguage: TGUID = '{77BAB934-B7DF-4304-AFA6-B8F6BEC16516}'; @@ -248,6 +253,8 @@ type IKeymanKeyboardLanguagesFileDisp = dispinterface; IKeymanKeyboardsInstalled2 = interface; IKeymanKeyboardsInstalled2Disp = dispinterface; + IKeymanKeyboardInstalled2 = interface; + IKeymanKeyboardInstalled2Disp = dispinterface; IKeymanPackagesInstalled2 = interface; IKeymanPackagesInstalled2Disp = dispinterface; IKeymanKeyboardFile2 = interface; @@ -258,6 +265,14 @@ type IKeymanKeyboardLanguageInstalled2Disp = dispinterface; IKeymanKeyboardLanguagesInstalled2 = interface; IKeymanKeyboardLanguagesInstalled2Disp = dispinterface; + IKeymanKeyboardFile3 = interface; + IKeymanKeyboardFile3Disp = dispinterface; + IKeymanPackageFile3 = interface; + IKeymanPackageFile3Disp = dispinterface; + IKeymanKeyboardsInstalled3 = interface; + IKeymanKeyboardsInstalled3Disp = dispinterface; + IKeymanPackagesInstalled3 = interface; + IKeymanPackagesInstalled3Disp = dispinterface; IKeymanDefaultLanguage = interface; IKeymanDefaultLanguageDisp = dispinterface; @@ -1569,27 +1584,6 @@ type procedure RefreshInstalledKeyboards; safecall; end; -// *********************************************************************// -// Interface: IKeymanKeyboardsInstalled3 -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641} -// *********************************************************************// - IKeymanKeyboardsInstalled3 = interface(IKeymanKeyboardsInstalled) - ['{B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641}'] - function Install3(const Filename: WideString; Force: WordBool; BasePackageID: Integer): IKeymanKeyboardInstalled; safecall; - procedure RefreshInstalledKeyboards; safecall; - end; - -// *********************************************************************// -// Interface: IKeymanKeyboardInstalled2 -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {3086C85C-932A-4726-BF76-2D74DD133AC9} -// *********************************************************************// - IKeymanKeyboardInstalled2 = interface(IKeymanKeyboardInstalled) - ['{3086C85C-932A-4726-BF76-2D74DD133AC9}'] - procedure MCompileForBaseKeyboard(KLID: Integer); safecall; - end; - // *********************************************************************// // DispIntf: IKeymanKeyboardsInstalled2Disp // Flags: (4416) Dual OleAutomation Dispatchable @@ -1611,6 +1605,51 @@ type out References: OleVariant): WideString; dispid 401; end; +// *********************************************************************// +// Interface: IKeymanKeyboardInstalled2 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {3086C85C-932A-4726-BF76-2D74DD133AC9} +// *********************************************************************// + IKeymanKeyboardInstalled2 = interface(IKeymanKeyboardInstalled) + ['{3086C85C-932A-4726-BF76-2D74DD133AC9}'] + procedure MCompileForBaseKeyboard(KLID: Integer); safecall; + end; + +// *********************************************************************// +// DispIntf: IKeymanKeyboardInstalled2Disp +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {3086C85C-932A-4726-BF76-2D74DD133AC9} +// *********************************************************************// + IKeymanKeyboardInstalled2Disp = dispinterface + ['{3086C85C-932A-4726-BF76-2D74DD133AC9}'] + procedure MCompileForBaseKeyboard(KLID: Integer); dispid 288; + property IconFilename: WideString readonly dispid 257; + procedure InstallVisualKeyboard(const Filename: WideString); dispid 258; + property KeymanID: Integer readonly dispid 259; + property Languages: IKeymanKeyboardLanguagesInstalled readonly dispid 260; + property Loaded: WordBool dispid 261; + property Options: IKeymanKeyboardOptions readonly dispid 262; + property OwnerPackage: IKeymanPackageInstalled readonly dispid 263; + property VisualKeyboard: IKeymanVisualKeyboard readonly dispid 264; + procedure Uninstall; dispid 265; + property Bitmap: IPicture readonly dispid 1; + property Copyright: WideString readonly dispid 2; + property DefaultBCP47Languages: WideString readonly dispid 3; + property DefaultPrimaryLanguage: Integer readonly dispid 4; + property DefaultWindowsLanguages: WideString readonly dispid 5; + property DefaultHotkey: IKeymanHotkey readonly dispid 6; + property Encodings: KeymanKeyboardEncodings readonly dispid 7; + property Filename: WideString readonly dispid 8; + function GetCharsUsed: WideString; dispid 9; + property ID: WideString readonly dispid 10; + property LayoutType: KeymanKeyboardLayoutType readonly dispid 11; + property Message: WideString readonly dispid 12; + property Name: WideString readonly dispid 13; + property Version: WideString readonly dispid 14; + function SerializeXML(Flags: tagKeymanSerializeFlags; const ImagePath: WideString; + out References: OleVariant): WideString; dispid 401; + end; + // *********************************************************************// // Interface: IKeymanPackagesInstalled2 // Flags: (4416) Dual OleAutomation Dispatchable @@ -1621,16 +1660,6 @@ type function Install2(const Filename: WideString; Force: WordBool): IKeymanPackageInstalled; safecall; end; -// *********************************************************************// -// Interface: IKeymanPackagesInstalled3 -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458} -// *********************************************************************// - IKeymanPackagesInstalled3 = interface(IKeymanPackagesInstalled) - ['{3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458}'] - function Install3(const Filename: WideString; Force: WordBool; BasePackageID: Integer): IKeymanPackageInstalled; safecall; - end; - // *********************************************************************// // DispIntf: IKeymanPackagesInstalled2Disp // Flags: (4416) Dual OleAutomation Dispatchable @@ -1660,16 +1689,6 @@ type function Install2(Force: WordBool): IKeymanKeyboardInstalled; safecall; end; -// *********************************************************************// -// Interface: IKeymanKeyboardFile3 -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {EDE4326B-51F4-42D5-8251-B20B71993EC8} -// *********************************************************************// - IKeymanKeyboardFile3 = interface(IKeymanKeyboardFile) - ['{8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4}'] - function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; safecall; - end; - // *********************************************************************// // DispIntf: IKeymanKeyboardFile2Disp // Flags: (4416) Dual OleAutomation Dispatchable @@ -1708,17 +1727,6 @@ type function Install2(Force: WordBool): IKeymanPackageInstalled; safecall; end; -// *********************************************************************// -// Interface: IKeymanPackageFile3 -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7} -// *********************************************************************// - IKeymanPackageFile3 = interface(IKeymanPackageFile) - ['{C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7}'] - function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; safecall; - end; - - // *********************************************************************// // DispIntf: IKeymanPackageFile2Disp // Flags: (4416) Dual OleAutomation Dispatchable @@ -1820,6 +1828,143 @@ type out References: OleVariant): WideString; dispid 401; end; +// *********************************************************************// +// Interface: IKeymanKeyboardFile3 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4} +// *********************************************************************// + IKeymanKeyboardFile3 = interface(IKeymanKeyboardFile) + ['{8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4}'] + function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; safecall; + end; + +// *********************************************************************// +// DispIntf: IKeymanKeyboardFile3Disp +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4} +// *********************************************************************// + IKeymanKeyboardFile3Disp = dispinterface + ['{8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4}'] + function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; dispid 289; + procedure Install(Force: WordBool); dispid 256; + property Languages: IKeymanKeyboardLanguagesFile readonly dispid 402; + property Bitmap: IPicture readonly dispid 1; + property Copyright: WideString readonly dispid 2; + property DefaultBCP47Languages: WideString readonly dispid 3; + property DefaultPrimaryLanguage: Integer readonly dispid 4; + property DefaultWindowsLanguages: WideString readonly dispid 5; + property DefaultHotkey: IKeymanHotkey readonly dispid 6; + property Encodings: KeymanKeyboardEncodings readonly dispid 7; + property Filename: WideString readonly dispid 8; + function GetCharsUsed: WideString; dispid 9; + property ID: WideString readonly dispid 10; + property LayoutType: KeymanKeyboardLayoutType readonly dispid 11; + property Message: WideString readonly dispid 12; + property Name: WideString readonly dispid 13; + property Version: WideString readonly dispid 14; + function SerializeXML(Flags: tagKeymanSerializeFlags; const ImagePath: WideString; + out References: OleVariant): WideString; dispid 401; + end; + +// *********************************************************************// +// Interface: IKeymanPackageFile3 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7} +// *********************************************************************// + IKeymanPackageFile3 = interface(IKeymanPackageFile) + ['{C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7}'] + function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageFile; safecall; + end; + +// *********************************************************************// +// DispIntf: IKeymanPackageFile3Disp +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7} +// *********************************************************************// + IKeymanPackageFile3Disp = dispinterface + ['{C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7}'] + function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageFile; dispid 292; + procedure Install(Force: WordBool); dispid 256; + property Author: WideString readonly dispid 1; + property AuthorEmail: WideString readonly dispid 2; + property Copyright: WideString readonly dispid 3; + property Filename: WideString readonly dispid 4; + property Files: IKeymanPackageContentFiles readonly dispid 5; + property Fonts: IKeymanPackageContentFonts readonly dispid 6; + property Graphic: IPicture readonly dispid 7; + property GraphicFile: IKeymanPackageContentFile readonly dispid 8; + property ID: WideString readonly dispid 9; + property KeyboardOptionsFile: IKeymanPackageContentFile readonly dispid 10; + property Keyboards: IKeymanPackageContentKeyboards readonly dispid 11; + property Name: WideString readonly dispid 12; + property ReadmeFile: IKeymanPackageContentFile readonly dispid 13; + property UsageFile: IKeymanPackageContentFile readonly dispid 14; + property Version: WideString readonly dispid 15; + property WelcomeFile: IKeymanPackageContentFile readonly dispid 16; + property Website: WideString readonly dispid 17; + function SerializeXML(Flags: tagKeymanSerializeFlags; const ImagePath: WideString; + out References: OleVariant): WideString; dispid 401; + end; + +// *********************************************************************// +// Interface: IKeymanKeyboardsInstalled3 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641} +// *********************************************************************// + IKeymanKeyboardsInstalled3 = interface(IKeymanKeyboardsInstalled) + ['{B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641}'] + function Install3(const Filename: WideString; Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; safecall; + end; + +// *********************************************************************// +// DispIntf: IKeymanKeyboardsInstalled3Disp +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641} +// *********************************************************************// + IKeymanKeyboardsInstalled3Disp = dispinterface + ['{B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641}'] + function Install3(const Filename: WideString; Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; dispid 290; + property Items[Index: OleVariant]: IKeymanKeyboardInstalled readonly dispid 0; default; + function GetKeyboardFromFile(const Filename: WideString): IKeymanKeyboardFile; dispid 16; + procedure Install(const Filename: WideString; Force: WordBool); dispid 17; + procedure Apply; dispid 18; + function IndexOf(const ID: WideString): Integer; dispid 5; + property Count: Integer readonly dispid 1; + property _NewEnum: IUnknown readonly dispid -4; + procedure Refresh; dispid 2; + function SerializeXML(Flags: tagKeymanSerializeFlags; const ImagePath: WideString; + out References: OleVariant): WideString; dispid 401; + end; + +// *********************************************************************// +// Interface: IKeymanPackagesInstalled3 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458} +// *********************************************************************// + IKeymanPackagesInstalled3 = interface(IKeymanPackagesInstalled) + ['{3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458}'] + function Install3(const Filename: WideString; Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; safecall; + end; + +// *********************************************************************// +// DispIntf: IKeymanPackagesInstalled3Disp +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458} +// *********************************************************************// + IKeymanPackagesInstalled3Disp = dispinterface + ['{3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458}'] + function Install3(const Filename: WideString; Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; dispid 291; + property Items[Index: OleVariant]: IKeymanPackageInstalled readonly dispid 0; default; + function GetPackageFromFile(const Filename: WideString): IKeymanPackageFile; dispid 16; + procedure Install(const Filename: WideString; Force: WordBool); dispid 17; + function IndexOf(const ID: WideString): Integer; dispid 18; + property Count: Integer readonly dispid 1; + property _NewEnum: IUnknown readonly dispid -4; + procedure Refresh; dispid 2; + function SerializeXML(Flags: tagKeymanSerializeFlags; const ImagePath: WideString; + out References: OleVariant): WideString; dispid 401; + end; + // *********************************************************************// // Interface: IKeymanDefaultLanguage // Flags: (4416) Dual OleAutomation Dispatchable diff --git a/windows/src/engine/kmcomapi/kmcomapi.ridl b/windows/src/engine/kmcomapi/kmcomapi.ridl index 91f49822b5..ecfff3d707 100644 --- a/windows/src/engine/kmcomapi/kmcomapi.ridl +++ b/windows/src/engine/kmcomapi/kmcomapi.ridl @@ -6,7 +6,7 @@ // However, when applying changes via the Editor this file will be regenerated // and comments or formatting changes will be lost. // ************************************************************************ // -// File generated on 16/09/2021 6:54:45 PM (- $Rev: 12980 $, 32940875). +// File generated on 31/08/2026 5:28:15 PM (- $Rev: 12980 $, 11059984). [ uuid(F16E2A9A-DA46-4EA3-BFF3-BA46B480C961), @@ -980,60 +980,6 @@ library keymanapi HRESULT _stdcall Install2([in] VARIANT_BOOL Force, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); }; - [ - uuid(8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4), - version(19.0), - helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanKeyboardFile3"), - dual, - oleautomation - ] - interface IKeymanKeyboardFile3: IKeymanKeyboardFile - { - [id(0x00000121)] - HRESULT _stdcall Install3([in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); - }; - - [ - uuid(C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7), - version(19.0), - helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanPackageFile3"), - dual, - oleautomation - ] - - interface IKeymanPackageFile3: IKeymanPackageFile - { - [id(0x00000124)] - HRESULT _stdcall Install3([in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanPackageFile** Package); - }; - - - [ - uuid(B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641), - version(19.0), - helpstring("https://help.keyman.com/developer/engine/windows/19.0/api/IKeymanKeyboardInstalled2\3"), - dual, - oleautomation - ] - interface IKeymanKeyboardsInstalled3: IKeymanKeyboardsInstalled - { - [id(0x00000122)] - HRESULT _stdcall Install3([in] BSTR Filename, [in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); - }; - - [ - uuid(3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458), - version(19.0), - helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanPackagesInstalled3"), - dual, - oleautomation - ] - interface IKeymanPackagesInstalled3: IKeymanPackagesInstalled - { - [id(0x00000123)] - HRESULT _stdcall Install3([in] BSTR Filename, [in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanPackageInstalled** PackageResult); - }; - [ uuid(9B43B6BC-C622-47EF-915E-6780CF53BAAA), version(14.0), @@ -1079,6 +1025,58 @@ library keymanapi HRESULT _stdcall Add([in] BSTR BCP47Tag, [out, retval] IKeymanKeyboardLanguageInstalled** Result); }; + [ + uuid(8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4), + version(19.0), + helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanKeyboardFile3"), + dual, + oleautomation + ] + interface IKeymanKeyboardFile3: IKeymanKeyboardFile + { + [id(0x00000121)] + HRESULT _stdcall Install3([in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); + }; + + [ + uuid(C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7), + version(19.0), + helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanPackageFile3"), + dual, + oleautomation + ] + interface IKeymanPackageFile3: IKeymanPackageFile + { + [id(0x00000124)] + HRESULT _stdcall Install3([in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanPackageFile** Package); + }; + + [ + uuid(B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641), + version(19.0), + helpstring("https://help.keyman.com/developer/engine/windows/19.0/api/IKeymanKeyboardInstalled2\x03"), + dual, + oleautomation + ] + interface IKeymanKeyboardsInstalled3: IKeymanKeyboardsInstalled + { + [id(0x00000122)] + HRESULT _stdcall Install3([in] BSTR Filename, [in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); + }; + + [ + uuid(3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458), + version(19.0), + helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanPackagesInstalled3"), + dual, + oleautomation + ] + interface IKeymanPackagesInstalled3: IKeymanPackagesInstalled + { + [id(0x00000123)] + HRESULT _stdcall Install3([in] BSTR Filename, [in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanPackageInstalled** PackageResult); + }; + [ uuid(CA3B3B00-EA42-4EED-9043-D1A1F1842D52), dual, From 0c68b1e0314086b94deb9ed0a5bf6e2697196ab6 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Wed, 2 Sep 2026 10:10:16 +1000 Subject: [PATCH 08/26] fix(windows): typos and return type in interface declaration --- windows/src/desktop/kmshell/main/initprog.pas | 2 +- windows/src/engine/kmcomapi/keymanapi_TLB.pas | 4 ++-- windows/src/engine/kmcomapi/kmcomapi.ridl | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas index b1afe4e10f..f4d2a4161d 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -263,7 +263,7 @@ begin else if s = '-bd' then FMode := fmBackgroundDownload else if s = '-an' then FMode := fmApplyInstallNow else if s = '-basekeyboard' then FMode := fmBaseKeyboard // I4169 - else if s = 'bkd' then begin Inc(i); FBaseKeyboard := StrToInt('$' + ParamStr(i)); end + else if s = '-bkd' then begin Inc(i); FBaseKeyboard := StrToInt('$' + ParamStr(i)); end else if s = '-mcompilekbds' then begin FMode := fmMCompileKbds; diff --git a/windows/src/engine/kmcomapi/keymanapi_TLB.pas b/windows/src/engine/kmcomapi/keymanapi_TLB.pas index 3c436dc5d9..b0530cb94a 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -1873,7 +1873,7 @@ type // *********************************************************************// IKeymanPackageFile3 = interface(IKeymanPackageFile) ['{C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7}'] - function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageFile; safecall; + function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; safecall; end; // *********************************************************************// @@ -1883,7 +1883,7 @@ type // *********************************************************************// IKeymanPackageFile3Disp = dispinterface ['{C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7}'] - function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageFile; dispid 292; + function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; dispid 292; procedure Install(Force: WordBool); dispid 256; property Author: WideString readonly dispid 1; property AuthorEmail: WideString readonly dispid 2; diff --git a/windows/src/engine/kmcomapi/kmcomapi.ridl b/windows/src/engine/kmcomapi/kmcomapi.ridl index ecfff3d707..0b2366c144 100644 --- a/windows/src/engine/kmcomapi/kmcomapi.ridl +++ b/windows/src/engine/kmcomapi/kmcomapi.ridl @@ -1048,7 +1048,7 @@ library keymanapi interface IKeymanPackageFile3: IKeymanPackageFile { [id(0x00000124)] - HRESULT _stdcall Install3([in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanPackageFile** Package); + HRESULT _stdcall Install3([in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanPackageInstalled** PackageResult); }; [ From 3c1b47eedc2bc9d8422fee659fddbdd2edbf4432 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Wed, 2 Sep 2026 12:37:03 +1000 Subject: [PATCH 09/26] fix(windows): Free the correct object --- .../engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas index 6d3bd1f3ed..1d198264cb 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas @@ -262,7 +262,7 @@ begin else RecompileMnemonicKeyboard.Execute(FDestFileName, PackageID, BaseKeyboardID); finally - Free; + RecompileMnemonicKeyboard.Free; end; end; finally From 8e77a5779a992f970b2a8f59caa0980b2c7f4af2 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Wed, 2 Sep 2026 17:54:26 +1000 Subject: [PATCH 10/26] fix(windows): CompileForBaseKeyboard doesn't return a value --- .../desktop/kmshell/main/UfrmBaseKeyboard.pas | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas index e9ce67d5e3..1f136871e6 100644 --- a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas @@ -21,7 +21,7 @@ type function ConfigureBaseKeyboard(out BaseKeyboardID: Integer): Boolean; function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolean; function MCompileBaseKeyboard(const BaseKeyboardIDText: string): Boolean; -function CompileForBaseKeyboard(BaseKeyboardID: Integer): Boolean; +procedure CompileForBaseKeyboard(BaseKeyboardID: Integer); implementation @@ -84,7 +84,9 @@ begin if not TryStrToInt('$' + BaseKeyboardIDText, BaseKeyboardID) or not kmcom.SystemInfo.IsAdministrator then Exit; - Result := CompileForBaseKeyboard(BaseKeyboardID); + CompileForBaseKeyboard(BaseKeyboardID); + // TODO: sort out whether we need todo return a result + Result := True; end; function BaseKeyboardNeedsMCompile(BaseKeyboardID: Integer): Boolean; @@ -108,29 +110,24 @@ begin end; function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolean; -var - MCompileResult: Boolean; begin - MCompileResult := True; Result := False; if BaseKeyboardNeedsMCompile(BaseKeyboardID) then begin if not kmcom.SystemInfo.IsAdministrator then begin - MCompileResult := WaitForElevatedConfiguration(WindowHandle, '-mcompilekbds ' + IntToHex(BaseKeyboardID, 8)) = 0; + WaitForElevatedConfiguration(WindowHandle, '-mcompilekbds ' + IntToHex(BaseKeyboardID, 8)); end else - MCompileResult := CompileForBaseKeyboard(BaseKeyboardID); + CompileForBaseKeyboard(BaseKeyboardID); end; - if not MCompileResult then - Exit; kmcom.Options['koBaseLayout'].Value := BaseKeyboardID; kmcom.Options.Apply; Result := True; end; -function CompileForBaseKeyboard(BaseKeyboardID: Integer): Boolean; +procedure CompileForBaseKeyboard(BaseKeyboardID: Integer); var i: Integer; kbd: IKeymanKeyboardInstalled; From 314dea4bacf1dbbedbeaa2064984e0ea6a583bef Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Thu, 3 Sep 2026 16:17:21 +1000 Subject: [PATCH 11/26] fix(windows): move non ui function from ufrmbasekeyboard --- windows/src/desktop/kmshell/kmshell.dpr | 3 +- windows/src/desktop/kmshell/kmshell.dproj | 13 +-- .../desktop/kmshell/main/UfrmBaseKeyboard.pas | 65 --------------- windows/src/desktop/kmshell/main/UfrmMain.pas | 1 + windows/src/desktop/kmshell/main/initprog.pas | 1 + ...an.Configuration.Settings.BaseKeyboard.pas | 83 +++++++++++++++++++ 6 files changed, 94 insertions(+), 72 deletions(-) create mode 100644 windows/src/desktop/kmshell/settings/Keyman.Configuration.Settings.BaseKeyboard.pas diff --git a/windows/src/desktop/kmshell/kmshell.dpr b/windows/src/desktop/kmshell/kmshell.dpr index e2d28b88d2..e4ce8316d3 100644 --- a/windows/src/desktop/kmshell/kmshell.dpr +++ b/windows/src/desktop/kmshell/kmshell.dpr @@ -183,7 +183,8 @@ uses Keyman.System.DownloadUpdate in 'main\Keyman.System.DownloadUpdate.pas', Keyman.System.ExecutionHistory in '..\..\..\..\common\windows\delphi\general\Keyman.System.ExecutionHistory.pas', Keyman.Configuration.UI.UfrmStartInstall in 'main\Keyman.Configuration.UI.UfrmStartInstall.pas' {frmStartInstall}, - Keyman.Configuration.Util.NetworkConnection in 'util\Keyman.Configuration.Util.NetworkConnection.pas'; + Keyman.Configuration.Util.NetworkConnection in 'util\Keyman.Configuration.Util.NetworkConnection.pas', + Keyman.Configuration.Settings.BaseKeyboard in 'settings\Keyman.Configuration.Settings.BaseKeyboard.pas'; {$R VERSION.RES} {$R manifest.res} diff --git a/windows/src/desktop/kmshell/kmshell.dproj b/windows/src/desktop/kmshell/kmshell.dproj index 371ce4cd49..ca611b40e4 100644 --- a/windows/src/desktop/kmshell/kmshell.dproj +++ b/windows/src/desktop/kmshell/kmshell.dproj @@ -358,6 +358,7 @@
frmStartInstall
+ Cfg_2 @@ -419,6 +420,12 @@ False + + + kmshell.exe + true + + .\ @@ -431,12 +438,6 @@ true - - - kmshell.exe - true - - 1 diff --git a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas index 1f136871e6..56e7c442b4 100644 --- a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas @@ -19,9 +19,6 @@ type end; function ConfigureBaseKeyboard(out BaseKeyboardID: Integer): Boolean; -function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolean; -function MCompileBaseKeyboard(const BaseKeyboardIDText: string): Boolean; -procedure CompileForBaseKeyboard(BaseKeyboardID: Integer); implementation @@ -76,67 +73,5 @@ begin ModalResult := mrOk; end; -function MCompileBaseKeyboard(const BaseKeyboardIDText: string): Boolean; -var - BaseKeyboardID: Integer; -begin - Result := False; - if not TryStrToInt('$' + BaseKeyboardIDText, BaseKeyboardID) or - not kmcom.SystemInfo.IsAdministrator then - Exit; - CompileForBaseKeyboard(BaseKeyboardID); - // TODO: sort out whether we need todo return a result - Result := True; -end; - -function BaseKeyboardNeedsMCompile(BaseKeyboardID: Integer): Boolean; -var - I: Integer; - Keyboard: IKeymanKeyboardInstalled; - BaseFileName: string; - BaseKeyboardIDHex: string; -begin - BaseKeyboardIDHex := IntToHex(BaseKeyboardID, 8); - for I := 0 to kmcom.Keyboards.Count - 1 do - begin - Keyboard := kmcom.Keyboards.Items[I]; - BaseFileName := Keyboard.Filename; - if FileExists(BaseFileName) and - (not FileExists(ChangeFileExt(BaseFileName, '') + '-' + BaseKeyboardIDHex + '.kmx') or - not FileExists(ChangeFileExt(BaseFileName, '') + '-' + BaseKeyboardIDHex + '-d.kmx')) then - Exit(True); - end; - Result := False; -end; - -function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolean; -begin - Result := False; - if BaseKeyboardNeedsMCompile(BaseKeyboardID) then - begin - if not kmcom.SystemInfo.IsAdministrator then - begin - WaitForElevatedConfiguration(WindowHandle, '-mcompilekbds ' + IntToHex(BaseKeyboardID, 8)); - end - else - CompileForBaseKeyboard(BaseKeyboardID); - end; - - kmcom.Options['koBaseLayout'].Value := BaseKeyboardID; - kmcom.Options.Apply; - Result := True; -end; - -procedure CompileForBaseKeyboard(BaseKeyboardID: Integer); -var - i: Integer; - kbd: IKeymanKeyboardInstalled; -begin - for i := 0 to kmcom.Keyboards.Count - 1 do - begin - kbd := kmcom.Keyboards[i]; - (kbd as IKeymanKeyboardInstalled2).MCompileForBaseKeyboard(BaseKeyboardID); - end; -end; end. diff --git a/windows/src/desktop/kmshell/main/UfrmMain.pas b/windows/src/desktop/kmshell/main/UfrmMain.pas index 100fd24fd2..599566b91c 100644 --- a/windows/src/desktop/kmshell/main/UfrmMain.pas +++ b/windows/src/desktop/kmshell/main/UfrmMain.pas @@ -174,6 +174,7 @@ uses Hints, HotkeyUtils, initprog, + Keyman.Configuration.Settings.BaseKeyboard, Keyman.Configuration.System.TIPMaintenance, Keyman.Configuration.UI.UfrmDiagnosticTests, KeymanOptionNames, diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas index f4d2a4161d..2d6cc1e6d2 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -115,6 +115,7 @@ uses GetOsVersion, help, HTMLHelpViewer, + Keyman.Configuration.Settings.BaseKeyboard, Keyman.Configuration.UI.InstallFile, Keyman.Configuration.System.TIPMaintenance, Keyman.Configuration.System.UImportOlderVersionKeyboards11To13, diff --git a/windows/src/desktop/kmshell/settings/Keyman.Configuration.Settings.BaseKeyboard.pas b/windows/src/desktop/kmshell/settings/Keyman.Configuration.Settings.BaseKeyboard.pas new file mode 100644 index 0000000000..44488179c9 --- /dev/null +++ b/windows/src/desktop/kmshell/settings/Keyman.Configuration.Settings.BaseKeyboard.pas @@ -0,0 +1,83 @@ +unit Keyman.Configuration.Settings.BaseKeyboard; + +interface + +uses + Winapi.Windows, + System.SysUtils, + keymanapi_TLB; + +function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolean; +function MCompileBaseKeyboard(const BaseKeyboardIDText: string): Boolean; +procedure CompileForBaseKeyboard(BaseKeyboardID: Integer); + +implementation + +uses + kmint, + utilkmshell; + +function BaseKeyboardNeedsMCompile(BaseKeyboardID: Integer): Boolean; +var + I: Integer; + Keyboard: IKeymanKeyboardInstalled; + BaseFileName: string; + BaseKeyboardIDHex: string; +begin + BaseKeyboardIDHex := IntToHex(BaseKeyboardID, 8); + for I := 0 to kmcom.Keyboards.Count - 1 do + begin + Keyboard := kmcom.Keyboards.Items[I]; + BaseFileName := Keyboard.Filename; + if FileExists(BaseFileName) and + (not FileExists(ChangeFileExt(BaseFileName, '') + '-' + BaseKeyboardIDHex + '.kmx') or + not FileExists(ChangeFileExt(BaseFileName, '') + '-' + BaseKeyboardIDHex + '-d.kmx')) then + Exit(True); + end; + Result := False; +end; + +function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolean; +begin + Result := False; + if BaseKeyboardNeedsMCompile(BaseKeyboardID) then + begin + if not kmcom.SystemInfo.IsAdministrator then + begin + WaitForElevatedConfiguration(WindowHandle, '-mcompilekbds ' + IntToHex(BaseKeyboardID, 8)); + end + else + CompileForBaseKeyboard(BaseKeyboardID); + end; + + kmcom.Options['koBaseLayout'].Value := BaseKeyboardID; + kmcom.Options.Apply; + Result := True; +end; + +function MCompileBaseKeyboard(const BaseKeyboardIDText: string): Boolean; +var + BaseKeyboardID: Integer; +begin + Result := False; + if not TryStrToInt('$' + BaseKeyboardIDText, BaseKeyboardID) or + not kmcom.SystemInfo.IsAdministrator then + Exit; + CompileForBaseKeyboard(BaseKeyboardID); + // TODO: sort out whether we need todo return a result + Result := True; +end; + +procedure CompileForBaseKeyboard(BaseKeyboardID: Integer); +var + i: Integer; + kbd: IKeymanKeyboardInstalled; +begin + for i := 0 to kmcom.Keyboards.Count - 1 do + begin + kbd := kmcom.Keyboards[i]; + (kbd as IKeymanKeyboardInstalled2).MCompileForBaseKeyboard(BaseKeyboardID); + end; +end; + +end. From c3160944e5f2cb2277d6580a9c931883277cbf3d Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Thu, 3 Sep 2026 17:29:04 +1000 Subject: [PATCH 12/26] chore(windows): Revert "fix(windows): typos and return type in interface declaration" This reverts commit 0c68b1e0314086b94deb9ed0a5bf6e2697196ab6. --- windows/src/desktop/kmshell/main/initprog.pas | 2 +- windows/src/engine/kmcomapi/keymanapi_TLB.pas | 4 ++-- windows/src/engine/kmcomapi/kmcomapi.ridl | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas index 2d6cc1e6d2..6457542bca 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -264,7 +264,7 @@ begin else if s = '-bd' then FMode := fmBackgroundDownload else if s = '-an' then FMode := fmApplyInstallNow else if s = '-basekeyboard' then FMode := fmBaseKeyboard // I4169 - else if s = '-bkd' then begin Inc(i); FBaseKeyboard := StrToInt('$' + ParamStr(i)); end + else if s = 'bkd' then begin Inc(i); FBaseKeyboard := StrToInt('$' + ParamStr(i)); end else if s = '-mcompilekbds' then begin FMode := fmMCompileKbds; diff --git a/windows/src/engine/kmcomapi/keymanapi_TLB.pas b/windows/src/engine/kmcomapi/keymanapi_TLB.pas index b0530cb94a..3c436dc5d9 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -1873,7 +1873,7 @@ type // *********************************************************************// IKeymanPackageFile3 = interface(IKeymanPackageFile) ['{C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7}'] - function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; safecall; + function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageFile; safecall; end; // *********************************************************************// @@ -1883,7 +1883,7 @@ type // *********************************************************************// IKeymanPackageFile3Disp = dispinterface ['{C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7}'] - function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; dispid 292; + function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageFile; dispid 292; procedure Install(Force: WordBool); dispid 256; property Author: WideString readonly dispid 1; property AuthorEmail: WideString readonly dispid 2; diff --git a/windows/src/engine/kmcomapi/kmcomapi.ridl b/windows/src/engine/kmcomapi/kmcomapi.ridl index 0b2366c144..ecfff3d707 100644 --- a/windows/src/engine/kmcomapi/kmcomapi.ridl +++ b/windows/src/engine/kmcomapi/kmcomapi.ridl @@ -1048,7 +1048,7 @@ library keymanapi interface IKeymanPackageFile3: IKeymanPackageFile { [id(0x00000124)] - HRESULT _stdcall Install3([in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanPackageInstalled** PackageResult); + HRESULT _stdcall Install3([in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanPackageFile** Package); }; [ From 5e89946c004c0e1f6b83a2109d26d2e06bddd39e Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Thu, 3 Sep 2026 17:29:51 +1000 Subject: [PATCH 13/26] chore(windows): Revert "fix(windows): strtoint for command line basekeyboardid" This reverts commit 155b8e15edab819bde11b564423a950366a05812. --- windows/src/desktop/kmshell/main/initprog.pas | 2 +- windows/src/engine/kmcomapi/keymanapi_TLB.pas | 251 ++++-------------- windows/src/engine/kmcomapi/kmcomapi.ridl | 108 ++++---- 3 files changed, 109 insertions(+), 252 deletions(-) diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas index 6457542bca..3143d72828 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -264,7 +264,7 @@ begin else if s = '-bd' then FMode := fmBackgroundDownload else if s = '-an' then FMode := fmApplyInstallNow else if s = '-basekeyboard' then FMode := fmBaseKeyboard // I4169 - else if s = 'bkd' then begin Inc(i); FBaseKeyboard := StrToInt('$' + ParamStr(i)); end + else if s = 'bkd' then begin Inc(i); FBaseKeyboard := ParamStr(i); end else if s = '-mcompilekbds' then begin FMode := fmMCompileKbds; diff --git a/windows/src/engine/kmcomapi/keymanapi_TLB.pas b/windows/src/engine/kmcomapi/keymanapi_TLB.pas index 3c436dc5d9..7246c9173f 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -12,7 +12,7 @@ unit keymanapi_TLB; // ************************************************************************ // // $Rev: 52393 $ -// File generated on 31/08/2026 5:28:13 PM from Type Library described below. +// File generated on 16/09/2021 6:54:44 PM from Type Library described below. // ************************************************************************ // // Type Lib: C:\Projects\keyman\app\windows\src\engine\kmcomapi\kmcomapi (1) @@ -87,16 +87,11 @@ const IID_IKeymanKeyboardLanguagesInstalled: TGUID = '{7DC22BC0-85BB-45C0-8EDB-A2F4BD1D500B}'; IID_IKeymanKeyboardLanguagesFile: TGUID = '{5F90BCDA-F1C1-433A-8FD0-B498299D3C30}'; IID_IKeymanKeyboardsInstalled2: TGUID = '{EA57C94F-C140-485E-941A-3F1D5A229024}'; - IID_IKeymanKeyboardInstalled2: TGUID = '{3086C85C-932A-4726-BF76-2D74DD133AC9}'; IID_IKeymanPackagesInstalled2: TGUID = '{F23B9848-2AEF-4A2B-BC3A-292E3A00D691}'; IID_IKeymanKeyboardFile2: TGUID = '{EDE4326B-51F4-42D5-8251-B20B71993EC8}'; IID_IKeymanPackageFile2: TGUID = '{9B43B6BC-C622-47EF-915E-6780CF53BAAA}'; IID_IKeymanKeyboardLanguageInstalled2: TGUID = '{414C26E6-BFAC-4A70-9EA1-E525BA9BBA7E}'; IID_IKeymanKeyboardLanguagesInstalled2: TGUID = '{628FF2E6-B490-462E-8FC7-7AE53B9D392C}'; - IID_IKeymanKeyboardFile3: TGUID = '{8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4}'; - IID_IKeymanPackageFile3: TGUID = '{C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7}'; - IID_IKeymanKeyboardsInstalled3: TGUID = '{B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641}'; - IID_IKeymanPackagesInstalled3: TGUID = '{3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458}'; CLASS_Keyman: TGUID = '{CF46549D-4D2D-4679-A2E1-23A815F172F8}'; IID_IKeymanDefaultLanguage: TGUID = '{77BAB934-B7DF-4304-AFA6-B8F6BEC16516}'; @@ -253,8 +248,6 @@ type IKeymanKeyboardLanguagesFileDisp = dispinterface; IKeymanKeyboardsInstalled2 = interface; IKeymanKeyboardsInstalled2Disp = dispinterface; - IKeymanKeyboardInstalled2 = interface; - IKeymanKeyboardInstalled2Disp = dispinterface; IKeymanPackagesInstalled2 = interface; IKeymanPackagesInstalled2Disp = dispinterface; IKeymanKeyboardFile2 = interface; @@ -265,14 +258,6 @@ type IKeymanKeyboardLanguageInstalled2Disp = dispinterface; IKeymanKeyboardLanguagesInstalled2 = interface; IKeymanKeyboardLanguagesInstalled2Disp = dispinterface; - IKeymanKeyboardFile3 = interface; - IKeymanKeyboardFile3Disp = dispinterface; - IKeymanPackageFile3 = interface; - IKeymanPackageFile3Disp = dispinterface; - IKeymanKeyboardsInstalled3 = interface; - IKeymanKeyboardsInstalled3Disp = dispinterface; - IKeymanPackagesInstalled3 = interface; - IKeymanPackagesInstalled3Disp = dispinterface; IKeymanDefaultLanguage = interface; IKeymanDefaultLanguageDisp = dispinterface; @@ -1584,6 +1569,27 @@ type procedure RefreshInstalledKeyboards; safecall; end; +// *********************************************************************// +// Interface: IKeymanKeyboardsInstalled3 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641} +// *********************************************************************// + IKeymanKeyboardsInstalled3 = interface(IKeymanKeyboardsInstalled) + ['{B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641}'] + function Install3(const Filename: WideString; Force: WordBool; BasePackageID: Integer): IKeymanKeyboardInstalled; safecall; + procedure RefreshInstalledKeyboards; safecall; + end; + +// *********************************************************************// +// Interface: IKeymanKeyboardInstalled2 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {3086C85C-932A-4726-BF76-2D74DD133AC9} +// *********************************************************************// + IKeymanKeyboardInstalled2 = interface(IKeymanKeyboardInstalled) + ['{3086C85C-932A-4726-BF76-2D74DD133AC9}'] + procedure MCompileForBaseKeyboard(KLID: Integer); safecall; + end; + // *********************************************************************// // DispIntf: IKeymanKeyboardsInstalled2Disp // Flags: (4416) Dual OleAutomation Dispatchable @@ -1605,51 +1611,6 @@ type out References: OleVariant): WideString; dispid 401; end; -// *********************************************************************// -// Interface: IKeymanKeyboardInstalled2 -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {3086C85C-932A-4726-BF76-2D74DD133AC9} -// *********************************************************************// - IKeymanKeyboardInstalled2 = interface(IKeymanKeyboardInstalled) - ['{3086C85C-932A-4726-BF76-2D74DD133AC9}'] - procedure MCompileForBaseKeyboard(KLID: Integer); safecall; - end; - -// *********************************************************************// -// DispIntf: IKeymanKeyboardInstalled2Disp -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {3086C85C-932A-4726-BF76-2D74DD133AC9} -// *********************************************************************// - IKeymanKeyboardInstalled2Disp = dispinterface - ['{3086C85C-932A-4726-BF76-2D74DD133AC9}'] - procedure MCompileForBaseKeyboard(KLID: Integer); dispid 288; - property IconFilename: WideString readonly dispid 257; - procedure InstallVisualKeyboard(const Filename: WideString); dispid 258; - property KeymanID: Integer readonly dispid 259; - property Languages: IKeymanKeyboardLanguagesInstalled readonly dispid 260; - property Loaded: WordBool dispid 261; - property Options: IKeymanKeyboardOptions readonly dispid 262; - property OwnerPackage: IKeymanPackageInstalled readonly dispid 263; - property VisualKeyboard: IKeymanVisualKeyboard readonly dispid 264; - procedure Uninstall; dispid 265; - property Bitmap: IPicture readonly dispid 1; - property Copyright: WideString readonly dispid 2; - property DefaultBCP47Languages: WideString readonly dispid 3; - property DefaultPrimaryLanguage: Integer readonly dispid 4; - property DefaultWindowsLanguages: WideString readonly dispid 5; - property DefaultHotkey: IKeymanHotkey readonly dispid 6; - property Encodings: KeymanKeyboardEncodings readonly dispid 7; - property Filename: WideString readonly dispid 8; - function GetCharsUsed: WideString; dispid 9; - property ID: WideString readonly dispid 10; - property LayoutType: KeymanKeyboardLayoutType readonly dispid 11; - property Message: WideString readonly dispid 12; - property Name: WideString readonly dispid 13; - property Version: WideString readonly dispid 14; - function SerializeXML(Flags: tagKeymanSerializeFlags; const ImagePath: WideString; - out References: OleVariant): WideString; dispid 401; - end; - // *********************************************************************// // Interface: IKeymanPackagesInstalled2 // Flags: (4416) Dual OleAutomation Dispatchable @@ -1660,6 +1621,16 @@ type function Install2(const Filename: WideString; Force: WordBool): IKeymanPackageInstalled; safecall; end; +// *********************************************************************// +// Interface: IKeymanPackagesInstalled3 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458} +// *********************************************************************// + IKeymanPackagesInstalled3 = interface(IKeymanPackagesInstalled) + ['{3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458}'] + function Install3(const Filename: WideString; Force: WordBool; BasePackageID: Integer): IKeymanPackageInstalled; safecall; + end; + // *********************************************************************// // DispIntf: IKeymanPackagesInstalled2Disp // Flags: (4416) Dual OleAutomation Dispatchable @@ -1689,6 +1660,16 @@ type function Install2(Force: WordBool): IKeymanKeyboardInstalled; safecall; end; +// *********************************************************************// +// Interface: IKeymanKeyboardFile3 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {EDE4326B-51F4-42D5-8251-B20B71993EC8} +// *********************************************************************// + IKeymanKeyboardFile3 = interface(IKeymanKeyboardFile) + ['{8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4}'] + function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; safecall; + end; + // *********************************************************************// // DispIntf: IKeymanKeyboardFile2Disp // Flags: (4416) Dual OleAutomation Dispatchable @@ -1727,6 +1708,17 @@ type function Install2(Force: WordBool): IKeymanPackageInstalled; safecall; end; +// *********************************************************************// +// Interface: IKeymanPackageFile3 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7} +// *********************************************************************// + IKeymanPackageFile3 = interface(IKeymanPackageFile) + ['{C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7}'] + function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; safecall; + end; + + // *********************************************************************// // DispIntf: IKeymanPackageFile2Disp // Flags: (4416) Dual OleAutomation Dispatchable @@ -1828,143 +1820,6 @@ type out References: OleVariant): WideString; dispid 401; end; -// *********************************************************************// -// Interface: IKeymanKeyboardFile3 -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4} -// *********************************************************************// - IKeymanKeyboardFile3 = interface(IKeymanKeyboardFile) - ['{8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4}'] - function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; safecall; - end; - -// *********************************************************************// -// DispIntf: IKeymanKeyboardFile3Disp -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4} -// *********************************************************************// - IKeymanKeyboardFile3Disp = dispinterface - ['{8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4}'] - function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; dispid 289; - procedure Install(Force: WordBool); dispid 256; - property Languages: IKeymanKeyboardLanguagesFile readonly dispid 402; - property Bitmap: IPicture readonly dispid 1; - property Copyright: WideString readonly dispid 2; - property DefaultBCP47Languages: WideString readonly dispid 3; - property DefaultPrimaryLanguage: Integer readonly dispid 4; - property DefaultWindowsLanguages: WideString readonly dispid 5; - property DefaultHotkey: IKeymanHotkey readonly dispid 6; - property Encodings: KeymanKeyboardEncodings readonly dispid 7; - property Filename: WideString readonly dispid 8; - function GetCharsUsed: WideString; dispid 9; - property ID: WideString readonly dispid 10; - property LayoutType: KeymanKeyboardLayoutType readonly dispid 11; - property Message: WideString readonly dispid 12; - property Name: WideString readonly dispid 13; - property Version: WideString readonly dispid 14; - function SerializeXML(Flags: tagKeymanSerializeFlags; const ImagePath: WideString; - out References: OleVariant): WideString; dispid 401; - end; - -// *********************************************************************// -// Interface: IKeymanPackageFile3 -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7} -// *********************************************************************// - IKeymanPackageFile3 = interface(IKeymanPackageFile) - ['{C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7}'] - function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageFile; safecall; - end; - -// *********************************************************************// -// DispIntf: IKeymanPackageFile3Disp -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7} -// *********************************************************************// - IKeymanPackageFile3Disp = dispinterface - ['{C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7}'] - function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageFile; dispid 292; - procedure Install(Force: WordBool); dispid 256; - property Author: WideString readonly dispid 1; - property AuthorEmail: WideString readonly dispid 2; - property Copyright: WideString readonly dispid 3; - property Filename: WideString readonly dispid 4; - property Files: IKeymanPackageContentFiles readonly dispid 5; - property Fonts: IKeymanPackageContentFonts readonly dispid 6; - property Graphic: IPicture readonly dispid 7; - property GraphicFile: IKeymanPackageContentFile readonly dispid 8; - property ID: WideString readonly dispid 9; - property KeyboardOptionsFile: IKeymanPackageContentFile readonly dispid 10; - property Keyboards: IKeymanPackageContentKeyboards readonly dispid 11; - property Name: WideString readonly dispid 12; - property ReadmeFile: IKeymanPackageContentFile readonly dispid 13; - property UsageFile: IKeymanPackageContentFile readonly dispid 14; - property Version: WideString readonly dispid 15; - property WelcomeFile: IKeymanPackageContentFile readonly dispid 16; - property Website: WideString readonly dispid 17; - function SerializeXML(Flags: tagKeymanSerializeFlags; const ImagePath: WideString; - out References: OleVariant): WideString; dispid 401; - end; - -// *********************************************************************// -// Interface: IKeymanKeyboardsInstalled3 -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641} -// *********************************************************************// - IKeymanKeyboardsInstalled3 = interface(IKeymanKeyboardsInstalled) - ['{B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641}'] - function Install3(const Filename: WideString; Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; safecall; - end; - -// *********************************************************************// -// DispIntf: IKeymanKeyboardsInstalled3Disp -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641} -// *********************************************************************// - IKeymanKeyboardsInstalled3Disp = dispinterface - ['{B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641}'] - function Install3(const Filename: WideString; Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; dispid 290; - property Items[Index: OleVariant]: IKeymanKeyboardInstalled readonly dispid 0; default; - function GetKeyboardFromFile(const Filename: WideString): IKeymanKeyboardFile; dispid 16; - procedure Install(const Filename: WideString; Force: WordBool); dispid 17; - procedure Apply; dispid 18; - function IndexOf(const ID: WideString): Integer; dispid 5; - property Count: Integer readonly dispid 1; - property _NewEnum: IUnknown readonly dispid -4; - procedure Refresh; dispid 2; - function SerializeXML(Flags: tagKeymanSerializeFlags; const ImagePath: WideString; - out References: OleVariant): WideString; dispid 401; - end; - -// *********************************************************************// -// Interface: IKeymanPackagesInstalled3 -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458} -// *********************************************************************// - IKeymanPackagesInstalled3 = interface(IKeymanPackagesInstalled) - ['{3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458}'] - function Install3(const Filename: WideString; Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; safecall; - end; - -// *********************************************************************// -// DispIntf: IKeymanPackagesInstalled3Disp -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458} -// *********************************************************************// - IKeymanPackagesInstalled3Disp = dispinterface - ['{3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458}'] - function Install3(const Filename: WideString; Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; dispid 291; - property Items[Index: OleVariant]: IKeymanPackageInstalled readonly dispid 0; default; - function GetPackageFromFile(const Filename: WideString): IKeymanPackageFile; dispid 16; - procedure Install(const Filename: WideString; Force: WordBool); dispid 17; - function IndexOf(const ID: WideString): Integer; dispid 18; - property Count: Integer readonly dispid 1; - property _NewEnum: IUnknown readonly dispid -4; - procedure Refresh; dispid 2; - function SerializeXML(Flags: tagKeymanSerializeFlags; const ImagePath: WideString; - out References: OleVariant): WideString; dispid 401; - end; - // *********************************************************************// // Interface: IKeymanDefaultLanguage // Flags: (4416) Dual OleAutomation Dispatchable diff --git a/windows/src/engine/kmcomapi/kmcomapi.ridl b/windows/src/engine/kmcomapi/kmcomapi.ridl index ecfff3d707..91f49822b5 100644 --- a/windows/src/engine/kmcomapi/kmcomapi.ridl +++ b/windows/src/engine/kmcomapi/kmcomapi.ridl @@ -6,7 +6,7 @@ // However, when applying changes via the Editor this file will be regenerated // and comments or formatting changes will be lost. // ************************************************************************ // -// File generated on 31/08/2026 5:28:15 PM (- $Rev: 12980 $, 11059984). +// File generated on 16/09/2021 6:54:45 PM (- $Rev: 12980 $, 32940875). [ uuid(F16E2A9A-DA46-4EA3-BFF3-BA46B480C961), @@ -980,6 +980,60 @@ library keymanapi HRESULT _stdcall Install2([in] VARIANT_BOOL Force, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); }; + [ + uuid(8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4), + version(19.0), + helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanKeyboardFile3"), + dual, + oleautomation + ] + interface IKeymanKeyboardFile3: IKeymanKeyboardFile + { + [id(0x00000121)] + HRESULT _stdcall Install3([in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); + }; + + [ + uuid(C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7), + version(19.0), + helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanPackageFile3"), + dual, + oleautomation + ] + + interface IKeymanPackageFile3: IKeymanPackageFile + { + [id(0x00000124)] + HRESULT _stdcall Install3([in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanPackageFile** Package); + }; + + + [ + uuid(B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641), + version(19.0), + helpstring("https://help.keyman.com/developer/engine/windows/19.0/api/IKeymanKeyboardInstalled2\3"), + dual, + oleautomation + ] + interface IKeymanKeyboardsInstalled3: IKeymanKeyboardsInstalled + { + [id(0x00000122)] + HRESULT _stdcall Install3([in] BSTR Filename, [in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); + }; + + [ + uuid(3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458), + version(19.0), + helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanPackagesInstalled3"), + dual, + oleautomation + ] + interface IKeymanPackagesInstalled3: IKeymanPackagesInstalled + { + [id(0x00000123)] + HRESULT _stdcall Install3([in] BSTR Filename, [in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanPackageInstalled** PackageResult); + }; + [ uuid(9B43B6BC-C622-47EF-915E-6780CF53BAAA), version(14.0), @@ -1025,58 +1079,6 @@ library keymanapi HRESULT _stdcall Add([in] BSTR BCP47Tag, [out, retval] IKeymanKeyboardLanguageInstalled** Result); }; - [ - uuid(8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4), - version(19.0), - helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanKeyboardFile3"), - dual, - oleautomation - ] - interface IKeymanKeyboardFile3: IKeymanKeyboardFile - { - [id(0x00000121)] - HRESULT _stdcall Install3([in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); - }; - - [ - uuid(C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7), - version(19.0), - helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanPackageFile3"), - dual, - oleautomation - ] - interface IKeymanPackageFile3: IKeymanPackageFile - { - [id(0x00000124)] - HRESULT _stdcall Install3([in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanPackageFile** Package); - }; - - [ - uuid(B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641), - version(19.0), - helpstring("https://help.keyman.com/developer/engine/windows/19.0/api/IKeymanKeyboardInstalled2\x03"), - dual, - oleautomation - ] - interface IKeymanKeyboardsInstalled3: IKeymanKeyboardsInstalled - { - [id(0x00000122)] - HRESULT _stdcall Install3([in] BSTR Filename, [in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); - }; - - [ - uuid(3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458), - version(19.0), - helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanPackagesInstalled3"), - dual, - oleautomation - ] - interface IKeymanPackagesInstalled3: IKeymanPackagesInstalled - { - [id(0x00000123)] - HRESULT _stdcall Install3([in] BSTR Filename, [in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanPackageInstalled** PackageResult); - }; - [ uuid(CA3B3B00-EA42-4EED-9043-D1A1F1842D52), dual, From 48923665d9f6c3270d0ebc4bbe77f70e27b01ba5 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Thu, 3 Sep 2026 17:30:21 +1000 Subject: [PATCH 14/26] chore(windows): Revert "fix(windows): pass basekeyboardid to installation api" This reverts commit 82fb40002b980a243edd7a9c647f7d3ca585c422. --- .../Keyman.Configuration.UI.InstallFile.pas | 30 +++++----- ...Configuration.UI.KeymanProtocolHandler.pas | 12 ++-- .../kmshell/install/UfrmInstallKeyboard.pas | 17 ++---- .../install/UfrmInstallKeyboardFromWeb.pas | 6 +- windows/src/desktop/kmshell/main/initprog.pas | 15 +++-- .../com/keyboards/keymankeyboardfile.pas | 23 +------- .../keyboards/keymankeyboardsinstalled.pas | 22 +------ .../com/packages/keymanpackagefile.pas | 43 ++++---------- .../com/packages/keymanpackagesinstalled.pas | 30 +--------- windows/src/engine/kmcomapi/keymanapi_TLB.pas | 42 -------------- windows/src/engine/kmcomapi/kmcomapi.ridl | 58 ------------------- .../processes/keyboard/kpinstallkeyboard.pas | 23 +++----- .../processes/package/kpinstallpackage.pas | 12 ++-- 13 files changed, 69 insertions(+), 264 deletions(-) diff --git a/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.InstallFile.pas b/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.InstallFile.pas index 3cc8dcc901..c6ee3564ae 100644 --- a/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.InstallFile.pas +++ b/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.InstallFile.pas @@ -18,9 +18,9 @@ type FPackage: IKeymanPackageInstalled; const BCP47: string); static; public class function BrowseAndInstallKeyboardFromFile(Owner: TComponent): Boolean; static; - class function Execute(KeyboardFileNames: TStrings; const FirstKeyboardFileName: string; FSilent, FNoWelcome: Boolean; const LogFile: string; BaseKeyboardID: Integer): Boolean; overload; static; - class function Execute(Owner: TComponent; const FileName: string; ASilent, ANoWelcome: Boolean; const LogFile, BCP47: string; BaseKeyboardID: Integer): Boolean; overload; static; - class function Execute(Owner: TComponent; const FileNames: TStrings; ASilent: Boolean; BaseKeyboardID: Integer): Boolean; overload; static; + class function Execute(KeyboardFileNames: TStrings; const FirstKeyboardFileName: string; FSilent, FNoWelcome: Boolean; const LogFile: string): Boolean; overload; static; + class function Execute(Owner: TComponent; const FileName: string; ASilent, ANoWelcome: Boolean; const LogFile, BCP47: string): Boolean; overload; static; + class function Execute(Owner: TComponent; const FileNames: TStrings; ASilent: Boolean): Boolean; overload; static; end; implementation @@ -35,30 +35,29 @@ uses Keyman.Configuration.UI.KeymanProtocolHandler, Keyman.Configuration.UI.MitigationForWin10_1803, kmint, - KeymanOptionNames, UfrmHTML, UfrmInstallKeyboard; class function TInstallFile.Execute(KeyboardFileNames: TStrings; const FirstKeyboardFileName: string; FSilent, FNoWelcome: Boolean; - const LogFile: string; BaseKeyboardID: Integer): Boolean; + const LogFile: string): Boolean; begin if TKeymanProtocolHandler.CanHandle(FirstKeyboardFileName) then begin - Result := TKeymanProtocolHandler.Handle(nil, FirstKeyboardFileName, FSilent, FNoWelcome, LogFile, BaseKeyboardID); + Result := TKeymanProtocolHandler.Handle(nil, FirstKeyboardFileName, FSilent, FNoWelcome, LogFile); end else if (KeyboardFileNames.Count > 1) or (Pos('=', FirstKeyboardFileName) > 0) then begin - Result := TInstallFile.Execute(nil, KeyboardFileNames, FSilent, BaseKeyboardID) + Result := TInstallFile.Execute(nil, KeyboardFileNames, FSilent) end // TODO: support bare package ids from command line (if it does not include a file extension, assume it is a .kmp and try and download it) // else if IsNotPackageOrKeyboardFile then else begin - Result := TInstallFile.Execute(nil, FirstKeyboardFileName, FSilent, FNoWelcome, LogFile, '', BaseKeyboardID); + Result := TInstallFile.Execute(nil, FirstKeyboardFileName, FSilent, FNoWelcome, LogFile, ''); end; end; -class function TInstallFile.Execute(Owner: TComponent; const FileName: string; ASilent, ANoWelcome: Boolean; const LogFile, BCP47: string; BaseKeyboardID: Integer): Boolean; +class function TInstallFile.Execute(Owner: TComponent; const FileName: string; ASilent, ANoWelcome: Boolean; const LogFile, BCP47: string): Boolean; var n: Integer; InstalledKeyboards: array of IKeymanKeyboardInstalled; @@ -78,7 +77,7 @@ begin begin if ASilent then begin - InstallKeyboard(LogFile, BCP47, BaseKeyboardID); + InstallKeyboard(LogFile, BCP47); Result := True; end else @@ -140,7 +139,7 @@ end; /// This is the handler for the `-i` parameter, e.g. /// kmshell -i khmer_angkor.kmp c:\temp\sil_euro_latin.kmp=fr /// -class function TInstallFile.Execute(Owner: TComponent; const FileNames: TStrings; ASilent: Boolean; BaseKeyboardID: Integer): Boolean; +class function TInstallFile.Execute(Owner: TComponent; const FileNames: TStrings; ASilent: Boolean): Boolean; var i, j: Integer; FPackage: IKeymanPackageInstalled; @@ -171,7 +170,7 @@ begin end; if IsPackage then begin - FPackage := (kmcom.Packages as IKeymanPackagesInstalled3).Install3(FileName, True, BaseKeyboardID); + FPackage := (kmcom.Packages as IKeymanPackagesInstalled2).Install2(FileName, True); if Length(FilenameBCP47) > 1 then RegisterKeyboardPackageLanguage(FPackage, FilenameBCP47[1]) else RegisterKeyboardPackageLanguage(FPackage, ''); @@ -179,7 +178,7 @@ begin end else begin - FKeyboard := (kmcom.Keyboards as IKeymanKeyboardsInstalled3).Install3(FileName, True, BaseKeyboardID); + FKeyboard := (kmcom.Keyboards as IKeymanKeyboardsInstalled2).Install2(FileName, True); if (Length(FilenameBCP47) > 1) and (Trim(FilenameBCP47[1]) <> '') then BCP47Tag := FilenameBCP47[1] else BCP47Tag := TTIPMaintenance.GetFirstLanguage(FKeyboard); @@ -210,7 +209,6 @@ end; class function TInstallFile.BrowseAndInstallKeyboardFromFile(Owner: TComponent): Boolean; var dlgOpen: TOpenDialog; - BaseKeyboardID : Integer; begin dlgOpen := TOpenDialog.Create(nil); try @@ -218,9 +216,9 @@ begin 'Keyman files (*.kmx, *.kxx, *.kmp)|*.kmx;*.kxx;*.kmp|Keyman keyboards (*.kmx,*.kxx)' + '|*.kmx;*.kxx|Keyman packages (*.kmp)|*.kmp|All files (*.*)|*.*'; dlgOpen.Title := 'Install Keyman Keyboard'; - BaseKeyboardID := kmcom.Options[KeymanOptionName(koBaseLayout)].Value; + if dlgOpen.Execute then - Result := Execute(Owner, dlgOpen.FileName, False, False, '', '', BaseKeyboardID) + Result := Execute(Owner, dlgOpen.FileName, False, False, '', '') else Result := False; finally diff --git a/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.KeymanProtocolHandler.pas b/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.KeymanProtocolHandler.pas index 60ac8ae43c..6f13f6777b 100644 --- a/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.KeymanProtocolHandler.pas +++ b/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.KeymanProtocolHandler.pas @@ -17,13 +17,13 @@ type FDownloadURL: string; frmDownloadProgress: TfrmDownloadProgress; function DoHandle(Owner: TComponent; const url: string; ASilent, - ANoWelcome: Boolean; const ALogFile: string; BaseKeyboardID: Integer): Boolean; + ANoWelcome: Boolean; const ALogFile: string): Boolean; procedure DoDownload(AOwner: TfrmDownloadProgress; var Result: Boolean); procedure HttpReceiveData(const Sender: TObject; AContentLength, AReadCount: Int64; var Abort: Boolean); public class function CanHandle(const url: string): Boolean; static; - class function Handle(Owner: TComponent; const url: string; ASilent, ANoWelcome: Boolean; const ALogFile: string; BaseKeyboardID: Integer): Boolean; static; + class function Handle(Owner: TComponent; const url: string; ASilent, ANoWelcome: Boolean; const ALogFile: string): Boolean; static; end; implementation @@ -51,13 +51,13 @@ end; class function TKeymanProtocolHandler.Handle(Owner: TComponent; const url: string; ASilent, ANoWelcome: Boolean; - const ALogFile: string; BaseKeyboardID: Integer): Boolean; + const ALogFile: string): Boolean; var h: TKeymanProtocolHandler; begin h := TKeymanProtocolHandler.Create; try - Result := h.DoHandle(Owner, url, ASilent, ANoWelcome, ALogFile, BaseKeyboardID); + Result := h.DoHandle(Owner, url, ASilent, ANoWelcome, ALogFile); finally h.Free; end; @@ -65,7 +65,7 @@ end; function TKeymanProtocolHandler.DoHandle(Owner: TComponent; const url: string; ASilent, ANoWelcome: Boolean; - const ALogFile: string; BaseKeyboardID: Integer): Boolean; + const ALogFile: string): Boolean; var FTempDir: string; PackageID, BCP47: string; @@ -98,7 +98,7 @@ begin end; // TODO: this makes a circular dependency, refactor it out! - Result := TInstallFile.Execute(nil, FDownloadFilename, False, False, '', BCP47, BaseKeyboardID); + Result := TInstallFile.Execute(nil, FDownloadFilename, False, False, '', BCP47); finally if FileExists(FDownloadFilename) then diff --git a/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas b/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas index 775aa1ca2e..6d79811a80 100644 --- a/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas +++ b/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas @@ -74,7 +74,6 @@ uses Vcl.StdCtrls, keymanapi_TLB, - KeymanOptionNames, UfrmKeymanBase, UfrmWebContainer; @@ -103,7 +102,7 @@ type protected procedure FireCommand(const command: WideString; params: TStringList); override; public - procedure InstallKeyboard(const ALogFile, BCP47Tag: string; BaseKeyboardID: Integer); + procedure InstallKeyboard(const ALogFile, BCP47Tag: string); property DefaultBCP47Tag: string read FDefaultBCP47Tag write SetDefaultBCP47Tag; property InstallFile: string read FInstallFile write SetInstallFile; property Silent: Boolean read FSilent write FSilent; @@ -272,7 +271,6 @@ end; procedure TfrmInstallKeyboard.FireCommand(const command: WideString; params: TStringList); var BCP47Tag: string; - BaseKeyboardID :Integer; begin BCP47Tag := ''; if (command = 'keyboard_install') and kmcom.SystemInfo.IsAdministrator then // I4172 @@ -285,8 +283,7 @@ begin Manager.Title := 'Installing Keyboard'; Manager.CanCancel := False; Manager.UpdateProgress('Installing Keyboard', 0, 0); - BaseKeyboardID := kmcom.Options[KeymanOptionName(koBaseLayout)].Value; - InstallKeyboard('', BCP47Tag, BaseKeyboardID); + InstallKeyboard('', BCP47Tag); Result := True; end ); @@ -302,7 +299,6 @@ begin var t: TTempFile; ExecParams: string; - BaseKeyboardString :string; begin KL.MethodEnter(Self, '"keyboard_install"', [params.Text]); try @@ -310,9 +306,8 @@ begin Manager.CanCancel := False; Manager.UpdateProgress('Installing Keyboard', 0, 0); t := TTempFileManager.Get('.log'); - BaseKeyboardString := IntToHex(kmcom.Options[KeymanOptionName(koBaseLayout)].Value, 8); try - ExecParams := '-log "'+t.Name+'" -bkd "'+BaseKeyboardString+'" -s -i "'+FInstallFile+'='+BCP47Tag+'"'+ + ExecParams := '-log "'+t.Name+'" -s -i "'+FInstallFile+'='+BCP47Tag+'"'+ ' -nowelcome '+TTIPMaintenance.GetUserDefaultLangParameterString; KL.Log('Calling elevated kmshell %s', [ExecParams]); if WaitForElevatedConfiguration(GetForegroundWindow, ExecParams) = 0 then @@ -363,7 +358,7 @@ end; ------------------------------------------------------------------------------} // TODO: move this to TInstallFile -procedure TfrmInstallKeyboard.InstallKeyboard(const ALogFile, BCP47Tag: string; BaseKeyboardID: Integer); +procedure TfrmInstallKeyboard.InstallKeyboard(const ALogFile, BCP47Tag: string); var i: Integer; kbd: IKeymanKeyboardInstalled; @@ -405,7 +400,7 @@ begin kbd := nil; kmcom.Keyboards.Apply; kmcom.Keyboards.Refresh; - FInstalledKeyboard := (FKeyboard as IKeymanKeyboardFile3).Install3(True, BaseKeyboardID); + FInstalledKeyboard := (FKeyboard as IKeymanKeyboardFile2).Install2(True); if not InstallTipForKeyboard(BCP47Tag) then begin // TODO can we return a failure code? @@ -466,7 +461,7 @@ begin kmcom.Keyboards.Apply; kmcom.Keyboards.Refresh; // I2169 - (FPackage as IKeymanPackageFile3).Install3(True, BaseKeyboardID); + (FPackage as IKeymanPackageFile2).Install2(True); kmcom.Refresh; diff --git a/windows/src/desktop/kmshell/install/UfrmInstallKeyboardFromWeb.pas b/windows/src/desktop/kmshell/install/UfrmInstallKeyboardFromWeb.pas index ed236d489d..aff3251037 100644 --- a/windows/src/desktop/kmshell/install/UfrmInstallKeyboardFromWeb.pas +++ b/windows/src/desktop/kmshell/install/UfrmInstallKeyboardFromWeb.pas @@ -87,7 +87,6 @@ uses Keyman.Configuration.UI.InstallFile, Keyman.System.LocaleStrings, kmint, - KeymanOptionNames, MessageIdentifierConsts, Upload_Settings, utilfiletypes, @@ -214,7 +213,6 @@ end; procedure TfrmInstallKeyboardFromWeb.DownloadAndInstallPackage(const PackageID, BCP47: string); var FTempDir: string; - BaseKeyboardID: Integer; begin FTempDir := IncludeTrailingPathDelimiter(CreateTempPath); // I1679 try @@ -232,8 +230,8 @@ begin finally frmDownloadProgress.Free; end; - BaseKeyboardID := kmcom.Options[KeymanOptionName(koBaseLayout)].Value; - if TInstallFile.Execute(Self, FDownloadFilename, False, False, '', BCP47, BaseKeyboardID) then + + if TInstallFile.Execute(Self, FDownloadFilename, False, False, '', BCP47) then ModalResult := mrOk; finally diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas index 3143d72828..64fc2cd214 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -207,7 +207,7 @@ end; function Init(var FMode: TKMShellMode; KeyboardFileNames: TStrings; var FSilent, FForce, FNoWelcome: Boolean; var FLogFile, FQuery: string; var FDisablePackages, FDefaultUILanguage: string; var FStartWithConfiguration: Boolean; - var FParentWindow: THandle; var FDefaultBCP47: string; var FDefaultLangID, FBaseKeyboard: Integer): Boolean; + var FParentWindow: THandle; var FDefaultBCP47: string; var FDefaultLangID: Integer): Boolean; var s: string; i: Integer; @@ -264,7 +264,6 @@ begin else if s = '-bd' then FMode := fmBackgroundDownload else if s = '-an' then FMode := fmApplyInstallNow else if s = '-basekeyboard' then FMode := fmBaseKeyboard // I4169 - else if s = 'bkd' then begin Inc(i); FBaseKeyboard := ParamStr(i); end else if s = '-mcompilekbds' then begin FMode := fmMCompileKbds; @@ -331,7 +330,7 @@ end; procedure RunKMCOM(FMode: TKMShellMode; KeyboardFileNames: TStrings; FSilent, FForce, FNoWelcome: Boolean; FLogFile, FQuery: string; FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; FParentWindow: THandle; - const FDefaultBCP47: string; FDefaultLangID, FBaseKeyboard: Integer); forward; + const FDefaultBCP47: string; FDefaultLangID: Integer); forward; procedure Run; var @@ -342,7 +341,7 @@ var FForce: Boolean; FParentWindow: THandle; FLogFile: string; - FDefaultLangID, FBaseKeyboard: Integer; + FDefaultLangID: Integer; FDefaultBCP47, FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; begin @@ -351,7 +350,7 @@ begin KeyboardFileNames := TStringList.Create; try FParentWindow := 0; - if not Init(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow, FDefaultBCP47, FDefaultLangID, FBaseKeyboard) then + if not Init(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow, FDefaultBCP47, FDefaultLangID) then begin //TODO: TUtilExecute.Shell(PChar('hh.exe mk:@MSITStore:'+ExtractFilePath(KMShellExe)+'keyman.chm::/context/keyman_usage.html'), SW_SHOWNORMAL); Exit; @@ -359,7 +358,7 @@ begin if not LoadKMCOM then Exit; try - RunKMCOM(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow, FDefaultBCP47, FDefaultLangID, FBaseKeyboard); + RunKMCOM(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow, FDefaultBCP47, FDefaultLangID); finally kmcom := nil; end; @@ -398,7 +397,7 @@ end; procedure RunKMCOM(FMode: TKMShellMode; KeyboardFileNames: TStrings; FSilent, FForce, FNoWelcome: Boolean; FLogFile, FQuery: string; FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; - FParentWindow: THandle; const FDefaultBCP47: string; FDefaultLangID, FBaseKeyboard: Integer); + FParentWindow: THandle; const FDefaultBCP47: string; FDefaultLangID: Integer); var kdl: IKeymanDefaultLanguage; FIcon: string; @@ -561,7 +560,7 @@ begin else ExitCode := 1; fmInstall: - if TInstallFile.Execute(KeyboardFileNames, FirstKeyboardFileName, FSilent, FNoWelcome, FLogFile, FBaseKeyboard) + if TInstallFile.Execute(KeyboardFileNames, FirstKeyboardFileName, FSilent, FNoWelcome, FLogFile) then ExitCode := 0 else ExitCode := 1; diff --git a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas index b7255869b7..5ea1e74265 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas @@ -37,7 +37,7 @@ uses keymankeyboard, keymancontext, Classes, PackageInfo, keymankeyboardlanguagesfile; type - TKeymanKeyboardFile = class(TKeymanKeyboard, IKeymanKeyboardFile, IKeymanKeyboardFile2, IKeymanKeyboardFile3) + TKeymanKeyboardFile = class(TKeymanKeyboard, IKeymanKeyboardFile, IKeymanKeyboardFile2) private FFileName: WideString; FError: Boolean; @@ -52,7 +52,6 @@ type { IKeymanKeyboardFile } procedure Install(Force: WordBool); safecall; function Install2(Force: WordBool): IKeymanKeyboardInstalled; safecall; - function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; safecall; { IKeymanKeyboard } function Get_Copyright: WideString; override; safecall; @@ -253,7 +252,7 @@ procedure TKeymanKeyboardFile.Install(Force: WordBool); begin with TKPInstallKeyboard.Create(Context) do try - Execute(FFileName, '', [ikLegacyRegisterAndInstallProfiles], nil, Force, 0); + Execute(FFileName, '', [ikLegacyRegisterAndInstallProfiles], nil, Force); finally Free; end; @@ -265,23 +264,7 @@ var begin with TKPInstallKeyboard.Create(Context) do try - Execute(FFileName, '', [], nil, Force, 0); - finally - Free; - end; - - kki := Context.Keyboards as IKeymanKeyboardsInstalled; - kki.Refresh; - Result := kki.Items[FFileName]; -end; - -function TKeymanKeyboardFile.Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; -var - kki: IKeymanKeyboardsInstalled; -begin - with TKPInstallKeyboard.Create(Context) do - try - Execute(FFileName, '', [], nil, Force, BaseKeyboardID); + Execute(FFileName, '', [], nil, Force); finally Free; end; diff --git a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardsinstalled.pas b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardsinstalled.pas index b37e0dfce0..f5f8b74448 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardsinstalled.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardsinstalled.pas @@ -37,8 +37,7 @@ uses keymanerrorcodes, keymankeyboardinstalled, keymankeyboard, internalinterfaces; type - TKeymanKeyboardsInstalled = class(TKeymanAutoCollectionObject, IKeymanKeyboardsInstalled, - IKeymanKeyboardsInstalled2, IIntKeymanKeyboardsInstalled, IKeymanKeyboardsInstalled3) // I4376 + TKeymanKeyboardsInstalled = class(TKeymanAutoCollectionObject, IKeymanKeyboardsInstalled, IKeymanKeyboardsInstalled2, IIntKeymanKeyboardsInstalled) // I4376 private FKeyboards: TKeyboardList; procedure TriggerWindowsLanguageSync; @@ -56,7 +55,6 @@ type procedure Install(const Filename: WideString; Force: WordBool); safecall; procedure Apply; safecall; function Install2(const Filename: WideString; Force: WordBool): IKeymanKeyboardInstalled; safecall; - function Install3(const Filename: WideString; Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; safecall; procedure RefreshInstalledKeyboards; safecall; { IIntKeymanKeyboardsInstalled } @@ -103,7 +101,7 @@ procedure TKeymanKeyboardsInstalled.Install(const Filename: WideString; Force: W begin with TKPInstallKeyboard.Create(Context) do try - Execute(FileName, '', [ikLegacyRegisterAndInstallProfiles], nil, Force, 0); + Execute(FileName, '', [ikLegacyRegisterAndInstallProfiles], nil, Force); finally Free; end; @@ -114,21 +112,7 @@ function TKeymanKeyboardsInstalled.Install2(const Filename: WideString; begin with TKPInstallKeyboard.Create(Context) do try - Execute(FileName, '', [], nil, Force, 0); - finally - Free; - end; - - DoRefresh; - Result := Get_Items(FileName); -end; - -function TKeymanKeyboardsInstalled.Install3(const Filename: WideString; - Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; -begin - with TKPInstallKeyboard.Create(Context) do - try - Execute(FileName, '', [], nil, Force, BaseKeyboardID); + Execute(FileName, '', [], nil, Force); finally Free; end; diff --git a/windows/src/engine/kmcomapi/com/packages/keymanpackagefile.pas b/windows/src/engine/kmcomapi/com/packages/keymanpackagefile.pas index 28ef2d064a..14b207e229 100644 --- a/windows/src/engine/kmcomapi/com/packages/keymanpackagefile.pas +++ b/windows/src/engine/kmcomapi/com/packages/keymanpackagefile.pas @@ -1,18 +1,18 @@ (* Name: keymanpackagefile Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 20 Jun 2006 Modified Date: 29 Mar 2010 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 20 Jun 2006 - mcdurdin - Initial version 01 Aug 2006 - mcdurdin - Avoid processmessages in unzip 04 Dec 2006 - mcdurdin - Add Serialize function, support ShortcutRootPath in installation @@ -37,7 +37,7 @@ uses keymanpackagecontentfiles, StdVcl, kmpinffile, KeymanContext, Graphics, Classes, internalinterfaces; type - TKeymanPackageFile = class(TKeymanAutoObject, IKeymanPackage, IKeymanPackageFile, IKeymanPackageFile2, IKeymanPackageFile3) + TKeymanPackageFile = class(TKeymanAutoObject, IKeymanPackage, IKeymanPackageFile, IKeymanPackageFile2) private FSourcePath: string; FSubFiles: IKeymanPackageContentFiles; @@ -74,7 +74,6 @@ type { IKeymanPackageFile } procedure Install(Force: WordBool); safecall; function Install2(Force: WordBool): IKeymanPackageInstalled; safecall; - function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; safecall; public constructor Create(AContext: TKeymanContext; const Filename: Widestring); destructor Destroy; override; @@ -176,7 +175,7 @@ begin o := [ipLegacyRegisterAndInstallProfiles]; if Force then Include(o, ipForce); - Execute(FFileName, o, 0); + Execute(FFileName, o); finally Free; end; @@ -192,27 +191,7 @@ begin o := []; if Force then Include(o, ipForce); - Execute(FFileName, o, 0); - finally - Free; - end; - - kpi := Context.Packages as IKeymanPackagesInstalled; - kpi.Refresh; - Result := kpi.Items[FFileName]; -end; - -function TKeymanPackageFile.Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; -var - o: TKPInstallPackageOptions; - kpi: IKeymanPackagesInstalled; -begin - with TKPInstallPackage.Create(Context) do - try - o := []; - if Force then - Include(o, ipForce); - Execute(FFileName, o, BaseKeyboardID); + Execute(FFileName, o); finally Free; end; @@ -232,7 +211,7 @@ var begin if not FileExists(FFileName) then raise Exception.Create('File '+FFileName+' does not exist.'); - + if GetTempPath(260, buf) = 0 then raise Exception.Create('Unable to get temporary path: ' + IntToHex(GetLastError, 8) + ' ' + SysErrorMessage(GetLastError)); FTempOutPath := buf; diff --git a/windows/src/engine/kmcomapi/com/packages/keymanpackagesinstalled.pas b/windows/src/engine/kmcomapi/com/packages/keymanpackagesinstalled.pas index 821a38bdc5..9dd9f1a52a 100644 --- a/windows/src/engine/kmcomapi/com/packages/keymanpackagesinstalled.pas +++ b/windows/src/engine/kmcomapi/com/packages/keymanpackagesinstalled.pas @@ -38,8 +38,7 @@ type property Items[Index: Integer]: IIntKeymanPackageInstalled read GetItem write SetItem; default; end; - TKeymanPackagesInstalled = class(TKeymanAutoCollectionObject, - IKeymanPackagesInstalled, IKeymanPackagesInstalled2, IKeymanPackagesInstalled3) + TKeymanPackagesInstalled = class(TKeymanAutoCollectionObject, IKeymanPackagesInstalled, IKeymanPackagesInstalled2) private FPackages: TPackageList; protected @@ -52,7 +51,6 @@ type function IndexOf(const ID: WideString): Integer; safecall; procedure Install(const Filename: WideString; Force: WordBool); safecall; function Install2(const Filename: WideString; Force: WordBool): IKeymanPackageInstalled; safecall; - function Install3(const Filename: WideString; Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; safecall; public constructor Create(AContext: TKeymanContext); destructor Destroy; override; @@ -120,7 +118,7 @@ begin o := [ipLegacyRegisterAndInstallProfiles]; if Force then Include(o, ipForce); - Execute(Filename, o, 0); + Execute(Filename, o); finally Free; end; @@ -138,29 +136,7 @@ begin o := []; if Force then Include(o, ipForce); - Execute(Filename, o, 0); - finally - Free; - end; - - DoRefresh; - Result := Get_Items(Filename); - - KL.MethodExit(Self, 'Install2'); -end; - -function TKeymanPackagesInstalled.Install3(const Filename: WideString; - Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; -var - o: TKPInstallPackageOptions; -begin - KL.MethodEnter(Self, 'Install2', [Filename, Force]); - with TKPInstallPackage.Create(Context) do - try - o := []; - if Force then - Include(o, ipForce); - Execute(Filename, o, BaseKeyboardID); + Execute(Filename, o); finally Free; end; diff --git a/windows/src/engine/kmcomapi/keymanapi_TLB.pas b/windows/src/engine/kmcomapi/keymanapi_TLB.pas index 7246c9173f..786ce6c9b2 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -1569,17 +1569,6 @@ type procedure RefreshInstalledKeyboards; safecall; end; -// *********************************************************************// -// Interface: IKeymanKeyboardsInstalled3 -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641} -// *********************************************************************// - IKeymanKeyboardsInstalled3 = interface(IKeymanKeyboardsInstalled) - ['{B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641}'] - function Install3(const Filename: WideString; Force: WordBool; BasePackageID: Integer): IKeymanKeyboardInstalled; safecall; - procedure RefreshInstalledKeyboards; safecall; - end; - // *********************************************************************// // Interface: IKeymanKeyboardInstalled2 // Flags: (4416) Dual OleAutomation Dispatchable @@ -1621,16 +1610,6 @@ type function Install2(const Filename: WideString; Force: WordBool): IKeymanPackageInstalled; safecall; end; -// *********************************************************************// -// Interface: IKeymanPackagesInstalled3 -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458} -// *********************************************************************// - IKeymanPackagesInstalled3 = interface(IKeymanPackagesInstalled) - ['{3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458}'] - function Install3(const Filename: WideString; Force: WordBool; BasePackageID: Integer): IKeymanPackageInstalled; safecall; - end; - // *********************************************************************// // DispIntf: IKeymanPackagesInstalled2Disp // Flags: (4416) Dual OleAutomation Dispatchable @@ -1660,16 +1639,6 @@ type function Install2(Force: WordBool): IKeymanKeyboardInstalled; safecall; end; -// *********************************************************************// -// Interface: IKeymanKeyboardFile3 -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {EDE4326B-51F4-42D5-8251-B20B71993EC8} -// *********************************************************************// - IKeymanKeyboardFile3 = interface(IKeymanKeyboardFile) - ['{8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4}'] - function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; safecall; - end; - // *********************************************************************// // DispIntf: IKeymanKeyboardFile2Disp // Flags: (4416) Dual OleAutomation Dispatchable @@ -1708,17 +1677,6 @@ type function Install2(Force: WordBool): IKeymanPackageInstalled; safecall; end; -// *********************************************************************// -// Interface: IKeymanPackageFile3 -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7} -// *********************************************************************// - IKeymanPackageFile3 = interface(IKeymanPackageFile) - ['{C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7}'] - function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; safecall; - end; - - // *********************************************************************// // DispIntf: IKeymanPackageFile2Disp // Flags: (4416) Dual OleAutomation Dispatchable diff --git a/windows/src/engine/kmcomapi/kmcomapi.ridl b/windows/src/engine/kmcomapi/kmcomapi.ridl index 91f49822b5..9eb63fbd68 100644 --- a/windows/src/engine/kmcomapi/kmcomapi.ridl +++ b/windows/src/engine/kmcomapi/kmcomapi.ridl @@ -66,10 +66,6 @@ library keymanapi interface IKeymanPackageFile2; interface IKeymanKeyboardLanguageInstalled2; interface IKeymanKeyboardLanguagesInstalled2; - interface IKeymanKeyboardFile3; - interface IKeymanPackageFile3; - interface IKeymanKeyboardsInstalled3; - interface IKeymanPackagesInstalled3; interface IKeymanBCP47Canonicalization; interface IKeymanDefaultLanguage; @@ -980,60 +976,6 @@ library keymanapi HRESULT _stdcall Install2([in] VARIANT_BOOL Force, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); }; - [ - uuid(8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4), - version(19.0), - helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanKeyboardFile3"), - dual, - oleautomation - ] - interface IKeymanKeyboardFile3: IKeymanKeyboardFile - { - [id(0x00000121)] - HRESULT _stdcall Install3([in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); - }; - - [ - uuid(C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7), - version(19.0), - helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanPackageFile3"), - dual, - oleautomation - ] - - interface IKeymanPackageFile3: IKeymanPackageFile - { - [id(0x00000124)] - HRESULT _stdcall Install3([in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanPackageFile** Package); - }; - - - [ - uuid(B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641), - version(19.0), - helpstring("https://help.keyman.com/developer/engine/windows/19.0/api/IKeymanKeyboardInstalled2\3"), - dual, - oleautomation - ] - interface IKeymanKeyboardsInstalled3: IKeymanKeyboardsInstalled - { - [id(0x00000122)] - HRESULT _stdcall Install3([in] BSTR Filename, [in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); - }; - - [ - uuid(3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458), - version(19.0), - helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanPackagesInstalled3"), - dual, - oleautomation - ] - interface IKeymanPackagesInstalled3: IKeymanPackagesInstalled - { - [id(0x00000123)] - HRESULT _stdcall Install3([in] BSTR Filename, [in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanPackageInstalled** PackageResult); - }; - [ uuid(9B43B6BC-C622-47EF-915E-6780CF53BAAA), version(14.0), diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas index 1d198264cb..1205d77f72 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas @@ -64,7 +64,7 @@ type ikLegacyRegisterAndInstallProfiles); TKPInstallKeyboard = class(TKPBase) - procedure Execute(const FileName: string; const PackageID: string; FInstallOptions: TKPInstallKeyboardOptions; Languages: TPackageKeyboardLanguageList; Force: Boolean; BaseKeyboardID: Integer); + procedure Execute(const FileName, PackageID: string; FInstallOptions: TKPInstallKeyboardOptions; Languages: TPackageKeyboardLanguageList; Force: Boolean); procedure RegisterProfiles(const FileName, PackageID: string; FInstallOptions: TKPInstallKeyboardOptions; PackageLanguageMetadata: TPackageKeyboardLanguageList); private procedure LegacyRegisterAndInstallLanguageProfile(Langs: array of Integer; @@ -112,7 +112,7 @@ uses utiltsf, keymanapi_TLB; -procedure TKPInstallKeyboard.Execute(const FileName: string; const PackageID: string; FInstallOptions: TKPInstallKeyboardOptions; Languages: TPackageKeyboardLanguageList; Force: Boolean; BaseKeyboardID: Integer); +procedure TKPInstallKeyboard.Execute(const FileName, PackageID: string; FInstallOptions: TKPInstallKeyboardOptions; Languages: TPackageKeyboardLanguageList; Force: Boolean); var ki: TKeyboardInfo; FDestPath: string; @@ -125,9 +125,7 @@ var FExitCode: Integer; FKVKName: WideString; FCreatedIcon: Boolean; - ElevatedBaseKeyboardID: Integer; - KeymanContext: TKeymanContext; - RecompileMnemonicKeyboard: TKPRecompileMnemonicKeyboard; + BaseKeyboardID: Integer; begin KL.MethodEnter(Self, 'Execute', [FileName,PackageID,ikPartOfPackage in FInstallOptions ,Force]); try @@ -248,19 +246,14 @@ begin KL.Log(FLogText); end; - // Recompile a mnemonic layout to the user's selected base layout. If - // the baselayout has not been passed through (=0) then use the current - // process configured value which is likely the Admin user + // Recompile a mnemonic layout to the user's selected base layout if ki.MnemonicLayout then // I4169 begin - KeymanContext := Context as TKeymanContext; - ElevatedBaseKeyboardID := (KeymanContext.Options as IKeymanOptions).Items['koBaseLayout'].Value; - RecompileMnemonicKeyboard := TKPRecompileMnemonicKeyboard.Create(Context); + with Context as TKeymanContext do + BaseKeyboardID := (Options as IKeymanOptions).Items['koBaseLayout'].Value; + with TKPRecompileMnemonicKeyboard.Create(Context) do try - if (BaseKeyboardID = 0) then - RecompileMnemonicKeyboard.Execute(FDestFileName, PackageID, ElevatedBaseKeyboardID) - else - RecompileMnemonicKeyboard.Execute(FDestFileName, PackageID, BaseKeyboardID); + Execute(FDestFileName, PackageID, BaseKeyboardID); finally RecompileMnemonicKeyboard.Free; end; diff --git a/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas b/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas index 4ab33cdfee..98edfbf3fb 100644 --- a/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas +++ b/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas @@ -50,7 +50,7 @@ type TKPInstallPackage = class(TKPBase) public - procedure Execute(const FileName: string; Options: TKPInstallPackageOptions; BaseKeyboardID: Integer); + procedure Execute(const FileName: string; Options: TKPInstallPackageOptions); end; implementation @@ -85,7 +85,7 @@ uses { TKPInstallPackage } -procedure TKPInstallPackage.Execute(const FileName: string; Options: TKPInstallPackageOptions; BaseKeyboardID: Integer); +procedure TKPInstallPackage.Execute(const FileName: string; Options: TKPInstallPackageOptions); function GetHHIcon: string; var buf: array[0..260] of char; @@ -112,7 +112,7 @@ var FErrorValue: Cardinal; FSrcFileName: string; - procedure InstallKeyboard(FileName: string; BaseKeyboardID: Integer); + procedure InstallKeyboard(FileName: string); var FOptions: TKPInstallKeyboardOptions; kbd: TPackageKeyboard; @@ -132,7 +132,7 @@ var with TKPInstallKeyboard.Create(Context) do try - Execute(FileName, PackageName, FOptions, FLanguages, ipForce in Options, BaseKeyboardID); + Execute(FileName, PackageName, FOptions, FLanguages, ipForce in Options); finally Free; end; @@ -253,12 +253,12 @@ begin begin case inf.Files[i].FileType of ftKeymanFile: - InstallKeyboard(dest + inf.Files[i].FileName, BaseKeyboardID); + InstallKeyboard(dest + inf.Files[i].FileName); ftPackageFile: with TKPInstallPackage.Create(Context) do try - Execute(dest + inf.Files[i].FileName, Options, BaseKeyboardID); + Execute(dest + inf.Files[i].FileName, Options); finally Free; end; From b9743d277b69077de9b6a934504eef56e8346479 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Thu, 3 Sep 2026 17:37:22 +1000 Subject: [PATCH 15/26] fix(windows): fix indentation --- windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas index 56e7c442b4..91a6710112 100644 --- a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas @@ -33,7 +33,8 @@ uses utilkmshell; function ConfigureBaseKeyboard(out BaseKeyboardID: Integer): Boolean; -begin with TfrmBaseKeyboard.Create(nil) do +begin + with TfrmBaseKeyboard.Create(nil) do try Result := ShowModal = mrOk; if Result then From d67c4911af9b5431cda22eb9a13e36e8574386ad Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Fri, 4 Sep 2026 13:48:49 +1000 Subject: [PATCH 16/26] fix(windows): rename Setting System Also update the command line to use FBaseKeyboardID instead of FQuery. --- windows/src/desktop/kmshell/kmshell.dpr | 2 +- windows/src/desktop/kmshell/kmshell.dproj | 2 +- ...man.Configuration.System.BaseKeyboard.pas} | 27 +++++++------------ windows/src/desktop/kmshell/main/UfrmMain.pas | 2 +- windows/src/desktop/kmshell/main/initprog.pas | 18 ++++++------- 5 files changed, 21 insertions(+), 30 deletions(-) rename windows/src/desktop/kmshell/{settings/Keyman.Configuration.Settings.BaseKeyboard.pas => main/Keyman.Configuration.System.BaseKeyboard.pas} (72%) diff --git a/windows/src/desktop/kmshell/kmshell.dpr b/windows/src/desktop/kmshell/kmshell.dpr index e4ce8316d3..124b0357ce 100644 --- a/windows/src/desktop/kmshell/kmshell.dpr +++ b/windows/src/desktop/kmshell/kmshell.dpr @@ -184,7 +184,7 @@ uses Keyman.System.ExecutionHistory in '..\..\..\..\common\windows\delphi\general\Keyman.System.ExecutionHistory.pas', Keyman.Configuration.UI.UfrmStartInstall in 'main\Keyman.Configuration.UI.UfrmStartInstall.pas' {frmStartInstall}, Keyman.Configuration.Util.NetworkConnection in 'util\Keyman.Configuration.Util.NetworkConnection.pas', - Keyman.Configuration.Settings.BaseKeyboard in 'settings\Keyman.Configuration.Settings.BaseKeyboard.pas'; + Keyman.Configuration.System.BaseKeyboard in 'main\Keyman.Configuration.System.BaseKeyboard.pas'; {$R VERSION.RES} {$R manifest.res} diff --git a/windows/src/desktop/kmshell/kmshell.dproj b/windows/src/desktop/kmshell/kmshell.dproj index ca611b40e4..abcb521597 100644 --- a/windows/src/desktop/kmshell/kmshell.dproj +++ b/windows/src/desktop/kmshell/kmshell.dproj @@ -358,7 +358,7 @@
frmStartInstall
- + Cfg_2 diff --git a/windows/src/desktop/kmshell/settings/Keyman.Configuration.Settings.BaseKeyboard.pas b/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas similarity index 72% rename from windows/src/desktop/kmshell/settings/Keyman.Configuration.Settings.BaseKeyboard.pas rename to windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas index 44488179c9..c47d90a1a5 100644 --- a/windows/src/desktop/kmshell/settings/Keyman.Configuration.Settings.BaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas @@ -1,4 +1,4 @@ -unit Keyman.Configuration.Settings.BaseKeyboard; +unit Keyman.Configuration.System.BaseKeyboard; interface @@ -8,8 +8,7 @@ uses keymanapi_TLB; function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolean; -function MCompileBaseKeyboard(const BaseKeyboardIDText: string): Boolean; -procedure CompileForBaseKeyboard(BaseKeyboardID: Integer); +function MCompileBaseKeyboard(BaseKeyboardID: Integer): Boolean; implementation @@ -47,7 +46,7 @@ begin WaitForElevatedConfiguration(WindowHandle, '-mcompilekbds ' + IntToHex(BaseKeyboardID, 8)); end else - CompileForBaseKeyboard(BaseKeyboardID); + MCompileBaseKeyboard(BaseKeyboardID); end; kmcom.Options['koBaseLayout'].Value := BaseKeyboardID; @@ -55,29 +54,21 @@ begin Result := True; end; -function MCompileBaseKeyboard(const BaseKeyboardIDText: string): Boolean; -var - BaseKeyboardID: Integer; -begin - Result := False; - if not TryStrToInt('$' + BaseKeyboardIDText, BaseKeyboardID) or - not kmcom.SystemInfo.IsAdministrator then - Exit; - CompileForBaseKeyboard(BaseKeyboardID); - // TODO: sort out whether we need todo return a result - Result := True; -end; - -procedure CompileForBaseKeyboard(BaseKeyboardID: Integer); +function MCompileBaseKeyboard(BaseKeyboardID: Integer): Boolean; var i: Integer; kbd: IKeymanKeyboardInstalled; begin + Result := False; + // can be called from command line so test for admin + if not kmcom.SystemInfo.IsAdministrator then + Exit; for i := 0 to kmcom.Keyboards.Count - 1 do begin kbd := kmcom.Keyboards[i]; (kbd as IKeymanKeyboardInstalled2).MCompileForBaseKeyboard(BaseKeyboardID); end; + Result := True; end; end. diff --git a/windows/src/desktop/kmshell/main/UfrmMain.pas b/windows/src/desktop/kmshell/main/UfrmMain.pas index 599566b91c..9c4478283e 100644 --- a/windows/src/desktop/kmshell/main/UfrmMain.pas +++ b/windows/src/desktop/kmshell/main/UfrmMain.pas @@ -174,7 +174,7 @@ uses Hints, HotkeyUtils, initprog, - Keyman.Configuration.Settings.BaseKeyboard, + Keyman.Configuration.System.BaseKeyboard, Keyman.Configuration.System.TIPMaintenance, Keyman.Configuration.UI.UfrmDiagnosticTests, KeymanOptionNames, diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas index 64fc2cd214..54f4a73f65 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -115,7 +115,7 @@ uses GetOsVersion, help, HTMLHelpViewer, - Keyman.Configuration.Settings.BaseKeyboard, + Keyman.Configuration.System.BaseKeyboard, Keyman.Configuration.UI.InstallFile, Keyman.Configuration.System.TIPMaintenance, Keyman.Configuration.System.UImportOlderVersionKeyboards11To13, @@ -207,7 +207,7 @@ end; function Init(var FMode: TKMShellMode; KeyboardFileNames: TStrings; var FSilent, FForce, FNoWelcome: Boolean; var FLogFile, FQuery: string; var FDisablePackages, FDefaultUILanguage: string; var FStartWithConfiguration: Boolean; - var FParentWindow: THandle; var FDefaultBCP47: string; var FDefaultLangID: Integer): Boolean; + var FParentWindow: THandle; var FDefaultBCP47: string; var FDefaultLangID, FBaseKeyboard: Integer): Boolean; var s: string; i: Integer; @@ -269,7 +269,7 @@ begin FMode := fmMCompileKbds; Inc(i); if i > ParamCount then Exit; - FQuery := ParamStr(i); + FBaseKeyboard := StrToInt('$' + ParamStr(i)); end else if s = '-nowelcome' then FNoWelcome := True else if s = '-kw' then FMode := fmKeyboardWelcome // I2569 @@ -330,7 +330,7 @@ end; procedure RunKMCOM(FMode: TKMShellMode; KeyboardFileNames: TStrings; FSilent, FForce, FNoWelcome: Boolean; FLogFile, FQuery: string; FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; FParentWindow: THandle; - const FDefaultBCP47: string; FDefaultLangID: Integer); forward; + const FDefaultBCP47: string; FDefaultLangID, FBaseKeyboard: Integer); forward; procedure Run; var @@ -341,7 +341,7 @@ var FForce: Boolean; FParentWindow: THandle; FLogFile: string; - FDefaultLangID: Integer; + FDefaultLangID, FBaseKeyboard: Integer; FDefaultBCP47, FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; begin @@ -350,7 +350,7 @@ begin KeyboardFileNames := TStringList.Create; try FParentWindow := 0; - if not Init(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow, FDefaultBCP47, FDefaultLangID) then + if not Init(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow, FDefaultBCP47, FDefaultLangID, FBaseKeyboard) then begin //TODO: TUtilExecute.Shell(PChar('hh.exe mk:@MSITStore:'+ExtractFilePath(KMShellExe)+'keyman.chm::/context/keyman_usage.html'), SW_SHOWNORMAL); Exit; @@ -358,7 +358,7 @@ begin if not LoadKMCOM then Exit; try - RunKMCOM(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow, FDefaultBCP47, FDefaultLangID); + RunKMCOM(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow, FDefaultBCP47, FDefaultLangID, FBaseKeyboard); finally kmcom := nil; end; @@ -397,7 +397,7 @@ end; procedure RunKMCOM(FMode: TKMShellMode; KeyboardFileNames: TStrings; FSilent, FForce, FNoWelcome: Boolean; FLogFile, FQuery: string; FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; - FParentWindow: THandle; const FDefaultBCP47: string; FDefaultLangID: Integer); + FParentWindow: THandle; const FDefaultBCP47: string; FDefaultLangID, FBaseKeyboard: Integer); var kdl: IKeymanDefaultLanguage; FIcon: string; @@ -555,7 +555,7 @@ begin else ExitCode := 1; fmMCompileKbds: - if MCompileBaseKeyboard(FQuery) + if MCompileBaseKeyboard(FBaseKeyboard) then ExitCode := 0 else ExitCode := 1; From 0409cda1201fa4c9ff296d148ceeacbebb689b89 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Mon, 7 Sep 2026 13:03:29 +1000 Subject: [PATCH 17/26] fix(windows): add comments for new functions --- ...yman.Configuration.System.BaseKeyboard.pas | 31 ++++++++++++++++--- .../desktop/kmshell/main/UfrmBaseKeyboard.pas | 8 +++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas b/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas index c47d90a1a5..d91b439f33 100644 --- a/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas @@ -7,7 +7,28 @@ uses System.SysUtils, keymanapi_TLB; +(** + Returns true if the keyboard files need to be compiled for the specified KLID. + @param BaseKeyboardID KLID of the base keyboard to compile. + @returns True If the keyboard files need to be compiled. +*) +function BaseKeyboardNeedsMCompile(BaseKeyboardID: Integer): Boolean; + +(** + Sets the base keyboard KLID for the current user and compiles the keyboard + files if necessary. In the case the compiled keyboard files are not present, + it will require elevation. + @param WindowHandle Window handle to own the elevation prompt. + @param BaseKeyboardID KLID of the base keyboard KLID to set. + @returns True when the base keyboard setting has been applied. +*) function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolean; + +(** + Compiles the base keyboard files for the specified KLID. + @param BaseKeyboardID KLID of the base keyboard to compile. + @returns True when the compilation is successful. +*) function MCompileBaseKeyboard(BaseKeyboardID: Integer): Boolean; implementation @@ -38,20 +59,20 @@ end; function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolean; begin - Result := False; + Result := True; if BaseKeyboardNeedsMCompile(BaseKeyboardID) then begin if not kmcom.SystemInfo.IsAdministrator then begin - WaitForElevatedConfiguration(WindowHandle, '-mcompilekbds ' + IntToHex(BaseKeyboardID, 8)); + Result := WaitForElevatedConfiguration(WindowHandle, '-mcompilekbds ' + IntToHex(BaseKeyboardID, 8)) = 0; end else - MCompileBaseKeyboard(BaseKeyboardID); + Result := MCompileBaseKeyboard(BaseKeyboardID); end; - + if not Result then + Exit; kmcom.Options['koBaseLayout'].Value := BaseKeyboardID; kmcom.Options.Apply; - Result := True; end; function MCompileBaseKeyboard(BaseKeyboardID: Integer): Boolean; diff --git a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas index 91a6710112..dd298a8642 100644 --- a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas @@ -18,6 +18,14 @@ type procedure FireCommand(const command: WideString; params: TStringList); override; end; + +(** + Form for the user to select a base keyboard. If the user selects a base + keyboard, the KLID of the selected base keyboard is returned in + BaseKeyboardID. + @param [out] BaseKeyboardID KLID of the base keyboard selected by the user. + @returns True if the user selected a base keyboard. +*) function ConfigureBaseKeyboard(out BaseKeyboardID: Integer): Boolean; implementation From 163806b712d97961b1fa099890a7b828b79149df Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Mon, 7 Sep 2026 17:17:39 +1000 Subject: [PATCH 18/26] fix(windows): git revert error fix --- windows/src/engine/kmcomapi/keymanapi_TLB.pas | 60 +++++++++++++++---- windows/src/engine/kmcomapi/kmcomapi.ridl | 2 +- .../processes/keyboard/kpinstallkeyboard.pas | 2 +- 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/windows/src/engine/kmcomapi/keymanapi_TLB.pas b/windows/src/engine/kmcomapi/keymanapi_TLB.pas index 786ce6c9b2..550a13064d 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -12,7 +12,7 @@ unit keymanapi_TLB; // ************************************************************************ // // $Rev: 52393 $ -// File generated on 16/09/2021 6:54:44 PM from Type Library described below. +// File generated on 7/09/2026 3:54:23 PM from Type Library described below. // ************************************************************************ // // Type Lib: C:\Projects\keyman\app\windows\src\engine\kmcomapi\kmcomapi (1) @@ -87,6 +87,7 @@ const IID_IKeymanKeyboardLanguagesInstalled: TGUID = '{7DC22BC0-85BB-45C0-8EDB-A2F4BD1D500B}'; IID_IKeymanKeyboardLanguagesFile: TGUID = '{5F90BCDA-F1C1-433A-8FD0-B498299D3C30}'; IID_IKeymanKeyboardsInstalled2: TGUID = '{EA57C94F-C140-485E-941A-3F1D5A229024}'; + IID_IKeymanKeyboardInstalled2: TGUID = '{3086C85C-932A-4726-BF76-2D74DD133AC9}'; IID_IKeymanPackagesInstalled2: TGUID = '{F23B9848-2AEF-4A2B-BC3A-292E3A00D691}'; IID_IKeymanKeyboardFile2: TGUID = '{EDE4326B-51F4-42D5-8251-B20B71993EC8}'; IID_IKeymanPackageFile2: TGUID = '{9B43B6BC-C622-47EF-915E-6780CF53BAAA}'; @@ -248,6 +249,8 @@ type IKeymanKeyboardLanguagesFileDisp = dispinterface; IKeymanKeyboardsInstalled2 = interface; IKeymanKeyboardsInstalled2Disp = dispinterface; + IKeymanKeyboardInstalled2 = interface; + IKeymanKeyboardInstalled2Disp = dispinterface; IKeymanPackagesInstalled2 = interface; IKeymanPackagesInstalled2Disp = dispinterface; IKeymanKeyboardFile2 = interface; @@ -1569,16 +1572,6 @@ type procedure RefreshInstalledKeyboards; safecall; end; -// *********************************************************************// -// Interface: IKeymanKeyboardInstalled2 -// Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {3086C85C-932A-4726-BF76-2D74DD133AC9} -// *********************************************************************// - IKeymanKeyboardInstalled2 = interface(IKeymanKeyboardInstalled) - ['{3086C85C-932A-4726-BF76-2D74DD133AC9}'] - procedure MCompileForBaseKeyboard(KLID: Integer); safecall; - end; - // *********************************************************************// // DispIntf: IKeymanKeyboardsInstalled2Disp // Flags: (4416) Dual OleAutomation Dispatchable @@ -1600,6 +1593,51 @@ type out References: OleVariant): WideString; dispid 401; end; +// *********************************************************************// +// Interface: IKeymanKeyboardInstalled2 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {3086C85C-932A-4726-BF76-2D74DD133AC9} +// *********************************************************************// + IKeymanKeyboardInstalled2 = interface(IKeymanKeyboardInstalled) + ['{3086C85C-932A-4726-BF76-2D74DD133AC9}'] + procedure MCompileForBaseKeyboard(KLID: Integer); safecall; + end; + +// *********************************************************************// +// DispIntf: IKeymanKeyboardInstalled2Disp +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {3086C85C-932A-4726-BF76-2D74DD133AC9} +// *********************************************************************// + IKeymanKeyboardInstalled2Disp = dispinterface + ['{3086C85C-932A-4726-BF76-2D74DD133AC9}'] + procedure MCompileForBaseKeyboard(KLID: Integer); dispid 288; + property IconFilename: WideString readonly dispid 257; + procedure InstallVisualKeyboard(const Filename: WideString); dispid 258; + property KeymanID: Integer readonly dispid 259; + property Languages: IKeymanKeyboardLanguagesInstalled readonly dispid 260; + property Loaded: WordBool dispid 261; + property Options: IKeymanKeyboardOptions readonly dispid 262; + property OwnerPackage: IKeymanPackageInstalled readonly dispid 263; + property VisualKeyboard: IKeymanVisualKeyboard readonly dispid 264; + procedure Uninstall; dispid 265; + property Bitmap: IPicture readonly dispid 1; + property Copyright: WideString readonly dispid 2; + property DefaultBCP47Languages: WideString readonly dispid 3; + property DefaultPrimaryLanguage: Integer readonly dispid 4; + property DefaultWindowsLanguages: WideString readonly dispid 5; + property DefaultHotkey: IKeymanHotkey readonly dispid 6; + property Encodings: KeymanKeyboardEncodings readonly dispid 7; + property Filename: WideString readonly dispid 8; + function GetCharsUsed: WideString; dispid 9; + property ID: WideString readonly dispid 10; + property LayoutType: KeymanKeyboardLayoutType readonly dispid 11; + property Message: WideString readonly dispid 12; + property Name: WideString readonly dispid 13; + property Version: WideString readonly dispid 14; + function SerializeXML(Flags: tagKeymanSerializeFlags; const ImagePath: WideString; + out References: OleVariant): WideString; dispid 401; + end; + // *********************************************************************// // Interface: IKeymanPackagesInstalled2 // Flags: (4416) Dual OleAutomation Dispatchable diff --git a/windows/src/engine/kmcomapi/kmcomapi.ridl b/windows/src/engine/kmcomapi/kmcomapi.ridl index 9eb63fbd68..4d65b37777 100644 --- a/windows/src/engine/kmcomapi/kmcomapi.ridl +++ b/windows/src/engine/kmcomapi/kmcomapi.ridl @@ -6,7 +6,7 @@ // However, when applying changes via the Editor this file will be regenerated // and comments or formatting changes will be lost. // ************************************************************************ // -// File generated on 16/09/2021 6:54:45 PM (- $Rev: 12980 $, 32940875). +// File generated on 7/09/2026 4:05:40 PM (- $Rev: 12980 $, 1707828). [ uuid(F16E2A9A-DA46-4EA3-BFF3-BA46B480C961), diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas index 1205d77f72..1df237b0c6 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas @@ -255,7 +255,7 @@ begin try Execute(FDestFileName, PackageID, BaseKeyboardID); finally - RecompileMnemonicKeyboard.Free; + Free; end; end; finally From 63d12b671a3a06647d11272bdfa8c4e5b2aa7270 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Mon, 7 Sep 2026 20:43:26 +1000 Subject: [PATCH 19/26] fix(windows): remove UpdateBaseLayout deadcode --- .../com/keyboards/keymankeyboardinstalled.pas | 17 ----------------- .../kmcomapi/util/internalinterfaces.pas | 19 +++++++++---------- 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas index 01b03ae3fc..7077bc1291 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas @@ -110,7 +110,6 @@ type { IIntKeymanKeyboardInstalled } function RegKeyboard: TRegKeyboard; procedure ClearVisualKeyboard; - procedure UpdateBaseLayout; // I4169 procedure RefreshInstallation; { IKeymanKeyboardInstalled2 } @@ -155,22 +154,6 @@ begin end; end; -procedure TKeymanKeyboardInstalled.UpdateBaseLayout; // I4169 -var - BaseKeyboardID: Integer; -begin - if FRegKeyboard.MnemonicLayout and FileExists(FRegKeyboard.KeymanFile) then // I4615 - begin - BaseKeyboardID := (Context.Options as IKeymanOptions).Items['koBaseLayout'].Value; - with TKPRecompileMnemonicKeyboard.Create(Context) do - try - Execute(FRegKeyboard.KeymanFile, FRegKeyboard.PackageName, BaseKeyboardID); - finally - Free; - end; - end; -end; - function TKeymanKeyboardInstalled.Get_Copyright: WideString; begin Result := FRegKeyboard.Copyright; diff --git a/windows/src/engine/kmcomapi/util/internalinterfaces.pas b/windows/src/engine/kmcomapi/util/internalinterfaces.pas index 1759468e00..edfc65bf28 100644 --- a/windows/src/engine/kmcomapi/util/internalinterfaces.pas +++ b/windows/src/engine/kmcomapi/util/internalinterfaces.pas @@ -1,24 +1,24 @@ (* Name: internalinterfaces Copyright: Copyright (C) 2003-2017 SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 25 Jan 2011 Modified Date: 17 Aug 2014 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 25 Jan 2011 - mcdurdin - I2569 - Keyboard welcome should always shown from kmshell 01 Jan 2013 - mcdurdin - I3717 - V9.0 - Need ability to select base keyboard in Keyman Configuration 16 Apr 2014 - mcdurdin - I4169 - V9.0 - Mnemonic layouts should be recompiled to positional based on user-selected base keyboard 17 Aug 2014 - mcdurdin - I4376 - V9.0 - Unticked keyboards in configuration should be removed from language profile 17 Aug 2014 - mcdurdin - I4381 - V9.0 - Keyman keyboards should be removed from language bar when Keyman exits - + *) unit internalinterfaces; @@ -41,7 +41,7 @@ type IIntKeymanInterface = interface ['{D1EBBED5-B9E3-4807-969D-DCF9E1FFB287}'] function XMLClassName: WideString; - function Serialize(Flags: TOleEnum; const ImagePath: WideString; References: TStrings): WideString; + function Serialize(Flags: TOleEnum; const ImagePath: WideString; References: TStrings): WideString; function DoSerialize(Flags: TOleEnum; const ImagePath: WideString; References: TStrings): WideString; // Wraps serialize with tag end; @@ -67,7 +67,6 @@ type ['{4876E6DF-C557-46E2-84F4-787BE5F55DDA}'] function RegKeyboard: TRegKeyboard; procedure ClearVisualKeyboard; - procedure UpdateBaseLayout; // I4169 procedure RefreshInstallation; end; From f80986dedd78c10c182a9c6b7b14782e3222f0c0 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Mon, 14 Sep 2026 14:42:32 +1000 Subject: [PATCH 20/26] fix(windows): apply batched suggestions from code review Co-authored-by: Marc Durdin --- ...yman.Configuration.System.BaseKeyboard.pas | 32 ++++++++++--------- .../desktop/kmshell/main/UfrmBaseKeyboard.pas | 12 +++---- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas b/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas index d91b439f33..926e766daa 100644 --- a/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas @@ -8,27 +8,29 @@ uses keymanapi_TLB; (** - Returns true if the keyboard files need to be compiled for the specified KLID. - @param BaseKeyboardID KLID of the base keyboard to compile. - @returns True If the keyboard files need to be compiled. -*) + * Returns true if the keyboard files need to be compiled for the specified KLID. + * @param BaseKeyboardID KLID of the base keyboard to compile. + * @returns True If the keyboard files need to be compiled. + *) function BaseKeyboardNeedsMCompile(BaseKeyboardID: Integer): Boolean; (** - Sets the base keyboard KLID for the current user and compiles the keyboard - files if necessary. In the case the compiled keyboard files are not present, - it will require elevation. - @param WindowHandle Window handle to own the elevation prompt. - @param BaseKeyboardID KLID of the base keyboard KLID to set. - @returns True when the base keyboard setting has been applied. -*) + * Sets the base keyboard KLID for the current user and compiles the keyboard + * files if necessary. In the case the compiled keyboard files are not present, + * it will require elevation. + * @param WindowHandle Window handle to own the elevation prompt. + * @param BaseKeyboardID KLID of the base keyboard KLID to set. + * @returns True when the base keyboard setting has been applied. + *) function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolean; (** - Compiles the base keyboard files for the specified KLID. - @param BaseKeyboardID KLID of the base keyboard to compile. - @returns True when the compilation is successful. -*) + * Compiles the base keyboard files for the specified KLID. + * Must run elevated. + * + * @param BaseKeyboardID KLID of the base keyboard to compile. + * @returns True when the compilation is successful. + *) function MCompileBaseKeyboard(BaseKeyboardID: Integer): Boolean; implementation diff --git a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas index dd298a8642..1d06e7ca25 100644 --- a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas @@ -20,12 +20,12 @@ type (** - Form for the user to select a base keyboard. If the user selects a base - keyboard, the KLID of the selected base keyboard is returned in - BaseKeyboardID. - @param [out] BaseKeyboardID KLID of the base keyboard selected by the user. - @returns True if the user selected a base keyboard. -*) + * Form for the user to select a base keyboard. If the user selects a base + * keyboard, the KLID of the selected base keyboard is returned in + * BaseKeyboardID. + * @param [out] BaseKeyboardID KLID of the base keyboard selected by the user. + * @returns True if the user selected a base keyboard. + *) function ConfigureBaseKeyboard(out BaseKeyboardID: Integer): Boolean; implementation From babd43ab29d39ea98d452cbe90303324c48f1702 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Tue, 15 Sep 2026 12:11:02 +1000 Subject: [PATCH 21/26] fix(windows): refactor ConfigureBaseKeyboard Refactor ConfigureBaseKeyboard to ConfigureAndSetBaseKeyboard call the SetBaseKeyboard from the form rather then from the initprog module. --- ...yman.Configuration.System.BaseKeyboard.pas | 16 ++++++++++++--- .../desktop/kmshell/main/UfrmBaseKeyboard.pas | 20 ++++++++++--------- windows/src/desktop/kmshell/main/UfrmMain.pas | 3 +-- windows/src/desktop/kmshell/main/initprog.pas | 3 +-- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas b/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas index 926e766daa..dedea86dae 100644 --- a/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas @@ -1,3 +1,13 @@ +(* + * Keyman is copyright (C) SIL Global. MIT License. + * + * Created by Ross Cruickshank on 2026-09-dd-12 + * + * + * This unit assists in setting the base keyboard configuration, + * including compiling the installed keyboard layouts against + * the selected base keyboard. + *) unit Keyman.Configuration.System.BaseKeyboard; interface @@ -16,8 +26,8 @@ function BaseKeyboardNeedsMCompile(BaseKeyboardID: Integer): Boolean; (** * Sets the base keyboard KLID for the current user and compiles the keyboard - * files if necessary. In the case the compiled keyboard files are not present, - * it will require elevation. + * layout files if necessary. In the case the compiled keyboard files are + *not present, it will require elevation. * @param WindowHandle Window handle to own the elevation prompt. * @param BaseKeyboardID KLID of the base keyboard KLID to set. * @returns True when the base keyboard setting has been applied. @@ -25,7 +35,7 @@ function BaseKeyboardNeedsMCompile(BaseKeyboardID: Integer): Boolean; function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolean; (** - * Compiles the base keyboard files for the specified KLID. + * Compiles the installed keyboard layouts for the specified KLID. * Must run elevated. * * @param BaseKeyboardID KLID of the base keyboard to compile. diff --git a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas index 1d06e7ca25..825088ad0a 100644 --- a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas @@ -18,15 +18,14 @@ type procedure FireCommand(const command: WideString; params: TStringList); override; end; - (** - * Form for the user to select a base keyboard. If the user selects a base - * keyboard, the KLID of the selected base keyboard is returned in - * BaseKeyboardID. - * @param [out] BaseKeyboardID KLID of the base keyboard selected by the user. - * @returns True if the user selected a base keyboard. + * Displays a form for the user to select a base keyboard. If the user selects a base + * keyboard, the KLID is used to Set the Base Keyboard. + * + * @returns True if the user selected base keyboard has been set. *) -function ConfigureBaseKeyboard(out BaseKeyboardID: Integer): Boolean; +function ConfigureAndSetBaseKeyboard(WindowHandle: THandle): Boolean; + implementation @@ -37,16 +36,19 @@ uses ErrorControlledRegistry, RegistryKeys, keymanapi_TLB, + Keyman.Configuration.System.BaseKeyboard, kmint, utilkmshell; -function ConfigureBaseKeyboard(out BaseKeyboardID: Integer): Boolean; + +function ConfigureAndSetBaseKeyboard(WindowHandle: THandle): Boolean; +var BaseKeyboardID: Integer; begin with TfrmBaseKeyboard.Create(nil) do try Result := ShowModal = mrOk; if Result then - BaseKeyboardID := FBaseKeyboardID; + SetBaseKeyboard(WindowHandle, FBaseKeyboardID) finally Free; end; diff --git a/windows/src/desktop/kmshell/main/UfrmMain.pas b/windows/src/desktop/kmshell/main/UfrmMain.pas index 9c4478283e..472353102c 100644 --- a/windows/src/desktop/kmshell/main/UfrmMain.pas +++ b/windows/src/desktop/kmshell/main/UfrmMain.pas @@ -666,9 +666,8 @@ procedure TfrmMain.Options_BaseKeyboard; // I4169 var BaseKeyboardID: Integer; begin - if ConfigureBaseKeyboard(BaseKeyboardID) then + if ConfigureAndSetBaseKeyboard(Handle) then begin - SetBaseKeyboard(Handle, BaseKeyboardID); DoRefresh; end; diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas index 54f4a73f65..f2392d6913 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -402,7 +402,6 @@ var kdl: IKeymanDefaultLanguage; FIcon: string; FMutex: TKeymanMutex; // I2720 - BaseKeyboardID: Integer; function FirstKeyboardFileName: WideString; begin if KeyboardFileNames.Count = 0 @@ -550,7 +549,7 @@ begin end; fmBaseKeyboard: // I4169 - if ConfigureBaseKeyboard(BaseKeyboardID) and SetBaseKeyboard(0, BaseKeyboardID) + if ConfigureAndSetBaseKeyboard(0) then ExitCode := 0 else ExitCode := 1; From b6f475a382fc763190c489c5f9cf35bf92284d0d Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Wed, 16 Sep 2026 17:37:59 +1000 Subject: [PATCH 22/26] fix(windows): add basekeyboard filename functions --- common/windows/delphi/general/utilstr.pas | 44 +++++++++++++++---- .../kmshell/install/UpgradeMnemonicLayout.pas | 19 ++++---- ...yman.Configuration.System.BaseKeyboard.pas | 13 +++--- .../keyboard/kprecompilemnemonickeyboard.pas | 5 ++- 4 files changed, 56 insertions(+), 25 deletions(-) diff --git a/common/windows/delphi/general/utilstr.pas b/common/windows/delphi/general/utilstr.pas index 01e085b8a8..b5bcd32e65 100644 --- a/common/windows/delphi/general/utilstr.pas +++ b/common/windows/delphi/general/utilstr.pas @@ -1,18 +1,18 @@ (* Name: utilstr Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 1 Aug 2006 Modified Date: 8 Jun 2012 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 01 Aug 2006 - mcdurdin - Refactor util functions into multiple units 23 Aug 2006 - mcdurdin - Add StringToExtString and WideQuotedStr functions 14 Sep 2006 - mcdurdin - Add RectToString, StringToRect, use widestrings for some functions @@ -58,7 +58,25 @@ function GetTokenFromCaret(line: string; var selx, sellen: Integer): string; function WideQuotedStr(const str: WideString): WideString; deprecated; // I3310 +(** + * Creates the compiled keyboard filename by inserting the base keyboard ID + * before the .kmx extension. + * + * @param BaseFileName Base keyboard filename, in the form keyboardname.kmx. + * @param BaseKeyboardIDHex Base keyboard ID in hexadecimal form. + * @return Compiled keyboard filename, in the form keyboardname-.kmx. + *) +function InsertBKLIDFilename(const BaseFileName: string; BaseKeyboardIDHex: string): string; +(** + * Creates the dead-key compiled keyboard filename by inserting the base + * keyboard ID and -d suffix before the .kmx extension. + * + * @param BaseFileName Base keyboard filename, in the form keyboardname.kmx. + * @param BaseKeyboardIDHex Base keyboard ID in hexadecimal form. + * @return Dead-key compiled keyboard filename, in the form keyboardname--d.kmx. + *) +function InsertBKLIDDeadkeyFilename(const BaseFileName: string; BaseKeyboardIDHex: string): string; implementation @@ -78,7 +96,7 @@ begin Result := ''; Exit; end; - + if s[1] = '"' then begin Delete(s,1,1); @@ -418,4 +436,14 @@ begin Result.Bottom := StrToIntDef(s, 0); end; +function InsertBKLIDFilename(const BaseFileName: string; BaseKeyboardIDHex: string): string; +begin + Result := ChangeFileExt(BaseFileName, '') + '-' + BaseKeyboardIDHex + '.kmx'; +end; + +function InsertBKLIDDeadkeyFilename(const BaseFileName: string; BaseKeyboardIDHex: string): string; +begin + Result := ChangeFileExt(BaseFileName, '') + '-' + BaseKeyboardIDHex + '-d.kmx' +end; + end. diff --git a/windows/src/desktop/kmshell/install/UpgradeMnemonicLayout.pas b/windows/src/desktop/kmshell/install/UpgradeMnemonicLayout.pas index acad765590..2639ac2072 100644 --- a/windows/src/desktop/kmshell/install/UpgradeMnemonicLayout.pas +++ b/windows/src/desktop/kmshell/install/UpgradeMnemonicLayout.pas @@ -1,18 +1,18 @@ (* Name: UpgradeMnemonicLayout Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 31 Dec 2014 Modified Date: 2 Jun 2015 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 31 Dec 2014 - mcdurdin - I4553 - V9.0 - Upgrade to 476 or later requires recompile of all mnemonic layouts 06 Feb 2015 - mcdurdin - I4552 - V9.0 - Add mnemonic recompile option to ignore deadkeys 08 Apr 2015 - mcdurdin - I4651 - V9.0 - Mnemonic layout recompiler maps AltGr+VK_BKSLASH rather than VK_OEM_102 @@ -46,7 +46,8 @@ uses kmint, RegistryKeys, utilexecute, - utilkmshell; + utilkmshell, + utilstr; const { CurrentMnemonicLayoutVersion = 476; // First 9.0 build with fixes for mnemonic layouts } @@ -171,7 +172,7 @@ begin FBaseKeyboardIDHex := IntToHex(BaseKeyboardID, 8); FBaseFileName := Keyboard.Filename; FDestFileName := OutputFileName; - FDestDeadkeyFileName := ChangeFileExt(FDestFileName, '') + '-d.kmx'; // I4552 + FDestDeadkeyFileName := InsertBKLIDDeadkeyFilename(FBaseFileName, FBaseKeyboardIDHex); // I4552 FMCompilePath := TKeymanPaths.KeymanEngineInstallPath(TKeymanPaths.S_MCompileExe); FDestPath := ExtractFileDir(Keyboard.Filename); diff --git a/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas b/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas index dedea86dae..4c398f1fe8 100644 --- a/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas @@ -47,23 +47,24 @@ implementation uses kmint, - utilkmshell; + utilkmshell, + utilstr; function BaseKeyboardNeedsMCompile(BaseKeyboardID: Integer): Boolean; var I: Integer; Keyboard: IKeymanKeyboardInstalled; - BaseFileName: string; + KeyboardFileName: string; BaseKeyboardIDHex: string; begin BaseKeyboardIDHex := IntToHex(BaseKeyboardID, 8); for I := 0 to kmcom.Keyboards.Count - 1 do begin Keyboard := kmcom.Keyboards.Items[I]; - BaseFileName := Keyboard.Filename; - if FileExists(BaseFileName) and - (not FileExists(ChangeFileExt(BaseFileName, '') + '-' + BaseKeyboardIDHex + '.kmx') or - not FileExists(ChangeFileExt(BaseFileName, '') + '-' + BaseKeyboardIDHex + '-d.kmx')) then + KeyboardFileName := Keyboard.Filename; + if FileExists(KeyboardFileName) and + (not FileExists(InsertBKLIDFilename(KeyboardFileName, BaseKeyboardIDHex)) or + not FileExists(InsertBKLIDDeadkeyFilename(KeyboardFileName, BaseKeyboardIDHex))) then Exit(True); end; Result := False; diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas b/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas index 3d806afda2..b05ab325d1 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas @@ -47,6 +47,7 @@ uses RegistryKeys, utilexecute, utilkeyman, + utilstr, utilsystem; function GetKeyboardLayoutFileName(id: Integer): string; @@ -83,8 +84,8 @@ begin FBaseKeyboardIDHex := IntToHex(BaseKeyboardID, 8); FBaseFileName := FDestPath + '\' + ExtractFileName(FileName); // I3581 - FDestFileName := ChangeFileExt(FBaseFileName, '') + '-'+FBaseKeyboardIDHex + '.kmx'; - FDestDeadkeyFileName := ChangeFileExt(FBaseFileName, '') + '-'+FBaseKeyboardIDHex + '-d.kmx'; // I4552 + FDestFileName := InsertBKLIDFilename(FBaseFileName, FBaseKeyboardIDHex); + FDestDeadkeyFileName := InsertBKLIDDeadkeyFilename(FBaseFileName, FBaseKeyboardIDHex); // I4552 FMCompilePath := TKeymanPaths.KeymanEngineInstallPath(TKeymanPaths.S_MCompileExe); { Recompile with the traditional deadkey behaviour } From eec0b12c449b56402991747d82d590fbb049a27f Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Thu, 17 Sep 2026 10:38:33 +1000 Subject: [PATCH 23/26] fix(windows): rename argument that was misleading --- common/windows/delphi/general/utilstr.pas | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/common/windows/delphi/general/utilstr.pas b/common/windows/delphi/general/utilstr.pas index b5bcd32e65..59a897ad2e 100644 --- a/common/windows/delphi/general/utilstr.pas +++ b/common/windows/delphi/general/utilstr.pas @@ -62,21 +62,21 @@ function WideQuotedStr(const str: WideString): WideString; deprecated; // I3310 * Creates the compiled keyboard filename by inserting the base keyboard ID * before the .kmx extension. * - * @param BaseFileName Base keyboard filename, in the form keyboardname.kmx. + * @param KeyboardFileName Keyboard filename, in the form keyboardname.kmx. * @param BaseKeyboardIDHex Base keyboard ID in hexadecimal form. * @return Compiled keyboard filename, in the form keyboardname-.kmx. *) -function InsertBKLIDFilename(const BaseFileName: string; BaseKeyboardIDHex: string): string; +function InsertBKLIDFilename(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; (** * Creates the dead-key compiled keyboard filename by inserting the base * keyboard ID and -d suffix before the .kmx extension. * - * @param BaseFileName Base keyboard filename, in the form keyboardname.kmx. + * @param KeyboardFileName Keyboard filename, in the form keyboardname.kmx. * @param BaseKeyboardIDHex Base keyboard ID in hexadecimal form. * @return Dead-key compiled keyboard filename, in the form keyboardname--d.kmx. *) -function InsertBKLIDDeadkeyFilename(const BaseFileName: string; BaseKeyboardIDHex: string): string; +function InsertBKLIDDeadkeyFilename(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; implementation @@ -436,14 +436,14 @@ begin Result.Bottom := StrToIntDef(s, 0); end; -function InsertBKLIDFilename(const BaseFileName: string; BaseKeyboardIDHex: string): string; +function InsertBKLIDFilename(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; begin - Result := ChangeFileExt(BaseFileName, '') + '-' + BaseKeyboardIDHex + '.kmx'; + Result := ChangeFileExt(KeyboardFileName, '') + '-' + BaseKeyboardIDHex + '.kmx'; end; -function InsertBKLIDDeadkeyFilename(const BaseFileName: string; BaseKeyboardIDHex: string): string; +function InsertBKLIDDeadkeyFilename(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; begin - Result := ChangeFileExt(BaseFileName, '') + '-' + BaseKeyboardIDHex + '-d.kmx' + Result := ChangeFileExt(KeyboardFileName, '') + '-' + BaseKeyboardIDHex + '-d.kmx' end; end. From c940caeb711d2524a50717d251b54631d7023d8d Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Fri, 18 Sep 2026 16:58:58 +1000 Subject: [PATCH 24/26] fix(windows): fix date in title block --- .../kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas b/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas index 4c398f1fe8..a1fecdd608 100644 --- a/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas @@ -1,7 +1,7 @@ (* * Keyman is copyright (C) SIL Global. MIT License. * - * Created by Ross Cruickshank on 2026-09-dd-12 + * Created by Ross Cruickshank on 2026-09-12 * * * This unit assists in setting the base keyboard configuration, From 587d74dee4841ec36ef085e39fb4f33fdbf3f025 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Fri, 18 Sep 2026 20:48:56 +1000 Subject: [PATCH 25/26] fix(windows): apply batched suggestions from code review Co-authored-by: Marc Durdin --- common/windows/delphi/general/utilstr.pas | 22 +++++++++---------- windows/src/desktop/kmshell/main/initprog.pas | 1 + 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/common/windows/delphi/general/utilstr.pas b/common/windows/delphi/general/utilstr.pas index 59a897ad2e..8319c37d04 100644 --- a/common/windows/delphi/general/utilstr.pas +++ b/common/windows/delphi/general/utilstr.pas @@ -62,21 +62,21 @@ function WideQuotedStr(const str: WideString): WideString; deprecated; // I3310 * Creates the compiled keyboard filename by inserting the base keyboard ID * before the .kmx extension. * - * @param KeyboardFileName Keyboard filename, in the form keyboardname.kmx. - * @param BaseKeyboardIDHex Base keyboard ID in hexadecimal form. - * @return Compiled keyboard filename, in the form keyboardname-.kmx. + * @param KeyboardFileName Keyboard filename, in the form '[path\]keyboardid[.kmx]' + * @param BaseKeyboardIDHex Base keyboard KLID in eight digit hexadecimal form + * @return Compiled keyboard filename, in the form '[path\]keyboardid-.kmx' *) -function InsertBKLIDFilename(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; +function GetKeyboardFilenameWithBaseKeyboardID(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; (** * Creates the dead-key compiled keyboard filename by inserting the base * keyboard ID and -d suffix before the .kmx extension. * - * @param KeyboardFileName Keyboard filename, in the form keyboardname.kmx. - * @param BaseKeyboardIDHex Base keyboard ID in hexadecimal form. - * @return Dead-key compiled keyboard filename, in the form keyboardname--d.kmx. + * @param KeyboardFileName Keyboard filename, in the form '[path]\keyboardid[.kmx]' + * @param BaseKeyboardIDHex Base keyboard KLID in eight digit hexadecimal form + * @return Dead-key compiled keyboard filename, in the form '[path\]keyboardid--d.kmx' *) -function InsertBKLIDDeadkeyFilename(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; +function GetKeyboardFilenameWithBaseKeyboardIDAndDeadkey(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; implementation @@ -436,14 +436,14 @@ begin Result.Bottom := StrToIntDef(s, 0); end; -function InsertBKLIDFilename(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; +function GetKeyboardFilenameWithBaseKeyboardID(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; begin Result := ChangeFileExt(KeyboardFileName, '') + '-' + BaseKeyboardIDHex + '.kmx'; end; -function InsertBKLIDDeadkeyFilename(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; +function GetKeyboardFilenameWithBaseKeyboardIDAndDeadkey(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; begin - Result := ChangeFileExt(KeyboardFileName, '') + '-' + BaseKeyboardIDHex + '-d.kmx' + Result := ChangeFileExt(KeyboardFileName, '') + '-' + BaseKeyboardIDHex + '-d.kmx'; end; end. diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas index f2392d6913..3010dae5cc 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -266,6 +266,7 @@ begin else if s = '-basekeyboard' then FMode := fmBaseKeyboard // I4169 else if s = '-mcompilekbds' then begin + // Requires elevated context FMode := fmMCompileKbds; Inc(i); if i > ParamCount then Exit; From bb20b890347a624e1e80a3afd3afc98858d3f8d2 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Fri, 18 Sep 2026 21:16:54 +1000 Subject: [PATCH 26/26] fix(windows): rename filename builder functions --- .../windows/delphi/general/utilfiletypes.pas | 31 +++++++++++++++++++ common/windows/delphi/general/utilstr.pas | 30 ------------------ .../kmshell/install/UpgradeMnemonicLayout.pas | 4 +-- ...yman.Configuration.System.BaseKeyboard.pas | 6 ++-- .../keyboard/kprecompilemnemonickeyboard.pas | 6 ++-- 5 files changed, 39 insertions(+), 38 deletions(-) diff --git a/common/windows/delphi/general/utilfiletypes.pas b/common/windows/delphi/general/utilfiletypes.pas index f34be0933d..28faa8804c 100644 --- a/common/windows/delphi/general/utilfiletypes.pas +++ b/common/windows/delphi/general/utilfiletypes.pas @@ -91,6 +91,27 @@ function IsProjectFile(const FileName: string): Boolean; function IsKeyboardFile(const FileName: string): Boolean; function RemoveFileExtension(Filename, Extension: string): string; +(** + * Builds the compiled keyboard filename by inserting the base keyboard ID + * before the .kmx extension. + * + * @param KeyboardFileName Keyboard filename, in the form '[path\]keyboardid[.kmx]' + * @param BaseKeyboardIDHex Base keyboard KLID in eight digit hexadecimal form + * @return Compiled keyboard filename, in the form '[path\]keyboardid-.kmx' + *) +function BuildKeyboardFilenameWithBaseKeyboardID(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; + +(** + * Builds the dead-key compiled keyboard filename by inserting the base + * keyboard ID and -d suffix before the .kmx extension. + * + * @param KeyboardFileName Keyboard filename, in the form '[path]\keyboardid[.kmx]' + * @param BaseKeyboardIDHex Base keyboard KLID in eight digit hexadecimal form + * @return Dead-key compiled keyboard filename, in the form '[path\]keyboardid--d.kmx' + *) +function BuildKeyboardFilenameWithBaseKeyboardIDAndDeadkey(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; + + type TKeymanFileTypeInfo = class public @@ -208,4 +229,14 @@ begin SameText(ExtractFileExt(Filename), ExtractFileExt(PackageFile_Welcome))); end; +function BuildKeyboardFilenameWithBaseKeyboardID(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; +begin + Result := ChangeFileExt(KeyboardFileName, '') + '-' + BaseKeyboardIDHex + '.kmx'; +end; + +function BuildKeyboardFilenameWithBaseKeyboardIDAndDeadkey(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; +begin + Result := ChangeFileExt(KeyboardFileName, '') + '-' + BaseKeyboardIDHex + '-d.kmx'; +end; + end. diff --git a/common/windows/delphi/general/utilstr.pas b/common/windows/delphi/general/utilstr.pas index 8319c37d04..4cd175e360 100644 --- a/common/windows/delphi/general/utilstr.pas +++ b/common/windows/delphi/general/utilstr.pas @@ -58,26 +58,6 @@ function GetTokenFromCaret(line: string; var selx, sellen: Integer): string; function WideQuotedStr(const str: WideString): WideString; deprecated; // I3310 -(** - * Creates the compiled keyboard filename by inserting the base keyboard ID - * before the .kmx extension. - * - * @param KeyboardFileName Keyboard filename, in the form '[path\]keyboardid[.kmx]' - * @param BaseKeyboardIDHex Base keyboard KLID in eight digit hexadecimal form - * @return Compiled keyboard filename, in the form '[path\]keyboardid-.kmx' - *) -function GetKeyboardFilenameWithBaseKeyboardID(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; - -(** - * Creates the dead-key compiled keyboard filename by inserting the base - * keyboard ID and -d suffix before the .kmx extension. - * - * @param KeyboardFileName Keyboard filename, in the form '[path]\keyboardid[.kmx]' - * @param BaseKeyboardIDHex Base keyboard KLID in eight digit hexadecimal form - * @return Dead-key compiled keyboard filename, in the form '[path\]keyboardid--d.kmx' - *) -function GetKeyboardFilenameWithBaseKeyboardIDAndDeadkey(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; - implementation uses @@ -436,14 +416,4 @@ begin Result.Bottom := StrToIntDef(s, 0); end; -function GetKeyboardFilenameWithBaseKeyboardID(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; -begin - Result := ChangeFileExt(KeyboardFileName, '') + '-' + BaseKeyboardIDHex + '.kmx'; -end; - -function GetKeyboardFilenameWithBaseKeyboardIDAndDeadkey(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; -begin - Result := ChangeFileExt(KeyboardFileName, '') + '-' + BaseKeyboardIDHex + '-d.kmx'; -end; - end. diff --git a/windows/src/desktop/kmshell/install/UpgradeMnemonicLayout.pas b/windows/src/desktop/kmshell/install/UpgradeMnemonicLayout.pas index 2639ac2072..62b75bf566 100644 --- a/windows/src/desktop/kmshell/install/UpgradeMnemonicLayout.pas +++ b/windows/src/desktop/kmshell/install/UpgradeMnemonicLayout.pas @@ -47,7 +47,7 @@ uses RegistryKeys, utilexecute, utilkmshell, - utilstr; + utilfiletypes; const { CurrentMnemonicLayoutVersion = 476; // First 9.0 build with fixes for mnemonic layouts } @@ -172,7 +172,7 @@ begin FBaseKeyboardIDHex := IntToHex(BaseKeyboardID, 8); FBaseFileName := Keyboard.Filename; FDestFileName := OutputFileName; - FDestDeadkeyFileName := InsertBKLIDDeadkeyFilename(FBaseFileName, FBaseKeyboardIDHex); // I4552 + FDestDeadkeyFileName := BuildKeyboardFilenameWithBaseKeyboardIDAndDeadkey(FBaseFileName, FBaseKeyboardIDHex); // I4552 FMCompilePath := TKeymanPaths.KeymanEngineInstallPath(TKeymanPaths.S_MCompileExe); FDestPath := ExtractFileDir(Keyboard.Filename); diff --git a/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas b/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas index a1fecdd608..c4fb428b49 100644 --- a/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas @@ -48,7 +48,7 @@ implementation uses kmint, utilkmshell, - utilstr; + utilfiletypes; function BaseKeyboardNeedsMCompile(BaseKeyboardID: Integer): Boolean; var @@ -63,8 +63,8 @@ begin Keyboard := kmcom.Keyboards.Items[I]; KeyboardFileName := Keyboard.Filename; if FileExists(KeyboardFileName) and - (not FileExists(InsertBKLIDFilename(KeyboardFileName, BaseKeyboardIDHex)) or - not FileExists(InsertBKLIDDeadkeyFilename(KeyboardFileName, BaseKeyboardIDHex))) then + (not FileExists(BuildKeyboardFilenameWithBaseKeyboardID(KeyboardFileName, BaseKeyboardIDHex)) or + not FileExists(BuildKeyboardFilenameWithBaseKeyboardIDAndDeadkey(KeyboardFileName, BaseKeyboardIDHex))) then Exit(True); end; Result := False; diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas b/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas index b05ab325d1..52139f5839 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas @@ -47,7 +47,7 @@ uses RegistryKeys, utilexecute, utilkeyman, - utilstr, + utilfiletypes, utilsystem; function GetKeyboardLayoutFileName(id: Integer): string; @@ -84,8 +84,8 @@ begin FBaseKeyboardIDHex := IntToHex(BaseKeyboardID, 8); FBaseFileName := FDestPath + '\' + ExtractFileName(FileName); // I3581 - FDestFileName := InsertBKLIDFilename(FBaseFileName, FBaseKeyboardIDHex); - FDestDeadkeyFileName := InsertBKLIDDeadkeyFilename(FBaseFileName, FBaseKeyboardIDHex); // I4552 + FDestFileName := BuildKeyboardFilenameWithBaseKeyboardID(FBaseFileName, FBaseKeyboardIDHex); + FDestDeadkeyFileName := BuildKeyboardFilenameWithBaseKeyboardIDAndDeadkey(FBaseFileName, FBaseKeyboardIDHex); // I4552 FMCompilePath := TKeymanPaths.KeymanEngineInstallPath(TKeymanPaths.S_MCompileExe); { Recompile with the traditional deadkey behaviour }