mirror of
https://github.com/microsoft/PowerToys
synced 2025-08-31 14:35:18 +00:00
[MouseJump]Long lived background process (#28380)
* [MouseJump] Long lived background exe * [MouseJump] Long lived background exe * [MouseJump] Long lived background exe * [MouseJump] Long lived background exe * [MouseJump] Close long lived background exe when parent runner exits * [MouseJump] Close long lived background exe when parent runner exits * [MouseJump] long lived background exe - fixing build * [MouseJump] - add FileSystemWatcher for config (#26703) * Fix telemetry event
This commit is contained in:
@@ -203,6 +203,10 @@ public
|
||||
return gcnew String(CommonSharedConstants::SHOW_POWEROCR_SHARED_EVENT);
|
||||
}
|
||||
|
||||
static String ^ MouseJumpShowPreviewEvent() {
|
||||
return gcnew String(CommonSharedConstants::MOUSE_JUMP_SHOW_PREVIEW_EVENT);
|
||||
}
|
||||
|
||||
static String ^ AwakeExitEvent() {
|
||||
return gcnew String(CommonSharedConstants::AWAKE_EXIT_EVENT);
|
||||
}
|
||||
|
@@ -50,6 +50,9 @@ namespace CommonSharedConstants
|
||||
// Path to the event used by PowerOCR
|
||||
const wchar_t SHOW_POWEROCR_SHARED_EVENT[] = L"Local\\PowerOCREvent-dc864e06-e1af-4ecc-9078-f98bee745e3a";
|
||||
|
||||
// Path to the events used by Mouse Jump
|
||||
const wchar_t MOUSE_JUMP_SHOW_PREVIEW_EVENT[] = L"Local\\MouseJumpEvent-aa0be051-3396-4976-b7ba-1a9cc7d236a5";
|
||||
|
||||
// Path to the event used by RegistryPreview
|
||||
const wchar_t REGISTRY_PREVIEW_TRIGGER_EVENT[] = L"Local\\RegistryPreviewEvent-4C559468-F75A-4E7F-BC4F-9C9688316687";
|
||||
|
||||
|
56
src/modules/MouseUtils/MouseJump/MouseJump.vcxproj.filters
Normal file
56
src/modules/MouseUtils/MouseJump/MouseJump.vcxproj.filters
Normal file
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Generated Files">
|
||||
<UniqueIdentifier>{875a08c6-f610-4667-bd0f-80171ed96072}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Generated Files\resource.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</None>
|
||||
<None Include="MouseJump.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Generated Files\MouseJump.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
@@ -1,32 +1,32 @@
|
||||
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||
#include "pch.h"
|
||||
|
||||
#include <interface/powertoy_module_interface.h>
|
||||
//#include <interface/lowlevel_keyboard_event_data.h>
|
||||
//#include <interface/win_hook_event_data.h>
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include "trace.h"
|
||||
#include <common/utils/winapi_error.h>
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include <common/utils/resources.h>
|
||||
#include <common/interop/shared_constants.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
HMODULE m_hModule;
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID /*lpReserved*/)
|
||||
BOOL APIENTRY DllMain(HMODULE /*hModule*/,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID /*lpReserved*/)
|
||||
{
|
||||
m_hModule = hModule;
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
Trace::RegisterProvider();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
break;
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
Trace::UnregisterProvider();
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -54,9 +54,17 @@ private:
|
||||
bool m_enabled = false;
|
||||
|
||||
// Hotkey to invoke the module
|
||||
Hotkey m_hotkey;
|
||||
|
||||
HANDLE m_hProcess;
|
||||
|
||||
// Time to wait for process to close after sending WM_CLOSE signal
|
||||
static const int MAX_WAIT_MILLISEC = 10000;
|
||||
|
||||
Hotkey m_hotkey;
|
||||
|
||||
// Handle to event used to invoke PowerOCR
|
||||
HANDLE m_hInvokeEvent;
|
||||
|
||||
void parse_hotkey(PowerToysSettings::PowerToyValues& settings)
|
||||
{
|
||||
auto settingsObject = settings.get_raw_json();
|
||||
@@ -123,11 +131,21 @@ private:
|
||||
}
|
||||
|
||||
// Load initial settings from the persisted values.
|
||||
void init_settings();
|
||||
|
||||
void terminate_process()
|
||||
void init_settings()
|
||||
{
|
||||
TerminateProcess(m_hProcess, 1);
|
||||
try
|
||||
{
|
||||
// Load and parse the settings file for this PowerToy.
|
||||
PowerToysSettings::PowerToyValues settings =
|
||||
PowerToysSettings::PowerToyValues::load_from_settings_file(get_key());
|
||||
|
||||
parse_hotkey(settings);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
Logger::warn(L"An exception occurred while loading the settings file");
|
||||
// Error while loading from the settings file. Let default values stay as they are.
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -135,6 +153,7 @@ public:
|
||||
MouseJump()
|
||||
{
|
||||
LoggerHelpers::init_logger(MODULE_NAME, L"ModuleInterface", LogSettings::mouseJumpLoggerName);
|
||||
m_hInvokeEvent = CreateDefaultEvent(CommonSharedConstants::MOUSE_JUMP_SHOW_PREVIEW_EVENT);
|
||||
init_settings();
|
||||
};
|
||||
|
||||
@@ -142,7 +161,6 @@ public:
|
||||
{
|
||||
if (m_enabled)
|
||||
{
|
||||
terminate_process();
|
||||
}
|
||||
m_enabled = false;
|
||||
}
|
||||
@@ -150,6 +168,7 @@ public:
|
||||
// Destroy the powertoy and free memory
|
||||
virtual void destroy() override
|
||||
{
|
||||
Logger::trace("MouseJump::destroy()");
|
||||
delete this;
|
||||
}
|
||||
|
||||
@@ -180,12 +199,14 @@ public:
|
||||
PowerToysSettings::Settings settings(hinstance, get_name());
|
||||
settings.set_description(MODULE_DESC);
|
||||
|
||||
settings.set_overview_link(L"https://aka.ms/PowerToysOverview_MouseUtilities/#mouse-jump");
|
||||
|
||||
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||
}
|
||||
|
||||
// Signal from the Settings editor to call a custom action.
|
||||
// This can be used to spawn more complex editors.
|
||||
virtual void call_custom_action(const wchar_t* action) override
|
||||
virtual void call_custom_action(const wchar_t* /*action*/) override
|
||||
{
|
||||
}
|
||||
|
||||
@@ -199,7 +220,6 @@ public:
|
||||
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
||||
|
||||
parse_hotkey(values);
|
||||
|
||||
values.save_to_settings_file();
|
||||
}
|
||||
catch (std::exception&)
|
||||
@@ -211,6 +231,9 @@ public:
|
||||
// Enable the powertoy
|
||||
virtual void enable()
|
||||
{
|
||||
Logger::trace("MouseJump::enable()");
|
||||
ResetEvent(m_hInvokeEvent);
|
||||
launch_process();
|
||||
m_enabled = true;
|
||||
Trace::EnableJumpTool(true);
|
||||
}
|
||||
@@ -218,33 +241,29 @@ public:
|
||||
// Disable the powertoy
|
||||
virtual void disable()
|
||||
{
|
||||
Logger::trace("MouseJump::disable()");
|
||||
if (m_enabled)
|
||||
{
|
||||
terminate_process();
|
||||
ResetEvent(m_hInvokeEvent);
|
||||
TerminateProcess(m_hProcess, 1);
|
||||
}
|
||||
|
||||
m_enabled = false;
|
||||
Trace::EnableJumpTool(false);
|
||||
}
|
||||
|
||||
// Returns if the powertoys is enabled
|
||||
virtual bool is_enabled() override
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
virtual bool on_hotkey(size_t /*hotkeyId*/) override
|
||||
{
|
||||
if (m_enabled)
|
||||
{
|
||||
Logger::trace(L"MouseJump hotkey pressed");
|
||||
Trace::InvokeJumpTool();
|
||||
if (is_process_running())
|
||||
if (!is_process_running())
|
||||
{
|
||||
terminate_process();
|
||||
launch_process();
|
||||
}
|
||||
launch_process();
|
||||
|
||||
SetEvent(m_hInvokeEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -268,6 +287,12 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Returns if the powertoys is enabled
|
||||
virtual bool is_enabled() override
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
// Returns whether the PowerToys should be enabled by default
|
||||
virtual bool is_enabled_by_default() const override
|
||||
{
|
||||
@@ -276,26 +301,6 @@ public:
|
||||
|
||||
};
|
||||
|
||||
// Load the settings file.
|
||||
void MouseJump::init_settings()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Load and parse the settings file for this PowerToy.
|
||||
PowerToysSettings::PowerToyValues settings =
|
||||
PowerToysSettings::PowerToyValues::load_from_settings_file(MouseJump::get_name());
|
||||
|
||||
parse_hotkey(settings);
|
||||
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
Logger::warn(L"An exception occurred while loading the settings file");
|
||||
// Error while loading from the settings file. Let default values stay as they are.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
{
|
||||
return new MouseJump();
|
||||
|
95
src/modules/MouseUtils/MouseJumpUI/Helpers/SettingsHelper.cs
Normal file
95
src/modules/MouseUtils/MouseJumpUI/Helpers/SettingsHelper.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Threading;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||
|
||||
namespace MouseJumpUI.Helpers;
|
||||
|
||||
internal class SettingsHelper
|
||||
{
|
||||
public SettingsHelper()
|
||||
{
|
||||
this.LockObject = new();
|
||||
this.CurrentSettings = this.LoadSettings();
|
||||
|
||||
// delay loading settings on change by some time to avoid file in use exception
|
||||
var throttledActionInvoker = new ThrottledActionInvoker();
|
||||
this.FileSystemWatcher = Helper.GetFileWatcher(
|
||||
moduleName: MouseJumpSettings.ModuleName,
|
||||
fileName: "settings.json",
|
||||
onChangedCallback: () => throttledActionInvoker.ScheduleAction(this.ReloadSettings, 250));
|
||||
}
|
||||
|
||||
private IFileSystemWatcher FileSystemWatcher
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
private object LockObject
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public MouseJumpSettings CurrentSettings
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
private MouseJumpSettings LoadSettings()
|
||||
{
|
||||
lock (this.LockObject)
|
||||
{
|
||||
{
|
||||
var settingsUtils = new SettingsUtils();
|
||||
|
||||
// set this to 1 to disable retries
|
||||
var remainingRetries = 5;
|
||||
|
||||
while (remainingRetries > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!settingsUtils.SettingsExists(MouseJumpSettings.ModuleName))
|
||||
{
|
||||
Logger.LogInfo("MouseJump settings.json was missing, creating a new one");
|
||||
var defaultSettings = new MouseJumpSettings();
|
||||
defaultSettings.Save(settingsUtils);
|
||||
}
|
||||
|
||||
var settings = settingsUtils.GetSettingsOrDefault<MouseJumpSettings>(MouseJumpSettings.ModuleName);
|
||||
return settings;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
Logger.LogError("Failed to read changed settings", ex);
|
||||
Thread.Sleep(250);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Failed to read changed settings", ex);
|
||||
Thread.Sleep(250);
|
||||
}
|
||||
|
||||
remainingRetries--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const string message = "Failed to read changed settings - ran out of retries";
|
||||
Logger.LogError(message);
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
public void ReloadSettings()
|
||||
{
|
||||
this.CurrentSettings = this.LoadSettings();
|
||||
}
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace MouseJumpUI.Helpers;
|
||||
|
||||
internal sealed class ThrottledActionInvoker
|
||||
{
|
||||
private readonly object _invokerLock = new();
|
||||
private readonly DispatcherTimer _timer;
|
||||
|
||||
private Action? _actionToRun;
|
||||
|
||||
public ThrottledActionInvoker()
|
||||
{
|
||||
_timer = new DispatcherTimer();
|
||||
_timer.Tick += Timer_Tick;
|
||||
}
|
||||
|
||||
public void ScheduleAction(Action action, int milliseconds)
|
||||
{
|
||||
lock (_invokerLock)
|
||||
{
|
||||
if (_timer.IsEnabled)
|
||||
{
|
||||
_timer.Stop();
|
||||
}
|
||||
|
||||
_actionToRun = action;
|
||||
_timer.Interval = new TimeSpan(0, 0, 0, 0, milliseconds);
|
||||
|
||||
_timer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
private void Timer_Tick(object? sender, EventArgs? e)
|
||||
{
|
||||
lock (_invokerLock)
|
||||
{
|
||||
_timer.Stop();
|
||||
_actionToRun?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
@@ -19,14 +19,13 @@ namespace MouseJumpUI;
|
||||
|
||||
internal partial class MainForm : Form
|
||||
{
|
||||
public MainForm(MouseJumpSettings settings)
|
||||
public MainForm(SettingsHelper settingsHelper)
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.Settings = settings ?? throw new ArgumentNullException(nameof(settings));
|
||||
this.ShowThumbnail();
|
||||
this.SettingsHelper = settingsHelper ?? throw new ArgumentNullException(nameof(settingsHelper));
|
||||
}
|
||||
|
||||
public MouseJumpSettings Settings
|
||||
public SettingsHelper SettingsHelper
|
||||
{
|
||||
get;
|
||||
}
|
||||
@@ -104,14 +103,8 @@ internal partial class MainForm : Form
|
||||
|
||||
private void MainForm_Deactivate(object sender, EventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
|
||||
if (this.Thumbnail.Image is not null)
|
||||
{
|
||||
var tmp = this.Thumbnail.Image;
|
||||
this.Thumbnail.Image = null;
|
||||
tmp.Dispose();
|
||||
}
|
||||
this.Hide();
|
||||
this.ClearPreview();
|
||||
}
|
||||
|
||||
private void Thumbnail_Click(object sender, EventArgs e)
|
||||
@@ -139,8 +132,11 @@ internal partial class MainForm : Form
|
||||
this.OnDeactivate(EventArgs.Empty);
|
||||
}
|
||||
|
||||
public void ShowThumbnail()
|
||||
public void ShowPreview()
|
||||
{
|
||||
// hide the form while we redraw it...
|
||||
this.Visible = false;
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
var layoutInfo = MainForm.GetLayoutInfo(this);
|
||||
LayoutHelper.PositionForm(this, layoutInfo.FormBounds);
|
||||
@@ -148,7 +144,7 @@ internal partial class MainForm : Form
|
||||
stopwatch.Stop();
|
||||
|
||||
// we have to activate the form to make sure the deactivate event fires
|
||||
Microsoft.PowerToys.Telemetry.PowerToysTelemetry.Log.WriteEvent(new Telemetry.MouseJumpTeleportCursorEvent());
|
||||
Microsoft.PowerToys.Telemetry.PowerToysTelemetry.Log.WriteEvent(new Telemetry.MouseJumpShowEvent());
|
||||
this.Activate();
|
||||
}
|
||||
|
||||
@@ -175,6 +171,9 @@ internal partial class MainForm : Form
|
||||
.Single(item => item.Screen.Handle == activatedScreenHandle.Value)
|
||||
.Index;
|
||||
|
||||
// avoid a race condition - cache the current settings in case they change
|
||||
var currentSettings = form.SettingsHelper.CurrentSettings;
|
||||
|
||||
var layoutConfig = new LayoutConfig(
|
||||
virtualScreenBounds: ScreenHelper.GetVirtualScreen(),
|
||||
screens: screens.Select(item => item.Screen).ToList(),
|
||||
@@ -182,13 +181,13 @@ internal partial class MainForm : Form
|
||||
activatedScreenIndex: activatedScreenIndex,
|
||||
activatedScreenNumber: activatedScreenIndex + 1,
|
||||
maximumFormSize: new(
|
||||
form.Settings.Properties.ThumbnailSize.Width,
|
||||
form.Settings.Properties.ThumbnailSize.Height),
|
||||
formPadding: new(
|
||||
form.panel1.Padding.Left,
|
||||
form.panel1.Padding.Top,
|
||||
form.panel1.Padding.Right,
|
||||
form.panel1.Padding.Bottom),
|
||||
currentSettings.Properties.ThumbnailSize.Width,
|
||||
currentSettings.Properties.ThumbnailSize.Height),
|
||||
/*
|
||||
don't read the panel padding values because they are affected by dpi scaling
|
||||
and can give wrong values when moving between monitors with different dpi scaling
|
||||
*/
|
||||
formPadding: new(5, 5, 5, 5),
|
||||
previewPadding: new(0));
|
||||
Logger.LogInfo(string.Join(
|
||||
'\n',
|
||||
@@ -295,10 +294,30 @@ internal partial class MainForm : Form
|
||||
stopwatch.Stop();
|
||||
}
|
||||
|
||||
private void ClearPreview()
|
||||
{
|
||||
if (this.Thumbnail.Image is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var tmp = this.Thumbnail.Image;
|
||||
this.Thumbnail.Image = null;
|
||||
tmp.Dispose();
|
||||
|
||||
// force preview image memory to be released, otherwise
|
||||
// all the disposed images can pile up without being GC'ed
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
private static void RefreshPreview(MainForm form)
|
||||
{
|
||||
if (!form.Visible)
|
||||
{
|
||||
// we seem to need to turn off topmost and then re-enable it again
|
||||
// when we show the form, otherwise it doesn't get shown topmost...
|
||||
form.TopMost = false;
|
||||
form.TopMost = true;
|
||||
form.Show();
|
||||
}
|
||||
|
||||
|
@@ -62,6 +62,7 @@
|
||||
<PackageReference Include="Microsoft.Windows.CsWinRT" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
|
||||
<ProjectReference Include="..\..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
|
||||
<ProjectReference Include="..\..\..\common\interop\PowerToys.Interop.vcxproj" />
|
||||
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
|
@@ -4,10 +4,16 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Threading;
|
||||
using Common.UI;
|
||||
using interop;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using MouseJumpUI.Helpers;
|
||||
|
||||
namespace MouseJumpUI;
|
||||
|
||||
@@ -17,7 +23,7 @@ internal static class Program
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
private static void Main()
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
Logger.InitializeLogger("\\MouseJump\\Logs");
|
||||
|
||||
@@ -38,10 +44,42 @@ internal static class Program
|
||||
return;
|
||||
}
|
||||
|
||||
var settings = Program.ReadSettings();
|
||||
var mainForm = new MainForm(settings);
|
||||
// validate command line arguments - we're expecting
|
||||
// a single argument containing the runner pid
|
||||
if ((args.Length != 1) || !int.TryParse(args[0], out var runnerPid))
|
||||
{
|
||||
var message = string.Join("\r\n", new[]
|
||||
{
|
||||
"Invalid command line arguments.",
|
||||
"Expected usage is:",
|
||||
string.Empty,
|
||||
$"{Assembly.GetExecutingAssembly().GetName().Name} <RunnerPid>",
|
||||
});
|
||||
Logger.LogInfo(message);
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
Application.Run(mainForm);
|
||||
Logger.LogInfo($"Mouse Jump started from the PowerToys Runner. Runner pid={runnerPid}");
|
||||
|
||||
var cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
RunnerHelper.WaitForPowerToysRunner(runnerPid, () =>
|
||||
{
|
||||
Logger.LogInfo("PowerToys Runner exited. Exiting Mouse Jump");
|
||||
cancellationTokenSource.Cancel();
|
||||
Application.Exit();
|
||||
});
|
||||
|
||||
var settingsHelper = new SettingsHelper();
|
||||
var mainForm = new MainForm(settingsHelper);
|
||||
|
||||
NativeEventWaiter.WaitForEventLoop(
|
||||
Constants.MouseJumpShowPreviewEvent(),
|
||||
mainForm.ShowPreview,
|
||||
Dispatcher.CurrentDispatcher,
|
||||
cancellationTokenSource.Token);
|
||||
|
||||
Application.Run();
|
||||
}
|
||||
|
||||
private static MouseJumpSettings ReadSettings()
|
||||
|
@@ -2,6 +2,8 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
|
||||
@@ -21,6 +23,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
Version = "1.0";
|
||||
}
|
||||
|
||||
public void Save(ISettingsUtils settingsUtils)
|
||||
{
|
||||
// Save settings to file
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
};
|
||||
|
||||
if (settingsUtils == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(settingsUtils));
|
||||
}
|
||||
|
||||
settingsUtils.SaveSettings(JsonSerializer.Serialize(this, options), ModuleName);
|
||||
}
|
||||
|
||||
public string GetModuleName()
|
||||
{
|
||||
return Name;
|
||||
|
Reference in New Issue
Block a user