mirror of
https://github.com/keymanapp/keyman.git
synced 2026-10-06 14:07:32 +00:00
Merge pull request #16603 from keymanapp/fix/windows/15785/windows-startup-apps-sync
fix(windows): add warning when system startup disabled
This commit is contained in:
commit
5be17e4366
10 changed files with 183 additions and 6 deletions
|
|
@ -283,6 +283,8 @@ const
|
|||
|
||||
SRegValue_WindowsRun_Keyman = 'Keyman';
|
||||
|
||||
SRegKey_StartupApproved_Run = 'Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run'; // CU
|
||||
|
||||
SRegValue_LanguageCheckDisabledItems = 'language check disabled items'; // CU
|
||||
|
||||
{-------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -184,6 +184,7 @@ uses
|
|||
Keyman.System.ExecutionHistory in '..\..\..\..\common\windows\delphi\general\Keyman.System.ExecutionHistory.pas',
|
||||
Keyman.Configuration.UI.UfrmStartInstall in 'main\Keyman.Configuration.UI.UfrmStartInstall.pas' {frmStartInstall},
|
||||
Keyman.Configuration.Util.NetworkConnection in 'util\Keyman.Configuration.Util.NetworkConnection.pas',
|
||||
Keyman.Configuration.System.StartupSettings in 'util\Keyman.Configuration.System.StartupSettings.pas',
|
||||
Keyman.Configuration.System.BaseKeyboard in 'main\Keyman.Configuration.System.BaseKeyboard.pas';
|
||||
|
||||
{$R VERSION.RES}
|
||||
|
|
|
|||
|
|
@ -358,6 +358,7 @@
|
|||
<Form>frmStartInstall</Form>
|
||||
</DCCReference>
|
||||
<DCCReference Include="util\Keyman.Configuration.Util.NetworkConnection.pas"/>
|
||||
<DCCReference Include="util\Keyman.Configuration.System.StartupSettings.pas"/>
|
||||
<DCCReference Include="main\Keyman.Configuration.System.BaseKeyboard.pas"/>
|
||||
<None Include="Profiling\AQtimeModule1.aqt"/>
|
||||
<BuildConfiguration Include="Debug">
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ inherited frmMain: TfrmMain
|
|||
PixelsPerInch = 96
|
||||
TextHeight = 13
|
||||
object AppEvents: TApplicationEvents
|
||||
OnActivate = AppEventsActivate
|
||||
OnMessage = AppEventsMessage
|
||||
Left = 416
|
||||
Top = 256
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -194,6 +197,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,
|
||||
|
|
@ -266,6 +270,15 @@ begin
|
|||
inherited;
|
||||
end;
|
||||
|
||||
procedure TfrmMain.AppEventsActivate(Sender: TObject);
|
||||
begin
|
||||
if FRefreshOnActivate then
|
||||
begin
|
||||
FRefreshOnActivate := False;
|
||||
DoRefresh;
|
||||
end;
|
||||
end;
|
||||
|
||||
{-------------------------------------------------------------------------------
|
||||
- Form-level functions -
|
||||
------------------------------------------------------------------------------}
|
||||
|
|
@ -345,6 +358,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
|
||||
|
||||
|
|
@ -691,17 +705,22 @@ begin
|
|||
end;
|
||||
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;
|
||||
|
||||
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
|
||||
|
|
@ -711,7 +730,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);
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ implementation
|
|||
|
||||
uses
|
||||
custinterfaces,
|
||||
Keyman.Configuration.System.StartupSettings,
|
||||
kmint,
|
||||
MessageIdentifiers,
|
||||
utilxml,
|
||||
|
|
@ -70,6 +71,10 @@ var
|
|||
begin
|
||||
References := Null; // I2678
|
||||
Result := kmcom.Options.SerializeXML(0, '', References);
|
||||
if TWindowsStartupSettings.IsWindowsStartupDisabled then
|
||||
Result := Result + '<StartupDisabled>True</StartupDisabled>'
|
||||
else
|
||||
Result := Result + '<StartupDisabled>False</StartupDisabled>';
|
||||
FGroups := TStringList.Create;
|
||||
try
|
||||
Result := Result + '<OptionGroups>';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
(**
|
||||
* 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;
|
||||
|
||||
(* 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.
|
||||
|
||||
| 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
|
||||
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;
|
||||
if reg.ReadBinaryData(SRegValue_WindowsRun_Keyman, data, SizeOf(data)) <> sizeof(data) then
|
||||
Exit;
|
||||
Result := data[0] in StartupDisabled;
|
||||
except
|
||||
on E: ERegistryException do
|
||||
Result := False;
|
||||
end;
|
||||
finally
|
||||
reg.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
|
@ -736,6 +736,32 @@ table tr
|
|||
{
|
||||
display: none;
|
||||
}
|
||||
.options_startup_warning
|
||||
{
|
||||
background: #FFFFFF;
|
||||
border: 2px solid #CC3846;
|
||||
color: #000000;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin: 4px 8px 8px 32px;
|
||||
padding: 8px;
|
||||
}
|
||||
.options_startup_warning_icon
|
||||
{
|
||||
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
|
||||
{
|
||||
left: 0;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,19 @@
|
|||
<xsl:for-each select="//KeymanOption[group=current()/name]">
|
||||
<xsl:if test="optiontype = 1">
|
||||
<xsl:call-template name="option" />
|
||||
<xsl:if test="id='koStartWithWindows' and value='True' and //StartupDisabled='True'">
|
||||
<div class="options_startup_warning">
|
||||
<img class="options_startup_warning_icon" src="/app/caution-icon.png" alt="" />
|
||||
<div class="options_startup_warning_content">
|
||||
<div><xsl:value-of select="$locale/string[@name='S_StartupDisabledWarning']"/></div>
|
||||
<xsl:call-template name="button">
|
||||
<xsl:with-param name="caption"><xsl:value-of select="$locale/string[@name='S_Button_StartupSettings']"/></xsl:with-param>
|
||||
<xsl:with-param name="command">keyman:options_startupsettings</xsl:with-param>
|
||||
<xsl:with-param name="tabid">1</xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</div>
|
||||
</div>
|
||||
</xsl:if>
|
||||
</xsl:if>
|
||||
</xsl:for-each>
|
||||
<xsl:if test="current() != //OptionGroups/OptionGroup[last()]">
|
||||
|
|
@ -105,4 +118,4 @@
|
|||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
</xsl:stylesheet>
|
||||
|
|
|
|||
|
|
@ -404,6 +404,21 @@
|
|||
<!-- Introduced: 7.0.230.0 -->
|
||||
<string name="koStartWithWindows" comment="Startup options - Start Keyman with Windows start">Start when Windows starts</string>
|
||||
|
||||
<!-- Context: Configuration Dialog - Options tab -->
|
||||
<!-- String Type: FormatString -->
|
||||
<!-- Introduced: 19.0.286.0 -->
|
||||
<string name="S_StartupDisabledWarning" comment="Startup options - Windows has disabled Keyman startup">Windows has disabled Keyman from starting on startup. Enable Keyman in Windows Startup settings.</string>
|
||||
|
||||
<!-- Context: Configuration Dialog - Options tab -->
|
||||
<!-- String Type: FormatString -->
|
||||
<!-- Introduced: 19.0.286.0 -->
|
||||
<string name="S_Button_StartupSettings" comment="Startup options - open Windows Startup settings">Open Windows Startup settings</string>
|
||||
|
||||
<!-- Context: Configuration Dialog - Options tab -->
|
||||
<!-- String Type: FormatString -->
|
||||
<!-- Introduced: 19.0.286.0 -->
|
||||
<string name="S_StartupDisabledWarningOpenSettings" comment="Startup options - Windows has disabled Keyman startup opening settings">Windows has disabled Keyman from starting on startup. Open Windows Startup settings now?</string>
|
||||
|
||||
<!-- Context: Configuration Dialog - Options tab -->
|
||||
<!-- String Type: FormatString -->
|
||||
<!-- Introduced: 7.0.230.0 -->
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue