diff --git a/common/windows/delphi/general/utilfiletypes.pas b/common/windows/delphi/general/utilfiletypes.pas index f34be0933d..28faa8804c 100644 --- a/common/windows/delphi/general/utilfiletypes.pas +++ b/common/windows/delphi/general/utilfiletypes.pas @@ -91,6 +91,27 @@ function IsProjectFile(const FileName: string): Boolean; function IsKeyboardFile(const FileName: string): Boolean; function RemoveFileExtension(Filename, Extension: string): string; +(** + * Builds the compiled keyboard filename by inserting the base keyboard ID + * before the .kmx extension. + * + * @param KeyboardFileName Keyboard filename, in the form '[path\]keyboardid[.kmx]' + * @param BaseKeyboardIDHex Base keyboard KLID in eight digit hexadecimal form + * @return Compiled keyboard filename, in the form '[path\]keyboardid-.kmx' + *) +function BuildKeyboardFilenameWithBaseKeyboardID(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; + +(** + * Builds the dead-key compiled keyboard filename by inserting the base + * keyboard ID and -d suffix before the .kmx extension. + * + * @param KeyboardFileName Keyboard filename, in the form '[path]\keyboardid[.kmx]' + * @param BaseKeyboardIDHex Base keyboard KLID in eight digit hexadecimal form + * @return Dead-key compiled keyboard filename, in the form '[path\]keyboardid--d.kmx' + *) +function BuildKeyboardFilenameWithBaseKeyboardIDAndDeadkey(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; + + type TKeymanFileTypeInfo = class public @@ -208,4 +229,14 @@ begin SameText(ExtractFileExt(Filename), ExtractFileExt(PackageFile_Welcome))); end; +function BuildKeyboardFilenameWithBaseKeyboardID(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; +begin + Result := ChangeFileExt(KeyboardFileName, '') + '-' + BaseKeyboardIDHex + '.kmx'; +end; + +function BuildKeyboardFilenameWithBaseKeyboardIDAndDeadkey(const KeyboardFileName: string; BaseKeyboardIDHex: string): string; +begin + Result := ChangeFileExt(KeyboardFileName, '') + '-' + BaseKeyboardIDHex + '-d.kmx'; +end; + end. diff --git a/common/windows/delphi/general/utilstr.pas b/common/windows/delphi/general/utilstr.pas index 01e085b8a8..4cd175e360 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,8 +58,6 @@ function GetTokenFromCaret(line: string; var selx, sellen: Integer): string; function WideQuotedStr(const str: WideString): WideString; deprecated; // I3310 - - implementation uses @@ -78,7 +76,7 @@ begin Result := ''; Exit; end; - + if s[1] = '"' then begin Delete(s,1,1); diff --git a/windows/src/desktop/kmshell/install/UpgradeMnemonicLayout.pas b/windows/src/desktop/kmshell/install/UpgradeMnemonicLayout.pas index 5ff65fd8d3..4386c46aff 100644 --- a/windows/src/desktop/kmshell/install/UpgradeMnemonicLayout.pas +++ b/windows/src/desktop/kmshell/install/UpgradeMnemonicLayout.pas @@ -46,7 +46,8 @@ uses kmint, RegistryKeys, utilexecute, - utilkmshell; + utilkmshell, + utilfiletypes; const { CurrentMnemonicLayoutVersion = 476; // First 9.0 build with fixes for mnemonic layouts } @@ -170,7 +171,7 @@ begin FBaseKeyboardIDHex := IntToHex(BaseKeyboardID, 8); FBaseFileName := Keyboard.Filename; FDestFileName := OutputFileName; - FDestDeadkeyFileName := ChangeFileExt(FDestFileName, '') + '-d.kmx'; // I4552 + FDestDeadkeyFileName := BuildKeyboardFilenameWithBaseKeyboardIDAndDeadkey(FBaseFileName, FBaseKeyboardIDHex); // I4552 FMCompilePath := TKeymanPaths.KeymanEngineInstallPath(TKeymanPaths.S_MCompileExe); FDestPath := ExtractFileDir(Keyboard.Filename); diff --git a/windows/src/desktop/kmshell/kmshell.dpr b/windows/src/desktop/kmshell/kmshell.dpr index e2d28b88d2..124b0357ce 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.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 371ce4cd49..abcb521597 100644 --- a/windows/src/desktop/kmshell/kmshell.dproj +++ b/windows/src/desktop/kmshell/kmshell.dproj @@ -358,6 +358,7 @@
frmStartInstall
+ Cfg_2 @@ -419,6 +420,12 @@ False + + + kmshell.exe + true + + .\ @@ -431,12 +438,6 @@ true - - - kmshell.exe - true - - 1 diff --git a/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas b/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas new file mode 100644 index 0000000000..c4fb428b49 --- /dev/null +++ b/windows/src/desktop/kmshell/main/Keyman.Configuration.System.BaseKeyboard.pas @@ -0,0 +1,108 @@ +(* + * Keyman is copyright (C) SIL Global. MIT License. + * + * Created by Ross Cruickshank on 2026-09-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 + +uses + Winapi.Windows, + 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 + * 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. + *) +function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolean; + +(** + * Compiles the installed keyboard layouts 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 + +uses + kmint, + utilkmshell, + utilfiletypes; + +function BaseKeyboardNeedsMCompile(BaseKeyboardID: Integer): Boolean; +var + I: Integer; + Keyboard: IKeymanKeyboardInstalled; + KeyboardFileName: string; + BaseKeyboardIDHex: string; +begin + BaseKeyboardIDHex := IntToHex(BaseKeyboardID, 8); + for I := 0 to kmcom.Keyboards.Count - 1 do + begin + Keyboard := kmcom.Keyboards.Items[I]; + KeyboardFileName := Keyboard.Filename; + if FileExists(KeyboardFileName) and + (not FileExists(BuildKeyboardFilenameWithBaseKeyboardID(KeyboardFileName, BaseKeyboardIDHex)) or + not FileExists(BuildKeyboardFilenameWithBaseKeyboardIDAndDeadkey(KeyboardFileName, BaseKeyboardIDHex))) then + Exit(True); + end; + Result := False; +end; + +function SetBaseKeyboard(WindowHandle: THandle; BaseKeyboardID: Integer): Boolean; +begin + Result := True; + if BaseKeyboardNeedsMCompile(BaseKeyboardID) then + begin + if not kmcom.SystemInfo.IsAdministrator then + begin + Result := WaitForElevatedConfiguration(WindowHandle, '-mcompilekbds ' + IntToHex(BaseKeyboardID, 8)) = 0; + end + else + Result := MCompileBaseKeyboard(BaseKeyboardID); + end; + if not Result then + Exit; + kmcom.Options['koBaseLayout'].Value := BaseKeyboardID; + kmcom.Options.Apply; +end; + +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/UfrmBaseKeyboard.pas b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas index 40a65e31ce..825088ad0a 100644 --- a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas @@ -11,13 +11,21 @@ type TfrmBaseKeyboard = class(TfrmWebContainer) procedure TntFormCreate(Sender: TObject); private + FBaseKeyboardID: Integer; procedure Footer_Cancel; procedure Footer_OK(params: TStringList); protected procedure FireCommand(const command: WideString; params: TStringList); override; end; -function ConfigureBaseKeyboard: Boolean; +(** + * 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 ConfigureAndSetBaseKeyboard(WindowHandle: THandle): Boolean; + implementation @@ -25,15 +33,22 @@ implementation uses BaseKeyboards, - kmint; + ErrorControlledRegistry, + RegistryKeys, + keymanapi_TLB, + Keyman.Configuration.System.BaseKeyboard, + kmint, + utilkmshell; -function ConfigureBaseKeyboard: Boolean; + +function ConfigureAndSetBaseKeyboard(WindowHandle: THandle): Boolean; +var BaseKeyboardID: Integer; begin with TfrmBaseKeyboard.Create(nil) do try Result := ShowModal = mrOk; if Result then - kmcom.Apply; + SetBaseKeyboard(WindowHandle, FBaseKeyboardID) finally Free; end; @@ -65,9 +80,9 @@ var v: Integer; begin if not TryStrToInt('$'+params.Values['id'], v) then Exit; - kmcom.Options['koBaseLayout'].Value := v; - kmcom.Options.Apply; + FBaseKeyboardID := v; ModalResult := mrOk; end; + end. diff --git a/windows/src/desktop/kmshell/main/UfrmMain.pas b/windows/src/desktop/kmshell/main/UfrmMain.pas index a8fdfe9845..46387131d2 100644 --- a/windows/src/desktop/kmshell/main/UfrmMain.pas +++ b/windows/src/desktop/kmshell/main/UfrmMain.pas @@ -174,6 +174,7 @@ uses Hints, HotkeyUtils, initprog, + Keyman.Configuration.System.BaseKeyboard, Keyman.Configuration.System.TIPMaintenance, Keyman.Configuration.UI.UfrmDiagnosticTests, KeymanOptionNames, @@ -198,6 +199,7 @@ uses Keyman.Configuration.UI.UfrmStartInstall, RegistryKeys, SupportXMLRenderer, + UfrmBaseKeyboard, UfrmChangeHotkey, UfrmHTML, UfrmInstallKeyboardFromWeb, @@ -664,9 +666,14 @@ end; ------------------------------------------------------------------------------} procedure TfrmMain.Options_BaseKeyboard; // I4169 +var + BaseKeyboardID: Integer; begin - WaitForElevatedConfiguration(Handle, '-basekeyboard'); - // Refresh will be triggered by elevated process + if ConfigureAndSetBaseKeyboard(Handle) then + begin + DoRefresh; + end; + end; procedure TfrmMain.Options_SettingsManager; diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas index 39c4cc50e8..3010dae5cc 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -90,6 +90,7 @@ type fmKeyboardWelcome, // I2569 fmKeyboardPrint, // I2329 fmBaseKeyboard, // I4169 + fmMCompileKbds, fmUpgradeMnemonicLayout, // I4553 fmRepair, fmKeepInTouch, @@ -114,6 +115,7 @@ uses GetOsVersion, help, HTMLHelpViewer, + Keyman.Configuration.System.BaseKeyboard, Keyman.Configuration.UI.InstallFile, Keyman.Configuration.System.TIPMaintenance, Keyman.Configuration.System.UImportOlderVersionKeyboards11To13, @@ -205,7 +207,7 @@ end; function Init(var FMode: TKMShellMode; KeyboardFileNames: TStrings; var FSilent, FForce, FNoWelcome: Boolean; var FLogFile, FQuery: string; var FDisablePackages, FDefaultUILanguage: string; var FStartWithConfiguration: Boolean; - var FParentWindow: THandle; var FDefaultBCP47: string; var FDefaultLangID: Integer): Boolean; + var FParentWindow: THandle; var FDefaultBCP47: string; var FDefaultLangID, FBaseKeyboard: Integer): Boolean; var s: string; i: Integer; @@ -262,6 +264,14 @@ 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 = '-mcompilekbds' then + begin + // Requires elevated context + FMode := fmMCompileKbds; + Inc(i); + if i > ParamCount then Exit; + FBaseKeyboard := StrToInt('$' + 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 @@ -321,7 +331,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 @@ -332,7 +342,7 @@ var FForce: Boolean; FParentWindow: THandle; FLogFile: string; - FDefaultLangID: Integer; + FDefaultLangID, FBaseKeyboard: Integer; FDefaultBCP47, FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; begin @@ -341,7 +351,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; @@ -349,7 +359,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; @@ -388,7 +398,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; @@ -540,7 +550,12 @@ begin end; fmBaseKeyboard: // I4169 - if ConfigureBaseKeyboard + if ConfigureAndSetBaseKeyboard(0) + then ExitCode := 0 + else ExitCode := 1; + + fmMCompileKbds: + if MCompileBaseKeyboard(FBaseKeyboard) 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 f920c35461..260612e738 100644 --- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas +++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardinstalled.pas @@ -63,7 +63,8 @@ type TKeymanKeyboardInstalled = class( // I3581 TKeymanKeyboard, IIntKeymanKeyboardInstalled, - IKeymanKeyboardInstalled) + IKeymanKeyboardInstalled, + IKeymanKeyboardInstalled2) private FRegKeyboard: TRegKeyboard; FVisualKeyboard: IKeymanVisualKeyboard; @@ -109,9 +110,11 @@ type { IIntKeymanKeyboardInstalled } function RegKeyboard: TRegKeyboard; procedure ClearVisualKeyboard; - procedure UpdateBaseLayout; // I4169 procedure RefreshInstallation; + { IKeymanKeyboardInstalled2 } + procedure MCompileForBaseKeyboard(KLID: Integer); safecall; + public constructor Create(AContext: TKeymanContext; const Name: string); destructor Destroy; override; @@ -151,17 +154,6 @@ begin end; end; -procedure TKeymanKeyboardInstalled.UpdateBaseLayout; // I4169 -begin - if FRegKeyboard.MnemonicLayout and FileExists(FRegKeyboard.KeymanFile) then // I4615 - with TKPRecompileMnemonicKeyboard.Create(Context) do - try - Execute(FRegKeyboard.KeymanFile, FRegKeyboard.PackageName); - finally - Free; - end; -end; - function TKeymanKeyboardInstalled.Get_Copyright: WideString; begin Result := FRegKeyboard.Copyright; @@ -475,5 +467,21 @@ begin Result := FRegKeyboard; end; +{ IKeymanKeyboardInstalled2 } +procedure TKeymanKeyboardInstalled.MCompileForBaseKeyboard(KLID: Integer); safecall; +var + RecompileMnemonicKeyboard: TKPRecompileMnemonicKeyboard; +begin + if FRegKeyboard.MnemonicLayout and FileExists(FRegKeyboard.KeymanFile) then + begin + RecompileMnemonicKeyboard := TKPRecompileMnemonicKeyboard.Create(Context); + try + RecompileMnemonicKeyboard.Execute(FRegKeyboard.KeymanFile, FRegKeyboard.PackageName, KLID); + finally + RecompileMnemonicKeyboard.Free; + end; + end; +end; + end. diff --git a/windows/src/engine/kmcomapi/com/options/keymanoptions.pas b/windows/src/engine/kmcomapi/com/options/keymanoptions.pas index 7bea91450b..1848428033 100644 --- a/windows/src/engine/kmcomapi/com/options/keymanoptions.pas +++ b/windows/src/engine/kmcomapi/com/options/keymanoptions.pas @@ -1,18 +1,18 @@ (* Name: keymanoptions Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 20 Jun 2006 Modified Date: 6 Feb 2015 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 20 Jun 2006 - mcdurdin - Initial version 01 Aug 2006 - mcdurdin - Add AutoRefershKeyman call 12 Aug 2008 - mcdurdin - Avoid crash with missing options @@ -67,6 +67,7 @@ uses ErrorControlledRegistry, RegistryKeys, Glossary, + isadmin, Keyman.System.BaseKeyboard, KeymanOptionNames, keymanerrorcodes; @@ -111,29 +112,8 @@ begin end; procedure TKeymanOptions.Apply; -var - I, FOldBaseLayout: 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); - - if FOldBaseLayout <> Get_Items('koBaseLayout').Value then - for I := 0 to Context.Keyboards.Count - 1 do // I4169 - (Context.Keyboards.Items[I] as IIntKeymanKeyboardInstalled).UpdateBaseLayout; - Context.Control.AutoApplyKeyman; end; diff --git a/windows/src/engine/kmcomapi/keymanapi_TLB.pas b/windows/src/engine/kmcomapi/keymanapi_TLB.pas index 3ceb5b15cd..550a13064d 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -12,7 +12,7 @@ unit keymanapi_TLB; // ************************************************************************ // // $Rev: 52393 $ -// File generated on 16/09/2021 6:54:44 PM from Type Library described below. +// File generated on 7/09/2026 3:54:23 PM from Type Library described below. // ************************************************************************ // // Type Lib: C:\Projects\keyman\app\windows\src\engine\kmcomapi\kmcomapi (1) @@ -87,6 +87,7 @@ const IID_IKeymanKeyboardLanguagesInstalled: TGUID = '{7DC22BC0-85BB-45C0-8EDB-A2F4BD1D500B}'; IID_IKeymanKeyboardLanguagesFile: TGUID = '{5F90BCDA-F1C1-433A-8FD0-B498299D3C30}'; IID_IKeymanKeyboardsInstalled2: TGUID = '{EA57C94F-C140-485E-941A-3F1D5A229024}'; + IID_IKeymanKeyboardInstalled2: TGUID = '{3086C85C-932A-4726-BF76-2D74DD133AC9}'; IID_IKeymanPackagesInstalled2: TGUID = '{F23B9848-2AEF-4A2B-BC3A-292E3A00D691}'; IID_IKeymanKeyboardFile2: TGUID = '{EDE4326B-51F4-42D5-8251-B20B71993EC8}'; IID_IKeymanPackageFile2: TGUID = '{9B43B6BC-C622-47EF-915E-6780CF53BAAA}'; @@ -248,6 +249,8 @@ type IKeymanKeyboardLanguagesFileDisp = dispinterface; IKeymanKeyboardsInstalled2 = interface; IKeymanKeyboardsInstalled2Disp = dispinterface; + IKeymanKeyboardInstalled2 = interface; + IKeymanKeyboardInstalled2Disp = dispinterface; IKeymanPackagesInstalled2 = interface; IKeymanPackagesInstalled2Disp = dispinterface; IKeymanKeyboardFile2 = interface; @@ -1590,6 +1593,51 @@ type out References: OleVariant): WideString; dispid 401; end; +// *********************************************************************// +// Interface: IKeymanKeyboardInstalled2 +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {3086C85C-932A-4726-BF76-2D74DD133AC9} +// *********************************************************************// + IKeymanKeyboardInstalled2 = interface(IKeymanKeyboardInstalled) + ['{3086C85C-932A-4726-BF76-2D74DD133AC9}'] + procedure MCompileForBaseKeyboard(KLID: Integer); safecall; + end; + +// *********************************************************************// +// DispIntf: IKeymanKeyboardInstalled2Disp +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {3086C85C-932A-4726-BF76-2D74DD133AC9} +// *********************************************************************// + IKeymanKeyboardInstalled2Disp = dispinterface + ['{3086C85C-932A-4726-BF76-2D74DD133AC9}'] + procedure MCompileForBaseKeyboard(KLID: Integer); dispid 288; + property IconFilename: WideString readonly dispid 257; + procedure InstallVisualKeyboard(const Filename: WideString); dispid 258; + property KeymanID: Integer readonly dispid 259; + property Languages: IKeymanKeyboardLanguagesInstalled readonly dispid 260; + property Loaded: WordBool dispid 261; + property Options: IKeymanKeyboardOptions readonly dispid 262; + property OwnerPackage: IKeymanPackageInstalled readonly dispid 263; + property VisualKeyboard: IKeymanVisualKeyboard readonly dispid 264; + procedure Uninstall; dispid 265; + property Bitmap: IPicture readonly dispid 1; + property Copyright: WideString readonly dispid 2; + property DefaultBCP47Languages: WideString readonly dispid 3; + property DefaultPrimaryLanguage: Integer readonly dispid 4; + property DefaultWindowsLanguages: WideString readonly dispid 5; + property DefaultHotkey: IKeymanHotkey readonly dispid 6; + property Encodings: KeymanKeyboardEncodings readonly dispid 7; + property Filename: WideString readonly dispid 8; + function GetCharsUsed: WideString; dispid 9; + property ID: WideString readonly dispid 10; + property LayoutType: KeymanKeyboardLayoutType readonly dispid 11; + property Message: WideString readonly dispid 12; + property Name: WideString readonly dispid 13; + property Version: WideString readonly dispid 14; + function SerializeXML(Flags: tagKeymanSerializeFlags; const ImagePath: WideString; + out References: OleVariant): WideString; dispid 401; + end; + // *********************************************************************// // Interface: IKeymanPackagesInstalled2 // Flags: (4416) Dual OleAutomation Dispatchable diff --git a/windows/src/engine/kmcomapi/kmcomapi.ridl b/windows/src/engine/kmcomapi/kmcomapi.ridl index ac20310a87..4d65b37777 100644 --- a/windows/src/engine/kmcomapi/kmcomapi.ridl +++ b/windows/src/engine/kmcomapi/kmcomapi.ridl @@ -6,7 +6,7 @@ // However, when applying changes via the Editor this file will be regenerated // and comments or formatting changes will be lost. // ************************************************************************ // -// File generated on 16/09/2021 6:54:45 PM (- $Rev: 12980 $, 32940875). +// File generated on 7/09/2026 4:05:40 PM (- $Rev: 12980 $, 1707828). [ uuid(F16E2A9A-DA46-4EA3-BFF3-BA46B480C961), @@ -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), diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas index 26c92faa90..1df237b0c6 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas @@ -125,6 +125,7 @@ var FExitCode: Integer; FKVKName: WideString; FCreatedIcon: Boolean; + BaseKeyboardID: Integer; begin KL.MethodEnter(Self, 'Execute', [FileName,PackageID,ikPartOfPackage in FInstallOptions ,Force]); try @@ -248,9 +249,11 @@ begin // Recompile a mnemonic layout to the user's selected base layout if ki.MnemonicLayout then // I4169 begin + with Context as TKeymanContext do + BaseKeyboardID := (Options as IKeymanOptions).Items['koBaseLayout'].Value; with TKPRecompileMnemonicKeyboard.Create(Context) do try - Execute(FDestFileName, PackageID); + Execute(FDestFileName, PackageID, BaseKeyboardID); finally Free; end; diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas b/windows/src/engine/kmcomapi/processes/keyboard/kprecompilemnemonickeyboard.pas index 30d0c275cc..52139f5839 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 @@ -27,7 +27,7 @@ uses type TKPRecompileMnemonicKeyboard = class(TKPBase) - procedure Execute(const FileName: string; const PackageName: string); + procedure Execute(const FileName: string; const PackageName: string; BaseKeyboardID: Cardinal); end; implementation @@ -42,13 +42,12 @@ uses Winapi.Windows, errorcontrolledregistry, - keymancontext, keymanerrorcodes, KeymanPaths, - keymanapi_TLB, RegistryKeys, utilexecute, utilkeyman, + utilfiletypes, utilsystem; function GetKeyboardLayoutFileName(id: Integer): string; @@ -67,7 +66,7 @@ begin Result := ''; end; -procedure TKPRecompileMnemonicKeyboard.Execute(const FileName,PackageName: string); +procedure TKPRecompileMnemonicKeyboard.Execute(const FileName,PackageName: string; BaseKeyboardID: Cardinal); var FDestPath, FDestFileName: string; FBaseKeyboardIDHex: string; @@ -76,7 +75,6 @@ var FExitCode: Integer; FMCompilePath: string; FBaseKeyboardFileName: string; - BaseKeyboardID: Cardinal; FDestDeadkeyFileName: string; FCommand: string; begin @@ -84,13 +82,10 @@ begin then FDestPath := GetPackageInstallPath(PackageName) // I3581 else FDestPath := GetKeyboardInstallPath(FileName); // I3581 - with Context as TKeymanContext do - BaseKeyboardID := (Options as IKeymanOptions).Items['koBaseLayout'].Value; - FBaseKeyboardIDHex := IntToHex(BaseKeyboardID, 8); FBaseFileName := FDestPath + '\' + ExtractFileName(FileName); // I3581 - FDestFileName := ChangeFileExt(FBaseFileName, '') + '-'+FBaseKeyboardIDHex + '.kmx'; - FDestDeadkeyFileName := ChangeFileExt(FBaseFileName, '') + '-'+FBaseKeyboardIDHex + '-d.kmx'; // I4552 + FDestFileName := BuildKeyboardFilenameWithBaseKeyboardID(FBaseFileName, FBaseKeyboardIDHex); + FDestDeadkeyFileName := BuildKeyboardFilenameWithBaseKeyboardIDAndDeadkey(FBaseFileName, FBaseKeyboardIDHex); // I4552 FMCompilePath := TKeymanPaths.KeymanEngineInstallPath(TKeymanPaths.S_MCompileExe); { Recompile with the traditional deadkey behaviour } diff --git a/windows/src/engine/kmcomapi/util/internalinterfaces.pas b/windows/src/engine/kmcomapi/util/internalinterfaces.pas index 1759468e00..edfc65bf28 100644 --- a/windows/src/engine/kmcomapi/util/internalinterfaces.pas +++ b/windows/src/engine/kmcomapi/util/internalinterfaces.pas @@ -1,24 +1,24 @@ (* Name: internalinterfaces Copyright: Copyright (C) 2003-2017 SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 25 Jan 2011 Modified Date: 17 Aug 2014 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 25 Jan 2011 - mcdurdin - I2569 - Keyboard welcome should always shown from kmshell 01 Jan 2013 - mcdurdin - I3717 - V9.0 - Need ability to select base keyboard in Keyman Configuration 16 Apr 2014 - mcdurdin - I4169 - V9.0 - Mnemonic layouts should be recompiled to positional based on user-selected base keyboard 17 Aug 2014 - mcdurdin - I4376 - V9.0 - Unticked keyboards in configuration should be removed from language profile 17 Aug 2014 - mcdurdin - I4381 - V9.0 - Keyman keyboards should be removed from language bar when Keyman exits - + *) unit internalinterfaces; @@ -41,7 +41,7 @@ type IIntKeymanInterface = interface ['{D1EBBED5-B9E3-4807-969D-DCF9E1FFB287}'] function XMLClassName: WideString; - function Serialize(Flags: TOleEnum; const ImagePath: WideString; References: TStrings): WideString; + function Serialize(Flags: TOleEnum; const ImagePath: WideString; References: TStrings): WideString; function DoSerialize(Flags: TOleEnum; const ImagePath: WideString; References: TStrings): WideString; // Wraps serialize with tag end; @@ -67,7 +67,6 @@ type ['{4876E6DF-C557-46E2-84F4-787BE5F55DDA}'] function RegKeyboard: TRegKeyboard; procedure ClearVisualKeyboard; - procedure UpdateBaseLayout; // I4169 procedure RefreshInstallation; end;