diff --git a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas index 40a65e31ce1..e9ce67d5e34 100644 --- a/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas +++ b/windows/src/desktop/kmshell/main/UfrmBaseKeyboard.pas @@ -11,13 +11,17 @@ 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; +function CompileForBaseKeyboard(BaseKeyboardID: Integer): Boolean; implementation @@ -25,15 +29,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 +72,74 @@ 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; +begin + Result := False; + if not TryStrToInt('$' + BaseKeyboardIDText, BaseKeyboardID) or + not kmcom.SystemInfo.IsAdministrator then + Exit; + Result := CompileForBaseKeyboard(BaseKeyboardID); +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) 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; + 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/UfrmMain.pas b/windows/src/desktop/kmshell/main/UfrmMain.pas index e367a795ae0..100fd24fd2f 100644 --- a/windows/src/desktop/kmshell/main/UfrmMain.pas +++ b/windows/src/desktop/kmshell/main/UfrmMain.pas @@ -198,6 +198,7 @@ implementation Keyman.Configuration.UI.UfrmStartInstall, RegistryKeys, SupportXMLRenderer, + UfrmBaseKeyboard, UfrmChangeHotkey, UfrmHTML, UfrmInstallKeyboardFromWeb, @@ -661,9 +662,15 @@ procedure TfrmMain.cefBeforeBrowseSync(Sender: TObject; const Url: string; ------------------------------------------------------------------------------} procedure TfrmMain.Options_BaseKeyboard; // I4169 +var + BaseKeyboardID: Integer; begin - WaitForElevatedConfiguration(Handle, '-basekeyboard'); - // Refresh will be triggered by elevated process + if ConfigureBaseKeyboard(BaseKeyboardID) then + begin + SetBaseKeyboard(Handle, BaseKeyboardID); + 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 39c4cc50e87..f9b5f9ac9b8 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 + fmMCompileKbds, 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 = '-mcompilekbds' then + begin + FMode := fmMCompileKbds; + 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; + + 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 051d399b6ec..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; @@ -152,14 +156,19 @@ procedure TKeymanKeyboardInstalled.Uninstall; 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); + Execute(FRegKeyboard.KeymanFile, FRegKeyboard.PackageName, BaseKeyboardID); finally Free; end; + end; end; function TKeymanKeyboardInstalled.Get_Copyright: WideString; @@ -471,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 7bea91450bc..1848428033c 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; @@ -111,29 +112,8 @@ function TKeymanOptions.IndexOf(const ID: WideString): Integer; 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 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), 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..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 @@ -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';