From 12f4bcee0acedcfc2551867366e97146fb747b67 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Fri, 18 Sep 2026 18:07:18 +1000 Subject: [PATCH 1/7] fix(windows): add warning when system startup disabled This is the initial commit to add a check to see if the Windows System setting for Keyman startup is disabled when the users as select Keyman to start with Windows. Fixes: #15785 --- .../windows/delphi/general/RegistryKeys.pas | 7 +++ windows/src/desktop/kmshell/kmshell.dpr | 3 +- windows/src/desktop/kmshell/kmshell.dproj | 13 ++-- windows/src/desktop/kmshell/main/UfrmMain.dfm | 1 + windows/src/desktop/kmshell/main/UfrmMain.pas | 38 ++++++++++-- .../kmshell/render/OptionsXMLRenderer.pas | 6 ++ ...n.Configuration.System.StartupSettings.pas | 59 +++++++++++++++++++ windows/src/desktop/kmshell/xml/config.css | 14 +++++ .../desktop/kmshell/xml/keyman_options.xsl | 12 +++- windows/src/desktop/kmshell/xml/strings.xml | 15 +++++ 10 files changed, 155 insertions(+), 13 deletions(-) create mode 100644 windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas diff --git a/common/windows/delphi/general/RegistryKeys.pas b/common/windows/delphi/general/RegistryKeys.pas index 0f627c7329..62dfd4250c 100644 --- a/common/windows/delphi/general/RegistryKeys.pas +++ b/common/windows/delphi/general/RegistryKeys.pas @@ -283,6 +283,8 @@ const SRegValue_WindowsRun_Keyman = 'Keyman'; + SRegKey_StartupApproved_Run = 'Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run'; + SRegValue_LanguageCheckDisabledItems = 'language check disabled items'; // CU {------------------------------------------------------------------------------- @@ -414,6 +416,11 @@ function BuildKeyboardLanguagesKey_CU(const KeyboardID: string): string; implementation +uses + System.Win.Registry, + Windows, + SysUtils; + function BuildKeyboardOptionKey_CU(const KeyboardID: string): string; begin Result := SRegKey_ActiveKeyboards_CU + '\' + KeyboardID + '\' + SRegSubKey_KeyboardOptions; diff --git a/windows/src/desktop/kmshell/kmshell.dpr b/windows/src/desktop/kmshell/kmshell.dpr index e2d28b88d2..eac9017de7 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.StartupSettings in 'util\Keyman.Configuration.System.StartupSettings.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..8680fa5a65 100644 --- a/windows/src/desktop/kmshell/kmshell.dproj +++ b/windows/src/desktop/kmshell/kmshell.dproj @@ -358,6 +358,7 @@
frmStartInstall
+ Cfg_2 @@ -419,12 +420,6 @@ False - - - .\ - true - - kmshell.rsm @@ -437,6 +432,12 @@ true + + + .\ + true + + 1 diff --git a/windows/src/desktop/kmshell/main/UfrmMain.dfm b/windows/src/desktop/kmshell/main/UfrmMain.dfm index 5a7dce719f..8d9d513ea4 100644 --- a/windows/src/desktop/kmshell/main/UfrmMain.dfm +++ b/windows/src/desktop/kmshell/main/UfrmMain.dfm @@ -16,6 +16,7 @@ inherited frmMain: TfrmMain PixelsPerInch = 96 TextHeight = 13 object AppEvents: TApplicationEvents + OnActivate = AppEventsActivate OnMessage = AppEventsMessage Left = 416 Top = 256 diff --git a/windows/src/desktop/kmshell/main/UfrmMain.pas b/windows/src/desktop/kmshell/main/UfrmMain.pas index a8fdfe9845..a3810ccbed 100644 --- a/windows/src/desktop/kmshell/main/UfrmMain.pas +++ b/windows/src/desktop/kmshell/main/UfrmMain.pas @@ -99,10 +99,12 @@ type procedure TntFormClose(Sender: TObject; var Action: TCloseAction); procedure TntFormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure AppEventsMessage(var Msg: tagMSG; var Handled: Boolean); + procedure AppEventsActivate(Sender: TObject); private FPageTag: Integer; FClosing: Boolean; + FRefreshOnActivate: Boolean; wm_keyman_refresh: Cardinal; LastRefreshToken: System.IntPtr; @@ -133,6 +135,7 @@ type procedure Options_ResetHints; procedure Options_BaseKeyboard; // I4169 procedure Options_SettingsManager; + procedure Options_StartupSettings; procedure Hotkey_Set(params: TStringList); procedure Hotkey_Clear(params: TStringList); @@ -193,6 +196,7 @@ uses Keyman.Configuration.Util.NetworkConnection, Keyman.Configuration.System.UmodWebHttpServer, Keyman.Configuration.System.HttpServer.App.ConfigMain, + Keyman.Configuration.System.StartupSettings, Keyman.Configuration.UI.InstallFile, Keyman.Configuration.UI.UfrmSettingsManager, Keyman.Configuration.UI.UfrmStartInstall, @@ -264,6 +268,15 @@ begin inherited; end; +procedure TfrmMain.AppEventsActivate(Sender: TObject); +begin + if FRefreshOnActivate then + begin + FRefreshOnActivate := False; + DoRefresh; + end; +end; + {------------------------------------------------------------------------------- - Form-level functions - ------------------------------------------------------------------------------} @@ -343,6 +356,7 @@ begin else if command = 'options_resethints' then Options_ResetHints else if command = 'options_basekeyboard' then Options_BaseKeyboard // I4169 else if command = 'options_settingsmanager' then Options_SettingsManager + else if command = 'options_startupsettings' then Options_StartupSettings else if command = 'language_underlyingkeyboard' then Options_BaseKeyboard @@ -686,17 +700,19 @@ begin end; end; +procedure TfrmMain.Options_StartupSettings; +begin + FRefreshOnActivate := TUtilExecute.Shell(0, 'ms-settings:startupapps', '', ''); +end; + procedure TfrmMain.Options_ClickCheck(params: TStringList); var option: IKeymanOption; + startupDisabled: Boolean; begin if GetOptionFromParams(params, option) and option.Enabled then begin option.Value := not option.Value; - - if (option.ID = 'koDebugging') and option.Value then - ShowMessage(MsgFromId(SKDebuggingWarning)); - kmcom.Errors.Clear; DoApply; if kmcom.Errors.Count > 0 then @@ -706,7 +722,19 @@ begin // be invalid ShowMessage(kmcom.Errors[0].Description); DoRefresh; - end; + end + else + begin + if (option.ID = 'koDebugging') and option.Value then + ShowMessage(MsgFromId(SKDebuggingWarning)); + startupDisabled := (option.ID = 'koStartWithWindows') and option.Value and TWindowsStartupSettings.IsWindowsStartupDisabled; + DoRefresh; + if startupDisabled then + if MessageDlg(MsgFromId(S_StartupDisabledWarningOpenSettings), + mtWarning, [mbYes, mbNo], 0) = mrYes then + Options_StartupSettings; + end + end else ShowMessage(params.Text); diff --git a/windows/src/desktop/kmshell/render/OptionsXMLRenderer.pas b/windows/src/desktop/kmshell/render/OptionsXMLRenderer.pas index fb37c9cae1..b0374ca7ff 100644 --- a/windows/src/desktop/kmshell/render/OptionsXMLRenderer.pas +++ b/windows/src/desktop/kmshell/render/OptionsXMLRenderer.pas @@ -42,8 +42,10 @@ implementation uses custinterfaces, + Keyman.Configuration.System.StartupSettings, kmint, MessageIdentifiers, + RegistryKeys, utilxml, Variants; @@ -70,6 +72,10 @@ var begin References := Null; // I2678 Result := kmcom.Options.SerializeXML(0, '', References); + if TWindowsStartupSettings.IsWindowsStartupDisabled then + Result := Result + 'True' + else + Result := Result + 'False'; FGroups := TStringList.Create; try Result := Result + ''; diff --git a/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas b/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas new file mode 100644 index 0000000000..a8c6c119a1 --- /dev/null +++ b/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas @@ -0,0 +1,59 @@ +(** + * Keyman is copyright (C) SIL Global. MIT License. + * + * Created by Ross Cruickshank on 2026-09-18 + * + * + * This unit assists in determining whether Keyman is enabled to start with Windows in the Windows startup settings. + *) +unit Keyman.Configuration.System.StartupSettings; + +interface + +type + TWindowsStartupSettings = class + class function IsWindowsStartupDisabled: Boolean; static; + end; + +implementation + +uses + RegistryKeys, + System.Win.Registry, + Windows, + SysUtils; + +const + StartupEnabled: Byte = $02; + StartupDisabled: Byte = $03; + + + +class function TWindowsStartupSettings.IsWindowsStartupDisabled: Boolean; +var + reg: TRegistry; + data: array[0..11] of Byte; +begin + Result := False; + reg := TRegistry.Create; + try + try + reg.RootKey := HKEY_CURRENT_USER; + if not reg.OpenKeyReadOnly('\' + SRegKey_StartupApproved_Run) then + Exit; + if not reg.ValueExists(SRegValue_WindowsRun_Keyman) then + Exit; + if reg.GetDataSize(SRegValue_WindowsRun_Keyman) <> SizeOf(data) then + Exit; + reg.ReadBinaryData(SRegValue_WindowsRun_Keyman, data, SizeOf(data)); + Result := data[0] = StartUpDisabled; + except + on E: ERegistryException do + Result := False; + end; + finally + reg.Free; + end; +end; + +end. diff --git a/windows/src/desktop/kmshell/xml/config.css b/windows/src/desktop/kmshell/xml/config.css index 2c00d41adc..cf0316c36f 100644 --- a/windows/src/desktop/kmshell/xml/config.css +++ b/windows/src/desktop/kmshell/xml/config.css @@ -736,6 +736,20 @@ table tr { display: none; } +.options_startup_warning +{ + background: #FFF4CE; + border: 1px solid #D6B656; + color: #4A3B00; + margin: 4px 8px 8px 32px; + padding: 8px; +} +.options_startup_warning input, +.options_startup_warning button +{ + margin-left: 0; + margin-top: 6px; +} #options_control { left: 0; diff --git a/windows/src/desktop/kmshell/xml/keyman_options.xsl b/windows/src/desktop/kmshell/xml/keyman_options.xsl index 0d68ca46ca..1d06a83dc9 100644 --- a/windows/src/desktop/kmshell/xml/keyman_options.xsl +++ b/windows/src/desktop/kmshell/xml/keyman_options.xsl @@ -16,6 +16,16 @@ + +
+
+ + + keyman:options_startupsettings + 1 + +
+
@@ -105,4 +115,4 @@ - \ No newline at end of file + diff --git a/windows/src/desktop/kmshell/xml/strings.xml b/windows/src/desktop/kmshell/xml/strings.xml index 7d6f53c85d..285ffd4965 100644 --- a/windows/src/desktop/kmshell/xml/strings.xml +++ b/windows/src/desktop/kmshell/xml/strings.xml @@ -404,6 +404,21 @@ Start when Windows starts + + + + Windows has disabled Keyman from starting automatically. Enable Keyman in Windows Startup settings. + + + + + Open Windows Startup settings + + + + + Windows has disabled Keyman from starting automatically. Open Windows Startup settings now? + From edd6bcd8dc6efbcdad7283483b45913beb0476a0 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Fri, 25 Sep 2026 16:21:09 +1000 Subject: [PATCH 2/7] fix(windows): add icon and flex layout for warning --- windows/src/desktop/kmshell/xml/config.css | 26 ++++++++++++++----- .../desktop/kmshell/xml/keyman_options.xsl | 15 ++++++----- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/windows/src/desktop/kmshell/xml/config.css b/windows/src/desktop/kmshell/xml/config.css index cf0316c36f..7293ad9b81 100644 --- a/windows/src/desktop/kmshell/xml/config.css +++ b/windows/src/desktop/kmshell/xml/config.css @@ -738,17 +738,29 @@ table tr } .options_startup_warning { - background: #FFF4CE; - border: 1px solid #D6B656; - color: #4A3B00; + background: #FFFFFF; + border: 2px solid #CC3846; + color: #000000; + display: flex; + align-items: flex-start; margin: 4px 8px 8px 32px; padding: 8px; } -.options_startup_warning input, -.options_startup_warning button +.options_startup_warning_icon { - margin-left: 0; - margin-top: 6px; + flex: 0 0 auto; + height: 32px; + margin: 8px 8px 0 0; + width: 32px; +} +.options_startup_warning_content +{ + flex: 1 1 auto; +} +#options .options_startup_warning input, +#options .options_startup_warning button +{ + margin: 6px 0 0; } #options_control { diff --git a/windows/src/desktop/kmshell/xml/keyman_options.xsl b/windows/src/desktop/kmshell/xml/keyman_options.xsl index 1d06a83dc9..0fafe7665c 100644 --- a/windows/src/desktop/kmshell/xml/keyman_options.xsl +++ b/windows/src/desktop/kmshell/xml/keyman_options.xsl @@ -18,12 +18,15 @@
-
- - - keyman:options_startupsettings - 1 - + +
+
+ + + keyman:options_startupsettings + 1 + +
From 1ab603d235d7e82b8cde08c73559c5b04adec677 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Fri, 25 Sep 2026 17:22:44 +1000 Subject: [PATCH 3/7] fix(windows): white space clean up --- .../util/Keyman.Configuration.System.StartupSettings.pas | 4 ---- windows/src/desktop/kmshell/xml/strings.xml | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas b/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas index a8c6c119a1..31e3da09ec 100644 --- a/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas +++ b/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas @@ -2,8 +2,6 @@ * Keyman is copyright (C) SIL Global. MIT License. * * Created by Ross Cruickshank on 2026-09-18 - * - * * This unit assists in determining whether Keyman is enabled to start with Windows in the Windows startup settings. *) unit Keyman.Configuration.System.StartupSettings; @@ -27,8 +25,6 @@ const StartupEnabled: Byte = $02; StartupDisabled: Byte = $03; - - class function TWindowsStartupSettings.IsWindowsStartupDisabled: Boolean; var reg: TRegistry; diff --git a/windows/src/desktop/kmshell/xml/strings.xml b/windows/src/desktop/kmshell/xml/strings.xml index 285ffd4965..579bb12c46 100644 --- a/windows/src/desktop/kmshell/xml/strings.xml +++ b/windows/src/desktop/kmshell/xml/strings.xml @@ -407,7 +407,7 @@ - Windows has disabled Keyman from starting automatically. Enable Keyman in Windows Startup settings. + Windows has disabled Keyman from starting automatically. Enable Keyman Configuration in Windows Startup settings. From 94e400300eb2dd0702fdca014ba30dbc35548a37 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Mon, 28 Sep 2026 13:29:34 +1000 Subject: [PATCH 4/7] fix(windows): change word automatically - on startup --- windows/src/desktop/kmshell/xml/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/src/desktop/kmshell/xml/strings.xml b/windows/src/desktop/kmshell/xml/strings.xml index 579bb12c46..eed85a5234 100644 --- a/windows/src/desktop/kmshell/xml/strings.xml +++ b/windows/src/desktop/kmshell/xml/strings.xml @@ -407,7 +407,7 @@ - Windows has disabled Keyman from starting automatically. Enable Keyman Configuration in Windows Startup settings. + Windows has disabled Keyman from starting on startup. Enable Keyman Configuration in Windows Startup settings. @@ -417,7 +417,7 @@ - Windows has disabled Keyman from starting automatically. Open Windows Startup settings now? + Windows has disabled Keyman from starting on startup. Open Windows Startup settings now? From 8d5608ee13fb066f592e0a3e4e0bce3329afcccb Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Tue, 29 Sep 2026 10:55:23 +1000 Subject: [PATCH 5/7] fix(windows): apply review suggestions Co-authored-by: Marc Durdin --- common/windows/delphi/general/RegistryKeys.pas | 7 +------ windows/src/desktop/kmshell/main/UfrmMain.pas | 3 +++ windows/src/desktop/kmshell/render/OptionsXMLRenderer.pas | 1 - .../util/Keyman.Configuration.System.StartupSettings.pas | 7 +++++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/common/windows/delphi/general/RegistryKeys.pas b/common/windows/delphi/general/RegistryKeys.pas index 62dfd4250c..da513ab12c 100644 --- a/common/windows/delphi/general/RegistryKeys.pas +++ b/common/windows/delphi/general/RegistryKeys.pas @@ -283,7 +283,7 @@ const SRegValue_WindowsRun_Keyman = 'Keyman'; - SRegKey_StartupApproved_Run = 'Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run'; + SRegKey_StartupApproved_Run = 'Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run'; // CU SRegValue_LanguageCheckDisabledItems = 'language check disabled items'; // CU @@ -416,11 +416,6 @@ function BuildKeyboardLanguagesKey_CU(const KeyboardID: string): string; implementation -uses - System.Win.Registry, - Windows, - SysUtils; - function BuildKeyboardOptionKey_CU(const KeyboardID: string): string; begin Result := SRegKey_ActiveKeyboards_CU + '\' + KeyboardID + '\' + SRegSubKey_KeyboardOptions; diff --git a/windows/src/desktop/kmshell/main/UfrmMain.pas b/windows/src/desktop/kmshell/main/UfrmMain.pas index 48a294d4f9..c8fb4612f3 100644 --- a/windows/src/desktop/kmshell/main/UfrmMain.pas +++ b/windows/src/desktop/kmshell/main/UfrmMain.pas @@ -707,6 +707,9 @@ end; procedure TfrmMain.Options_StartupSettings; begin + // We'll refresh the page when we return to Keyman Configuration + // after the Startup Apps settings page is popped up in case the + // user has changed the setting FRefreshOnActivate := TUtilExecute.Shell(0, 'ms-settings:startupapps', '', ''); end; diff --git a/windows/src/desktop/kmshell/render/OptionsXMLRenderer.pas b/windows/src/desktop/kmshell/render/OptionsXMLRenderer.pas index b0374ca7ff..5bdbda402e 100644 --- a/windows/src/desktop/kmshell/render/OptionsXMLRenderer.pas +++ b/windows/src/desktop/kmshell/render/OptionsXMLRenderer.pas @@ -45,7 +45,6 @@ uses Keyman.Configuration.System.StartupSettings, kmint, MessageIdentifiers, - RegistryKeys, utilxml, Variants; diff --git a/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas b/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas index 31e3da09ec..ff5c126521 100644 --- a/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas +++ b/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas @@ -2,7 +2,9 @@ * Keyman is copyright (C) SIL Global. MIT License. * * Created by Ross Cruickshank on 2026-09-18 - * This unit assists in determining whether Keyman is enabled to start with Windows in the Windows startup settings. + * + * This unit assists in determining whether Keyman is enabled to start + * with Windows in the Windows startup settings. *) unit Keyman.Configuration.System.StartupSettings; @@ -41,7 +43,8 @@ begin Exit; if reg.GetDataSize(SRegValue_WindowsRun_Keyman) <> SizeOf(data) then Exit; - reg.ReadBinaryData(SRegValue_WindowsRun_Keyman, data, SizeOf(data)); + if reg.ReadBinaryData(SRegValue_WindowsRun_Keyman, data, SizeOf(data)) <> sizeof(data) then + Exit; Result := data[0] = StartUpDisabled; except on E: ERegistryException do From 6112104e55b3e889a1c90aa37bcf81677d7ec245 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Tue, 29 Sep 2026 11:30:21 +1000 Subject: [PATCH 6/7] fix(windows): add docnote on startupapproved key --- .../Keyman.Configuration.System.StartupSettings.pas | 12 ++++++++++-- windows/src/desktop/kmshell/xml/strings.xml | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas b/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas index ff5c126521..2ba972445a 100644 --- a/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas +++ b/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas @@ -3,7 +3,7 @@ * * Created by Ross Cruickshank on 2026-09-18 * - * This unit assists in determining whether Keyman is enabled to start + * This unit assists in determining whether Keyman is enabled to start * with Windows in the Windows startup settings. *) unit Keyman.Configuration.System.StartupSettings; @@ -24,6 +24,14 @@ uses SysUtils; const +// This registry key is not documented by Microsoft, others have determined: +// The value associated with it is 12 bytes in length the first being the +// enabled/disabled state. The rest of the byte is the timestamp +// of when it was disabled. +// 03 - startup disabled, user with admin rights can enable +// 02 - startup enabled, user with admin rights can disable +// See issue #15785 for more details. + StartupEnabled: Byte = $02; StartupDisabled: Byte = $03; @@ -43,7 +51,7 @@ begin Exit; if reg.GetDataSize(SRegValue_WindowsRun_Keyman) <> SizeOf(data) then Exit; - if reg.ReadBinaryData(SRegValue_WindowsRun_Keyman, data, SizeOf(data)) <> sizeof(data) then + if reg.ReadBinaryData(SRegValue_WindowsRun_Keyman, data, SizeOf(data)) <> sizeof(data) then Exit; Result := data[0] = StartUpDisabled; except diff --git a/windows/src/desktop/kmshell/xml/strings.xml b/windows/src/desktop/kmshell/xml/strings.xml index eed85a5234..c09cc98c72 100644 --- a/windows/src/desktop/kmshell/xml/strings.xml +++ b/windows/src/desktop/kmshell/xml/strings.xml @@ -407,7 +407,7 @@ - Windows has disabled Keyman from starting on startup. Enable Keyman Configuration in Windows Startup settings. + Windows has disabled Keyman from starting on startup. Enable Keyman in Windows Startup settings. From f09ff0f48732ecd100d2a77ca48c765882231c9f Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Thu, 1 Oct 2026 11:57:44 +1000 Subject: [PATCH 7/7] fix(windows): add other observed cases of disabled --- ...n.Configuration.System.StartupSettings.pas | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas b/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas index 2ba972445a..371ad31c60 100644 --- a/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas +++ b/windows/src/desktop/kmshell/util/Keyman.Configuration.System.StartupSettings.pas @@ -23,17 +23,33 @@ uses Windows, SysUtils; -const -// This registry key is not documented by Microsoft, others have determined: -// The value associated with it is 12 bytes in length the first being the -// enabled/disabled state. The rest of the byte is the timestamp -// of when it was disabled. -// 03 - startup disabled, user with admin rights can enable -// 02 - startup enabled, user with admin rights can disable -// See issue #15785 for more details. +(* This registry key is not documented by Microsoft, others have determined: +The value associated with it is 12 bytes in length the first being the +enabled/disabled state. The rest of the byte is the timestamp +of when it was disabled. Drawing from our investigation of the registry +and a broader search of stackoverflow, superuser and other sources on +the web, the following table can be derived for the first byte of the value: +See issue #15785 for more details and links. - StartupEnabled: Byte = $02; - StartupDisabled: Byte = $03; +| First byte | Reported behaviour | Source quality | +| ---------- | ------------------------------ | --------------------------------------| +| `00` | enabled, user can disable | Our test on two Win 11 Home Machines | +| `01` | Disabled, user can enable | Our test + Super User | +| `02` | Enabled, user can disable | Multiple sources | +| `03` | Disabled, user can enable | Multiple sources | +| `06` | Enableduser can disable | Stack Overflow, not seen by us | +| `07` | Disabled, user can enable | Stack Overflow, not seen by us | +| `08` | Enabled, user cannot disable | Super User, not seen by us | +| `09` | Disabled, user cannot enable | Super User, not seen by us | + +Maybe it is just bit 0 of the first byte that is enabled disabled? There in no +point checking for $09 as the user cannot change the setting. We would need a +different message. + +*) + +const + StartupDisabled: set of Byte = [$01, $03, $07]; class function TWindowsStartupSettings.IsWindowsStartupDisabled: Boolean; var @@ -53,7 +69,7 @@ begin Exit; if reg.ReadBinaryData(SRegValue_WindowsRun_Keyman, data, SizeOf(data)) <> sizeof(data) then Exit; - Result := data[0] = StartUpDisabled; + Result := data[0] in StartupDisabled; except on E: ERegistryException do Result := False;