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 6a631fb5461..a469db480c3 100644 --- a/windows/src/desktop/kmshell/main/UfrmMain.pas +++ b/windows/src/desktop/kmshell/main/UfrmMain.pas @@ -661,6 +661,8 @@ procedure TfrmMain.cefBeforeBrowseSync(Sender: TObject; const Url: string; 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 40a65e31ce1..b3f60a5067b 100644 --- a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas @@ -11,13 +11,16 @@ interface 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 @@ procedure TfrmBaseKeyboard.Footer_OK(params: TStringList); 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 a469db480c3..a556019abd2 100644 --- a/windows/src/desktop/kmshell/main/UfrmMain.pas +++ b/windows/src/desktop/kmshell/main/UfrmMain.pas @@ -197,6 +197,7 @@ implementation Keyman.Configuration.UI.UfrmStartInstall, RegistryKeys, SupportXMLRenderer, + UfrmBaseKeyboard, UfrmChangeHotkey, UfrmHTML, UfrmInstallKeyboardFromWeb, @@ -660,11 +661,15 @@ procedure TfrmMain.cefBeforeBrowseSync(Sender: TObject; const Url: string; ------------------------------------------------------------------------------} 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 359130f27e7..8ea4331995f 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -90,6 +90,7 @@ function Main(Owner: TComponent = nil): TModalResult; fmKeyboardWelcome, // I2569 fmKeyboardPrint, // I2329 fmBaseKeyboard, // I4169 + fmMCompile, fmUpgradeMnemonicLayout, // I4553 fmRepair, fmKeepInTouch, @@ -262,6 +263,13 @@ function Init(var FMode: TKMShellMode; KeyboardFileNames: TStrings; var FSilent, 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 @@ procedure RunKMCOM(FMode: TKMShellMode; KeyboardFileNames: TStrings; FSilent, FF kdl: IKeymanDefaultLanguage; FIcon: string; FMutex: TKeymanMutex; // I2720 + BaseKeyboardID: Integer; function FirstKeyboardFileName: WideString; begin if KeyboardFileNames.Count = 0 @@ -540,7 +549,12 @@ procedure RunKMCOM(FMode: TKMShellMode; KeyboardFileNames: TStrings; FSilent, FF 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 051d399b6ec..91ecaa9b5f8 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas @@ -109,7 +109,7 @@ TKeymanKeyboardInstalled = class( // I3581 { IIntKeymanKeyboardInstalled } function RegKeyboard: TRegKeyboard; procedure ClearVisualKeyboard; - procedure UpdateBaseLayout; // I4169 + procedure UpdateBaseLayout(BaseKeyboardID: Integer); // I4169 procedure RefreshInstallation; public @@ -151,12 +151,12 @@ procedure TKeymanKeyboardInstalled.Uninstall; 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 7bea91450bc..8635a748083 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 @@ implementation ErrorControlledRegistry, RegistryKeys, Glossary, + isadmin, Keyman.System.BaseKeyboard, KeymanOptionNames, keymanerrorcodes; @@ -112,7 +113,9 @@ function TKeymanOptions.IndexOf(const ID: WideString): Integer; procedure TKeymanOptions.Apply; var - I, FOldBaseLayout: Integer; + I: Integer; + FOldBaseLayout: Integer; + FNewBaseLayout: Integer; begin with TRegistryErrorControlled.Create do // I3717 try @@ -130,9 +133,10 @@ procedure TKeymanOptions.Apply; 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 26c92faa90a..1df237b0c60 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas @@ -125,6 +125,7 @@ procedure TKPInstallKeyboard.Execute(const FileName, PackageID: string; FInstall FExitCode: Integer; FKVKName: WideString; FCreatedIcon: Boolean; + BaseKeyboardID: Integer; begin KL.MethodEnter(Self, 'Execute', [FileName,PackageID,ikPartOfPackage in FInstallOptions ,Force]); try @@ -248,9 +249,11 @@ procedure TKPInstallKeyboard.Execute(const FileName, PackageID: string; FInstall // 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 30d0c275cc2..7a4d5a2b395 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas @@ -27,7 +27,7 @@ interface 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 @@ implementation Winapi.Windows, errorcontrolledregistry, - keymancontext, keymanerrorcodes, KeymanPaths, - keymanapi_TLB, RegistryKeys, utilexecute, utilkeyman, @@ -67,7 +65,7 @@ function GetKeyboardLayoutFileName(id: Integer): string; 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 @@ procedure TKPRecompileMnemonicKeyboard.Execute(const FileName,PackageName: strin FExitCode: Integer; FMCompilePath: string; FBaseKeyboardFileName: string; - BaseKeyboardID: Cardinal; FDestDeadkeyFileName: string; FCommand: string; begin @@ -84,9 +81,6 @@ procedure TKPRecompileMnemonicKeyboard.Execute(const FileName,PackageName: strin 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 1759468e006..11093ac89a1 100644 --- a/windows/src/engine/kmcomapi/util/internalinterfaces.pas +++ b/windows/src/engine/kmcomapi/util/internalinterfaces.pas @@ -67,7 +67,7 @@ interface ['{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 91ecaa9b5f8..52fd6984354 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas @@ -109,7 +109,7 @@ TKeymanKeyboardInstalled = class( // I3581 { IIntKeymanKeyboardInstalled } function RegKeyboard: TRegKeyboard; procedure ClearVisualKeyboard; - procedure UpdateBaseLayout(BaseKeyboardID: Integer); // I4169 + procedure UpdateBaseLayout; // I4169 procedure RefreshInstallation; public @@ -151,15 +151,20 @@ procedure TKeymanKeyboardInstalled.Uninstall; 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 8635a748083..a60c5da0416 100644 --- a/windows/src/engine/kmcomapi/com/options/keymanoptions.pas +++ b/windows/src/engine/kmcomapi/com/options/keymanoptions.pas @@ -136,7 +136,7 @@ procedure TKeymanOptions.Apply; 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 7a4d5a2b395..3d806afda2e 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 11093ac89a1..1759468e006 100644 --- a/windows/src/engine/kmcomapi/util/internalinterfaces.pas +++ b/windows/src/engine/kmcomapi/util/internalinterfaces.pas @@ -67,7 +67,7 @@ interface ['{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 a556019abd2..4ee970cca57 100644 --- a/windows/src/desktop/kmshell/main/UfrmMain.pas +++ b/windows/src/desktop/kmshell/main/UfrmMain.pas @@ -666,8 +666,8 @@ procedure TfrmMain.Options_BaseKeyboard; // I4169 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 b3f60a5067b..e9ce67d5e34 100644 --- a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas @@ -21,6 +21,7 @@ TfrmBaseKeyboard = class(TfrmWebContainer) 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 @@ procedure TfrmBaseKeyboard.Footer_OK(params: TStringList); 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 @@ function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolea 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 3444e7ce538..f9b5f9ac9b8 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -90,7 +90,7 @@ function Main(Owner: TComponent = nil): TModalResult; fmKeyboardWelcome, // I2569 fmKeyboardPrint, // I2329 fmBaseKeyboard, // I4169 - fmMCompile, + fmMCompileKbds, fmUpgradeMnemonicLayout, // I4553 fmRepair, fmKeepInTouch, @@ -263,9 +263,9 @@ function Init(var FMode: TKMShellMode; KeyboardFileNames: TStrings; var FSilent, 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 @@ procedure RunKMCOM(FMode: TKMShellMode; KeyboardFileNames: TStrings; FSilent, FF 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 52fd6984354..01b03ae3fc8 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas @@ -63,7 +63,8 @@ TKeymanKeyboardInstalled = class; TKeymanKeyboardInstalled = class( // I3581 TKeymanKeyboard, IIntKeymanKeyboardInstalled, - IKeymanKeyboardInstalled) + IKeymanKeyboardInstalled, + IKeymanKeyboardInstalled2) private FRegKeyboard: TRegKeyboard; FVisualKeyboard: IKeymanVisualKeyboard; @@ -112,6 +113,9 @@ TKeymanKeyboardInstalled = class( // I3581 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 @@ function TKeymanKeyboardInstalled.RegKeyboard: TRegKeyboard; 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 a60c5da0416..1848428033c 100644 --- a/windows/src/engine/kmcomapi/com/options/keymanoptions.pas +++ b/windows/src/engine/kmcomapi/com/options/keymanoptions.pas @@ -112,32 +112,8 @@ function TKeymanOptions.IndexOf(const ID: WideString): Integer; 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 3ceb5b15cd7..786ce6c9b2d 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -1569,6 +1569,16 @@ interface 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 ac20310a871..9eb63fbd68d 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 c6ee3564ae7..3cc8dcc9016 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 @@ TInstallFile = class sealed 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 @@ implementation 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 @@ class function TInstallFile.Execute(Owner: TComponent; const FileName: string; A begin if ASilent then begin - InstallKeyboard(LogFile, BCP47); + InstallKeyboard(LogFile, BCP47, BaseKeyboardID); Result := True; end else @@ -139,7 +140,7 @@ class function TInstallFile.Execute(Owner: TComponent; const FileName: string; A /// 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 @@ class function TInstallFile.Execute(Owner: TComponent; const FileNames: TStrings 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 @@ class function TInstallFile.Execute(Owner: TComponent; const FileNames: TStrings 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 @@ class function TInstallFile.Execute(Owner: TComponent; const FileNames: TStrings class function TInstallFile.BrowseAndInstallKeyboardFromFile(Owner: TComponent): Boolean; var dlgOpen: TOpenDialog; + BaseKeyboardID : Integer; begin dlgOpen := TOpenDialog.Create(nil); try @@ -216,9 +218,9 @@ class function TInstallFile.BrowseAndInstallKeyboardFromFile(Owner: TComponent): '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 6f13f6777bd..60ac8ae43c5 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 @@ TKeymanProtocolHandler = class sealed 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 @@ class function TKeymanProtocolHandler.CanHandle(const url: string): Boolean; 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 @@ class function TKeymanProtocolHandler.Handle(Owner: TComponent; 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 @@ function TKeymanProtocolHandler.DoHandle(Owner: TComponent; 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 6d79811a80a..775aa1ca2eb 100644 --- a/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas +++ b/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas @@ -74,6 +74,7 @@ interface Vcl.StdCtrls, keymanapi_TLB, + KeymanOptionNames, UfrmKeymanBase, UfrmWebContainer; @@ -102,7 +103,7 @@ TfrmInstallKeyboard = class(TfrmWebContainer) 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 @@ procedure TfrmInstallKeyboard.DeleteFileReferences; 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 @@ procedure TfrmInstallKeyboard.FireCommand(const command: WideString; params: TSt 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 @@ procedure TfrmInstallKeyboard.FireCommand(const command: WideString; params: TSt var t: TTempFile; ExecParams: string; + BaseKeyboardString :string; begin KL.MethodEnter(Self, '"keyboard_install"', [params.Text]); try @@ -306,8 +310,9 @@ procedure TfrmInstallKeyboard.FireCommand(const command: WideString; params: TSt 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 @@ procedure TfrmInstallKeyboard.CheckLogFileForWarnings(const Filename: string; Si ------------------------------------------------------------------------------} // 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 @@ procedure TfrmInstallKeyboard.InstallKeyboard(const ALogFile, BCP47Tag: string); 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 @@ procedure TfrmInstallKeyboard.InstallKeyboard(const ALogFile, BCP47Tag: string); 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 aff32510372..ed236d489d6 100644 --- a/windows/src/desktop/kmshell/install/UfrmInstallKeyboardFromWeb.pas +++ b/windows/src/desktop/kmshell/install/UfrmInstallKeyboardFromWeb.pas @@ -87,6 +87,7 @@ implementation Keyman.Configuration.UI.InstallFile, Keyman.System.LocaleStrings, kmint, + KeymanOptionNames, MessageIdentifierConsts, Upload_Settings, utilfiletypes, @@ -213,6 +214,7 @@ procedure TfrmInstallKeyboardFromWeb.cefBeforeBrowseEx(Sender: TObject; const Ur procedure TfrmInstallKeyboardFromWeb.DownloadAndInstallPackage(const PackageID, BCP47: string); var FTempDir: string; + BaseKeyboardID: Integer; begin FTempDir := IncludeTrailingPathDelimiter(CreateTempPath); // I1679 try @@ -230,8 +232,8 @@ procedure TfrmInstallKeyboardFromWeb.DownloadAndInstallPackage(const PackageID, 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 f9b5f9ac9b8..0f0cc6f3671 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -206,7 +206,7 @@ function Show_frmHTML(AParent: TComponent; const ACaption, AText, AFileName: str 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 @@ function Init(var FMode: TKMShellMode; KeyboardFileNames: TStrings; var FSilent, 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 @@ procedure RegisterControlClasses; 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 @@ procedure Run; FForce: Boolean; FParentWindow: THandle; FLogFile: string; - FDefaultLangID: Integer; + FDefaultLangID, FBaseKeyboard: Integer; FDefaultBCP47, FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; begin @@ -349,7 +350,7 @@ procedure Run; 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 @@ procedure Run; 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 @@ function DoCheckTIPInstallStatus(FSilent: Boolean): Boolean; 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 @@ procedure RunKMCOM(FMode: TKMShellMode; KeyboardFileNames: TStrings; FSilent, FF 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 5ea1e74265c..b7255869b7b 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas @@ -37,7 +37,7 @@ interface 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 @@ TKeymanKeyboardFile = class(TKeymanKeyboard, IKeymanKeyboardFile, IKeymanKeybo { 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 @@ function TKeymanKeyboardFile.Install2(Force: WordBool): IKeymanKeyboardInstalled 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 f5f8b744483..b37e0dfce0e 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardsinstalled.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardsinstalled.pas @@ -37,7 +37,8 @@ interface 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 @@ TKeymanKeyboardsInstalled = class(TKeymanAutoCollectionObject, IKeymanKeyboard 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 14b207e2299..28ef2d064a4 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 @@ interface 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 @@ TKeymanPackageFile = class(TKeymanAutoObject, IKeymanPackage, IKeymanPackageFi { 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 @@ procedure TKeymanPackageFile.Install(Force: WordBool); o := [ipLegacyRegisterAndInstallProfiles]; if Force then Include(o, ipForce); - Execute(FFileName, o); + Execute(FFileName, o, 0); finally Free; end; @@ -191,7 +192,27 @@ function TKeymanPackageFile.Install2(Force: WordBool): IKeymanPackageInstalled; 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 @@ procedure TKeymanPackageFile.LoadPackage; 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 9dd9f1a52ad..821a38bdc5f 100644 --- a/windows/src/engine/kmcomapi/com/packages/keymanpackagesinstalled.pas +++ b/windows/src/engine/kmcomapi/com/packages/keymanpackagesinstalled.pas @@ -38,7 +38,8 @@ TPackageList = class(TAutoObjectList) 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 @@ TKeymanPackagesInstalled = class(TKeymanAutoCollectionObject, IKeymanPackagesI 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 @@ procedure TKeymanPackagesInstalled.Install(const Filename: WideString; Force: Wo o := [ipLegacyRegisterAndInstallProfiles]; if Force then Include(o, ipForce); - Execute(Filename, o); + Execute(Filename, o, 0); finally Free; end; @@ -136,7 +138,29 @@ function TKeymanPackagesInstalled.Install2(const Filename: WideString; 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 786ce6c9b2d..7246c9173f7 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -1569,6 +1569,17 @@ interface 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 @@ interface 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 @@ interface 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 @@ interface 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 9eb63fbd68d..91f49822b52 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 1df237b0c60..6d3bd1f3ed8 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas @@ -64,7 +64,7 @@ interface 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 @@ implementation 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 @@ procedure TKPInstallKeyboard.Execute(const FileName, PackageID: string; FInstall 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 @@ procedure TKPInstallKeyboard.Execute(const FileName, PackageID: string; FInstall 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 98edfbf3fb1..4ab33cdfeec 100644 --- a/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas +++ b/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas @@ -50,7 +50,7 @@ interface 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 @@ implementation { 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 @@ procedure TKPInstallPackage.Execute(const FileName: string; Options: TKPInstallP FErrorValue: Cardinal; FSrcFileName: string; - procedure InstallKeyboard(FileName: string); + procedure InstallKeyboard(FileName: string; BaseKeyboardID: Integer); var FOptions: TKPInstallKeyboardOptions; kbd: TPackageKeyboard; @@ -132,7 +132,7 @@ procedure TKPInstallPackage.Execute(const FileName: string; Options: TKPInstallP 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 @@ procedure TKPInstallPackage.Execute(const FileName: string; Options: TKPInstallP 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 | 249 ++++++++++++++---- windows/src/engine/kmcomapi/kmcomapi.ridl | 98 ++++--- 3 files changed, 246 insertions(+), 103 deletions(-) diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas index 0f0cc6f3671..b1afe4e10f7 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -263,7 +263,7 @@ function Init(var FMode: TKMShellMode; KeyboardFileNames: TStrings; var FSilent, 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 7246c9173f7..3c436dc5d98 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -12,7 +12,7 @@ // ************************************************************************ // // $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 @@ interface 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 @@ interface IKeymanKeyboardLanguagesFileDisp = dispinterface; IKeymanKeyboardsInstalled2 = interface; IKeymanKeyboardsInstalled2Disp = dispinterface; + IKeymanKeyboardInstalled2 = interface; + IKeymanKeyboardInstalled2Disp = dispinterface; IKeymanPackagesInstalled2 = interface; IKeymanPackagesInstalled2Disp = dispinterface; IKeymanKeyboardFile2 = interface; @@ -258,6 +265,14 @@ interface 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; @@ -1570,14 +1585,24 @@ interface end; // *********************************************************************// -// Interface: IKeymanKeyboardsInstalled3 +// DispIntf: IKeymanKeyboardsInstalled2Disp // Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641} +// GUID: {EA57C94F-C140-485E-941A-3F1D5A229024} // *********************************************************************// - IKeymanKeyboardsInstalled3 = interface(IKeymanKeyboardsInstalled) - ['{B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641}'] - function Install3(const Filename: WideString; Force: WordBool; BasePackageID: Integer): IKeymanKeyboardInstalled; safecall; - procedure RefreshInstalledKeyboards; safecall; + IKeymanKeyboardsInstalled2Disp = dispinterface + ['{EA57C94F-C140-485E-941A-3F1D5A229024}'] + function Install2(const Filename: WideString; Force: WordBool): IKeymanKeyboardInstalled; dispid 19; + procedure RefreshInstalledKeyboards; dispid 601; + 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; // *********************************************************************// @@ -1591,22 +1616,36 @@ interface end; // *********************************************************************// -// DispIntf: IKeymanKeyboardsInstalled2Disp +// DispIntf: IKeymanKeyboardInstalled2Disp // Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {EA57C94F-C140-485E-941A-3F1D5A229024} +// GUID: {3086C85C-932A-4726-BF76-2D74DD133AC9} // *********************************************************************// - IKeymanKeyboardsInstalled2Disp = dispinterface - ['{EA57C94F-C140-485E-941A-3F1D5A229024}'] - function Install2(const Filename: WideString; Force: WordBool): IKeymanKeyboardInstalled; dispid 19; - procedure RefreshInstalledKeyboards; dispid 601; - 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; + 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; @@ -1621,16 +1660,6 @@ interface 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 @@ interface 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 @@ interface 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 @@ interface 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 91f49822b52..ecfff3d7074 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,6 +980,51 @@ library keymanapi HRESULT _stdcall Install2([in] VARIANT_BOOL Force, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); }; + [ + uuid(9B43B6BC-C622-47EF-915E-6780CF53BAAA), + version(14.0), + helpstring("https://help.keyman.com/developer/engine/desktop/14.0/api/IKeymanPackageFile2"), + dual, + oleautomation + ] + interface IKeymanPackageFile2: IKeymanPackageFile + { + [id(0x00000101)] + HRESULT _stdcall Install2([in] VARIANT_BOOL Force, [out, retval] IKeymanPackageInstalled** PackageResult); + }; + + [ + uuid(414C26E6-BFAC-4A70-9EA1-E525BA9BBA7E), + version(14.0), + dual, + oleautomation + ] + interface IKeymanKeyboardLanguageInstalled2: IKeymanKeyboardLanguageInstalled + { + [id(0x00000194)] + HRESULT _stdcall FindInstallationLangID([out] long* LangID, [out] BSTR* TemporaryKeyboardID, [out] VARIANT_BOOL* RegistrationRequired, [in] enum tagKeymanInstallFlags Flags, [out, retval] VARIANT_BOOL* Result); + [id(0x00000195)] + HRESULT _stdcall RegisterTip([in] long LangID); + [id(0x00000196)] + HRESULT _stdcall InstallTip([in] long LangID, [in] BSTR TemporaryKeyboardToRemove); + [propget, id(0x000001F5)] + HRESULT _stdcall IsRegistered([out, retval] VARIANT_BOOL* Value); + [propget, id(0x000001F6)] + HRESULT _stdcall WindowsBCP47Code([out, retval] BSTR* Value); + }; + + [ + uuid(628FF2E6-B490-462E-8FC7-7AE53B9D392C), + version(14.0), + dual, + oleautomation + ] + interface IKeymanKeyboardLanguagesInstalled2: IKeymanKeyboardLanguagesInstalled + { + [id(0x00000259)] + HRESULT _stdcall Add([in] BSTR BCP47Tag, [out, retval] IKeymanKeyboardLanguageInstalled** Result); + }; + [ uuid(8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4), version(19.0), @@ -1000,18 +1045,16 @@ library keymanapi 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"), + helpstring("https://help.keyman.com/developer/engine/windows/19.0/api/IKeymanKeyboardInstalled2\x03"), dual, oleautomation ] @@ -1034,51 +1077,6 @@ library keymanapi 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), - helpstring("https://help.keyman.com/developer/engine/desktop/14.0/api/IKeymanPackageFile2"), - dual, - oleautomation - ] - interface IKeymanPackageFile2: IKeymanPackageFile - { - [id(0x00000101)] - HRESULT _stdcall Install2([in] VARIANT_BOOL Force, [out, retval] IKeymanPackageInstalled** PackageResult); - }; - - [ - uuid(414C26E6-BFAC-4A70-9EA1-E525BA9BBA7E), - version(14.0), - dual, - oleautomation - ] - interface IKeymanKeyboardLanguageInstalled2: IKeymanKeyboardLanguageInstalled - { - [id(0x00000194)] - HRESULT _stdcall FindInstallationLangID([out] long* LangID, [out] BSTR* TemporaryKeyboardID, [out] VARIANT_BOOL* RegistrationRequired, [in] enum tagKeymanInstallFlags Flags, [out, retval] VARIANT_BOOL* Result); - [id(0x00000195)] - HRESULT _stdcall RegisterTip([in] long LangID); - [id(0x00000196)] - HRESULT _stdcall InstallTip([in] long LangID, [in] BSTR TemporaryKeyboardToRemove); - [propget, id(0x000001F5)] - HRESULT _stdcall IsRegistered([out, retval] VARIANT_BOOL* Value); - [propget, id(0x000001F6)] - HRESULT _stdcall WindowsBCP47Code([out, retval] BSTR* Value); - }; - - [ - uuid(628FF2E6-B490-462E-8FC7-7AE53B9D392C), - version(14.0), - dual, - oleautomation - ] - interface IKeymanKeyboardLanguagesInstalled2: IKeymanKeyboardLanguagesInstalled - { - [id(0x00000259)] - HRESULT _stdcall Add([in] BSTR BCP47Tag, [out, retval] IKeymanKeyboardLanguageInstalled** Result); - }; - [ 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 b1afe4e10f7..f4d2a4161d5 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -263,7 +263,7 @@ function Init(var FMode: TKMShellMode; KeyboardFileNames: TStrings; var FSilent, 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 3c436dc5d98..b0530cb94a0 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -1873,7 +1873,7 @@ interface // *********************************************************************// 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 @@ interface // *********************************************************************// 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 ecfff3d7074..0b2366c144f 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 6d3bd1f3ed8..1d198264cb9 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas @@ -262,7 +262,7 @@ procedure TKPInstallKeyboard.Execute(const FileName: string; const PackageID: st 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 e9ce67d5e34..1f136871e67 100644 --- a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas @@ -21,7 +21,7 @@ TfrmBaseKeyboard = class(TfrmWebContainer) 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 @@ function MCompileBaseKeyboard(const BaseKeyboardIDText: string): Boolean; 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 @@ function BaseKeyboardNeedsMCompile(BaseKeyboardID: Integer): Boolean; 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 e2d28b88d2b..e4ce8316d31 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 371ce4cd495..ca611b40e44 100644 --- a/windows/src/desktop/kmshell/kmshell.dproj +++ b/windows/src/desktop/kmshell/kmshell.dproj @@ -358,6 +358,7 @@
frmStartInstall
+ Cfg_2 @@ -419,21 +420,21 @@ False - + - .\ + kmshell.exe true - + - kmshell.rsm + .\ true - + - kmshell.exe + kmshell.rsm true diff --git a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas index 1f136871e67..56e7c442b4f 100644 --- a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas @@ -19,9 +19,6 @@ TfrmBaseKeyboard = class(TfrmWebContainer) 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 @@ procedure TfrmBaseKeyboard.Footer_OK(params: TStringList); 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 100fd24fd2f..599566b91cb 100644 --- a/windows/src/desktop/kmshell/main/UfrmMain.pas +++ b/windows/src/desktop/kmshell/main/UfrmMain.pas @@ -174,6 +174,7 @@ implementation 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 f4d2a4161d5..2d6cc1e6d2f 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -115,6 +115,7 @@ implementation 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 00000000000..44488179c9d --- /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 2d6cc1e6d2f..6457542bcac 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -264,7 +264,7 @@ function Init(var FMode: TKMShellMode; KeyboardFileNames: TStrings; var FSilent, 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 b0530cb94a0..3c436dc5d98 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -1873,7 +1873,7 @@ interface // *********************************************************************// 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 @@ interface // *********************************************************************// 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 0b2366c144f..ecfff3d7074 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 | 249 ++++-------------- windows/src/engine/kmcomapi/kmcomapi.ridl | 98 +++---- 3 files changed, 103 insertions(+), 246 deletions(-) diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas index 6457542bcac..3143d728288 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -264,7 +264,7 @@ function Init(var FMode: TKMShellMode; KeyboardFileNames: TStrings; var FSilent, 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 3c436dc5d98..7246c9173f7 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -12,7 +12,7 @@ // ************************************************************************ // // $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 @@ interface 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 @@ interface IKeymanKeyboardLanguagesFileDisp = dispinterface; IKeymanKeyboardsInstalled2 = interface; IKeymanKeyboardsInstalled2Disp = dispinterface; - IKeymanKeyboardInstalled2 = interface; - IKeymanKeyboardInstalled2Disp = dispinterface; IKeymanPackagesInstalled2 = interface; IKeymanPackagesInstalled2Disp = dispinterface; IKeymanKeyboardFile2 = interface; @@ -265,14 +258,6 @@ interface 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; @@ -1585,24 +1570,14 @@ interface end; // *********************************************************************// -// DispIntf: IKeymanKeyboardsInstalled2Disp +// Interface: IKeymanKeyboardsInstalled3 // Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {EA57C94F-C140-485E-941A-3F1D5A229024} +// GUID: {B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641} // *********************************************************************// - IKeymanKeyboardsInstalled2Disp = dispinterface - ['{EA57C94F-C140-485E-941A-3F1D5A229024}'] - function Install2(const Filename: WideString; Force: WordBool): IKeymanKeyboardInstalled; dispid 19; - procedure RefreshInstalledKeyboards; dispid 601; - 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; + IKeymanKeyboardsInstalled3 = interface(IKeymanKeyboardsInstalled) + ['{B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641}'] + function Install3(const Filename: WideString; Force: WordBool; BasePackageID: Integer): IKeymanKeyboardInstalled; safecall; + procedure RefreshInstalledKeyboards; safecall; end; // *********************************************************************// @@ -1616,36 +1591,22 @@ interface end; // *********************************************************************// -// DispIntf: IKeymanKeyboardInstalled2Disp +// DispIntf: IKeymanKeyboardsInstalled2Disp // Flags: (4416) Dual OleAutomation Dispatchable -// GUID: {3086C85C-932A-4726-BF76-2D74DD133AC9} +// GUID: {EA57C94F-C140-485E-941A-3F1D5A229024} // *********************************************************************// - 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; + IKeymanKeyboardsInstalled2Disp = dispinterface + ['{EA57C94F-C140-485E-941A-3F1D5A229024}'] + function Install2(const Filename: WideString; Force: WordBool): IKeymanKeyboardInstalled; dispid 19; + procedure RefreshInstalledKeyboards; dispid 601; + 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; @@ -1660,6 +1621,16 @@ interface 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 @@ interface 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 @@ interface 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 @@ interface 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 ecfff3d7074..91f49822b52 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,51 +980,6 @@ library keymanapi HRESULT _stdcall Install2([in] VARIANT_BOOL Force, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); }; - [ - uuid(9B43B6BC-C622-47EF-915E-6780CF53BAAA), - version(14.0), - helpstring("https://help.keyman.com/developer/engine/desktop/14.0/api/IKeymanPackageFile2"), - dual, - oleautomation - ] - interface IKeymanPackageFile2: IKeymanPackageFile - { - [id(0x00000101)] - HRESULT _stdcall Install2([in] VARIANT_BOOL Force, [out, retval] IKeymanPackageInstalled** PackageResult); - }; - - [ - uuid(414C26E6-BFAC-4A70-9EA1-E525BA9BBA7E), - version(14.0), - dual, - oleautomation - ] - interface IKeymanKeyboardLanguageInstalled2: IKeymanKeyboardLanguageInstalled - { - [id(0x00000194)] - HRESULT _stdcall FindInstallationLangID([out] long* LangID, [out] BSTR* TemporaryKeyboardID, [out] VARIANT_BOOL* RegistrationRequired, [in] enum tagKeymanInstallFlags Flags, [out, retval] VARIANT_BOOL* Result); - [id(0x00000195)] - HRESULT _stdcall RegisterTip([in] long LangID); - [id(0x00000196)] - HRESULT _stdcall InstallTip([in] long LangID, [in] BSTR TemporaryKeyboardToRemove); - [propget, id(0x000001F5)] - HRESULT _stdcall IsRegistered([out, retval] VARIANT_BOOL* Value); - [propget, id(0x000001F6)] - HRESULT _stdcall WindowsBCP47Code([out, retval] BSTR* Value); - }; - - [ - uuid(628FF2E6-B490-462E-8FC7-7AE53B9D392C), - version(14.0), - dual, - oleautomation - ] - interface IKeymanKeyboardLanguagesInstalled2: IKeymanKeyboardLanguagesInstalled - { - [id(0x00000259)] - HRESULT _stdcall Add([in] BSTR BCP47Tag, [out, retval] IKeymanKeyboardLanguageInstalled** Result); - }; - [ uuid(8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4), version(19.0), @@ -1045,16 +1000,18 @@ library keymanapi 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"), + helpstring("https://help.keyman.com/developer/engine/windows/19.0/api/IKeymanKeyboardInstalled2\3"), dual, oleautomation ] @@ -1077,6 +1034,51 @@ library keymanapi 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), + helpstring("https://help.keyman.com/developer/engine/desktop/14.0/api/IKeymanPackageFile2"), + dual, + oleautomation + ] + interface IKeymanPackageFile2: IKeymanPackageFile + { + [id(0x00000101)] + HRESULT _stdcall Install2([in] VARIANT_BOOL Force, [out, retval] IKeymanPackageInstalled** PackageResult); + }; + + [ + uuid(414C26E6-BFAC-4A70-9EA1-E525BA9BBA7E), + version(14.0), + dual, + oleautomation + ] + interface IKeymanKeyboardLanguageInstalled2: IKeymanKeyboardLanguageInstalled + { + [id(0x00000194)] + HRESULT _stdcall FindInstallationLangID([out] long* LangID, [out] BSTR* TemporaryKeyboardID, [out] VARIANT_BOOL* RegistrationRequired, [in] enum tagKeymanInstallFlags Flags, [out, retval] VARIANT_BOOL* Result); + [id(0x00000195)] + HRESULT _stdcall RegisterTip([in] long LangID); + [id(0x00000196)] + HRESULT _stdcall InstallTip([in] long LangID, [in] BSTR TemporaryKeyboardToRemove); + [propget, id(0x000001F5)] + HRESULT _stdcall IsRegistered([out, retval] VARIANT_BOOL* Value); + [propget, id(0x000001F6)] + HRESULT _stdcall WindowsBCP47Code([out, retval] BSTR* Value); + }; + + [ + uuid(628FF2E6-B490-462E-8FC7-7AE53B9D392C), + version(14.0), + dual, + oleautomation + ] + interface IKeymanKeyboardLanguagesInstalled2: IKeymanKeyboardLanguagesInstalled + { + [id(0x00000259)] + HRESULT _stdcall Add([in] BSTR BCP47Tag, [out, retval] IKeymanKeyboardLanguageInstalled** Result); + }; + [ 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 3cc8dcc9016..c6ee3564ae7 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 @@ TInstallFile = class sealed 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 @@ implementation 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 @@ class function TInstallFile.Execute(Owner: TComponent; const FileName: string; A begin if ASilent then begin - InstallKeyboard(LogFile, BCP47, BaseKeyboardID); + InstallKeyboard(LogFile, BCP47); Result := True; end else @@ -140,7 +139,7 @@ class function TInstallFile.Execute(Owner: TComponent; const FileName: string; A /// 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 @@ class function TInstallFile.Execute(Owner: TComponent; const FileNames: TStrings 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 @@ class function TInstallFile.Execute(Owner: TComponent; const FileNames: TStrings 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 @@ class function TInstallFile.Execute(Owner: TComponent; const FileNames: TStrings class function TInstallFile.BrowseAndInstallKeyboardFromFile(Owner: TComponent): Boolean; var dlgOpen: TOpenDialog; - BaseKeyboardID : Integer; begin dlgOpen := TOpenDialog.Create(nil); try @@ -218,9 +216,9 @@ class function TInstallFile.BrowseAndInstallKeyboardFromFile(Owner: TComponent): '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 60ac8ae43c5..6f13f6777bd 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 @@ TKeymanProtocolHandler = class sealed 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 @@ class function TKeymanProtocolHandler.CanHandle(const url: string): Boolean; 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 @@ class function TKeymanProtocolHandler.Handle(Owner: TComponent; 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 @@ function TKeymanProtocolHandler.DoHandle(Owner: TComponent; 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 775aa1ca2eb..6d79811a80a 100644 --- a/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas +++ b/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas @@ -74,7 +74,6 @@ interface Vcl.StdCtrls, keymanapi_TLB, - KeymanOptionNames, UfrmKeymanBase, UfrmWebContainer; @@ -103,7 +102,7 @@ TfrmInstallKeyboard = class(TfrmWebContainer) 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 @@ procedure TfrmInstallKeyboard.DeleteFileReferences; 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 @@ procedure TfrmInstallKeyboard.FireCommand(const command: WideString; params: TSt 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 @@ procedure TfrmInstallKeyboard.FireCommand(const command: WideString; params: TSt var t: TTempFile; ExecParams: string; - BaseKeyboardString :string; begin KL.MethodEnter(Self, '"keyboard_install"', [params.Text]); try @@ -310,9 +306,8 @@ procedure TfrmInstallKeyboard.FireCommand(const command: WideString; params: TSt 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 @@ procedure TfrmInstallKeyboard.CheckLogFileForWarnings(const Filename: string; Si ------------------------------------------------------------------------------} // 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 @@ procedure TfrmInstallKeyboard.InstallKeyboard(const ALogFile, BCP47Tag: string; 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 @@ procedure TfrmInstallKeyboard.InstallKeyboard(const ALogFile, BCP47Tag: string; 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 ed236d489d6..aff32510372 100644 --- a/windows/src/desktop/kmshell/install/UfrmInstallKeyboardFromWeb.pas +++ b/windows/src/desktop/kmshell/install/UfrmInstallKeyboardFromWeb.pas @@ -87,7 +87,6 @@ implementation Keyman.Configuration.UI.InstallFile, Keyman.System.LocaleStrings, kmint, - KeymanOptionNames, MessageIdentifierConsts, Upload_Settings, utilfiletypes, @@ -214,7 +213,6 @@ procedure TfrmInstallKeyboardFromWeb.cefBeforeBrowseEx(Sender: TObject; const Ur procedure TfrmInstallKeyboardFromWeb.DownloadAndInstallPackage(const PackageID, BCP47: string); var FTempDir: string; - BaseKeyboardID: Integer; begin FTempDir := IncludeTrailingPathDelimiter(CreateTempPath); // I1679 try @@ -232,8 +230,8 @@ procedure TfrmInstallKeyboardFromWeb.DownloadAndInstallPackage(const PackageID, 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 3143d728288..64fc2cd2142 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -207,7 +207,7 @@ function Show_frmHTML(AParent: TComponent; const ACaption, AText, AFileName: str 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 @@ function Init(var FMode: TKMShellMode; KeyboardFileNames: TStrings; var FSilent, 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 @@ procedure RegisterControlClasses; 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 @@ procedure Run; FForce: Boolean; FParentWindow: THandle; FLogFile: string; - FDefaultLangID, FBaseKeyboard: Integer; + FDefaultLangID: Integer; FDefaultBCP47, FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; begin @@ -351,7 +350,7 @@ procedure Run; 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 @@ procedure Run; 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 @@ function DoCheckTIPInstallStatus(FSilent: Boolean): Boolean; 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 @@ procedure RunKMCOM(FMode: TKMShellMode; KeyboardFileNames: TStrings; FSilent, FF 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 b7255869b7b..5ea1e74265c 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas @@ -37,7 +37,7 @@ interface 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 @@ TKeymanKeyboardFile = class(TKeymanKeyboard, IKeymanKeyboardFile, IKeymanKeybo { 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 @@ function TKeymanKeyboardFile.Install2(Force: WordBool): IKeymanKeyboardInstalled 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 b37e0dfce0e..f5f8b744483 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardsinstalled.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardsinstalled.pas @@ -37,8 +37,7 @@ interface 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 @@ TKeymanKeyboardsInstalled = class(TKeymanAutoCollectionObject, IKeymanKeyboard 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 28ef2d064a4..14b207e2299 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 @@ interface 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 @@ TKeymanPackageFile = class(TKeymanAutoObject, IKeymanPackage, IKeymanPackageFi { 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 @@ procedure TKeymanPackageFile.Install(Force: WordBool); o := [ipLegacyRegisterAndInstallProfiles]; if Force then Include(o, ipForce); - Execute(FFileName, o, 0); + Execute(FFileName, o); finally Free; end; @@ -192,27 +191,7 @@ function TKeymanPackageFile.Install2(Force: WordBool): IKeymanPackageInstalled; 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 @@ procedure TKeymanPackageFile.LoadPackage; 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 821a38bdc5f..9dd9f1a52ad 100644 --- a/windows/src/engine/kmcomapi/com/packages/keymanpackagesinstalled.pas +++ b/windows/src/engine/kmcomapi/com/packages/keymanpackagesinstalled.pas @@ -38,8 +38,7 @@ TPackageList = class(TAutoObjectList) 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 @@ TKeymanPackagesInstalled = class(TKeymanAutoCollectionObject, 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 @@ procedure TKeymanPackagesInstalled.Install(const Filename: WideString; Force: Wo o := [ipLegacyRegisterAndInstallProfiles]; if Force then Include(o, ipForce); - Execute(Filename, o, 0); + Execute(Filename, o); finally Free; end; @@ -138,29 +136,7 @@ function TKeymanPackagesInstalled.Install2(const Filename: WideString; 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 7246c9173f7..786ce6c9b2d 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -1569,17 +1569,6 @@ interface 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 @@ interface 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 @@ interface 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 @@ interface 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 91f49822b52..9eb63fbd68d 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 1d198264cb9..1205d77f720 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas @@ -64,7 +64,7 @@ interface 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 @@ implementation 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 @@ procedure TKPInstallKeyboard.Execute(const FileName: string; const PackageID: st 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 @@ procedure TKPInstallKeyboard.Execute(const FileName: string; const PackageID: st 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 4ab33cdfeec..98edfbf3fb1 100644 --- a/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas +++ b/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas @@ -50,7 +50,7 @@ interface 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 @@ implementation { 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 @@ procedure TKPInstallPackage.Execute(const FileName: string; Options: TKPInstallP FErrorValue: Cardinal; FSrcFileName: string; - procedure InstallKeyboard(FileName: string; BaseKeyboardID: Integer); + procedure InstallKeyboard(FileName: string); var FOptions: TKPInstallKeyboardOptions; kbd: TPackageKeyboard; @@ -132,7 +132,7 @@ procedure TKPInstallPackage.Execute(const FileName: string; Options: TKPInstallP 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 @@ procedure TKPInstallPackage.Execute(const FileName: string; Options: TKPInstallP 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 56e7c442b4f..91a6710112b 100644 --- a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas @@ -33,7 +33,8 @@ implementation 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 e4ce8316d31..124b0357ce2 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 ca611b40e44..abcb5215972 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 44488179c9d..c47d90a1a57 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 @@ interface 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 @@ function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolea WaitForElevatedConfiguration(WindowHandle, '-mcompilekbds ' + IntToHex(BaseKeyboardID, 8)); end else - CompileForBaseKeyboard(BaseKeyboardID); + MCompileBaseKeyboard(BaseKeyboardID); end; kmcom.Options['koBaseLayout'].Value := BaseKeyboardID; @@ -55,29 +54,21 @@ function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolea 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 599566b91cb..9c4478283e9 100644 --- a/windows/src/desktop/kmshell/main/UfrmMain.pas +++ b/windows/src/desktop/kmshell/main/UfrmMain.pas @@ -174,7 +174,7 @@ implementation 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 64fc2cd2142..54f4a73f65d 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -115,7 +115,7 @@ implementation 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 @@ function Show_frmHTML(AParent: TComponent; const ACaption, AText, AFileName: str 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 @@ function Init(var FMode: TKMShellMode; KeyboardFileNames: TStrings; var FSilent, 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 @@ procedure RegisterControlClasses; 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 @@ procedure Run; FForce: Boolean; FParentWindow: THandle; FLogFile: string; - FDefaultLangID: Integer; + FDefaultLangID, FBaseKeyboard: Integer; FDefaultBCP47, FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; begin @@ -350,7 +350,7 @@ procedure Run; 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 @@ procedure Run; 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 @@ function DoCheckTIPInstallStatus(FSilent: Boolean): Boolean; 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 @@ procedure RunKMCOM(FMode: TKMShellMode; KeyboardFileNames: TStrings; FSilent, FF 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 c47d90a1a57..d91b439f336 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 @@ interface 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 @@ function BaseKeyboardNeedsMCompile(BaseKeyboardID: Integer): Boolean; 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 91a6710112b..dd298a86421 100644 --- a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas @@ -18,6 +18,14 @@ TfrmBaseKeyboard = class(TfrmWebContainer) 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 786ce6c9b2d..550a13064d9 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -12,7 +12,7 @@ // ************************************************************************ // // $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 @@ interface 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 @@ interface IKeymanKeyboardLanguagesFileDisp = dispinterface; IKeymanKeyboardsInstalled2 = interface; IKeymanKeyboardsInstalled2Disp = dispinterface; + IKeymanKeyboardInstalled2 = interface; + IKeymanKeyboardInstalled2Disp = dispinterface; IKeymanPackagesInstalled2 = interface; IKeymanPackagesInstalled2Disp = dispinterface; IKeymanKeyboardFile2 = interface; @@ -1569,16 +1572,6 @@ interface 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 @@ interface 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 9eb63fbd68d..4d65b37777a 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 1205d77f720..1df237b0c60 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas @@ -255,7 +255,7 @@ procedure TKPInstallKeyboard.Execute(const FileName, PackageID: string; FInstall 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 01b03ae3fc8..7077bc12913 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas @@ -110,7 +110,6 @@ TKeymanKeyboardInstalled = class( // I3581 { IIntKeymanKeyboardInstalled } function RegKeyboard: TRegKeyboard; procedure ClearVisualKeyboard; - procedure UpdateBaseLayout; // I4169 procedure RefreshInstallation; { IKeymanKeyboardInstalled2 } @@ -155,22 +154,6 @@ procedure TKeymanKeyboardInstalled.Uninstall; 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 1759468e006..edfc65bf286 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 @@ interface 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 @@ interface ['{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 d91b439f336..926e766daaf 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 @@ interface 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 dd298a86421..1d06e7ca25d 100644 --- a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas @@ -20,12 +20,12 @@ TfrmBaseKeyboard = class(TfrmWebContainer) (** - 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 926e766daaf..dedea86dae5 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 1d06e7ca25d..825088ad0a7 100644 --- a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas @@ -18,15 +18,14 @@ TfrmBaseKeyboard = class(TfrmWebContainer) 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 @@ implementation 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 9c4478283e9..472353102cf 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 54f4a73f65d..f2392d69130 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -402,7 +402,6 @@ procedure RunKMCOM(FMode: TKMShellMode; KeyboardFileNames: TStrings; FSilent, FF kdl: IKeymanDefaultLanguage; FIcon: string; FMutex: TKeymanMutex; // I2720 - BaseKeyboardID: Integer; function FirstKeyboardFileName: WideString; begin if KeyboardFileNames.Count = 0 @@ -550,7 +549,7 @@ procedure RunKMCOM(FMode: TKMShellMode; KeyboardFileNames: TStrings; FSilent, FF 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 | 46 +++++++++++++++---- .../kmshell/install/UpgradeMnemonicLayout.pas | 19 ++++---- ...yman.Configuration.System.BaseKeyboard.pas | 13 +++--- .../keyboard/kprecompilemnemonickeyboard.pas | 5 +- 4 files changed, 57 insertions(+), 26 deletions(-) diff --git a/common/windows/delphi/general/utilstr.pas b/common/windows/delphi/general/utilstr.pas index 01e085b8a8c..b5bcd32e659 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 @@ function CommaToken(var s: WideString): WideString; Result := ''; Exit; end; - + if s[1] = '"' then begin Delete(s,1,1); @@ -418,4 +436,14 @@ function StringToRect(s: string): TRect; 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 acad7655909..2639ac20728 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 @@ implementation kmint, RegistryKeys, utilexecute, - utilkmshell; + utilkmshell, + utilstr; const { CurrentMnemonicLayoutVersion = 476; // First 9.0 build with fixes for mnemonic layouts } @@ -171,7 +172,7 @@ class procedure TUpgradeMnemonicLayout.UpgradeLayoutLanguage( 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 dedea86dae5..4c398f1fe8d 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 3d806afda2e..b05ab325d15 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas @@ -47,6 +47,7 @@ implementation RegistryKeys, utilexecute, utilkeyman, + utilstr, utilsystem; function GetKeyboardLayoutFileName(id: Integer): string; @@ -83,8 +84,8 @@ procedure TKPRecompileMnemonicKeyboard.Execute(const FileName,PackageName: strin 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 b5bcd32e659..59a897ad2e1 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 @@ function StringToRect(s: string): TRect; 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 4c398f1fe8d..a1fecdd6085 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 59a897ad2e1..8319c37d04c 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 @@ function StringToRect(s: string): TRect; 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 f2392d69130..3010dae5ccc 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -266,6 +266,7 @@ function Init(var FMode: TKMShellMode; KeyboardFileNames: TStrings; var FSilent, 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 f34be0933d7..28faa8804c4 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 @@ class function TKeymanFileTypeInfo.IsPackageWelcomeFile( 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 8319c37d04c..4cd175e3601 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 @@ function StringToRect(s: string): TRect; 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 2639ac20728..62b75bf5660 100644 --- a/windows/src/desktop/kmshell/install/UpgradeMnemonicLayout.pas +++ b/windows/src/desktop/kmshell/install/UpgradeMnemonicLayout.pas @@ -47,7 +47,7 @@ implementation RegistryKeys, utilexecute, utilkmshell, - utilstr; + utilfiletypes; const { CurrentMnemonicLayoutVersion = 476; // First 9.0 build with fixes for mnemonic layouts } @@ -172,7 +172,7 @@ class procedure TUpgradeMnemonicLayout.UpgradeLayoutLanguage( 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 a1fecdd6085..c4fb428b496 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 @@ function BaseKeyboardNeedsMCompile(BaseKeyboardID: Integer): Boolean; 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 b05ab325d15..52139f58397 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas @@ -47,7 +47,7 @@ implementation RegistryKeys, utilexecute, utilkeyman, - utilstr, + utilfiletypes, utilsystem; function GetKeyboardLayoutFileName(id: Integer): string; @@ -84,8 +84,8 @@ procedure TKPRecompileMnemonicKeyboard.Execute(const FileName,PackageName: strin 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 }