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] fix(windows): pass basekeyboardid to installation api The updates all the apis so that the basekeyboardid or klid can be passed in as an argument. This in needed so that elevated process required to compile the keyboard has the call users keyboard base id. --- .../Keyman.Configuration.UI.InstallFile.pas | 30 +++++----- ...Configuration.UI.KeymanProtocolHandler.pas | 12 ++-- .../kmshell/install/UfrmInstallKeyboard.pas | 17 ++++-- .../install/UfrmInstallKeyboardFromWeb.pas | 6 +- windows/src/desktop/kmshell/main/initprog.pas | 15 ++--- .../com/keyboards/keymankeyboardfile.pas | 23 +++++++- .../keyboards/keymankeyboardsinstalled.pas | 22 ++++++- .../com/packages/keymanpackagefile.pas | 43 ++++++++++---- .../com/packages/keymanpackagesinstalled.pas | 30 +++++++++- windows/src/engine/kmcomapi/keymanapi_TLB.pas | 42 ++++++++++++++ windows/src/engine/kmcomapi/kmcomapi.ridl | 58 +++++++++++++++++++ .../processes/keyboard/kpinstallkeyboard.pas | 23 +++++--- .../processes/package/kpinstallpackage.pas | 12 ++-- 13 files changed, 264 insertions(+), 69 deletions(-) diff --git a/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.InstallFile.pas b/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.InstallFile.pas index c6ee3564ae..3cc8dcc901 100644 --- a/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.InstallFile.pas +++ b/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.InstallFile.pas @@ -18,9 +18,9 @@ type FPackage: IKeymanPackageInstalled; const BCP47: string); static; public class function BrowseAndInstallKeyboardFromFile(Owner: TComponent): Boolean; static; - class function Execute(KeyboardFileNames: TStrings; const FirstKeyboardFileName: string; FSilent, FNoWelcome: Boolean; const LogFile: string): Boolean; overload; static; - class function Execute(Owner: TComponent; const FileName: string; ASilent, ANoWelcome: Boolean; const LogFile, BCP47: string): Boolean; overload; static; - class function Execute(Owner: TComponent; const FileNames: TStrings; ASilent: Boolean): Boolean; overload; static; + class function Execute(KeyboardFileNames: TStrings; const FirstKeyboardFileName: string; FSilent, FNoWelcome: Boolean; const LogFile: string; BaseKeyboardID: Integer): Boolean; overload; static; + class function Execute(Owner: TComponent; const FileName: string; ASilent, ANoWelcome: Boolean; const LogFile, BCP47: string; BaseKeyboardID: Integer): Boolean; overload; static; + class function Execute(Owner: TComponent; const FileNames: TStrings; ASilent: Boolean; BaseKeyboardID: Integer): Boolean; overload; static; end; implementation @@ -35,29 +35,30 @@ uses Keyman.Configuration.UI.KeymanProtocolHandler, Keyman.Configuration.UI.MitigationForWin10_1803, kmint, + KeymanOptionNames, UfrmHTML, UfrmInstallKeyboard; class function TInstallFile.Execute(KeyboardFileNames: TStrings; const FirstKeyboardFileName: string; FSilent, FNoWelcome: Boolean; - const LogFile: string): Boolean; + const LogFile: string; BaseKeyboardID: Integer): Boolean; begin if TKeymanProtocolHandler.CanHandle(FirstKeyboardFileName) then begin - Result := TKeymanProtocolHandler.Handle(nil, FirstKeyboardFileName, FSilent, FNoWelcome, LogFile); + Result := TKeymanProtocolHandler.Handle(nil, FirstKeyboardFileName, FSilent, FNoWelcome, LogFile, BaseKeyboardID); end else if (KeyboardFileNames.Count > 1) or (Pos('=', FirstKeyboardFileName) > 0) then begin - Result := TInstallFile.Execute(nil, KeyboardFileNames, FSilent) + Result := TInstallFile.Execute(nil, KeyboardFileNames, FSilent, BaseKeyboardID) end // TODO: support bare package ids from command line (if it does not include a file extension, assume it is a .kmp and try and download it) // else if IsNotPackageOrKeyboardFile then else begin - Result := TInstallFile.Execute(nil, FirstKeyboardFileName, FSilent, FNoWelcome, LogFile, ''); + Result := TInstallFile.Execute(nil, FirstKeyboardFileName, FSilent, FNoWelcome, LogFile, '', BaseKeyboardID); end; end; -class function TInstallFile.Execute(Owner: TComponent; const FileName: string; ASilent, ANoWelcome: Boolean; const LogFile, BCP47: string): Boolean; +class function TInstallFile.Execute(Owner: TComponent; const FileName: string; ASilent, ANoWelcome: Boolean; const LogFile, BCP47: string; BaseKeyboardID: Integer): Boolean; var n: Integer; InstalledKeyboards: array of IKeymanKeyboardInstalled; @@ -77,7 +78,7 @@ begin begin if ASilent then begin - InstallKeyboard(LogFile, BCP47); + InstallKeyboard(LogFile, BCP47, BaseKeyboardID); Result := True; end else @@ -139,7 +140,7 @@ end; /// This is the handler for the `-i` parameter, e.g. /// kmshell -i khmer_angkor.kmp c:\temp\sil_euro_latin.kmp=fr /// -class function TInstallFile.Execute(Owner: TComponent; const FileNames: TStrings; ASilent: Boolean): Boolean; +class function TInstallFile.Execute(Owner: TComponent; const FileNames: TStrings; ASilent: Boolean; BaseKeyboardID: Integer): Boolean; var i, j: Integer; FPackage: IKeymanPackageInstalled; @@ -170,7 +171,7 @@ begin end; if IsPackage then begin - FPackage := (kmcom.Packages as IKeymanPackagesInstalled2).Install2(FileName, True); + FPackage := (kmcom.Packages as IKeymanPackagesInstalled3).Install3(FileName, True, BaseKeyboardID); if Length(FilenameBCP47) > 1 then RegisterKeyboardPackageLanguage(FPackage, FilenameBCP47[1]) else RegisterKeyboardPackageLanguage(FPackage, ''); @@ -178,7 +179,7 @@ begin end else begin - FKeyboard := (kmcom.Keyboards as IKeymanKeyboardsInstalled2).Install2(FileName, True); + FKeyboard := (kmcom.Keyboards as IKeymanKeyboardsInstalled3).Install3(FileName, True, BaseKeyboardID); if (Length(FilenameBCP47) > 1) and (Trim(FilenameBCP47[1]) <> '') then BCP47Tag := FilenameBCP47[1] else BCP47Tag := TTIPMaintenance.GetFirstLanguage(FKeyboard); @@ -209,6 +210,7 @@ end; class function TInstallFile.BrowseAndInstallKeyboardFromFile(Owner: TComponent): Boolean; var dlgOpen: TOpenDialog; + BaseKeyboardID : Integer; begin dlgOpen := TOpenDialog.Create(nil); try @@ -216,9 +218,9 @@ begin 'Keyman files (*.kmx, *.kxx, *.kmp)|*.kmx;*.kxx;*.kmp|Keyman keyboards (*.kmx,*.kxx)' + '|*.kmx;*.kxx|Keyman packages (*.kmp)|*.kmp|All files (*.*)|*.*'; dlgOpen.Title := 'Install Keyman Keyboard'; - + BaseKeyboardID := kmcom.Options[KeymanOptionName(koBaseLayout)].Value; if dlgOpen.Execute then - Result := Execute(Owner, dlgOpen.FileName, False, False, '', '') + Result := Execute(Owner, dlgOpen.FileName, False, False, '', '', BaseKeyboardID) else Result := False; finally diff --git a/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.KeymanProtocolHandler.pas b/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.KeymanProtocolHandler.pas index 6f13f6777b..60ac8ae43c 100644 --- a/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.KeymanProtocolHandler.pas +++ b/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.KeymanProtocolHandler.pas @@ -17,13 +17,13 @@ type FDownloadURL: string; frmDownloadProgress: TfrmDownloadProgress; function DoHandle(Owner: TComponent; const url: string; ASilent, - ANoWelcome: Boolean; const ALogFile: string): Boolean; + ANoWelcome: Boolean; const ALogFile: string; BaseKeyboardID: Integer): Boolean; procedure DoDownload(AOwner: TfrmDownloadProgress; var Result: Boolean); procedure HttpReceiveData(const Sender: TObject; AContentLength, AReadCount: Int64; var Abort: Boolean); public class function CanHandle(const url: string): Boolean; static; - class function Handle(Owner: TComponent; const url: string; ASilent, ANoWelcome: Boolean; const ALogFile: string): Boolean; static; + class function Handle(Owner: TComponent; const url: string; ASilent, ANoWelcome: Boolean; const ALogFile: string; BaseKeyboardID: Integer): Boolean; static; end; implementation @@ -51,13 +51,13 @@ end; class function TKeymanProtocolHandler.Handle(Owner: TComponent; const url: string; ASilent, ANoWelcome: Boolean; - const ALogFile: string): Boolean; + const ALogFile: string; BaseKeyboardID: Integer): Boolean; var h: TKeymanProtocolHandler; begin h := TKeymanProtocolHandler.Create; try - Result := h.DoHandle(Owner, url, ASilent, ANoWelcome, ALogFile); + Result := h.DoHandle(Owner, url, ASilent, ANoWelcome, ALogFile, BaseKeyboardID); finally h.Free; end; @@ -65,7 +65,7 @@ end; function TKeymanProtocolHandler.DoHandle(Owner: TComponent; const url: string; ASilent, ANoWelcome: Boolean; - const ALogFile: string): Boolean; + const ALogFile: string; BaseKeyboardID: Integer): Boolean; var FTempDir: string; PackageID, BCP47: string; @@ -98,7 +98,7 @@ begin end; // TODO: this makes a circular dependency, refactor it out! - Result := TInstallFile.Execute(nil, FDownloadFilename, False, False, '', BCP47); + Result := TInstallFile.Execute(nil, FDownloadFilename, False, False, '', BCP47, BaseKeyboardID); finally if FileExists(FDownloadFilename) then diff --git a/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas b/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas index 6d79811a80..775aa1ca2e 100644 --- a/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas +++ b/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas @@ -74,6 +74,7 @@ uses Vcl.StdCtrls, keymanapi_TLB, + KeymanOptionNames, UfrmKeymanBase, UfrmWebContainer; @@ -102,7 +103,7 @@ type protected procedure FireCommand(const command: WideString; params: TStringList); override; public - procedure InstallKeyboard(const ALogFile, BCP47Tag: string); + procedure InstallKeyboard(const ALogFile, BCP47Tag: string; BaseKeyboardID: Integer); property DefaultBCP47Tag: string read FDefaultBCP47Tag write SetDefaultBCP47Tag; property InstallFile: string read FInstallFile write SetInstallFile; property Silent: Boolean read FSilent write FSilent; @@ -271,6 +272,7 @@ end; procedure TfrmInstallKeyboard.FireCommand(const command: WideString; params: TStringList); var BCP47Tag: string; + BaseKeyboardID :Integer; begin BCP47Tag := ''; if (command = 'keyboard_install') and kmcom.SystemInfo.IsAdministrator then // I4172 @@ -283,7 +285,8 @@ begin Manager.Title := 'Installing Keyboard'; Manager.CanCancel := False; Manager.UpdateProgress('Installing Keyboard', 0, 0); - InstallKeyboard('', BCP47Tag); + BaseKeyboardID := kmcom.Options[KeymanOptionName(koBaseLayout)].Value; + InstallKeyboard('', BCP47Tag, BaseKeyboardID); Result := True; end ); @@ -299,6 +302,7 @@ begin var t: TTempFile; ExecParams: string; + BaseKeyboardString :string; begin KL.MethodEnter(Self, '"keyboard_install"', [params.Text]); try @@ -306,8 +310,9 @@ begin Manager.CanCancel := False; Manager.UpdateProgress('Installing Keyboard', 0, 0); t := TTempFileManager.Get('.log'); + BaseKeyboardString := IntToHex(kmcom.Options[KeymanOptionName(koBaseLayout)].Value, 8); try - ExecParams := '-log "'+t.Name+'" -s -i "'+FInstallFile+'='+BCP47Tag+'"'+ + ExecParams := '-log "'+t.Name+'" -bkd "'+BaseKeyboardString+'" -s -i "'+FInstallFile+'='+BCP47Tag+'"'+ ' -nowelcome '+TTIPMaintenance.GetUserDefaultLangParameterString; KL.Log('Calling elevated kmshell %s', [ExecParams]); if WaitForElevatedConfiguration(GetForegroundWindow, ExecParams) = 0 then @@ -358,7 +363,7 @@ end; ------------------------------------------------------------------------------} // TODO: move this to TInstallFile -procedure TfrmInstallKeyboard.InstallKeyboard(const ALogFile, BCP47Tag: string); +procedure TfrmInstallKeyboard.InstallKeyboard(const ALogFile, BCP47Tag: string; BaseKeyboardID: Integer); var i: Integer; kbd: IKeymanKeyboardInstalled; @@ -400,7 +405,7 @@ begin kbd := nil; kmcom.Keyboards.Apply; kmcom.Keyboards.Refresh; - FInstalledKeyboard := (FKeyboard as IKeymanKeyboardFile2).Install2(True); + FInstalledKeyboard := (FKeyboard as IKeymanKeyboardFile3).Install3(True, BaseKeyboardID); if not InstallTipForKeyboard(BCP47Tag) then begin // TODO can we return a failure code? @@ -461,7 +466,7 @@ begin kmcom.Keyboards.Apply; kmcom.Keyboards.Refresh; // I2169 - (FPackage as IKeymanPackageFile2).Install2(True); + (FPackage as IKeymanPackageFile3).Install3(True, BaseKeyboardID); kmcom.Refresh; diff --git a/windows/src/desktop/kmshell/install/UfrmInstallKeyboardFromWeb.pas b/windows/src/desktop/kmshell/install/UfrmInstallKeyboardFromWeb.pas index aff3251037..ed236d489d 100644 --- a/windows/src/desktop/kmshell/install/UfrmInstallKeyboardFromWeb.pas +++ b/windows/src/desktop/kmshell/install/UfrmInstallKeyboardFromWeb.pas @@ -87,6 +87,7 @@ uses Keyman.Configuration.UI.InstallFile, Keyman.System.LocaleStrings, kmint, + KeymanOptionNames, MessageIdentifierConsts, Upload_Settings, utilfiletypes, @@ -213,6 +214,7 @@ end; procedure TfrmInstallKeyboardFromWeb.DownloadAndInstallPackage(const PackageID, BCP47: string); var FTempDir: string; + BaseKeyboardID: Integer; begin FTempDir := IncludeTrailingPathDelimiter(CreateTempPath); // I1679 try @@ -230,8 +232,8 @@ begin finally frmDownloadProgress.Free; end; - - if TInstallFile.Execute(Self, FDownloadFilename, False, False, '', BCP47) then + BaseKeyboardID := kmcom.Options[KeymanOptionName(koBaseLayout)].Value; + if TInstallFile.Execute(Self, FDownloadFilename, False, False, '', BCP47, BaseKeyboardID) then ModalResult := mrOk; finally diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas index f9b5f9ac9b..0f0cc6f367 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -206,7 +206,7 @@ end; function Init(var FMode: TKMShellMode; KeyboardFileNames: TStrings; var FSilent, FForce, FNoWelcome: Boolean; var FLogFile, FQuery: string; var FDisablePackages, FDefaultUILanguage: string; var FStartWithConfiguration: Boolean; - var FParentWindow: THandle; var FDefaultBCP47: string; var FDefaultLangID: Integer): Boolean; + var FParentWindow: THandle; var FDefaultBCP47: string; var FDefaultLangID, FBaseKeyboard: Integer): Boolean; var s: string; i: Integer; @@ -263,6 +263,7 @@ begin else if s = '-bd' then FMode := fmBackgroundDownload else if s = '-an' then FMode := fmApplyInstallNow else if s = '-basekeyboard' then FMode := fmBaseKeyboard // I4169 + else if s = 'bkd' then begin Inc(i); FBaseKeyboard := ParamStr(i); end else if s = '-mcompilekbds' then begin FMode := fmMCompileKbds; @@ -329,7 +330,7 @@ end; procedure RunKMCOM(FMode: TKMShellMode; KeyboardFileNames: TStrings; FSilent, FForce, FNoWelcome: Boolean; FLogFile, FQuery: string; FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; FParentWindow: THandle; - const FDefaultBCP47: string; FDefaultLangID: Integer); forward; + const FDefaultBCP47: string; FDefaultLangID, FBaseKeyboard: Integer); forward; procedure Run; var @@ -340,7 +341,7 @@ var FForce: Boolean; FParentWindow: THandle; FLogFile: string; - FDefaultLangID: Integer; + FDefaultLangID, FBaseKeyboard: Integer; FDefaultBCP47, FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; begin @@ -349,7 +350,7 @@ begin KeyboardFileNames := TStringList.Create; try FParentWindow := 0; - if not Init(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow, FDefaultBCP47, FDefaultLangID) then + if not Init(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow, FDefaultBCP47, FDefaultLangID, FBaseKeyboard) then begin //TODO: TUtilExecute.Shell(PChar('hh.exe mk:@MSITStore:'+ExtractFilePath(KMShellExe)+'keyman.chm::/context/keyman_usage.html'), SW_SHOWNORMAL); Exit; @@ -357,7 +358,7 @@ begin if not LoadKMCOM then Exit; try - RunKMCOM(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow, FDefaultBCP47, FDefaultLangID); + RunKMCOM(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow, FDefaultBCP47, FDefaultLangID, FBaseKeyboard); finally kmcom := nil; end; @@ -396,7 +397,7 @@ end; procedure RunKMCOM(FMode: TKMShellMode; KeyboardFileNames: TStrings; FSilent, FForce, FNoWelcome: Boolean; FLogFile, FQuery: string; FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; - FParentWindow: THandle; const FDefaultBCP47: string; FDefaultLangID: Integer); + FParentWindow: THandle; const FDefaultBCP47: string; FDefaultLangID, FBaseKeyboard: Integer); var kdl: IKeymanDefaultLanguage; FIcon: string; @@ -559,7 +560,7 @@ begin else ExitCode := 1; fmInstall: - if TInstallFile.Execute(KeyboardFileNames, FirstKeyboardFileName, FSilent, FNoWelcome, FLogFile) + if TInstallFile.Execute(KeyboardFileNames, FirstKeyboardFileName, FSilent, FNoWelcome, FLogFile, FBaseKeyboard) then ExitCode := 0 else ExitCode := 1; diff --git a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas index 5ea1e74265..b7255869b7 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas @@ -37,7 +37,7 @@ uses keymankeyboard, keymancontext, Classes, PackageInfo, keymankeyboardlanguagesfile; type - TKeymanKeyboardFile = class(TKeymanKeyboard, IKeymanKeyboardFile, IKeymanKeyboardFile2) + TKeymanKeyboardFile = class(TKeymanKeyboard, IKeymanKeyboardFile, IKeymanKeyboardFile2, IKeymanKeyboardFile3) private FFileName: WideString; FError: Boolean; @@ -52,6 +52,7 @@ type { IKeymanKeyboardFile } procedure Install(Force: WordBool); safecall; function Install2(Force: WordBool): IKeymanKeyboardInstalled; safecall; + function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; safecall; { IKeymanKeyboard } function Get_Copyright: WideString; override; safecall; @@ -252,7 +253,7 @@ procedure TKeymanKeyboardFile.Install(Force: WordBool); begin with TKPInstallKeyboard.Create(Context) do try - Execute(FFileName, '', [ikLegacyRegisterAndInstallProfiles], nil, Force); + Execute(FFileName, '', [ikLegacyRegisterAndInstallProfiles], nil, Force, 0); finally Free; end; @@ -264,7 +265,23 @@ var begin with TKPInstallKeyboard.Create(Context) do try - Execute(FFileName, '', [], nil, Force); + Execute(FFileName, '', [], nil, Force, 0); + finally + Free; + end; + + kki := Context.Keyboards as IKeymanKeyboardsInstalled; + kki.Refresh; + Result := kki.Items[FFileName]; +end; + +function TKeymanKeyboardFile.Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; +var + kki: IKeymanKeyboardsInstalled; +begin + with TKPInstallKeyboard.Create(Context) do + try + Execute(FFileName, '', [], nil, Force, BaseKeyboardID); finally Free; end; diff --git a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardsinstalled.pas b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardsinstalled.pas index f5f8b74448..b37e0dfce0 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardsinstalled.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardsinstalled.pas @@ -37,7 +37,8 @@ uses keymanerrorcodes, keymankeyboardinstalled, keymankeyboard, internalinterfaces; type - TKeymanKeyboardsInstalled = class(TKeymanAutoCollectionObject, IKeymanKeyboardsInstalled, IKeymanKeyboardsInstalled2, IIntKeymanKeyboardsInstalled) // I4376 + TKeymanKeyboardsInstalled = class(TKeymanAutoCollectionObject, IKeymanKeyboardsInstalled, + IKeymanKeyboardsInstalled2, IIntKeymanKeyboardsInstalled, IKeymanKeyboardsInstalled3) // I4376 private FKeyboards: TKeyboardList; procedure TriggerWindowsLanguageSync; @@ -55,6 +56,7 @@ type procedure Install(const Filename: WideString; Force: WordBool); safecall; procedure Apply; safecall; function Install2(const Filename: WideString; Force: WordBool): IKeymanKeyboardInstalled; safecall; + function Install3(const Filename: WideString; Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; safecall; procedure RefreshInstalledKeyboards; safecall; { IIntKeymanKeyboardsInstalled } @@ -101,7 +103,7 @@ procedure TKeymanKeyboardsInstalled.Install(const Filename: WideString; Force: W begin with TKPInstallKeyboard.Create(Context) do try - Execute(FileName, '', [ikLegacyRegisterAndInstallProfiles], nil, Force); + Execute(FileName, '', [ikLegacyRegisterAndInstallProfiles], nil, Force, 0); finally Free; end; @@ -112,7 +114,21 @@ function TKeymanKeyboardsInstalled.Install2(const Filename: WideString; begin with TKPInstallKeyboard.Create(Context) do try - Execute(FileName, '', [], nil, Force); + Execute(FileName, '', [], nil, Force, 0); + finally + Free; + end; + + DoRefresh; + Result := Get_Items(FileName); +end; + +function TKeymanKeyboardsInstalled.Install3(const Filename: WideString; + Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; +begin + with TKPInstallKeyboard.Create(Context) do + try + Execute(FileName, '', [], nil, Force, BaseKeyboardID); finally Free; end; diff --git a/windows/src/engine/kmcomapi/com/packages/keymanpackagefile.pas b/windows/src/engine/kmcomapi/com/packages/keymanpackagefile.pas index 14b207e229..28ef2d064a 100644 --- a/windows/src/engine/kmcomapi/com/packages/keymanpackagefile.pas +++ b/windows/src/engine/kmcomapi/com/packages/keymanpackagefile.pas @@ -1,18 +1,18 @@ (* Name: keymanpackagefile Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 20 Jun 2006 Modified Date: 29 Mar 2010 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 20 Jun 2006 - mcdurdin - Initial version 01 Aug 2006 - mcdurdin - Avoid processmessages in unzip 04 Dec 2006 - mcdurdin - Add Serialize function, support ShortcutRootPath in installation @@ -37,7 +37,7 @@ uses keymanpackagecontentfiles, StdVcl, kmpinffile, KeymanContext, Graphics, Classes, internalinterfaces; type - TKeymanPackageFile = class(TKeymanAutoObject, IKeymanPackage, IKeymanPackageFile, IKeymanPackageFile2) + TKeymanPackageFile = class(TKeymanAutoObject, IKeymanPackage, IKeymanPackageFile, IKeymanPackageFile2, IKeymanPackageFile3) private FSourcePath: string; FSubFiles: IKeymanPackageContentFiles; @@ -74,6 +74,7 @@ type { IKeymanPackageFile } procedure Install(Force: WordBool); safecall; function Install2(Force: WordBool): IKeymanPackageInstalled; safecall; + function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; safecall; public constructor Create(AContext: TKeymanContext; const Filename: Widestring); destructor Destroy; override; @@ -175,7 +176,7 @@ begin o := [ipLegacyRegisterAndInstallProfiles]; if Force then Include(o, ipForce); - Execute(FFileName, o); + Execute(FFileName, o, 0); finally Free; end; @@ -191,7 +192,27 @@ begin o := []; if Force then Include(o, ipForce); - Execute(FFileName, o); + Execute(FFileName, o, 0); + finally + Free; + end; + + kpi := Context.Packages as IKeymanPackagesInstalled; + kpi.Refresh; + Result := kpi.Items[FFileName]; +end; + +function TKeymanPackageFile.Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; +var + o: TKPInstallPackageOptions; + kpi: IKeymanPackagesInstalled; +begin + with TKPInstallPackage.Create(Context) do + try + o := []; + if Force then + Include(o, ipForce); + Execute(FFileName, o, BaseKeyboardID); finally Free; end; @@ -211,7 +232,7 @@ var begin if not FileExists(FFileName) then raise Exception.Create('File '+FFileName+' does not exist.'); - + if GetTempPath(260, buf) = 0 then raise Exception.Create('Unable to get temporary path: ' + IntToHex(GetLastError, 8) + ' ' + SysErrorMessage(GetLastError)); FTempOutPath := buf; diff --git a/windows/src/engine/kmcomapi/com/packages/keymanpackagesinstalled.pas b/windows/src/engine/kmcomapi/com/packages/keymanpackagesinstalled.pas index 9dd9f1a52a..821a38bdc5 100644 --- a/windows/src/engine/kmcomapi/com/packages/keymanpackagesinstalled.pas +++ b/windows/src/engine/kmcomapi/com/packages/keymanpackagesinstalled.pas @@ -38,7 +38,8 @@ type property Items[Index: Integer]: IIntKeymanPackageInstalled read GetItem write SetItem; default; end; - TKeymanPackagesInstalled = class(TKeymanAutoCollectionObject, IKeymanPackagesInstalled, IKeymanPackagesInstalled2) + TKeymanPackagesInstalled = class(TKeymanAutoCollectionObject, + IKeymanPackagesInstalled, IKeymanPackagesInstalled2, IKeymanPackagesInstalled3) private FPackages: TPackageList; protected @@ -51,6 +52,7 @@ type function IndexOf(const ID: WideString): Integer; safecall; procedure Install(const Filename: WideString; Force: WordBool); safecall; function Install2(const Filename: WideString; Force: WordBool): IKeymanPackageInstalled; safecall; + function Install3(const Filename: WideString; Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; safecall; public constructor Create(AContext: TKeymanContext); destructor Destroy; override; @@ -118,7 +120,7 @@ begin o := [ipLegacyRegisterAndInstallProfiles]; if Force then Include(o, ipForce); - Execute(Filename, o); + Execute(Filename, o, 0); finally Free; end; @@ -136,7 +138,29 @@ begin o := []; if Force then Include(o, ipForce); - Execute(Filename, o); + Execute(Filename, o, 0); + finally + Free; + end; + + DoRefresh; + Result := Get_Items(Filename); + + KL.MethodExit(Self, 'Install2'); +end; + +function TKeymanPackagesInstalled.Install3(const Filename: WideString; + Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; +var + o: TKPInstallPackageOptions; +begin + KL.MethodEnter(Self, 'Install2', [Filename, Force]); + with TKPInstallPackage.Create(Context) do + try + o := []; + if Force then + Include(o, ipForce); + Execute(Filename, o, BaseKeyboardID); finally Free; end; diff --git a/windows/src/engine/kmcomapi/keymanapi_TLB.pas b/windows/src/engine/kmcomapi/keymanapi_TLB.pas index 786ce6c9b2..7246c9173f 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -1569,6 +1569,17 @@ type procedure RefreshInstalledKeyboards; safecall; end; +// *********************************************************************// +// Interface: IKeymanKeyboardsInstalled3 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641} +// *********************************************************************// + IKeymanKeyboardsInstalled3 = interface(IKeymanKeyboardsInstalled) + ['{B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641}'] + function Install3(const Filename: WideString; Force: WordBool; BasePackageID: Integer): IKeymanKeyboardInstalled; safecall; + procedure RefreshInstalledKeyboards; safecall; + end; + // *********************************************************************// // Interface: IKeymanKeyboardInstalled2 // Flags: (4416) Dual OleAutomation Dispatchable @@ -1610,6 +1621,16 @@ type function Install2(const Filename: WideString; Force: WordBool): IKeymanPackageInstalled; safecall; end; +// *********************************************************************// +// Interface: IKeymanPackagesInstalled3 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458} +// *********************************************************************// + IKeymanPackagesInstalled3 = interface(IKeymanPackagesInstalled) + ['{3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458}'] + function Install3(const Filename: WideString; Force: WordBool; BasePackageID: Integer): IKeymanPackageInstalled; safecall; + end; + // *********************************************************************// // DispIntf: IKeymanPackagesInstalled2Disp // Flags: (4416) Dual OleAutomation Dispatchable @@ -1639,6 +1660,16 @@ type function Install2(Force: WordBool): IKeymanKeyboardInstalled; safecall; end; +// *********************************************************************// +// Interface: IKeymanKeyboardFile3 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {EDE4326B-51F4-42D5-8251-B20B71993EC8} +// *********************************************************************// + IKeymanKeyboardFile3 = interface(IKeymanKeyboardFile) + ['{8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4}'] + function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanKeyboardInstalled; safecall; + end; + // *********************************************************************// // DispIntf: IKeymanKeyboardFile2Disp // Flags: (4416) Dual OleAutomation Dispatchable @@ -1677,6 +1708,17 @@ type function Install2(Force: WordBool): IKeymanPackageInstalled; safecall; end; +// *********************************************************************// +// Interface: IKeymanPackageFile3 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7} +// *********************************************************************// + IKeymanPackageFile3 = interface(IKeymanPackageFile) + ['{C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7}'] + function Install3(Force: WordBool; BaseKeyboardID: Integer): IKeymanPackageInstalled; safecall; + end; + + // *********************************************************************// // DispIntf: IKeymanPackageFile2Disp // Flags: (4416) Dual OleAutomation Dispatchable diff --git a/windows/src/engine/kmcomapi/kmcomapi.ridl b/windows/src/engine/kmcomapi/kmcomapi.ridl index 9eb63fbd68..91f49822b5 100644 --- a/windows/src/engine/kmcomapi/kmcomapi.ridl +++ b/windows/src/engine/kmcomapi/kmcomapi.ridl @@ -66,6 +66,10 @@ library keymanapi interface IKeymanPackageFile2; interface IKeymanKeyboardLanguageInstalled2; interface IKeymanKeyboardLanguagesInstalled2; + interface IKeymanKeyboardFile3; + interface IKeymanPackageFile3; + interface IKeymanKeyboardsInstalled3; + interface IKeymanPackagesInstalled3; interface IKeymanBCP47Canonicalization; interface IKeymanDefaultLanguage; @@ -976,6 +980,60 @@ library keymanapi HRESULT _stdcall Install2([in] VARIANT_BOOL Force, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); }; + [ + uuid(8F4B2D91-6C37-4A05-BE82-1D9F7C53A6E4), + version(19.0), + helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanKeyboardFile3"), + dual, + oleautomation + ] + interface IKeymanKeyboardFile3: IKeymanKeyboardFile + { + [id(0x00000121)] + HRESULT _stdcall Install3([in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); + }; + + [ + uuid(C27A6E4B-9D13-47F8-A052-6B8E31D4F9C7), + version(19.0), + helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanPackageFile3"), + dual, + oleautomation + ] + + interface IKeymanPackageFile3: IKeymanPackageFile + { + [id(0x00000124)] + HRESULT _stdcall Install3([in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanPackageFile** Package); + }; + + + [ + uuid(B7D3A8F1-6C42-4E95-AB17-93F0C2D8E641), + version(19.0), + helpstring("https://help.keyman.com/developer/engine/windows/19.0/api/IKeymanKeyboardInstalled2\3"), + dual, + oleautomation + ] + interface IKeymanKeyboardsInstalled3: IKeymanKeyboardsInstalled + { + [id(0x00000122)] + HRESULT _stdcall Install3([in] BSTR Filename, [in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanKeyboardInstalled** KeyboardResult); + }; + + [ + uuid(3F8C2D71-94A6-4B0E-87D5-C1E3A9F62458), + version(19.0), + helpstring("http://help.keyman.com/developer/engine/desktop/19.0/api/IKeymanPackagesInstalled3"), + dual, + oleautomation + ] + interface IKeymanPackagesInstalled3: IKeymanPackagesInstalled + { + [id(0x00000123)] + HRESULT _stdcall Install3([in] BSTR Filename, [in] VARIANT_BOOL Force, [in] long BaseKeyboardID, [out, retval] IKeymanPackageInstalled** PackageResult); + }; + [ uuid(9B43B6BC-C622-47EF-915E-6780CF53BAAA), version(14.0), diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas index 1df237b0c6..6d3bd1f3ed 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas @@ -64,7 +64,7 @@ type ikLegacyRegisterAndInstallProfiles); TKPInstallKeyboard = class(TKPBase) - procedure Execute(const FileName, PackageID: string; FInstallOptions: TKPInstallKeyboardOptions; Languages: TPackageKeyboardLanguageList; Force: Boolean); + procedure Execute(const FileName: string; const PackageID: string; FInstallOptions: TKPInstallKeyboardOptions; Languages: TPackageKeyboardLanguageList; Force: Boolean; BaseKeyboardID: Integer); procedure RegisterProfiles(const FileName, PackageID: string; FInstallOptions: TKPInstallKeyboardOptions; PackageLanguageMetadata: TPackageKeyboardLanguageList); private procedure LegacyRegisterAndInstallLanguageProfile(Langs: array of Integer; @@ -112,7 +112,7 @@ uses utiltsf, keymanapi_TLB; -procedure TKPInstallKeyboard.Execute(const FileName, PackageID: string; FInstallOptions: TKPInstallKeyboardOptions; Languages: TPackageKeyboardLanguageList; Force: Boolean); +procedure TKPInstallKeyboard.Execute(const FileName: string; const PackageID: string; FInstallOptions: TKPInstallKeyboardOptions; Languages: TPackageKeyboardLanguageList; Force: Boolean; BaseKeyboardID: Integer); var ki: TKeyboardInfo; FDestPath: string; @@ -125,7 +125,9 @@ var FExitCode: Integer; FKVKName: WideString; FCreatedIcon: Boolean; - BaseKeyboardID: Integer; + ElevatedBaseKeyboardID: Integer; + KeymanContext: TKeymanContext; + RecompileMnemonicKeyboard: TKPRecompileMnemonicKeyboard; begin KL.MethodEnter(Self, 'Execute', [FileName,PackageID,ikPartOfPackage in FInstallOptions ,Force]); try @@ -246,14 +248,19 @@ begin KL.Log(FLogText); end; - // Recompile a mnemonic layout to the user's selected base layout + // Recompile a mnemonic layout to the user's selected base layout. If + // the baselayout has not been passed through (=0) then use the current + // process configured value which is likely the Admin user if ki.MnemonicLayout then // I4169 begin - with Context as TKeymanContext do - BaseKeyboardID := (Options as IKeymanOptions).Items['koBaseLayout'].Value; - with TKPRecompileMnemonicKeyboard.Create(Context) do + KeymanContext := Context as TKeymanContext; + ElevatedBaseKeyboardID := (KeymanContext.Options as IKeymanOptions).Items['koBaseLayout'].Value; + RecompileMnemonicKeyboard := TKPRecompileMnemonicKeyboard.Create(Context); try - Execute(FDestFileName, PackageID, BaseKeyboardID); + if (BaseKeyboardID = 0) then + RecompileMnemonicKeyboard.Execute(FDestFileName, PackageID, ElevatedBaseKeyboardID) + else + RecompileMnemonicKeyboard.Execute(FDestFileName, PackageID, BaseKeyboardID); finally Free; end; diff --git a/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas b/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas index 98edfbf3fb..4ab33cdfee 100644 --- a/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas +++ b/windows/src/engine/kmcomapi/processes/package/kpinstallpackage.pas @@ -50,7 +50,7 @@ type TKPInstallPackage = class(TKPBase) public - procedure Execute(const FileName: string; Options: TKPInstallPackageOptions); + procedure Execute(const FileName: string; Options: TKPInstallPackageOptions; BaseKeyboardID: Integer); end; implementation @@ -85,7 +85,7 @@ uses { TKPInstallPackage } -procedure TKPInstallPackage.Execute(const FileName: string; Options: TKPInstallPackageOptions); +procedure TKPInstallPackage.Execute(const FileName: string; Options: TKPInstallPackageOptions; BaseKeyboardID: Integer); function GetHHIcon: string; var buf: array[0..260] of char; @@ -112,7 +112,7 @@ var FErrorValue: Cardinal; FSrcFileName: string; - procedure InstallKeyboard(FileName: string); + procedure InstallKeyboard(FileName: string; BaseKeyboardID: Integer); var FOptions: TKPInstallKeyboardOptions; kbd: TPackageKeyboard; @@ -132,7 +132,7 @@ var with TKPInstallKeyboard.Create(Context) do try - Execute(FileName, PackageName, FOptions, FLanguages, ipForce in Options); + Execute(FileName, PackageName, FOptions, FLanguages, ipForce in Options, BaseKeyboardID); finally Free; end; @@ -253,12 +253,12 @@ begin begin case inf.Files[i].FileType of ftKeymanFile: - InstallKeyboard(dest + inf.Files[i].FileName); + InstallKeyboard(dest + inf.Files[i].FileName, BaseKeyboardID); ftPackageFile: with TKPInstallPackage.Create(Context) do try - Execute(dest + inf.Files[i].FileName, Options); + Execute(dest + inf.Files[i].FileName, Options, BaseKeyboardID); finally Free; end;