Merge pull request #3773 from keymanapp/fix/windows/3562-start-keyman-on-demand-tasks

fix(windows): Start Keyman on Demand - tasks
This commit is contained in:
Marc Durdin 2020-10-28 16:08:46 +11:00 committed by GitHub
commit 24fe11e6fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 3199 additions and 3 deletions

View file

@ -176,7 +176,9 @@ uses
Keyman.System.SettingsManager in '..\..\global\delphi\general\Keyman.System.SettingsManager.pas',
Keyman.Configuration.UI.UfrmSettingsManager in 'settings\Keyman.Configuration.UI.UfrmSettingsManager.pas' {frmSettingsManager},
Keyman.Configuration.UI.UfrmSettingsAddTSFApp in 'settings\Keyman.Configuration.UI.UfrmSettingsAddTSFApp.pas' {frmSettingsAddTSFApp},
Keyman.System.SettingsManagerFile in '..\..\global\delphi\general\Keyman.System.SettingsManagerFile.pas';
Keyman.System.SettingsManagerFile in '..\..\global\delphi\general\Keyman.System.SettingsManagerFile.pas',
Keyman.System.KeymanStartTask in 'util\Keyman.System.KeymanStartTask.pas',
TaskScheduler_TLB in '..\..\global\delphi\winapi\TaskScheduler_TLB.pas';
{$R VERSION.RES}
{$R manifest.res}

View file

@ -336,6 +336,8 @@
<FormType>dfm</FormType>
</DCCReference>
<DCCReference Include="..\..\global\delphi\general\Keyman.System.SettingsManagerFile.pas"/>
<DCCReference Include="util\Keyman.System.KeymanStartTask.pas"/>
<DCCReference Include="..\..\global\delphi\winapi\TaskScheduler_TLB.pas"/>
<None Include="Profiling\AQtimeModule1.aqt"/>
<BuildConfiguration Include="Debug">
<Key>Cfg_2</Key>

View file

@ -113,6 +113,7 @@ uses
Keyman.Configuration.System.TIPMaintenance,
Keyman.Configuration.System.UImportOlderVersionKeyboards11To13,
Keyman.Configuration.UI.UfrmSettingsManager,
Keyman.System.KeymanStartTask,
KeymanPaths,
KLog,
kmint,
@ -373,7 +374,9 @@ begin
FMutex := nil; // I2720
{ Locate the appropriate product }
{ Run app reconfiguration tasks }
TKeymanStartTask.RecreateTask;
UILanguages.CreateUILanguages;

View file

@ -0,0 +1,133 @@
unit Keyman.System.KeymanStartTask;
interface
type
/// <summary>Create or recreate the automatic task to start Keyman if a TIP
/// is selected based on an event in the Event Log</summary>
TKeymanStartTask = class
private
public
class procedure RecreateTask;
class procedure DeleteTask;
class procedure CreateTask;
end;
implementation
uses
System.Variants,
Winapi.ActiveX,
Winapi.Windows,
DebugPaths,
KeymanPaths,
KeymanVersion,
RegistryKeys,
TaskScheduler_TLB;
{ TKeymanStartTask }
const
CTaskName = 'Start On Demand';
CTaskDescription = 'Starts Keyman on demand when a Keyman input method is selected';
CTaskAuthor = 'SIL International';
CTaskFolderName = 'Keyman';
CTaskTrigger =
'<QueryList>'+
'<Query Id="0" Path="Application">'+
'<Select Path="Application">*[System[Provider[@Name=''Keyman''] and EventID=256]]</Select>'+
'</Query>'+
'</QueryList>';
CTaskEventTriggerId = 'Keyman_StartOnDemand';
CKeymanExeStartArguments = '-kmc start';
class procedure TKeymanStartTask.CreateTask;
var
pService: ITaskService;
pTaskFolder: ITaskFolder;
pTask: ITaskDefinition;
pRegInfo: IRegistrationInfo;
pSettings: ITaskSettings;
pEventTrigger: IEventTrigger;
pAction: IExecAction;
begin
pService := CoTaskScheduler_.Create;
pService.Connect(EmptyParam, EmptyParam, EmptyParam, EmptyParam);
// Create or open the Keyman task folder
try
pTaskFolder := pService.GetFolder('\' + CTaskFolderName);
except
pTaskFolder := pService.GetFolder('\').CreateFolder(CTaskFolderName, EmptyParam);
end;
// Create a new task
pTask := pService.NewTask(0);
pRegInfo := pTask.RegistrationInfo;
pRegInfo.Author := CTaskAuthor;
pRegInfo.Description := CTaskDescription;
pRegInfo.Version := CKeymanVersionInfo.VersionWithTag;
pSettings := pTask.Settings;
pSettings.DisallowStartIfOnBatteries := False;
pSettings.StopIfGoingOnBatteries := False;
pSettings.ExecutionTimeLimit := 'PT0S'; // no time limit
pSettings.Priority := 4; // https://github.com/microsoft/WinDev/issues/55
// Start the task when Keyman event 256 is logged
pEventTrigger := pTask.Triggers.Create(TASK_TRIGGER_EVENT) as IEventTrigger;
pEventTrigger.Id := CTaskEventTriggerId;
pEventTrigger.Subscription := CTaskTrigger;
// Action is to run keyman.exe as login user
pAction := pTask.Actions.Create(TASK_ACTION_EXEC) as IExecAction;
pAction.Path := TKeymanPaths.KeymanEngineInstallPath(TKeymanPaths.S_KeymanExe);
pAction.Arguments := CKeymanExeStartArguments;
pTaskFolder.RegisterTaskDefinition(CTaskName, pTask, TASK_CREATE_OR_UPDATE or TASK_IGNORE_REGISTRATION_TRIGGERS,
EmptyParam, EmptyParam, TASK_LOGON_NONE, EmptyParam);
end;
class procedure TKeymanStartTask.DeleteTask;
var
pService: ITaskService;
pTaskFolder: ITaskFolder;
begin
pService := CoTaskScheduler_.Create;
pService.Connect(EmptyParam, EmptyParam, EmptyParam, EmptyParam);
try
pTaskFolder := pService.GetFolder('\'+CTaskFolderName);
except
// Assume that the folder doesn't exist, nothing to do
Exit;
end;
try
pTaskFolder.DeleteTask(CTaskName, 0);
except
// We'll assume that the task doesn't exist, and continue
end;
if pTaskFolder.GetTasks(0).Count = 0 then
begin
pTaskFolder := nil;
pService.GetFolder('\').DeleteFolder(CTaskFolderName, 0);
end;
end;
class procedure TKeymanStartTask.RecreateTask;
begin
if not Reg_GetDebugFlag(SRegValue_Flag_UseAutoStartTask, True) then
begin
DeleteTask;
Exit;
end;
CreateTask;
end;
end.

View file

@ -95,7 +95,7 @@ const
ValueType: kstInteger
);
BaseKeymanSettings: array[0..31] of TKeymanSettingBase = (
BaseKeymanSettings: array[0..32] of TKeymanSettingBase = (
// TIKE:UTikeDebugMode.TikeDebugMode
(
@ -409,6 +409,20 @@ const
ValueType: kstInteger
),
// kmshell:Keyman.System.KeymanStartTask
(
ID: 'engine.compatibility.use_autostart_task';
Name: SRegValue_Flag_UseAutoStartTask;
RootKey: HKCU;
Key: SRegKey_KeymanEngineDebug_CU;
Description: 'Set to 0 to disable the autostart task that starts '+
'Keyman when a Keyman TIP is selected. After making this '+
'change, you will need to open Keyman Configuration once '+
'for it to take effect.';
DefaultInt: 1;
ValueType: kstInteger
),
//
// engine.diagnostics
//

View file

@ -447,6 +447,8 @@ const
SRegValue_Flag_UseRegisterHotkey = 'Flag_UseRegisterHotkey';
SRegValue_Flag_ShouldSerializeInput = 'Flag_ShouldSerializeInput';
SRegValue_Flag_UseAutoStartTask = 'Flag_UseAutoStartTask';
// Fixed path names
const
// PF = CSIDL_PROGRAM_FILES

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,30 @@
unit Keyman.System.Test.KeymanStartTaskTest;
interface
procedure Run;
implementation
uses
Winapi.ActiveX,
Winapi.Windows,
Keyman.System.KeymanStartTask;
procedure Run;
begin
CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
try
if ParamStr(1) = '-d' then
TKeymanStartTask.DeleteTask
else if ParamStr(1) = '-c' then
TKeymanStartTask.CreateTask
else
TKeymanStartTask.Recreate;
finally
CoUninitialize;
end;
end;
end.

View file

@ -0,0 +1,26 @@
program test_starttask;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
Keyman.System.KeymanStartTask in '..\..\desktop\kmshell\util\Keyman.System.KeymanStartTask.pas',
DebugPaths in '..\..\global\delphi\general\DebugPaths.pas',
RegistryKeys in '..\..\global\delphi\general\RegistryKeys.pas',
TaskScheduler_TLB in '..\..\global\delphi\winapi\TaskScheduler_TLB.pas',
ErrorControlledRegistry in '..\..\global\delphi\vcl\ErrorControlledRegistry.pas',
KeymanVersion in '..\..\global\delphi\general\KeymanVersion.pas',
Keyman.System.Test.KeymanStartTaskTest in 'Keyman.System.Test.KeymanStartTaskTest.pas',
KeymanPaths in '..\..\global\delphi\general\KeymanPaths.pas';
begin
try
Run;
{ TODO -oUser -cConsole Main : Insert code here }
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.

File diff suppressed because it is too large Load diff

Binary file not shown.