mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-01 18:06:25 +01:00
Compare commits
4 Commits
jay/DarkMo
...
yuleng/cmd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
036127d900 | ||
|
|
75526b9580 | ||
|
|
ce4d8dc11e | ||
|
|
917da2e07e |
32
.github/actions/spell-check/expect.txt
vendored
32
.github/actions/spell-check/expect.txt
vendored
@@ -25,6 +25,8 @@ ADMINS
|
||||
adml
|
||||
admx
|
||||
advancedpaste
|
||||
advancedpasteui
|
||||
advancedpasteuishortcut
|
||||
advfirewall
|
||||
AFeature
|
||||
affordances
|
||||
@@ -40,6 +42,7 @@ ALLINPUT
|
||||
Allman
|
||||
Allmodule
|
||||
ALLOWUNDO
|
||||
allpc
|
||||
ALLVIEW
|
||||
ALPHATYPE
|
||||
AModifier
|
||||
@@ -629,6 +632,7 @@ HKCU
|
||||
hkey
|
||||
HKLM
|
||||
HKM
|
||||
hkmng
|
||||
HKPD
|
||||
HKU
|
||||
HMD
|
||||
@@ -646,7 +650,11 @@ Hostx
|
||||
hotfixes
|
||||
hotkeycontrol
|
||||
HOTKEYF
|
||||
hotkeylockmachine
|
||||
hotkeyreconnect
|
||||
hotkeys
|
||||
hotkeyswitch
|
||||
hotkeytoggleeasymouse
|
||||
hotlight
|
||||
hotspot
|
||||
HPAINTBUFFER
|
||||
@@ -704,9 +712,12 @@ IMAGERESIZERCONTEXTMENU
|
||||
IMAGERESIZEREXT
|
||||
imageresizerinput
|
||||
imageresizersettings
|
||||
imagetotext
|
||||
imagetotextshortcut
|
||||
imagingdevices
|
||||
ime
|
||||
imgflip
|
||||
inapp
|
||||
inbox
|
||||
INCONTACT
|
||||
Indo
|
||||
@@ -789,6 +800,7 @@ keyvault
|
||||
KILLFOCUS
|
||||
killrunner
|
||||
kmph
|
||||
kvp
|
||||
Kybd
|
||||
lastcodeanalysissucceeded
|
||||
LASTEXITCODE
|
||||
@@ -827,6 +839,7 @@ localappdata
|
||||
localpackage
|
||||
LOCALSYSTEM
|
||||
LOCATIONCHANGE
|
||||
LOCKMACHINE
|
||||
LOCKTYPE
|
||||
LOGFONT
|
||||
LOGFONTW
|
||||
@@ -912,6 +925,7 @@ MDL
|
||||
mdtext
|
||||
mdtxt
|
||||
mdwn
|
||||
measuretool
|
||||
meme
|
||||
memicmp
|
||||
MENUITEMINFO
|
||||
@@ -961,6 +975,7 @@ MOUSEHWHEEL
|
||||
MOUSEINPUT
|
||||
mousejump
|
||||
mousepointer
|
||||
mousepointercrosshairs
|
||||
mouseutils
|
||||
MOVESIZEEND
|
||||
MOVESIZESTART
|
||||
@@ -1161,6 +1176,18 @@ PARENTRELATIVEFORADDRESSBAR
|
||||
PARENTRELATIVEPARSING
|
||||
parray
|
||||
PARTIALCONFIRMATIONDIALOGTITLE
|
||||
pasteashtmlfile
|
||||
pasteashtmlfileshortcut
|
||||
pasteasjson
|
||||
pasteasjsonshortcut
|
||||
pasteasmarkdown
|
||||
pasteasmarkdownshortcut
|
||||
pasteasplaintext
|
||||
pasteasplaintextshortcut
|
||||
pasteaspngfile
|
||||
pasteaspngfileshortcut
|
||||
pasteastxtfile
|
||||
pasteastxtfileshortcut
|
||||
PATCOPY
|
||||
PATHMUSTEXIST
|
||||
PATINVERT
|
||||
@@ -1228,6 +1255,7 @@ Pomodoro
|
||||
Popups
|
||||
POPUPWINDOW
|
||||
POSITIONITEM
|
||||
powerocr
|
||||
POWERRENAMECONTEXTMENU
|
||||
powerrenameinput
|
||||
POWERRENAMETEST
|
||||
@@ -1368,6 +1396,7 @@ Removelnk
|
||||
renamable
|
||||
RENAMEONCOLLISION
|
||||
reparented
|
||||
reparenthotkey
|
||||
reparenting
|
||||
reportfileaccesses
|
||||
requery
|
||||
@@ -1687,6 +1716,7 @@ THH
|
||||
THICKFRAME
|
||||
THISCOMPONENT
|
||||
throughs
|
||||
thumbnailhotkey
|
||||
TILEDWINDOW
|
||||
TILLSON
|
||||
timedate
|
||||
@@ -1701,6 +1731,7 @@ tlb
|
||||
tlbimp
|
||||
tlc
|
||||
TNP
|
||||
TOGGLEEASYMOUSE
|
||||
Toolhelp
|
||||
toolkitconverters
|
||||
toolwindow
|
||||
@@ -1714,6 +1745,7 @@ tracelogging
|
||||
tracerpt
|
||||
trackbar
|
||||
trafficmanager
|
||||
transcodetomp
|
||||
transicc
|
||||
TRAYMOUSEMESSAGE
|
||||
triaging
|
||||
|
||||
@@ -5,13 +5,11 @@ MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "src\runner\runner.vcxproj", "{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73} = {031AC72E-FA28-4AB7-B690-6F7B9C28AA73}
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC} = {08E71C67-6A7E-4CA1-B04E-2FB336410BAC}
|
||||
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B} = {0B43679E-EDFA-4DA0-AD30-F4628B308B1B}
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB} = {0B593A6C-4143-4337-860E-DB5710FB87DB}
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E} = {17DA04DF-E393-4397-9CF0-84DABE11032E}
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA} = {217DF501-135C-4E38-BFC8-99D4821032EA}
|
||||
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34} = {2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166} = {38177D56-6AD1-4ADF-88C9-2843A7932166}
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227} = {48804216-2A0E-4168-A6D8-9CD068D14227}
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481} = {5CCC8468-DEC8-4D36-99D4-5C891BEBD481}
|
||||
@@ -790,12 +788,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Window
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.UnitTestBase", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.UnitTestsBase\Microsoft.CmdPal.Ext.UnitTestBase.csproj", "{00D8659C-2068-40B6-8B86-759CD6284BBB}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LightSwitch", "LightSwitch", "{5B201255-53C8-490B-A34F-01F05D48A477}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LightSwitchModuleInterface", "src\modules\LightSwitch\LightSwitchModuleInterface\LightSwitchModuleInterface.vcxproj", "{38177D56-6AD1-4ADF-88C9-2843A7932166}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LightModeService", "src\modules\LightSwitch\LightSwitchService\LightSwitchService.vcxproj", "{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
@@ -2858,22 +2850,6 @@ Global
|
||||
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|x64.ActiveCfg = Release|x64
|
||||
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|x64.Build.0 = Release|x64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Debug|x64.Build.0 = Debug|x64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Release|x64.ActiveCfg = Release|x64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Release|x64.Build.0 = Release|x64
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Debug|x64.Build.0 = Debug|x64
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Release|x64.ActiveCfg = Release|x64
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -3185,9 +3161,6 @@ Global
|
||||
{E816D7AF-4688-4ECB-97CC-3D8E798F3828} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{E816D7B0-4688-4ECB-97CC-3D8E798F3829} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{00D8659C-2068-40B6-8B86-759CD6284BBB} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{5B201255-53C8-490B-A34F-01F05D48A477} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166} = {5B201255-53C8-490B-A34F-01F05D48A477}
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC} = {5B201255-53C8-490B-A34F-01F05D48A477}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
||||
@@ -71,6 +71,41 @@ When the user changes settings in the UI:
|
||||
3. The runner calls the `set_config` function on the appropriate module
|
||||
4. The module parses the JSON and applies the new settings
|
||||
|
||||
# Shortcut Conflict Detection
|
||||
|
||||
Steps to enable conflict detection for a hotkey:
|
||||
|
||||
### 1. Implement module interface for hotkeys
|
||||
Ensure the module interface provides either `size_t get_hotkeys(Hotkey* hotkeys, size_t buffer_size)` or `std::optional<HotkeyEx> GetHotkeyEx()`.
|
||||
|
||||
- If not yet implemented, you need to add it so that it returns all hotkeys used by the module.
|
||||
- **Important**: The order of the returned hotkeys matters. This order is used as an index to uniquely identify each hotkey for conflict detection and lookup.
|
||||
- For reference, see: `src/modules/AdvancedPaste/AdvancedPasteModuleInterface/dllmain.cpp`
|
||||
|
||||
### 2. Implement IHotkeyConfig in the module settings (UI side)
|
||||
Make sure the module’s settings file inherits from `IHotkeyConfig` and implements `HotkeyAccessor[] GetAllHotkeyAccessors()`.
|
||||
|
||||
- This method should return all hotkeys used in the module.
|
||||
- **Important**: The order of the returned hotkeys must be consistent with step 1 (`get_hotkeys()` or `GetHotkeyEx()`).
|
||||
- For reference, see: `src/settings-ui/Settings.UI.Library/AdvancedPasteSettings.cs`
|
||||
- **_Note:_** `HotkeyAccessor` is a wrapper around HotkeySettings.
|
||||
It provides both `getter` and `setter` methods to read and update the corresponding hotkey.
|
||||
Additionally, each `HotkeyAccessor` requires a resource string that describes the purpose of the hotkey.
|
||||
This string is typically defined in: `src/settings-ui/Settings.UI/Strings/en-us/Resources.resw`
|
||||
|
||||
### 3. Update the module’s ViewModel
|
||||
The corresponding ViewModel should inherit from `PageViewModelBase` and implement `Dictionary<string, HotkeySettings[]> GetAllHotkeySettings()`.
|
||||
|
||||
- This method should return all hotkeys, maintaining the same order as in steps 1 and 2.
|
||||
- For reference, see: `src/settings-ui/Settings.UI/ViewModels/AdvancedPasteViewModel.cs`
|
||||
|
||||
### 4. Ensure the module’s Views call `OnPageLoaded()`
|
||||
Once the module’s view is loaded, make sure to invoke the ViewModel’s `OnPageLoaded()` method:
|
||||
```cs
|
||||
Loaded += (s, e) => ViewModel.OnPageLoaded();
|
||||
```
|
||||
- For reference, see: `src/settings-ui/Settings.UI/SettingsXAML/Views/AdvancedPaste.xaml.cs`
|
||||
|
||||
## Debugging Settings
|
||||
|
||||
To debug settings issues:
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<clear />
|
||||
<add key="PowerToysPublicDependencies" value="https://pkgs.dev.azure.com/shine-oss/PowerToys/_packaging/PowerToysPublicDependencies%40Local/nuget/v3/index.json" />
|
||||
<add key="PowerToysPublicDependencies" value="https://pkgs.dev.azure.com/shine-oss/PowerToys/_packaging/PowerToysPublicDependencies/nuget/v3/index.json" />
|
||||
</packageSources>
|
||||
<packageSourceMapping>
|
||||
<packageSource key="PowerToysPublicDependencies">
|
||||
<package pattern="*" />
|
||||
</packageSource>
|
||||
</packageSourceMapping>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace Common.UI
|
||||
Awake,
|
||||
ColorPicker,
|
||||
CmdNotFound,
|
||||
LightSwitch,
|
||||
FancyZones,
|
||||
FileLocksmith,
|
||||
Run,
|
||||
@@ -61,8 +60,6 @@ namespace Common.UI
|
||||
return "ColorPicker";
|
||||
case SettingsWindow.CmdNotFound:
|
||||
return "CmdNotFound";
|
||||
case SettingsWindow.LightSwitch:
|
||||
return "LightSwitch";
|
||||
case SettingsWindow.FancyZones:
|
||||
return "FancyZones";
|
||||
case SettingsWindow.FileLocksmith:
|
||||
|
||||
@@ -28,10 +28,6 @@ namespace winrt::PowerToys::GPOWrapper::implementation
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredCropAndLockEnabledValue());
|
||||
}
|
||||
GpoRuleConfigured GPOWrapper::GetConfiguredLightSwitchEnabledValue()
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredLightSwitchEnabledValue());
|
||||
}
|
||||
GpoRuleConfigured GPOWrapper::GetConfiguredFancyZonesEnabledValue()
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredFancyZonesEnabledValue());
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace winrt::PowerToys::GPOWrapper::implementation
|
||||
static GpoRuleConfigured GetConfiguredCmdPalEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredColorPickerEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredCropAndLockEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredLightSwitchEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredFancyZonesEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredFileLocksmithEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredSvgPreviewEnabledValue();
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace PowerToys
|
||||
static GpoRuleConfigured GetConfiguredCmdPalEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredColorPickerEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredCropAndLockEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredLightSwitchEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredFancyZonesEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredFileLocksmithEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredSvgPreviewEnabledValue();
|
||||
|
||||
@@ -12,7 +12,6 @@ namespace ManagedCommon
|
||||
ColorPicker,
|
||||
CmdPal,
|
||||
CropAndLock,
|
||||
LightSwitch,
|
||||
EnvironmentVariables,
|
||||
FancyZones,
|
||||
FileLocksmith,
|
||||
|
||||
@@ -81,7 +81,6 @@ struct LogSettings
|
||||
inline const static std::string workspacesSnapshotToolLoggerName = "workspaces-snapshot-tool";
|
||||
inline const static std::wstring workspacesSnapshotToolLogPath = L"workspaces-snapshot-tool-log.log";
|
||||
inline const static std::string zoomItLoggerName = "zoom-it";
|
||||
inline const static std::string lightSwitchLoggerName = "light-switch";
|
||||
inline const static int retention = 30;
|
||||
std::wstring logLevel;
|
||||
LogSettings();
|
||||
|
||||
@@ -257,10 +257,7 @@ inline HANDLE run_elevated(const std::wstring& file, const std::wstring& params,
|
||||
exec_info.nShow = SW_HIDE;
|
||||
}
|
||||
|
||||
// failing bc using "runas" with PowerToys.exe already running?
|
||||
BOOL result = ShellExecuteExW(&exec_info);
|
||||
|
||||
return result ? exec_info.hProcess : nullptr;
|
||||
return ShellExecuteExW(&exec_info) ? exec_info.hProcess : nullptr;
|
||||
}
|
||||
|
||||
// Run command as non-elevated user, returns true if succeeded, puts the process id into returnPid if returnPid != NULL
|
||||
|
||||
@@ -30,7 +30,6 @@ namespace powertoys_gpo
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_CMD_NOT_FOUND = L"ConfigureEnabledUtilityCmdNotFound";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_COLOR_PICKER = L"ConfigureEnabledUtilityColorPicker";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_CROP_AND_LOCK = L"ConfigureEnabledUtilityCropAndLock";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_LIGHT_SWITCH = L"ConfigureEnabledUtilityLightSwitch";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_FANCYZONES = L"ConfigureEnabledUtilityFancyZones";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_FILE_LOCKSMITH = L"ConfigureEnabledUtilityFileLocksmith";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_SVG_PREVIEW = L"ConfigureEnabledUtilityFileExplorerSVGPreview";
|
||||
@@ -296,11 +295,6 @@ namespace powertoys_gpo
|
||||
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_CROP_AND_LOCK);
|
||||
}
|
||||
|
||||
inline gpo_rule_configured_t getConfiguredLightSwitchEnabledValue()
|
||||
{
|
||||
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_LIGHT_SWITCH);
|
||||
}
|
||||
|
||||
inline gpo_rule_configured_t getConfiguredFancyZonesEnabledValue()
|
||||
{
|
||||
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_FANCYZONES);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <filesystem>
|
||||
#include <common/version/version.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/logger/logger_settings.h>
|
||||
|
||||
namespace LoggerHelpers
|
||||
{
|
||||
|
||||
@@ -137,16 +137,6 @@
|
||||
<decimal value="0" />
|
||||
</disabledValue>
|
||||
</policy>
|
||||
<policy name="ConfigureEnabledUtilityLightSwitch" class="Both" displayName="$(string.ConfigureEnabledUtilityLightSwitch)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityLightSwitch">
|
||||
<parentCategory ref="PowerToys" />
|
||||
<supportedOn ref="SUPPORTED_POWERTOYS_0_90_0" />
|
||||
<enabledValue>
|
||||
<decimal value="1" />
|
||||
</enabledValue>
|
||||
<disabledValue>
|
||||
<decimal value="0" />
|
||||
</disabledValue>
|
||||
</policy>
|
||||
<policy name="ConfigureEnabledUtilityEnvironmentVariables" class="Both" displayName="$(string.ConfigureEnabledUtilityEnvironmentVariables)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityEnvironmentVariables">
|
||||
<parentCategory ref="PowerToys" />
|
||||
<supportedOn ref="SUPPORTED_POWERTOYS_0_75_0" />
|
||||
|
||||
@@ -245,7 +245,6 @@ If you don't configure this policy, the user will be able to control the setting
|
||||
<string id="ConfigureEnabledUtilityCmdNotFound">Command Not Found: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityCmdPal">CmdPal: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityCropAndLock">Crop And Lock: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityLightSwitch">Light Switch: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityEnvironmentVariables">Environment Variables: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityFancyZones">FancyZones: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityFileLocksmith">File Locksmith: Configure enabled state</string>
|
||||
|
||||
@@ -112,7 +112,7 @@ private:
|
||||
return {};
|
||||
}
|
||||
|
||||
static Hotkey parse_single_hotkey(const winrt::Windows::Data::Json::JsonObject& jsonHotkeyObject)
|
||||
static Hotkey parse_single_hotkey(const winrt::Windows::Data::Json::JsonObject& jsonHotkeyObject, bool isShown = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -122,6 +122,7 @@ private:
|
||||
hotkey.shift = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_SHIFT);
|
||||
hotkey.ctrl = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_CTRL);
|
||||
hotkey.key = static_cast<unsigned char>(jsonHotkeyObject.GetNamedNumber(JSON_KEY_CODE));
|
||||
hotkey.isShown = isShown;
|
||||
return hotkey;
|
||||
}
|
||||
catch (...)
|
||||
@@ -231,8 +232,10 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
void process_additional_action(const winrt::hstring& actionName, const winrt::Windows::Data::Json::IJsonValue& actionValue)
|
||||
void process_additional_action(const winrt::hstring& actionName, const winrt::Windows::Data::Json::IJsonValue& actionValue, bool actionsGroupIsShown = true)
|
||||
{
|
||||
bool actionIsShown = true;
|
||||
|
||||
if (actionValue.ValueType() != winrt::Windows::Data::Json::JsonValueType::Object)
|
||||
{
|
||||
return;
|
||||
@@ -240,9 +243,9 @@ private:
|
||||
|
||||
const auto action = actionValue.GetObjectW();
|
||||
|
||||
if (!action.GetNamedBoolean(JSON_KEY_IS_SHOWN, false))
|
||||
if (!action.GetNamedBoolean(JSON_KEY_IS_SHOWN, false) || !actionsGroupIsShown)
|
||||
{
|
||||
return;
|
||||
actionIsShown = false;
|
||||
}
|
||||
|
||||
if (action.HasKey(JSON_KEY_SHORTCUT))
|
||||
@@ -250,7 +253,7 @@ private:
|
||||
const AdditionalAction additionalAction
|
||||
{
|
||||
actionName.c_str(),
|
||||
parse_single_hotkey(action.GetNamedObject(JSON_KEY_SHORTCUT))
|
||||
parse_single_hotkey(action.GetNamedObject(JSON_KEY_SHORTCUT), actionIsShown)
|
||||
};
|
||||
|
||||
m_additional_actions.push_back(additionalAction);
|
||||
@@ -259,12 +262,12 @@ private:
|
||||
{
|
||||
for (const auto& [subActionName, subAction] : action)
|
||||
{
|
||||
process_additional_action(subActionName, subAction);
|
||||
process_additional_action(subActionName, subAction, actionIsShown);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void read_settings(PowerToysSettings::PowerToyValues& settings)
|
||||
void read_settings(PowerToysSettings::PowerToyValues& settings)
|
||||
{
|
||||
const auto settingsObject = settings.get_raw_json();
|
||||
|
||||
@@ -317,9 +320,21 @@ private:
|
||||
{
|
||||
const auto additionalActions = propertiesObject.GetNamedObject(JSON_KEY_ADDITIONAL_ACTIONS);
|
||||
|
||||
for (const auto& [actionName, additionalAction] : additionalActions)
|
||||
// Define the expected order to ensure consistent hotkey ID assignment
|
||||
const std::vector<winrt::hstring> expectedOrder = {
|
||||
L"image-to-text",
|
||||
L"paste-as-file",
|
||||
L"transcode"
|
||||
};
|
||||
|
||||
// Process actions in the predefined order
|
||||
for (auto& actionKey : expectedOrder)
|
||||
{
|
||||
process_additional_action(actionName, additionalAction);
|
||||
if (additionalActions.HasKey(actionKey))
|
||||
{
|
||||
const auto actionValue = additionalActions.GetNamedValue(actionKey);
|
||||
process_additional_action(actionKey, actionValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,17 +346,14 @@ private:
|
||||
for (const auto& customAction : customActions)
|
||||
{
|
||||
const auto object = customAction.GetObjectW();
|
||||
bool actionIsShown = object.GetNamedBoolean(JSON_KEY_IS_SHOWN, false);
|
||||
|
||||
if (object.GetNamedBoolean(JSON_KEY_IS_SHOWN, false))
|
||||
{
|
||||
const CustomAction customActionData
|
||||
{
|
||||
static_cast<int>(object.GetNamedNumber(JSON_KEY_ID)),
|
||||
parse_single_hotkey(object.GetNamedObject(JSON_KEY_SHORTCUT))
|
||||
};
|
||||
const CustomAction customActionData{
|
||||
static_cast<int>(object.GetNamedNumber(JSON_KEY_ID)),
|
||||
parse_single_hotkey(object.GetNamedObject(JSON_KEY_SHORTCUT), actionIsShown)
|
||||
};
|
||||
|
||||
m_custom_actions.push_back(customActionData);
|
||||
}
|
||||
m_custom_actions.push_back(customActionData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 0,1,0,0
|
||||
PRODUCTVERSION 0,1,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Company Name"
|
||||
VALUE "FileDescription", "Light Switch Module"
|
||||
VALUE "FileVersion", "0.1.0.0"
|
||||
VALUE "InternalName", "Light Switch"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2019 Company Name"
|
||||
VALUE "OriginalFilename", "PowerToys.LightSwitchModuleInterface.dll"
|
||||
VALUE "ProductName", "Light Switch"
|
||||
VALUE "ProductVersion", "0.1.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.14.36127.28 d17.14
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LightSwitchModuleInterface", "LightSwitchModuleInterface.vcxproj", "{38177D56-6AD1-4ADF-88C9-2843A7932166}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Debug|x64.Build.0 = Debug|x64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Release|x64.ActiveCfg = Release|x64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {FAF634A3-0D98-4A45-B082-D93B59782572}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,229 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|ARM64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|ARM64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{38177d56-6ad1-4adf-88c9-2843a7932166}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>LightSwitchModuleInterface</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>LightSwitchModuleInterface</ProjectName>
|
||||
<TargetName>PowerToys.LightSwitchModuleInterface</TargetName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>
|
||||
$(SolutionDir)src\;
|
||||
$(SolutionDir)src\modules;
|
||||
$(SolutionDir)src\common\Telemetry;
|
||||
%(AdditionalIncludeDirectories)
|
||||
</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">$(CoreLibraryDependencies);%(AdditionalDependencies);advapi32.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="ThemeHelper.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ThemeHelper.cpp" />
|
||||
<ClCompile Include="trace.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="LightSwitchModuleInterface.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj">
|
||||
<Project>{4aed67b6-55fd-486f-b917-e543dee2cb3c}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -1,50 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<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>
|
||||
<ClCompile Include="ThemeHelper.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ThemeHelper.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{bbf22ac8-46f8-4206-b44b-9c3897e99ce5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{530ed784-9a70-46a0-8fb6-20d5dee4f7d3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{da1cb871-86d3-414c-adf5-a7e9f2077d2f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="LightSwitchModuleInterface.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,81 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include <windows.h>
|
||||
#include "ThemeHelper.h"
|
||||
|
||||
// Controls changing the themes.
|
||||
|
||||
void SetAppsTheme(bool mode)
|
||||
{
|
||||
HKEY hKey;
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
0,
|
||||
KEY_SET_VALUE,
|
||||
&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD value = mode;
|
||||
RegSetValueEx(hKey, L"AppsUseLightTheme", 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(value));
|
||||
RegCloseKey(hKey);
|
||||
|
||||
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast<LPARAM>(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||
|
||||
SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void SetSystemTheme(bool mode)
|
||||
{
|
||||
HKEY hKey;
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
0,
|
||||
KEY_SET_VALUE,
|
||||
&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD value = mode;
|
||||
RegSetValueEx(hKey, L"SystemUsesLightTheme", 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(value));
|
||||
RegCloseKey(hKey);
|
||||
|
||||
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast<LPARAM>(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||
|
||||
SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool GetCurrentSystemTheme()
|
||||
{
|
||||
HKEY hKey;
|
||||
DWORD value = 1; // default = light
|
||||
DWORD size = sizeof(value);
|
||||
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
0,
|
||||
KEY_READ,
|
||||
&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
RegQueryValueEx(hKey, L"SystemUsesLightTheme", nullptr, nullptr, reinterpret_cast<LPBYTE>(&value), &size);
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
return value == 0; // 0 = dark, 1 = light
|
||||
}
|
||||
|
||||
bool GetCurrentAppsTheme()
|
||||
{
|
||||
HKEY hKey;
|
||||
DWORD value = 1;
|
||||
DWORD size = sizeof(value);
|
||||
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
0,
|
||||
KEY_READ,
|
||||
&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
RegQueryValueEx(hKey, L"SystemUsesLightTheme", nullptr, nullptr, reinterpret_cast<LPBYTE>(&value), &size);
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
return value == 0;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
void SetSystemTheme(bool dark);
|
||||
void SetAppsTheme(bool dark);
|
||||
bool GetCurrentSystemTheme();
|
||||
bool GetCurrentAppsTheme();
|
||||
@@ -1,669 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include <interface/powertoy_module_interface.h>
|
||||
#include "trace.h"
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include "ThemeHelper.h"
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
namespace
|
||||
{
|
||||
const wchar_t JSON_KEY_PROPERTIES[] = L"properties";
|
||||
const wchar_t JSON_KEY_WIN[] = L"win";
|
||||
const wchar_t JSON_KEY_ALT[] = L"alt";
|
||||
const wchar_t JSON_KEY_CTRL[] = L"ctrl";
|
||||
const wchar_t JSON_KEY_SHIFT[] = L"shift";
|
||||
const wchar_t JSON_KEY_CODE[] = L"code";
|
||||
const wchar_t JSON_KEY_FORCE_LIGHT_HOTKEY[] = L"force-light-mode-hotkey";
|
||||
const wchar_t JSON_KEY_FORCE_DARK_HOTKEY[] = L"force-dark-mode-hotkey";
|
||||
const wchar_t JSON_KEY_VALUE[] = L"value";
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
Trace::RegisterProvider();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
Trace::UnregisterProvider();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// The PowerToy name that will be shown in the settings.
|
||||
const static wchar_t* MODULE_NAME = L"LightSwitch";
|
||||
// Add a description that will we shown in the module settings page.
|
||||
const static wchar_t* MODULE_DESC = L"This is a module that allows you to control light/dark theming via set times, sun rise, or directly invoking the change.";
|
||||
|
||||
enum class ScheduleMode
|
||||
{
|
||||
FixedHours,
|
||||
SunsetToSunriseGeo,
|
||||
SunsetToSunriseUser
|
||||
// add more later
|
||||
};
|
||||
|
||||
inline std::wstring ToString(ScheduleMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case ScheduleMode::SunsetToSunriseGeo:
|
||||
return L"SunsetToSunriseGeo";
|
||||
case ScheduleMode::SunsetToSunriseUser:
|
||||
return L"SunsetToSunriseUser";
|
||||
case ScheduleMode::FixedHours:
|
||||
default:
|
||||
return L"FixedHours";
|
||||
}
|
||||
}
|
||||
|
||||
inline ScheduleMode FromString(const std::wstring& str)
|
||||
{
|
||||
if (str == L"SunsetToSunriseGeo")
|
||||
return ScheduleMode::SunsetToSunriseGeo;
|
||||
if (str == L"SunsetToSunriseUser")
|
||||
return ScheduleMode::SunsetToSunriseUser;
|
||||
return ScheduleMode::FixedHours;
|
||||
}
|
||||
|
||||
// These are the properties shown in the Settings page.
|
||||
struct ModuleSettings
|
||||
{
|
||||
bool m_changeSystem = true;
|
||||
bool m_changeApps = true;
|
||||
ScheduleMode m_scheduleMode = ScheduleMode::FixedHours;
|
||||
int m_lightTime = 480;
|
||||
int m_darkTime = 1200;
|
||||
int m_offset = 0;
|
||||
std::wstring m_latitude = L"0.0";
|
||||
std::wstring m_longitude = L"0.0";
|
||||
} g_settings;
|
||||
|
||||
// Implement the PowerToy Module Interface and all the required methods.
|
||||
class LightSwitchInterface : public PowertoyModuleIface
|
||||
{
|
||||
private:
|
||||
// The PowerToy state.
|
||||
bool m_enabled = false;
|
||||
|
||||
HANDLE m_process{ nullptr };
|
||||
HANDLE m_force_light_event_handle;
|
||||
HANDLE m_force_dark_event_handle;
|
||||
|
||||
static const constexpr int NUM_DEFAULT_HOTKEYS = 4;
|
||||
|
||||
Hotkey m_force_light_mode_hotkey = { .win = true, .ctrl = true, .shift = true, .alt = false, .key = 'L' };
|
||||
Hotkey m_force_dark_mode_hotkey = { .win = true, .ctrl = true, .shift = true, .alt = false, .key = 'D' };
|
||||
|
||||
// Load initial settings from the persisted values.
|
||||
void init_settings();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
LightSwitchInterface()
|
||||
{
|
||||
LoggerHelpers::init_logger(L"LightSwitch", L"ModuleInterface", LogSettings::lightSwitchLoggerName);
|
||||
|
||||
m_force_light_event_handle = CreateDefaultEvent(L"POWEROYS_LIGHTSWITCH_FORCE_LIGHT");
|
||||
m_force_dark_event_handle = CreateDefaultEvent(L"POWEROYS_LIGHTSWITCH_FORCE_DARK");
|
||||
|
||||
init_settings();
|
||||
};
|
||||
|
||||
virtual const wchar_t* get_key() override
|
||||
{
|
||||
return L"LightSwitch"; // your unique key string
|
||||
}
|
||||
|
||||
// Destroy the powertoy and free memory
|
||||
virtual void destroy() override
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
// Return the display name of the powertoy, this will be cached by the runner
|
||||
virtual const wchar_t* get_name() override
|
||||
{
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
// Return the configured status for the gpo policy for the module
|
||||
virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override
|
||||
{
|
||||
return powertoys_gpo::getConfiguredLightSwitchEnabledValue();
|
||||
}
|
||||
|
||||
// Return array of the names of all events that this powertoy listens for, with
|
||||
// nullptr as the last element of the array. Nullptr can also be retured for empty
|
||||
// list.
|
||||
//virtual const wchar_t** get_events() override
|
||||
//{
|
||||
// static const wchar_t* events[] = { nullptr };
|
||||
// // Available events:
|
||||
// // - ll_keyboard
|
||||
// // - win_hook_event
|
||||
// //
|
||||
// // static const wchar_t* events[] = { ll_keyboard,
|
||||
// // win_hook_event,
|
||||
// // nullptr };
|
||||
|
||||
// return events;
|
||||
//}
|
||||
|
||||
// Return JSON with the configuration options.
|
||||
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
|
||||
{
|
||||
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||
|
||||
// Create a Settings object with your module name
|
||||
PowerToysSettings::Settings settings(hinstance, get_name());
|
||||
settings.set_description(MODULE_DESC);
|
||||
settings.set_overview_link(L"https://aka.ms/powertoys");
|
||||
|
||||
// Boolean toggles
|
||||
settings.add_bool_toggle(
|
||||
L"changeSystem",
|
||||
L"Change System Theme",
|
||||
g_settings.m_changeSystem);
|
||||
|
||||
settings.add_bool_toggle(
|
||||
L"changeApps",
|
||||
L"Change Apps Theme",
|
||||
g_settings.m_changeApps);
|
||||
|
||||
settings.add_choice_group(
|
||||
L"scheduleMode",
|
||||
L"Theme schedule mode",
|
||||
ToString(g_settings.m_scheduleMode),
|
||||
{ { L"FixedHours", L"Set hours manually" },
|
||||
{ L"SunsetToSunriseGeo", L"Use sunrise/sunset times (Geolocation)" },
|
||||
{ L"SunsetToSunriseUser", L"Use sunrise/sunset times (User selected)" } });
|
||||
|
||||
// Integer spinners (for time in minutes since midnight)
|
||||
settings.add_int_spinner(
|
||||
L"lightTime",
|
||||
L"Time to switch to light theme (minutes after midnight).",
|
||||
g_settings.m_lightTime,
|
||||
0,
|
||||
1439,
|
||||
1);
|
||||
|
||||
settings.add_int_spinner(
|
||||
L"darkTime",
|
||||
L"Time to switch to dark theme (minutes after midnight).",
|
||||
g_settings.m_darkTime,
|
||||
0,
|
||||
1439,
|
||||
1);
|
||||
|
||||
settings.add_int_spinner(
|
||||
L"offset",
|
||||
L"Time to offset turning on your light/dark themes.",
|
||||
g_settings.m_offset,
|
||||
0,
|
||||
1439,
|
||||
1);
|
||||
|
||||
// Strings for latitude and longitude
|
||||
settings.add_string(
|
||||
L"latitude",
|
||||
L"Your latitude in decimal degrees (e.g. 39.95).",
|
||||
g_settings.m_latitude);
|
||||
|
||||
settings.add_string(
|
||||
L"longitude",
|
||||
L"Your longitude in decimal degrees (e.g. -75.16).",
|
||||
g_settings.m_longitude);
|
||||
|
||||
// One-shot actions (buttons)
|
||||
settings.add_custom_action(
|
||||
L"forceLight",
|
||||
L"Switch immediately to light theme",
|
||||
L"Force Light",
|
||||
L"{}");
|
||||
|
||||
settings.add_custom_action(
|
||||
L"forceDark",
|
||||
L"Switch immediately to dark theme",
|
||||
L"Force Dark",
|
||||
L"{}");
|
||||
|
||||
PowerToysSettings::HotkeyObject lm_hk = PowerToysSettings::HotkeyObject::from_settings(
|
||||
m_force_light_mode_hotkey.win,
|
||||
m_force_light_mode_hotkey.ctrl,
|
||||
m_force_light_mode_hotkey.alt,
|
||||
m_force_light_mode_hotkey.shift,
|
||||
m_force_light_mode_hotkey.key);
|
||||
|
||||
settings.add_hotkey(
|
||||
L"force-light-hotkey",
|
||||
L"Shortcut to force light theme immediately",
|
||||
lm_hk);
|
||||
|
||||
PowerToysSettings::HotkeyObject dm_hk = PowerToysSettings::HotkeyObject::from_settings(
|
||||
m_force_dark_mode_hotkey.win,
|
||||
m_force_dark_mode_hotkey.ctrl,
|
||||
m_force_dark_mode_hotkey.alt,
|
||||
m_force_dark_mode_hotkey.shift,
|
||||
m_force_dark_mode_hotkey.key);
|
||||
|
||||
settings.add_hotkey(
|
||||
L"force-dark-hotkey",
|
||||
L"Shortcut to force dark theme immediately",
|
||||
dm_hk);
|
||||
|
||||
// Serialize to buffer for the PowerToys runner
|
||||
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.
|
||||
void call_custom_action(const wchar_t* action) override
|
||||
{
|
||||
try
|
||||
{
|
||||
auto action_object = PowerToysSettings::CustomActionObject::from_json_string(action);
|
||||
|
||||
if (action_object.get_name() == L"forceLight")
|
||||
{
|
||||
Logger::info(L"[Light Switch] Custom action triggered: Force Light");
|
||||
SetSystemTheme(true);
|
||||
SetAppsTheme(true);
|
||||
}
|
||||
else if (action_object.get_name() == L"forceDark")
|
||||
{
|
||||
Logger::info(L"[Light Switch] Custom action triggered: Force Dark");
|
||||
SetSystemTheme(false);
|
||||
SetAppsTheme(false);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"[Light Switch] Invalid custom action JSON");
|
||||
}
|
||||
}
|
||||
|
||||
// Called by the runner to pass the updated settings values as a serialized JSON.
|
||||
virtual void set_config(const wchar_t* config) override
|
||||
{
|
||||
try
|
||||
{
|
||||
auto values = PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
||||
|
||||
parse_hotkey(values);
|
||||
|
||||
if (auto v = values.get_bool_value(L"changeSystem"))
|
||||
{
|
||||
g_settings.m_changeSystem = *v;
|
||||
}
|
||||
|
||||
if (auto v = values.get_bool_value(L"changeApps"))
|
||||
{
|
||||
g_settings.m_changeApps = *v;
|
||||
}
|
||||
|
||||
if (auto v = values.get_string_value(L"scheduleMode"))
|
||||
{
|
||||
g_settings.m_scheduleMode = FromString(*v);
|
||||
}
|
||||
|
||||
if (auto v = values.get_int_value(L"lightTime"))
|
||||
{
|
||||
g_settings.m_lightTime = *v;
|
||||
}
|
||||
|
||||
if (auto v = values.get_int_value(L"darkTime"))
|
||||
{
|
||||
g_settings.m_darkTime = *v;
|
||||
}
|
||||
|
||||
if (auto v = values.get_int_value(L"offset"))
|
||||
{
|
||||
g_settings.m_offset = *v;
|
||||
}
|
||||
|
||||
if (auto v = values.get_string_value(L"latitude"))
|
||||
{
|
||||
g_settings.m_latitude = *v;
|
||||
}
|
||||
if (auto v = values.get_string_value(L"longitude"))
|
||||
{
|
||||
g_settings.m_longitude = *v;
|
||||
}
|
||||
|
||||
|
||||
values.save_to_settings_file();
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
Logger::error("[Light Switch] set_config: Failed to parse or apply config.");
|
||||
}
|
||||
}
|
||||
|
||||
virtual void enable()
|
||||
{
|
||||
m_enabled = true;
|
||||
Logger::info(L"Enabling Light Switch module...");
|
||||
|
||||
unsigned long powertoys_pid = GetCurrentProcessId();
|
||||
std::wstring args = L"--pid " + std::to_wstring(powertoys_pid);
|
||||
std::wstring exe_name = L"LightSwitchService\\PowerToys.LightSwitchService.exe";
|
||||
|
||||
// Resolve the executable path
|
||||
std::wstring resolved_path(MAX_PATH, L'\0');
|
||||
DWORD result = SearchPathW(
|
||||
nullptr,
|
||||
exe_name.c_str(),
|
||||
nullptr,
|
||||
static_cast<DWORD>(resolved_path.size()),
|
||||
resolved_path.data(),
|
||||
nullptr);
|
||||
|
||||
if (result == 0 || result >= resolved_path.size())
|
||||
{
|
||||
Logger::error(L"Failed to locate Light Switch executable: '{}'", exe_name);
|
||||
return;
|
||||
}
|
||||
|
||||
resolved_path.resize(result);
|
||||
Logger::debug(L"Resolved executable path: {}", resolved_path);
|
||||
|
||||
std::wstring command_line = L"\"" + resolved_path + L"\" " + args;
|
||||
|
||||
STARTUPINFO si = { sizeof(si) };
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
if (!CreateProcessW(
|
||||
resolved_path.c_str(), // lpApplicationName
|
||||
command_line.data(), // lpCommandLine (must be mutable)
|
||||
nullptr,
|
||||
nullptr,
|
||||
TRUE,
|
||||
0,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&si,
|
||||
&pi))
|
||||
{
|
||||
Logger::error(L"Failed to launch Light Switch process. {}", get_last_error_or_default(GetLastError()));
|
||||
return;
|
||||
}
|
||||
|
||||
Logger::info(L"Light Switch process launched successfully (PID: {}).", pi.dwProcessId);
|
||||
m_process = pi.hProcess;
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
|
||||
// Disable the powertoy
|
||||
virtual void disable()
|
||||
{
|
||||
Logger::info("Light Switch disabling");
|
||||
m_enabled = false;
|
||||
|
||||
if (m_process)
|
||||
{
|
||||
// Try waiting briefly to allow graceful exit, if needed
|
||||
constexpr DWORD timeout_ms = 1500;
|
||||
DWORD result = WaitForSingleObject(m_process, timeout_ms);
|
||||
|
||||
if (result == WAIT_TIMEOUT)
|
||||
{
|
||||
// Force kill if it didn<64>t exit in time
|
||||
Logger::warn("Light Switch: Process didn't exit in time. Forcing termination.");
|
||||
TerminateProcess(m_process, 0);
|
||||
}
|
||||
|
||||
// Always clean up the handle
|
||||
CloseHandle(m_process);
|
||||
m_process = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns if the powertoys is enabled
|
||||
virtual bool is_enabled() override
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
void parse_hotkey(PowerToysSettings::PowerToyValues& settings)
|
||||
{
|
||||
auto settingsObject = settings.get_raw_json();
|
||||
if (settingsObject.GetView().Size())
|
||||
{
|
||||
try
|
||||
{
|
||||
Hotkey _temp_force_light;
|
||||
auto jsonHotkeyObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_FORCE_LIGHT_HOTKEY).GetNamedObject(JSON_KEY_VALUE);
|
||||
_temp_force_light.win = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_WIN);
|
||||
_temp_force_light.alt = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_ALT);
|
||||
_temp_force_light.shift = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_SHIFT);
|
||||
_temp_force_light.ctrl = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_CTRL);
|
||||
_temp_force_light.key = static_cast<unsigned char>(jsonHotkeyObject.GetNamedNumber(JSON_KEY_CODE));
|
||||
m_force_light_mode_hotkey = _temp_force_light;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error("Failed to initialize Light Switch force light mode shortcut from settings. Value will keep unchanged.");
|
||||
}
|
||||
try
|
||||
{
|
||||
Hotkey _temp_force_dark;
|
||||
auto jsonHotkeyObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_FORCE_DARK_HOTKEY).GetNamedObject(JSON_KEY_VALUE);
|
||||
_temp_force_dark.win = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_WIN);
|
||||
_temp_force_dark.alt = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_ALT);
|
||||
_temp_force_dark.shift = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_SHIFT);
|
||||
_temp_force_dark.ctrl = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_CTRL);
|
||||
_temp_force_dark.key = static_cast<unsigned char>(jsonHotkeyObject.GetNamedNumber(JSON_KEY_CODE));
|
||||
m_force_dark_mode_hotkey = _temp_force_dark;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error("Failed to initialize Light Switch force dark mode shortcut from settings. Value will keep unchanged.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info("Light Switch settings are empty");
|
||||
}
|
||||
}
|
||||
|
||||
virtual size_t get_hotkeys(Hotkey* hotkeys, size_t buffer_size) override
|
||||
{
|
||||
if (hotkeys && buffer_size >= 2)
|
||||
{
|
||||
hotkeys[0] = m_force_light_mode_hotkey;
|
||||
hotkeys[1] = m_force_dark_mode_hotkey;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
virtual bool on_hotkey(size_t hotkeyId) override
|
||||
{
|
||||
if (m_enabled)
|
||||
{
|
||||
Logger::trace(L"Light Switch hotkey pressed");
|
||||
if (!is_process_running())
|
||||
{
|
||||
enable();
|
||||
}
|
||||
|
||||
if (hotkeyId == 0)
|
||||
{
|
||||
Logger::info(L"[Light Switch] Hotkey triggered: Force Light");
|
||||
SetSystemTheme(true);
|
||||
SetAppsTheme(true);
|
||||
}
|
||||
else if (hotkeyId == 1)
|
||||
{
|
||||
Logger::info(L"[Light Switch] Hotkey triggered: Force Dark");
|
||||
SetSystemTheme(false);
|
||||
SetAppsTheme(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_process_running()
|
||||
{
|
||||
return WaitForSingleObject(m_process, 0) == WAIT_TIMEOUT;
|
||||
}
|
||||
|
||||
// Handle incoming event, data is event-specific
|
||||
//virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override
|
||||
//{
|
||||
// if (wcscmp(name, ll_keyboard) == 0)
|
||||
// {
|
||||
// auto& event = *(reinterpret_cast<LowlevelKeyboardEvent*>(data));
|
||||
// // Return 1 if the keypress is to be suppressed (not forwarded to Windows),
|
||||
// // otherwise return 0.
|
||||
// return 0;
|
||||
// }
|
||||
// else if (wcscmp(name, win_hook_event) == 0)
|
||||
// {
|
||||
// auto& event = *(reinterpret_cast<WinHookEvent*>(data));
|
||||
// // Return value is ignored
|
||||
// return 0;
|
||||
// }
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
//// This methods are part of an experimental features not fully supported yet
|
||||
//virtual void register_system_menu_helper(PowertoySystemMenuIface* helper) override
|
||||
//{
|
||||
//}
|
||||
|
||||
//virtual void signal_system_menu_action(const wchar_t* name) override
|
||||
//{
|
||||
//}
|
||||
};
|
||||
|
||||
std::wstring utf8_to_wstring(const std::string& str)
|
||||
{
|
||||
if (str.empty())
|
||||
return std::wstring();
|
||||
|
||||
int size_needed = MultiByteToWideChar(
|
||||
CP_UTF8,
|
||||
0,
|
||||
str.c_str(),
|
||||
static_cast<int>(str.size()),
|
||||
nullptr,
|
||||
0);
|
||||
|
||||
std::wstring wstr(size_needed, 0);
|
||||
|
||||
MultiByteToWideChar(
|
||||
CP_UTF8,
|
||||
0,
|
||||
str.c_str(),
|
||||
static_cast<int>(str.size()),
|
||||
&wstr[0],
|
||||
size_needed);
|
||||
|
||||
return wstr;
|
||||
}
|
||||
|
||||
// Load the settings file.
|
||||
void LightSwitchInterface::init_settings()
|
||||
{
|
||||
Logger::info(L"[Light Switch] init_settings: starting to load settings for module");
|
||||
|
||||
try
|
||||
{
|
||||
PowerToysSettings::PowerToyValues settings =
|
||||
PowerToysSettings::PowerToyValues::load_from_settings_file(get_name());
|
||||
|
||||
parse_hotkey(settings);
|
||||
|
||||
if (auto v = settings.get_bool_value(L"changeSystem"))
|
||||
g_settings.m_changeSystem = *v;
|
||||
if (auto v = settings.get_bool_value(L"changeApps"))
|
||||
g_settings.m_changeApps = *v;
|
||||
if (auto v = settings.get_string_value(L"scheduleMode"))
|
||||
g_settings.m_scheduleMode = FromString(*v);
|
||||
if (auto v = settings.get_int_value(L"lightTime"))
|
||||
g_settings.m_lightTime = *v;
|
||||
if (auto v = settings.get_int_value(L"darkTime"))
|
||||
g_settings.m_darkTime = *v;
|
||||
if (auto v = settings.get_int_value(L"offset"))
|
||||
g_settings.m_offset = *v;
|
||||
if (auto v = settings.get_string_value(L"latitude"))
|
||||
g_settings.m_latitude = *v;
|
||||
if (auto v = settings.get_string_value(L"longitude"))
|
||||
g_settings.m_longitude = *v;
|
||||
|
||||
Logger::info(L"[Light Switch] init_settings: loaded successfully");
|
||||
}
|
||||
catch (const winrt::hresult_error& e)
|
||||
{
|
||||
Logger::error(L"[Light Switch] init_settings: hresult_error 0x{:08X} - {}", e.code(), e.message().c_str());
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::wstring whatStr = utf8_to_wstring(e.what());
|
||||
Logger::error(L"[Light Switch] init_settings: std::exception - {}", whatStr);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"[Light Switch] init_settings: unknown exception while loading settings");
|
||||
}
|
||||
}
|
||||
|
||||
// This method of saving the module settings is only required if you need to do any
|
||||
// custom processing of the settings before saving them to disk.
|
||||
//void $projectname$::save_settings() {
|
||||
// try {
|
||||
// // Create a PowerToyValues object for this PowerToy
|
||||
// PowerToysSettings::PowerToyValues values(get_name());
|
||||
//
|
||||
// // Save a bool property.
|
||||
// //values.add_property(
|
||||
// // L"bool_toggle_1", // property name
|
||||
// // g_settings.bool_prop // property value
|
||||
// // g_settings.bool_prop // property value
|
||||
// //);
|
||||
//
|
||||
// // Save an int property.
|
||||
// //values.add_property(
|
||||
// // L"int_spinner_1", // property name
|
||||
// // g_settings.int_prop // property value
|
||||
// //);
|
||||
//
|
||||
// // Save a string property.
|
||||
// //values.add_property(
|
||||
// // L"string_text_1", // property name
|
||||
// // g_settings.string_prop // property value
|
||||
// );
|
||||
//
|
||||
// // Save a color property.
|
||||
// //values.add_property(
|
||||
// // L"color_picker_1", // property name
|
||||
// // g_settings.color_prop // property value
|
||||
// //);
|
||||
//
|
||||
// // Save the PowerToyValues JSON to the power toy settings file.
|
||||
// values.save_to_settings_file();
|
||||
// }
|
||||
// catch (std::exception ex) {
|
||||
// // Couldn't save the settings.
|
||||
// }
|
||||
//}
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
{
|
||||
return new LightSwitchInterface();
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "pch.h"
|
||||
#pragma comment(lib, "windowsapp")
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/utils/gpo.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
#include <shlwapi.h>
|
||||
#include <shellapi.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.System.h>
|
||||
#include <winrt/Windows.Globalization.h>
|
||||
#include <winrt/Windows.ApplicationModel.h>
|
||||
#include <winrt/Windows.ApplicationModel.Core.h>
|
||||
@@ -1,30 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "trace.h"
|
||||
#include <TraceLoggingProvider.h>
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
g_hProvider,
|
||||
"Microsoft.PowerToys",
|
||||
// {38e8889b-9731-53f5-e901-e8a7c1753074}
|
||||
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
|
||||
TraceLoggingOptionProjectTelemetry());
|
||||
|
||||
void Trace::RegisterProvider()
|
||||
{
|
||||
TraceLoggingRegister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::UnregisterProvider()
|
||||
{
|
||||
TraceLoggingUnregister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::MyEvent()
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"PowerToyName_MyEvent",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <TraceLoggingActivity.h>
|
||||
#include <common/telemetry/ProjectTelemetry.h>
|
||||
|
||||
TRACELOGGING_DECLARE_PROVIDER(g_hProvider);
|
||||
|
||||
class Trace
|
||||
{
|
||||
public:
|
||||
static void RegisterProvider();
|
||||
static void UnregisterProvider();
|
||||
static void MyEvent();
|
||||
};
|
||||
@@ -1,258 +0,0 @@
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include "ThemeScheduler.h"
|
||||
#include "ThemeHelper.h"
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <LightSwitchSettings.h>
|
||||
#include <common/utils/gpo.h>
|
||||
|
||||
// Global service variables
|
||||
SERVICE_STATUS g_ServiceStatus = {};
|
||||
SERVICE_STATUS_HANDLE g_StatusHandle = nullptr;
|
||||
HANDLE g_ServiceStopEvent = nullptr;
|
||||
|
||||
// Forward declarations of service functions (we<77>ll define them later)
|
||||
VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
|
||||
VOID WINAPI ServiceCtrlHandler(DWORD dwCtrl);
|
||||
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam);
|
||||
|
||||
// Entry point for the executable
|
||||
int _tmain(int argc, TCHAR* argv[])
|
||||
{
|
||||
// Parse args
|
||||
DWORD parentPid = 0;
|
||||
bool debug = false;
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (_tcscmp(argv[i], _T("--debug")) == 0)
|
||||
debug = true;
|
||||
else if (_tcscmp(argv[i], _T("--pid")) == 0 && i + 1 < argc)
|
||||
parentPid = _tstoi(argv[++i]);
|
||||
}
|
||||
|
||||
if (debug)
|
||||
{
|
||||
// Create a console window for debug output
|
||||
AllocConsole();
|
||||
FILE* f;
|
||||
freopen_s(&f, "CONOUT$", "w", stdout);
|
||||
freopen_s(&f, "CONOUT$", "w", stderr);
|
||||
|
||||
// Optional: set a title so you can find it easily
|
||||
SetConsoleTitle(L"LightSwitchService Debug");
|
||||
|
||||
// Console mode (debug)
|
||||
g_ServiceStopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
ServiceWorkerThread(reinterpret_cast<void*>(static_cast<ULONG_PTR>(parentPid)));
|
||||
CloseHandle(g_ServiceStopEvent);
|
||||
|
||||
// Keep window open until a key is pressed (optional)
|
||||
// system("pause");
|
||||
|
||||
FreeConsole();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Try to connect to SCM
|
||||
wchar_t serviceName[] = L"LightSwitchService";
|
||||
SERVICE_TABLE_ENTRYW table[] = { { serviceName, ServiceMain }, { nullptr, nullptr } };
|
||||
|
||||
if (!StartServiceCtrlDispatcherW(table))
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
if (err == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) // not launched by SCM
|
||||
{
|
||||
g_ServiceStopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
HANDLE hThread = CreateThread(
|
||||
nullptr, 0, ServiceWorkerThread, reinterpret_cast<void*>(static_cast<ULONG_PTR>(parentPid)), 0, nullptr);
|
||||
|
||||
// Wait so the process stays alive
|
||||
WaitForSingleObject(hThread, INFINITE);
|
||||
CloseHandle(hThread);
|
||||
CloseHandle(g_ServiceStopEvent);
|
||||
return 0;
|
||||
}
|
||||
return static_cast<int>(err);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Called when the service is launched by Windows
|
||||
VOID WINAPI ServiceMain(DWORD, LPTSTR*)
|
||||
{
|
||||
g_StatusHandle = RegisterServiceCtrlHandler(_T("LightSwitchService"), ServiceCtrlHandler);
|
||||
if (!g_StatusHandle)
|
||||
return;
|
||||
|
||||
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
|
||||
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
|
||||
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
|
||||
|
||||
g_ServiceStopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
if (!g_ServiceStopEvent)
|
||||
{
|
||||
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
|
||||
g_ServiceStatus.dwWin32ExitCode = GetLastError();
|
||||
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
|
||||
return;
|
||||
}
|
||||
|
||||
SECURITY_ATTRIBUTES sa{ sizeof(sa) };
|
||||
sa.bInheritHandle = FALSE;
|
||||
sa.lpSecurityDescriptor = nullptr;
|
||||
|
||||
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
||||
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
|
||||
|
||||
HANDLE hThread = CreateThread(nullptr, 0, ServiceWorkerThread, nullptr, 0, nullptr);
|
||||
WaitForSingleObject(hThread, INFINITE);
|
||||
CloseHandle(hThread);
|
||||
|
||||
CloseHandle(g_ServiceStopEvent);
|
||||
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
|
||||
g_ServiceStatus.dwWin32ExitCode = 0;
|
||||
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
|
||||
}
|
||||
|
||||
VOID WINAPI ServiceCtrlHandler(DWORD dwCtrl)
|
||||
{
|
||||
switch (dwCtrl)
|
||||
{
|
||||
case SERVICE_CONTROL_STOP:
|
||||
if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
|
||||
break;
|
||||
|
||||
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
||||
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
|
||||
|
||||
// Signal the service to stop
|
||||
SetEvent(g_ServiceStopEvent);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
|
||||
{
|
||||
DWORD parentPid = static_cast<DWORD>(reinterpret_cast<ULONG_PTR>(lpParam));
|
||||
HANDLE hParent = nullptr;
|
||||
if (parentPid)
|
||||
hParent = OpenProcess(SYNCHRONIZE, FALSE, parentPid);
|
||||
|
||||
OutputDebugString(L"[LightSwitchService] Worker thread starting...\n");
|
||||
|
||||
// Initialize settings system
|
||||
LightSwitchSettings::instance().InitFileWatcher();
|
||||
|
||||
auto applyTheme = [](int nowMinutes, int lightMinutes, int darkMinutes, const auto& settings) {
|
||||
bool isLightActive = false;
|
||||
|
||||
if (lightMinutes < darkMinutes)
|
||||
{
|
||||
// Normal case: sunrise < sunset
|
||||
isLightActive = (nowMinutes >= lightMinutes && nowMinutes < darkMinutes);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Wraparound case: e.g. light at 21:00, dark at 06:00
|
||||
isLightActive = (nowMinutes >= lightMinutes || nowMinutes < darkMinutes);
|
||||
}
|
||||
|
||||
if (isLightActive)
|
||||
{
|
||||
if (settings.changeSystem)
|
||||
SetSystemTheme(true);
|
||||
if (settings.changeApps)
|
||||
SetAppsTheme(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (settings.changeSystem)
|
||||
SetSystemTheme(false);
|
||||
if (settings.changeApps)
|
||||
SetAppsTheme(false);
|
||||
}
|
||||
};
|
||||
|
||||
// --- At service start: immediately honor the schedule ---
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
GetLocalTime(&st);
|
||||
int nowMinutes = st.wHour * 60 + st.wMinute;
|
||||
|
||||
LightSwitchSettings::instance().LoadSettings();
|
||||
const auto& settings = LightSwitchSettings::instance().settings();
|
||||
|
||||
applyTheme(nowMinutes, settings.lightTime + settings.offset, settings.darkTime + settings.offset, settings);
|
||||
}
|
||||
|
||||
// --- Main loop: wakes once per minute or stop/parent death ---
|
||||
for (;;)
|
||||
{
|
||||
HANDLE waits[2] = { g_ServiceStopEvent, hParent };
|
||||
DWORD count = hParent ? 2 : 1;
|
||||
|
||||
SYSTEMTIME st;
|
||||
GetLocalTime(&st);
|
||||
int nowMinutes = st.wHour * 60 + st.wMinute;
|
||||
|
||||
LightSwitchSettings::instance().LoadSettings();
|
||||
const auto& settings = LightSwitchSettings::instance().settings();
|
||||
|
||||
// Debug print
|
||||
wchar_t msg[160];
|
||||
swprintf_s(msg,
|
||||
L"[LightSwitchService] now=%02d:%02d | light=%02d:%02d | dark=%02d:%02d\n",
|
||||
st.wHour,
|
||||
st.wMinute,
|
||||
settings.lightTime / 60,
|
||||
settings.lightTime % 60,
|
||||
settings.darkTime / 60,
|
||||
settings.darkTime % 60);
|
||||
OutputDebugString(msg);
|
||||
|
||||
// Apply theme logic
|
||||
applyTheme(nowMinutes, settings.lightTime + settings.offset, settings.darkTime + settings.offset, settings);
|
||||
|
||||
// Sleep until next minute, wake early if stop/parent dies
|
||||
GetLocalTime(&st);
|
||||
int msToNextMinute = (60 - st.wSecond) * 1000 - st.wMilliseconds;
|
||||
if (msToNextMinute < 50)
|
||||
msToNextMinute = 50;
|
||||
|
||||
DWORD wait = WaitForMultipleObjects(count, waits, FALSE, msToNextMinute);
|
||||
if (wait == WAIT_OBJECT_0) // stop event
|
||||
break;
|
||||
if (hParent && wait == WAIT_OBJECT_0 + 1) // parent exited
|
||||
break;
|
||||
}
|
||||
|
||||
if (hParent)
|
||||
CloseHandle(hParent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APIENTRY wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
|
||||
{
|
||||
if (powertoys_gpo::getConfiguredLightSwitchEnabledValue() == powertoys_gpo::gpo_rule_configured_disabled)
|
||||
{
|
||||
wchar_t msg[160];
|
||||
swprintf_s(
|
||||
msg,
|
||||
L"Tried to start with a GPO policy setting the utility to always be disabled. Please contact your systems administrator.\n");
|
||||
OutputDebugString(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int argc = 0;
|
||||
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||
int rc = _tmain(argc, argv); // reuse your existing logic
|
||||
LocalFree(argv);
|
||||
return rc;
|
||||
}
|
||||
@@ -1,254 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|ARM64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|ARM64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{08e71c67-6a7e-4ca1-b04e-2fb336410bac}</ProjectGuid>
|
||||
<RootNamespace>LightSwitchService</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>LightSwitchService</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\</OutDir>
|
||||
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\</IntDir>
|
||||
<TargetName>PowerToys.LightSwitchService</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>
|
||||
./../;
|
||||
$(SolutionDir)src\common\Telemetry;
|
||||
$(SolutionDir)src\common;
|
||||
$(SolutionDir)src\;
|
||||
$(SolutionDir)deps\spdlog\include;
|
||||
./;
|
||||
%(AdditionalIncludeDirectories)
|
||||
</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>Advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\notifications\notifications.vcxproj">
|
||||
<Project>{1d5be09d-78c0-4fd7-af00-ae7c1af7c525}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\Telemetry\EtwTrace\EtwTrace.vcxproj">
|
||||
<Project>{8f021b46-362b-485c-bfba-ccf83e820cbd}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\common\SettingsAPI\FileWatcher.cpp" />
|
||||
<ClCompile Include="..\..\..\common\SettingsAPI\settings_helpers.cpp" />
|
||||
<ClCompile Include="..\..\..\common\SettingsAPI\settings_objects.cpp" />
|
||||
<ClCompile Include="LightSwitchService.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LightSwitchSettings.cpp" />
|
||||
<ClCompile Include="SettingsConstants.cpp" />
|
||||
<ClCompile Include="ThemeHelper.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ThemeScheduler.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="WinHookEventIDs.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="LightSwitchSettings.h" />
|
||||
<ClInclude Include="SettingsConstants.h" />
|
||||
<ClInclude Include="SettingsObserver.h" />
|
||||
<ClInclude Include="ThemeHelper.h" />
|
||||
<ClInclude Include="ThemeScheduler.h">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">false</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="WinHookEventIDs.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -1,72 +0,0 @@
|
||||
<?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++;cppm;ixx;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>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="LightSwitchService.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ThemeScheduler.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ThemeHelper.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\common\SettingsAPI\settings_helpers.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\common\SettingsAPI\settings_objects.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\common\SettingsAPI\FileWatcher.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LightSwitchSettings.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SettingsConstants.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="WinHookEventIDs.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ThemeScheduler.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ThemeHelper.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="LightSwitchSettings.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SettingsConstants.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SettingsObserver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="WinHookEventIDs.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,148 +0,0 @@
|
||||
#include "LightSwitchSettings.h"
|
||||
#include <common/utils/json.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include "SettingsObserver.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <WinHookEventIDs.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
LightSwitchSettings& LightSwitchSettings::instance()
|
||||
{
|
||||
static LightSwitchSettings inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
LightSwitchSettings::LightSwitchSettings()
|
||||
{
|
||||
LoadSettings();
|
||||
}
|
||||
|
||||
std::wstring LightSwitchSettings::GetSettingsFileName()
|
||||
{
|
||||
// Mirrors AlwaysOnTop: <module name>.json
|
||||
return PTSettingsHelper::get_module_save_file_location(L"LightSwitch");
|
||||
}
|
||||
|
||||
void LightSwitchSettings::InitFileWatcher()
|
||||
{
|
||||
const std::wstring& settingsFileName = GetSettingsFileName();
|
||||
m_settingsFileWatcher = std::make_unique<FileWatcher>(settingsFileName, [&]() {
|
||||
PostMessageW(HWND_BROADCAST, WM_PRIV_SETTINGS_CHANGED, NULL, NULL);
|
||||
});
|
||||
}
|
||||
|
||||
void LightSwitchSettings::AddObserver(SettingsObserver& observer)
|
||||
{
|
||||
m_observers.insert(&observer);
|
||||
}
|
||||
|
||||
void LightSwitchSettings::RemoveObserver(SettingsObserver& observer)
|
||||
{
|
||||
m_observers.erase(&observer);
|
||||
}
|
||||
|
||||
void LightSwitchSettings::NotifyObservers(SettingId id) const
|
||||
{
|
||||
for (auto observer : m_observers)
|
||||
{
|
||||
if (observer->WantsToBeNotified(id))
|
||||
{
|
||||
observer->SettingsUpdate(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LightSwitchSettings::LoadSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
PowerToysSettings::PowerToyValues values =
|
||||
PowerToysSettings::PowerToyValues::load_from_settings_file(L"LightSwitch");
|
||||
|
||||
|
||||
if (const auto jsonVal = values.get_string_value(L"scheduleMode"))
|
||||
{
|
||||
auto val = *jsonVal;
|
||||
auto newMode = FromString(val);
|
||||
if (m_settings.scheduleMode != newMode)
|
||||
{
|
||||
m_settings.scheduleMode = newMode;
|
||||
NotifyObservers(SettingId::ScheduleMode);
|
||||
}
|
||||
}
|
||||
|
||||
// Latitude
|
||||
if (const auto jsonVal = values.get_string_value(L"latitude"))
|
||||
{
|
||||
auto val = *jsonVal;
|
||||
if (m_settings.latitude != val)
|
||||
{
|
||||
m_settings.latitude = val;
|
||||
NotifyObservers(SettingId::Latitude);
|
||||
}
|
||||
}
|
||||
|
||||
// Longitude
|
||||
if (const auto jsonVal = values.get_string_value(L"longitude"))
|
||||
{
|
||||
auto val = *jsonVal;
|
||||
if (m_settings.longitude != val)
|
||||
{
|
||||
m_settings.longitude = val;
|
||||
NotifyObservers(SettingId::Longitude);
|
||||
}
|
||||
}
|
||||
|
||||
// LightTime
|
||||
if (const auto jsonVal = values.get_int_value(L"lightTime"))
|
||||
{
|
||||
auto val = *jsonVal;
|
||||
if (m_settings.lightTime != val)
|
||||
{
|
||||
m_settings.lightTime = val;
|
||||
NotifyObservers(SettingId::LightTime);
|
||||
}
|
||||
}
|
||||
|
||||
// DarkTime
|
||||
if (const auto jsonVal = values.get_int_value(L"darkTime"))
|
||||
{
|
||||
auto val = *jsonVal;
|
||||
if (m_settings.darkTime != val)
|
||||
{
|
||||
m_settings.darkTime = val;
|
||||
NotifyObservers(SettingId::DarkTime);
|
||||
}
|
||||
}
|
||||
|
||||
// ChangeSystem
|
||||
if (const auto jsonVal = values.get_bool_value(L"changeSystem"))
|
||||
{
|
||||
auto val = *jsonVal;
|
||||
if (m_settings.changeSystem != val)
|
||||
{
|
||||
m_settings.changeSystem = val;
|
||||
NotifyObservers(SettingId::ChangeSystem);
|
||||
}
|
||||
}
|
||||
|
||||
// ChangeApps
|
||||
if (const auto jsonVal = values.get_bool_value(L"changeApps"))
|
||||
{
|
||||
auto val = *jsonVal;
|
||||
if (m_settings.changeApps != val)
|
||||
{
|
||||
m_settings.changeApps = val;
|
||||
NotifyObservers(SettingId::ChangeApps);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
//Logger::error(L"[LightSwitchSettings] Failed to read settings file");
|
||||
// Keeps defaults if load fails
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <windows.h>
|
||||
|
||||
#include <common/SettingsAPI/FileWatcher.h>
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include <SettingsConstants.h>
|
||||
|
||||
class SettingsObserver;
|
||||
|
||||
enum class ScheduleMode
|
||||
{
|
||||
FixedHours,
|
||||
SunsetToSunrise
|
||||
// Add more in the future
|
||||
};
|
||||
|
||||
inline std::wstring ToString(ScheduleMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case ScheduleMode::FixedHours:
|
||||
return L"FixedHours";
|
||||
case ScheduleMode::SunsetToSunrise:
|
||||
return L"SunsetToSunrise";
|
||||
default:
|
||||
return L"FixedHours";
|
||||
}
|
||||
}
|
||||
|
||||
inline ScheduleMode FromString(const std::wstring& str)
|
||||
{
|
||||
if (str == L"SunsetToSunrise")
|
||||
return ScheduleMode::SunsetToSunrise;
|
||||
else
|
||||
return ScheduleMode::FixedHours;
|
||||
}
|
||||
|
||||
struct LightSwitchConfig
|
||||
{
|
||||
ScheduleMode scheduleMode = ScheduleMode::FixedHours;
|
||||
|
||||
std::wstring latitude = L"0.0";
|
||||
std::wstring longitude = L"0.0";
|
||||
|
||||
// Stored as minutes since midnight
|
||||
int lightTime = 8 * 60; // 08:00 default
|
||||
int darkTime = 20 * 60; // 20:00 default
|
||||
|
||||
int offset = 0; // offset in minutes to apply to calculated times
|
||||
|
||||
bool changeSystem = false;
|
||||
bool changeApps = false;
|
||||
};
|
||||
|
||||
class LightSwitchSettings
|
||||
{
|
||||
public:
|
||||
static LightSwitchSettings& instance();
|
||||
|
||||
static inline const LightSwitchConfig& settings()
|
||||
{
|
||||
return instance().m_settings;
|
||||
}
|
||||
|
||||
void InitFileWatcher();
|
||||
static std::wstring GetSettingsFileName();
|
||||
|
||||
void AddObserver(SettingsObserver& observer);
|
||||
void RemoveObserver(SettingsObserver& observer);
|
||||
|
||||
void LoadSettings();
|
||||
|
||||
private:
|
||||
LightSwitchSettings();
|
||||
~LightSwitchSettings() = default;
|
||||
|
||||
LightSwitchConfig m_settings;
|
||||
std::unique_ptr<FileWatcher> m_settingsFileWatcher;
|
||||
std::unordered_set<SettingsObserver*> m_observers;
|
||||
|
||||
void NotifyObservers(SettingId id) const;
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
#include "SettingsConstants.h"
|
||||
@@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
enum class SettingId
|
||||
{
|
||||
ScheduleMode = 0,
|
||||
Latitude,
|
||||
Longitude,
|
||||
LightTime,
|
||||
DarkTime,
|
||||
ChangeSystem,
|
||||
ChangeApps
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_set>
|
||||
#include "SettingsConstants.h"
|
||||
|
||||
class LightSwitchSettings;
|
||||
|
||||
class SettingsObserver
|
||||
{
|
||||
public:
|
||||
SettingsObserver(std::unordered_set<SettingId> observedSettings) :
|
||||
m_observedSettings(std::move(observedSettings))
|
||||
{
|
||||
LightSwitchSettings::instance().AddObserver(*this);
|
||||
}
|
||||
|
||||
virtual ~SettingsObserver()
|
||||
{
|
||||
LightSwitchSettings::instance().RemoveObserver(*this);
|
||||
}
|
||||
|
||||
// Override this in your class to respond to updates
|
||||
virtual void SettingsUpdate(SettingId type) {}
|
||||
|
||||
bool WantsToBeNotified(SettingId type) const noexcept
|
||||
{
|
||||
return m_observedSettings.contains(type);
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unordered_set<SettingId> m_observedSettings;
|
||||
};
|
||||
@@ -1,80 +0,0 @@
|
||||
#include <windows.h>
|
||||
#include "ThemeHelper.h"
|
||||
|
||||
// Controls changing the themes.
|
||||
|
||||
void SetAppsTheme(bool mode)
|
||||
{
|
||||
HKEY hKey;
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
0,
|
||||
KEY_SET_VALUE,
|
||||
&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD value = mode;
|
||||
RegSetValueEx(hKey, L"AppsUseLightTheme", 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(value));
|
||||
RegCloseKey(hKey);
|
||||
|
||||
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast<LPARAM>(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||
|
||||
SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void SetSystemTheme(bool mode)
|
||||
{
|
||||
HKEY hKey;
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
0,
|
||||
KEY_SET_VALUE,
|
||||
&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD value = mode;
|
||||
RegSetValueEx(hKey, L"SystemUsesLightTheme", 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(value));
|
||||
RegCloseKey(hKey);
|
||||
|
||||
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast<LPARAM>(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||
|
||||
SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool GetCurrentSystemTheme()
|
||||
{
|
||||
HKEY hKey;
|
||||
DWORD value = 1; // default = light
|
||||
DWORD size = sizeof(value);
|
||||
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
0,
|
||||
KEY_READ,
|
||||
&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
RegQueryValueEx(hKey, L"SystemUsesLightTheme", nullptr, nullptr, reinterpret_cast<LPBYTE>(&value), &size);
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
return value == 0; // 0 = dark, 1 = light
|
||||
}
|
||||
|
||||
bool GetCurrentAppsTheme()
|
||||
{
|
||||
HKEY hKey;
|
||||
DWORD value = 1;
|
||||
DWORD size = sizeof(value);
|
||||
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
0,
|
||||
KEY_READ,
|
||||
&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
RegQueryValueEx(hKey, L"SystemUsesLightTheme", nullptr, nullptr, reinterpret_cast<LPBYTE>(&value), &size);
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
return value == 0;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
void SetSystemTheme(bool dark);
|
||||
void SetAppsTheme(bool dark);
|
||||
bool GetCurrentSystemTheme();
|
||||
bool GetCurrentAppsTheme();
|
||||
@@ -1,89 +0,0 @@
|
||||
#include "ThemeScheduler.h"
|
||||
#include <utility>
|
||||
|
||||
SunTimes CalculateSunriseSunset(double latitude, double longitude, int year, int month, int day)
|
||||
{
|
||||
double zenith = 90.833;
|
||||
int N1 = static_cast<int>(floor(275.0 * month / 9.0));
|
||||
int N2 = static_cast<int>(floor((static_cast<double>(month) + 9) / 12.0));
|
||||
int N3 = static_cast<int>(floor((1.0 + floor((year - 4.0 * floor(year / 4.0) + 2.0) / 3.0))));
|
||||
int N = N1 - (N2 * N3) + day - 30;
|
||||
|
||||
auto calcTime = [&](bool sunrise) -> double {
|
||||
double lngHour = longitude / 15.0;
|
||||
double t = sunrise ? N + ((6 - lngHour) / 24) : N + ((18 - lngHour) / 24);
|
||||
|
||||
double M = (0.9856 * t) - 3.289;
|
||||
double L = M + (1.916 * sin(deg2rad(M))) + (0.020 * sin(2 * deg2rad(M))) + 282.634;
|
||||
if (L < 0)
|
||||
L += 360;
|
||||
if (L > 360)
|
||||
L -= 360;
|
||||
|
||||
double RA = rad2deg(atan(0.91764 * tan(deg2rad(L))));
|
||||
if (RA < 0)
|
||||
RA += 360;
|
||||
if (RA > 360)
|
||||
RA -= 360;
|
||||
|
||||
double Lquadrant = floor(L / 90) * 90;
|
||||
double RAquadrant = floor(RA / 90) * 90;
|
||||
RA = RA + (Lquadrant - RAquadrant);
|
||||
RA /= 15;
|
||||
|
||||
double sinDec = 0.39782 * sin(deg2rad(L));
|
||||
double cosDec = cos(asin(sinDec));
|
||||
|
||||
double cosH = (cos(deg2rad(zenith)) - (sinDec * sin(deg2rad(latitude)))) / (cosDec * cos(deg2rad(latitude)));
|
||||
if (cosH > 1 || cosH < -1)
|
||||
return -1;
|
||||
|
||||
double H = sunrise ? 360 - rad2deg(acos(cosH)) : rad2deg(acos(cosH));
|
||||
H /= 15;
|
||||
|
||||
double T = H + RA - (0.06571 * t) - 6.622;
|
||||
double UT = T - lngHour;
|
||||
while (UT < 0)
|
||||
UT += 24;
|
||||
while (UT >= 24)
|
||||
UT -= 24;
|
||||
|
||||
return UT;
|
||||
};
|
||||
|
||||
double riseUT = calcTime(true);
|
||||
double setUT = calcTime(false);
|
||||
|
||||
auto toLocal = [](double UT) {
|
||||
TIME_ZONE_INFORMATION tz;
|
||||
DWORD state = GetTimeZoneInformation(&tz);
|
||||
double totalBias = tz.Bias;
|
||||
|
||||
if (state == TIME_ZONE_ID_DAYLIGHT)
|
||||
totalBias += tz.DaylightBias;
|
||||
else if (state == TIME_ZONE_ID_STANDARD)
|
||||
totalBias += tz.StandardBias;
|
||||
|
||||
double biasHours = -(totalBias / 60.0);
|
||||
double localTime = UT + biasHours;
|
||||
|
||||
while (localTime < 0)
|
||||
localTime += 24;
|
||||
while (localTime >= 24)
|
||||
localTime -= 24;
|
||||
|
||||
int hour = static_cast<int>(localTime);
|
||||
int minute = static_cast<int>((localTime - hour) * 60);
|
||||
return std::pair<int, int>{ hour, minute };
|
||||
};
|
||||
|
||||
auto [riseHour, riseMinute] = toLocal(riseUT);
|
||||
auto [setHour, setMinute] = toLocal(setUT);
|
||||
|
||||
SunTimes result;
|
||||
result.sunriseHour = riseHour;
|
||||
result.sunriseMinute = riseMinute;
|
||||
result.sunsetHour = setHour;
|
||||
result.sunsetMinute = setMinute;
|
||||
return result;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <windows.h>
|
||||
|
||||
// Struct to hold calculated sunrise/sunset times
|
||||
struct SunTimes
|
||||
{
|
||||
int sunriseHour;
|
||||
int sunriseMinute;
|
||||
int sunsetHour;
|
||||
int sunsetMinute;
|
||||
};
|
||||
|
||||
constexpr double PI = 3.14159265358979323846;
|
||||
constexpr double deg2rad(double deg)
|
||||
{
|
||||
return deg * PI / 180.0;
|
||||
}
|
||||
constexpr double rad2deg(double rad)
|
||||
{
|
||||
return rad * 180.0 / PI;
|
||||
}
|
||||
|
||||
SunTimes CalculateSunriseSunset(double latitude, double longitude, int year, int month, int day);
|
||||
@@ -1,15 +0,0 @@
|
||||
|
||||
#include "WinHookEventIDs.h"
|
||||
#include <wtypes.h>
|
||||
#include <mutex>
|
||||
|
||||
UINT WM_PRIV_SETTINGS_CHANGED = 0;
|
||||
|
||||
std::once_flag init_flag;
|
||||
|
||||
void InitializeWinhookEventIds()
|
||||
{
|
||||
std::call_once(init_flag, [&] {
|
||||
WM_PRIV_SETTINGS_CHANGED = RegisterWindowMessage(L"{11978F7B-221A-4E65-B9A9-693F7D6E4B25}");
|
||||
});
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
|
||||
extern UINT WM_PRIV_SETTINGS_CHANGED; // Scheduled when a watched settings file is updated
|
||||
|
||||
void InitializeWinhookEventIds();
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231216.1" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -556,6 +556,61 @@ public:
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
virtual size_t get_hotkeys(Hotkey* hotkeys, size_t buffer_size) override
|
||||
{
|
||||
constexpr size_t num_hotkeys = 4; // We have 4 hotkeys
|
||||
|
||||
if (hotkeys && buffer_size >= num_hotkeys)
|
||||
{
|
||||
PowerToysSettings::PowerToyValues values = PowerToysSettings::PowerToyValues::load_from_settings_file(MODULE_NAME);
|
||||
|
||||
// Cache the raw JSON object to avoid multiple parsing
|
||||
json::JsonObject root_json = values.get_raw_json();
|
||||
json::JsonObject properties_json = root_json.GetNamedObject(L"properties", json::JsonObject{});
|
||||
|
||||
size_t hotkey_index = 0;
|
||||
|
||||
// Helper lambda to extract hotkey from JSON properties
|
||||
auto extract_hotkey = [&](const wchar_t* property_name) -> Hotkey {
|
||||
if (properties_json.HasKey(property_name))
|
||||
{
|
||||
try
|
||||
{
|
||||
json::JsonObject hotkey_json = properties_json.GetNamedObject(property_name);
|
||||
|
||||
// Extract hotkey properties directly from JSON
|
||||
bool win = hotkey_json.GetNamedBoolean(L"win", false);
|
||||
bool ctrl = hotkey_json.GetNamedBoolean(L"ctrl", false);
|
||||
bool alt = hotkey_json.GetNamedBoolean(L"alt", false);
|
||||
bool shift = hotkey_json.GetNamedBoolean(L"shift", false);
|
||||
unsigned char key = static_cast<unsigned char>(
|
||||
hotkey_json.GetNamedNumber(L"code", 0));
|
||||
|
||||
return { win, ctrl, shift, alt, key };
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// If parsing individual hotkey fails, use defaults
|
||||
return { false, false, false, false, 0 };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Property doesn't exist, use defaults
|
||||
return { false, false, false, false, 0 };
|
||||
}
|
||||
};
|
||||
|
||||
// Extract all hotkeys using the optimized helper
|
||||
hotkeys[hotkey_index++] = extract_hotkey(L"ToggleEasyMouseShortcut"); // [0] Toggle Easy Mouse
|
||||
hotkeys[hotkey_index++] = extract_hotkey(L"LockMachineShortcut"); // [1] Lock Machine
|
||||
hotkeys[hotkey_index++] = extract_hotkey(L"Switch2AllPCShortcut"); // [2] Switch to All PCs
|
||||
hotkeys[hotkey_index++] = extract_hotkey(L"ReconnectShortcut"); // [3] Reconnect
|
||||
}
|
||||
|
||||
return num_hotkeys;
|
||||
}
|
||||
|
||||
void launch_add_firewall_process()
|
||||
{
|
||||
Logger::trace(L"Starting Process to add firewall rule");
|
||||
|
||||
@@ -141,6 +141,9 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
// see 9806fe5d8 for the last commit that had this with sections
|
||||
_isFetching = true;
|
||||
|
||||
// Collect all the items into new viewmodels
|
||||
Collection<ListItemViewModel> newViewModels = [];
|
||||
|
||||
try
|
||||
{
|
||||
// Check for cancellation before starting expensive operations
|
||||
@@ -151,9 +154,6 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
// Check for cancellation after getting items from extension
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
// Collect all the items into new viewmodels
|
||||
Collection<ListItemViewModel> newViewModels = [];
|
||||
|
||||
// TODO we can probably further optimize this by also keeping a
|
||||
// HashSet of every ExtensionObject we currently have, and only
|
||||
// building new viewmodels for the ones we haven't already built.
|
||||
@@ -187,11 +187,22 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
// Check for cancellation before updating the list
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
List<ListItemViewModel> removedItems = [];
|
||||
lock (_listLock)
|
||||
{
|
||||
// Now that we have new ViewModels for everything from the
|
||||
// extension, smartly update our list of VMs
|
||||
ListHelpers.InPlaceUpdateList(Items, newViewModels);
|
||||
ListHelpers.InPlaceUpdateList(Items, newViewModels, out removedItems);
|
||||
|
||||
// DO NOT ThrowIfCancellationRequested AFTER THIS! If you do,
|
||||
// you'll clean up list items that we've now transferred into
|
||||
// .Items
|
||||
}
|
||||
|
||||
// If we removed items, we need to clean them up, to remove our event handlers
|
||||
foreach (var removedItem in removedItems)
|
||||
{
|
||||
removedItem.SafeCleanup();
|
||||
}
|
||||
|
||||
// TODO: Iterate over everything in Items, and prune items from the
|
||||
@@ -200,6 +211,15 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// Cancellation is expected, don't treat as error
|
||||
|
||||
// However, if we were cancelled, we didn't actually add these items to
|
||||
// our Items list. Before we release them to the GC, make sure we clean
|
||||
// them up
|
||||
foreach (var vm in newViewModels)
|
||||
{
|
||||
vm.SafeCleanup();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -1194,6 +1194,15 @@ namespace Microsoft.CmdPal.Ext.WindowsSettings.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Dark mode.
|
||||
/// </summary>
|
||||
internal static string DarkMode {
|
||||
get {
|
||||
return ResourceManager.GetString("DarkMode", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Data usage.
|
||||
/// </summary>
|
||||
@@ -2121,15 +2130,6 @@ namespace Microsoft.CmdPal.Ext.WindowsSettings.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Light Switch.
|
||||
/// </summary>
|
||||
internal static string LightSwitch {
|
||||
get {
|
||||
return ResourceManager.GetString("LightSwitch", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Local Computer Policy.
|
||||
/// </summary>
|
||||
|
||||
@@ -572,8 +572,8 @@
|
||||
<data name="DarkColor" xml:space="preserve">
|
||||
<value>Dark color</value>
|
||||
</data>
|
||||
<data name="LightSwitch" xml:space="preserve">
|
||||
<value>Light Switch</value>
|
||||
<data name="DarkMode" xml:space="preserve">
|
||||
<value>Dark mode</value>
|
||||
</data>
|
||||
<data name="DataUsage" xml:space="preserve">
|
||||
<value>Data usage</value>
|
||||
|
||||
@@ -8,7 +8,6 @@ using Microsoft.CmdPal.Ext.WindowsTerminal.Helpers;
|
||||
using Microsoft.CmdPal.Ext.WindowsTerminal.Properties;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.WindowsTerminal.Pages;
|
||||
|
||||
@@ -16,7 +15,6 @@ internal sealed partial class ProfilesListPage : ListPage
|
||||
{
|
||||
private readonly TerminalQuery _terminalQuery = new();
|
||||
private readonly SettingsManager _terminalSettings;
|
||||
private readonly Dictionary<string, BitmapImage> _logoCache = [];
|
||||
|
||||
private bool showHiddenProfiles;
|
||||
private bool openNewTab;
|
||||
@@ -54,14 +52,6 @@ internal sealed partial class ProfilesListPage : ListPage
|
||||
MoreCommands = [
|
||||
new CommandContextItem(new LaunchProfileAsAdminCommand(profile.Terminal.AppUserModelId, profile.Name, openNewTab, openQuake)),
|
||||
],
|
||||
|
||||
// Icon = () => GetLogo(profile.Terminal),
|
||||
// Action = _ =>
|
||||
// {
|
||||
// Launch(profile.Terminal.AppUserModelId, profile.Name);
|
||||
// return true;
|
||||
// },
|
||||
// ContextData = profile,
|
||||
#pragma warning restore SA1108
|
||||
});
|
||||
}
|
||||
@@ -70,17 +60,4 @@ internal sealed partial class ProfilesListPage : ListPage
|
||||
}
|
||||
|
||||
public override IListItem[] GetItems() => Query().ToArray();
|
||||
|
||||
private BitmapImage GetLogo(TerminalPackage terminal)
|
||||
{
|
||||
var aumid = terminal.AppUserModelId;
|
||||
|
||||
if (!_logoCache.TryGetValue(aumid, out var value))
|
||||
{
|
||||
value = terminal.GetLogo();
|
||||
_logoCache.Add(aumid, value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using ManagedCommon;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
|
||||
// using Wox.Infrastructure.Image;
|
||||
namespace Microsoft.CmdPal.Ext.WindowsTerminal;
|
||||
@@ -30,23 +29,4 @@ public class TerminalPackage
|
||||
SettingsPath = settingsPath;
|
||||
LogoPath = logoPath;
|
||||
}
|
||||
|
||||
public BitmapImage GetLogo()
|
||||
{
|
||||
var image = new BitmapImage();
|
||||
|
||||
if (File.Exists(LogoPath))
|
||||
{
|
||||
using var fileStream = File.OpenRead(LogoPath);
|
||||
image.SetSource(fileStream.AsRandomAccessStream());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not using wox anymore, TODO: find the right new way to handle this
|
||||
// image.UriSource = new Uri(ImageLoader.ErrorIconPath);
|
||||
Logger.LogError($"Logo file not found: {LogoPath}");
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,10 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
|
||||
Tools extension to be activated for this project even if the Windows App SDK Nuget
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" />
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
|
||||
@@ -65,12 +65,32 @@ public partial class ListHelpers
|
||||
public static void InPlaceUpdateList<T>(IList<T> original, IEnumerable<T> newContents)
|
||||
where T : class
|
||||
{
|
||||
InPlaceUpdateList(original, newContents, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Modifies the contents of `original` in-place, to match those of
|
||||
/// `newContents`. The canonical use being:
|
||||
/// ```cs
|
||||
/// ListHelpers.InPlaceUpdateList(FilteredItems, FilterList(ItemsToFilter, TextToFilterOn));
|
||||
/// ```
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Any type that can be compared for equality</typeparam>
|
||||
/// <param name="original">Collection to modify</param>
|
||||
/// <param name="newContents">The enumerable which `original` should match</param>
|
||||
/// <param name="removedItems">List of items that were removed from the original collection</param>
|
||||
public static void InPlaceUpdateList<T>(IList<T> original, IEnumerable<T> newContents, out List<T> removedItems)
|
||||
where T : class
|
||||
{
|
||||
removedItems = [];
|
||||
|
||||
// we're not changing newContents - stash this so we don't re-evaluate it every time
|
||||
var numberOfNew = newContents.Count();
|
||||
|
||||
// Short circuit - new contents should just be empty
|
||||
if (numberOfNew == 0)
|
||||
{
|
||||
removedItems.AddRange(original);
|
||||
original.Clear();
|
||||
return;
|
||||
}
|
||||
@@ -92,6 +112,7 @@ public partial class ListHelpers
|
||||
for (var k = i; k < j; k++)
|
||||
{
|
||||
// This item from the original list was not in the new list. Remove it.
|
||||
removedItems.Add(original[i]);
|
||||
original.RemoveAt(i);
|
||||
}
|
||||
|
||||
@@ -120,6 +141,7 @@ public partial class ListHelpers
|
||||
while (original.Count > numberOfNew)
|
||||
{
|
||||
// RemoveAtEnd
|
||||
removedItems.Add(original[original.Count - 1]);
|
||||
original.RemoveAt(original.Count - 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,8 +41,6 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" />
|
||||
<PackageReference Include="System.Drawing.Common" />
|
||||
<!-- This line forces the WebView2 version used by Windows App SDK to be the one we expect from Directory.Packages.props . -->
|
||||
</ItemGroup>
|
||||
|
||||
@@ -180,4 +180,4 @@
|
||||
<Error Condition="!Exists('$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.targets'))" />
|
||||
<Error Condition="!Exists('$(WebView2Nuget)\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(WebView2Nuget)\build\native\Microsoft.Web.WebView2.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -1,7 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Web.WebView2" version="1.0.2903.40" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.SDK.BuildTools" version="10.0.26100.4188" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK" version="1.7.250513003" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -1,324 +0,0 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<AssemblyName>PowerToys.ImageResizer</AssemblyName>
|
||||
<IntermediateOutputPath>obj\ARM64\Debug\</IntermediateOutputPath>
|
||||
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
|
||||
<MSBuildProjectExtensionsPath>D:\source\repos\PowerToys\src\modules\imageresizer\ui\obj\</MSBuildProjectExtensionsPath>
|
||||
<_TargetAssemblyProjectName>ImageResizerUI</_TargetAssemblyProjectName>
|
||||
<RootNamespace>ImageResizer</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
|
||||
<!-- Look at Directory.Build.props in root for common stuff as well -->
|
||||
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\Common.SelfContained.props" />
|
||||
<PropertyGroup>
|
||||
<AssemblyTitle>PowerToys.ImageResizer</AssemblyTitle>
|
||||
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
|
||||
<UseWPF>true</UseWPF>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>ImageResizer</RootNamespace>
|
||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>Resources\ImageResizer.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" />
|
||||
<PackageReference Include="System.IO.Abstractions" />
|
||||
<PackageReference Include="WPF-UI" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\GPOWrapperProjection\GPOWrapperProjection.csproj" />
|
||||
<ProjectReference Include="..\..\..\common\interop\PowerToys.Interop.vcxproj" />
|
||||
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
|
||||
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\Accessibility.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\controlzex\6.0.0\lib\net5.0-windows7.0\ControlzEx.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.diagnostics.tracing.traceevent\3.1.16\lib\netstandard2.0\Dia2Lib.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\Microsoft.CSharp.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.diagnostics.tracing.traceevent\3.1.16\lib\netstandard2.0\Microsoft.Diagnostics.FastSerialization.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.diagnostics.netcore.client\0.2.510501\lib\net6.0\Microsoft.Diagnostics.NETCore.Client.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.diagnostics.tracing.traceevent\3.1.16\lib\netstandard2.0\Microsoft.Diagnostics.Tracing.TraceEvent.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.extensions.dependencyinjection.abstractions\9.0.8\lib\net9.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.extensions.dependencyinjection\9.0.8\lib\net9.0\Microsoft.Extensions.DependencyInjection.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.extensions.logging.abstractions\9.0.8\lib\net9.0\Microsoft.Extensions.Logging.Abstractions.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.extensions.logging\9.0.8\lib\net9.0\Microsoft.Extensions.Logging.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.extensions.options\9.0.8\lib\net9.0\Microsoft.Extensions.Options.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.extensions.primitives\9.0.8\lib\net9.0\Microsoft.Extensions.Primitives.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\Microsoft.VisualBasic.Core.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\Microsoft.VisualBasic.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\Microsoft.VisualBasic.Forms.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\Microsoft.Win32.Primitives.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\Microsoft.Win32.Registry.AccessControl.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\Microsoft.Win32.Registry.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\Microsoft.Win32.SystemEvents.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.windows.sdk.net.ref\10.0.26100.68-preview\lib\net8.0\Microsoft.Windows.SDK.NET.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.xaml.behaviors.wpf\1.1.39\lib\net5.0-windows7.0\Microsoft.Xaml.Behaviors.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\mscorlib.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\netstandard.dll" />
|
||||
<ReferencePath Include="D:\source\repos\PowerToys\src\common\Common.UI\bin\ARM64\Debug\net9.0-windows10.0.26100.0\PowerToys.Common.UI.dll" />
|
||||
<ReferencePath Include="D:\source\repos\PowerToys\src\common\GPOWrapperProjection\bin\ARM64\Debug\net9.0-windows10.0.26100.0\PowerToys.GPOWrapperProjection.dll" />
|
||||
<ReferencePath Include="D:\source\repos\PowerToys\src\common\ManagedCommon\bin\ARM64\Debug\net9.0-windows10.0.26100.0\PowerToys.ManagedCommon.dll" />
|
||||
<ReferencePath Include="D:\source\repos\PowerToys\src\common\ManagedTelemetry\Telemetry\bin\ARM64\Debug\net9.0-windows10.0.26100.0\PowerToys.ManagedTelemetry.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\PresentationCore.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\PresentationFramework.Aero.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\PresentationFramework.Aero2.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\PresentationFramework.AeroLite.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\PresentationFramework.Classic.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\PresentationFramework.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\PresentationFramework.Luna.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\PresentationFramework.Royale.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\PresentationUI.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\ReachFramework.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.AppContext.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Buffers.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.CodeDom.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Collections.Concurrent.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Collections.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Collections.Immutable.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Collections.NonGeneric.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Collections.Specialized.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ComponentModel.Annotations.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ComponentModel.DataAnnotations.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ComponentModel.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ComponentModel.EventBasedAsync.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ComponentModel.Primitives.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ComponentModel.TypeConverter.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Configuration.ConfigurationManager.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Configuration.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Console.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Core.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Data.Common.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Data.DataSetExtensions.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Data.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Design.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.Contracts.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.Debug.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.DiagnosticSource.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.EventLog.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.FileVersionInfo.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.PerformanceCounter.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.Process.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.StackTrace.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.TextWriterTraceListener.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.Tools.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.TraceSource.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.Tracing.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.DirectoryServices.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Drawing.Common.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Drawing.Design.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Drawing.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Drawing.Primitives.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Dynamic.Runtime.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Formats.Asn1.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Formats.Nrbf.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Formats.Tar.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Globalization.Calendars.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Globalization.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Globalization.Extensions.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\system.io.abstractions\22.0.13\lib\net9.0\System.IO.Abstractions.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.Compression.Brotli.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.Compression.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.Compression.FileSystem.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.Compression.ZipFile.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.FileSystem.AccessControl.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.FileSystem.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.FileSystem.DriveInfo.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.FileSystem.Primitives.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.FileSystem.Watcher.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.IsolatedStorage.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.MemoryMappedFiles.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.IO.Packaging.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.Pipelines.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.Pipes.AccessControl.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.Pipes.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.UnmanagedMemoryStream.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Linq.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Linq.Expressions.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Linq.Parallel.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Linq.Queryable.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\system.management\9.0.8\lib\net9.0\System.Management.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Memory.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.Http.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.Http.Json.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.HttpListener.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.Mail.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.NameResolution.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.NetworkInformation.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.Ping.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.Primitives.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.Quic.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.Requests.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.Security.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.ServicePoint.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.Sockets.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.WebClient.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.WebHeaderCollection.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.WebProxy.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.WebSockets.Client.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.WebSockets.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Numerics.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Numerics.Vectors.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ObjectModel.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Printing.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Private.Windows.Core.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Reflection.DispatchProxy.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Reflection.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Reflection.Emit.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Reflection.Emit.ILGeneration.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Reflection.Emit.Lightweight.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Reflection.Extensions.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Reflection.Metadata.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Reflection.Primitives.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Reflection.TypeExtensions.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Resources.Extensions.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Resources.Reader.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Resources.ResourceManager.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Resources.Writer.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.CompilerServices.Unsafe.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.CompilerServices.VisualC.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Extensions.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Handles.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.InteropServices.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.InteropServices.JavaScript.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.InteropServices.RuntimeInformation.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Intrinsics.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Loader.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Numerics.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Serialization.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Serialization.Formatters.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Serialization.Json.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Serialization.Primitives.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Serialization.Xml.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.AccessControl.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Claims.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.Algorithms.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.Cng.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.Csp.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.Encoding.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.OpenSsl.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.Pkcs.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.Primitives.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.ProtectedData.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.X509Certificates.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.Xml.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Security.Permissions.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Principal.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Principal.Windows.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.SecureString.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ServiceModel.Web.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ServiceProcess.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Text.Encoding.CodePages.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Text.Encoding.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Text.Encoding.Extensions.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Text.Encodings.Web.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Text.Json.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Text.RegularExpressions.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Threading.AccessControl.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.Channels.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.Overlapped.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.Tasks.Dataflow.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.Tasks.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.Tasks.Extensions.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.Tasks.Parallel.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.Thread.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.ThreadPool.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.Timer.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Transactions.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Transactions.Local.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ValueTuple.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Web.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Web.HttpUtility.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Windows.Controls.Ribbon.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Windows.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Windows.Extensions.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Windows.Forms.Design.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Windows.Forms.Design.Editors.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Windows.Forms.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Windows.Forms.Primitives.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Windows.Input.Manipulations.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Windows.Presentation.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Xaml.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Xml.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Xml.Linq.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Xml.ReaderWriter.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Xml.Serialization.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Xml.XDocument.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Xml.XmlDocument.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Xml.XmlSerializer.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Xml.XPath.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Xml.XPath.XDocument.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\testableio.system.io.abstractions\22.0.13\lib\net9.0\TestableIO.System.IO.Abstractions.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\testableio.system.io.abstractions.wrappers\22.0.13\lib\net9.0\TestableIO.System.IO.Abstractions.Wrappers.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\testably.abstractions.filesystem.interface\9.0.0\lib\net9.0\Testably.Abstractions.FileSystem.Interface.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.diagnostics.tracing.traceevent\3.1.16\lib\netstandard2.0\TraceReloggerLib.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\UIAutomationClient.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\UIAutomationClientSideProviders.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\UIAutomationProvider.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\UIAutomationTypes.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\WindowsBase.dll" />
|
||||
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\WindowsFormsIntegration.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.windows.sdk.net.ref\10.0.26100.68-preview\lib\net8.0\WinRT.Runtime.dll" />
|
||||
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\wpf-ui\3.0.5\lib\net8.0-windows7.0\Wpf.Ui.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="D:\source\repos\PowerToys\src\modules\imageresizer\ui\obj\ARM64\Debug\Views\InputPage.g.cs" />
|
||||
<Compile Include="D:\source\repos\PowerToys\src\modules\imageresizer\ui\obj\ARM64\Debug\Views\MainWindow.g.cs" />
|
||||
<Compile Include="D:\source\repos\PowerToys\src\modules\imageresizer\ui\obj\ARM64\Debug\Views\ProgressPage.g.cs" />
|
||||
<Compile Include="D:\source\repos\PowerToys\src\modules\imageresizer\ui\obj\ARM64\Debug\Views\ResultsPage.g.cs" />
|
||||
<Compile Include="D:\source\repos\PowerToys\src\modules\imageresizer\ui\obj\ARM64\Debug\App.g.cs" />
|
||||
<Compile Include="D:\source\repos\PowerToys\src\modules\imageresizer\ui\obj\ARM64\Debug\GeneratedInternalTypeHelper.g.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Analyzer Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.codeanalysis.netanalyzers\9.0.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.CSharp.NetAnalyzers.dll" />
|
||||
<Analyzer Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.codeanalysis.netanalyzers\9.0.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.NetAnalyzers.dll" />
|
||||
<Analyzer Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.extensions.logging.abstractions\9.0.8\analyzers\dotnet\roslyn4.4\cs\Microsoft.Extensions.Logging.Generators.dll" />
|
||||
<Analyzer Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.extensions.options\9.0.8\analyzers\dotnet\roslyn4.4\cs\Microsoft.Extensions.Options.SourceGeneration.dll" />
|
||||
<Analyzer Include="C:\Users\jaylynbarbee\.nuget\packages\stylecop.analyzers.unstable\1.2.0.556\analyzers\dotnet\cs\StyleCop.Analyzers.CodeFixes.dll" />
|
||||
<Analyzer Include="C:\Users\jaylynbarbee\.nuget\packages\stylecop.analyzers.unstable\1.2.0.556\analyzers\dotnet\cs\StyleCop.Analyzers.dll" />
|
||||
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\analyzers/dotnet/cs/Microsoft.Interop.ComInterfaceGenerator.dll" />
|
||||
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\analyzers/dotnet/cs/Microsoft.Interop.JavaScript.JSImportGenerator.dll" />
|
||||
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\analyzers/dotnet/cs/Microsoft.Interop.LibraryImportGenerator.dll" />
|
||||
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\analyzers/dotnet/cs/Microsoft.Interop.SourceGeneration.dll" />
|
||||
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\analyzers/dotnet/cs/System.Text.Json.SourceGeneration.dll" />
|
||||
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\analyzers/dotnet/cs/System.Text.RegularExpressions.Generator.dll" />
|
||||
<Analyzer Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.windows.sdk.net.ref\10.0.26100.68-preview\analyzers/dotnet/cs/WinRT.SourceGenerator.dll" />
|
||||
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\analyzers/dotnet/System.Windows.Forms.Analyzers.dll" />
|
||||
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\analyzers/dotnet/cs/System.Windows.Forms.Analyzers.CSharp.dll" />
|
||||
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\analyzers/dotnet/cs/System.Windows.Forms.Analyzers.CodeFixes.CSharp.dll" />
|
||||
</ItemGroup>
|
||||
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
|
||||
</Project>
|
||||
@@ -45,14 +45,44 @@ public:
|
||||
bool shift = false;
|
||||
bool alt = false;
|
||||
unsigned char key = 0;
|
||||
// The id is used to identify the hotkey in the module. The order in module interface should be the same as in the settings.
|
||||
int id = 0;
|
||||
// Currently, this is only used by AdvancedPaste to determine if the hotkey is shown in the settings.
|
||||
bool isShown = true;
|
||||
|
||||
std::strong_ordering operator<=>(const Hotkey&) const = default;
|
||||
std::strong_ordering operator<=>(const Hotkey& other) const
|
||||
{
|
||||
// Compare bool fields first
|
||||
if (auto cmp = (win <=> other.win); cmp != 0)
|
||||
return cmp;
|
||||
if (auto cmp = (ctrl <=> other.ctrl); cmp != 0)
|
||||
return cmp;
|
||||
if (auto cmp = (shift <=> other.shift); cmp != 0)
|
||||
return cmp;
|
||||
if (auto cmp = (alt <=> other.alt); cmp != 0)
|
||||
return cmp;
|
||||
|
||||
// Compare key value only
|
||||
return key <=> other.key;
|
||||
|
||||
// Note: Deliberately NOT comparing 'name' field
|
||||
}
|
||||
|
||||
bool operator==(const Hotkey& other) const
|
||||
{
|
||||
return win == other.win &&
|
||||
ctrl == other.ctrl &&
|
||||
shift == other.shift &&
|
||||
alt == other.alt &&
|
||||
key == other.key;
|
||||
}
|
||||
};
|
||||
|
||||
struct HotkeyEx
|
||||
{
|
||||
WORD modifiersMask = 0;
|
||||
WORD vkCode = 0;
|
||||
int id = 0;
|
||||
};
|
||||
|
||||
/* Returns the localized name of the PowerToy*/
|
||||
|
||||
@@ -14,8 +14,7 @@ namespace Microsoft.PowerToys.Run.Plugin.PowerToys.Components
|
||||
ShortcutGuide = 5,
|
||||
RegistryPreview = 6,
|
||||
CropAndLock = 7,
|
||||
LightSwitch = 8,
|
||||
EnvironmentVariables = 9,
|
||||
Workspaces = 10,
|
||||
EnvironmentVariables = 8,
|
||||
Workspaces = 9,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,18 +77,7 @@ namespace Microsoft.PowerToys.Run.Plugin.PowerToys.Properties {
|
||||
return ResourceManager.GetString("Action_Run_As_Administrator", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Light Switch.
|
||||
/// </summary>
|
||||
internal static string Light_Switch
|
||||
{
|
||||
get
|
||||
{
|
||||
return ResourceManager.GetString("Light_Switch", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Color Picker.
|
||||
/// </summary>
|
||||
|
||||
@@ -572,8 +572,8 @@
|
||||
<data name="DarkColor" xml:space="preserve">
|
||||
<value>Dark color</value>
|
||||
</data>
|
||||
<data name="LightSwitch" xml:space="preserve">
|
||||
<value>Light Switch</value>
|
||||
<data name="DarkMode" xml:space="preserve">
|
||||
<value>Dark mode</value>
|
||||
</data>
|
||||
<data name="DataUsage" xml:space="preserve">
|
||||
<value>Data usage</value>
|
||||
|
||||
@@ -20,11 +20,13 @@ namespace CentralizedHotkeys
|
||||
{
|
||||
WORD modifiersMask;
|
||||
WORD vkCode;
|
||||
int hotkeyID;
|
||||
|
||||
Shortcut(WORD modifiersMask = 0, WORD vkCode = 0)
|
||||
Shortcut(WORD modifiersMask = 0, WORD vkCode = 0, const int hotkeyID = 0)
|
||||
{
|
||||
this->modifiersMask = modifiersMask;
|
||||
this->vkCode = vkCode;
|
||||
this->hotkeyID = hotkeyID;
|
||||
}
|
||||
|
||||
bool operator<(const Shortcut& key) const
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "auto_start_helper.h"
|
||||
#include "tray_icon.h"
|
||||
#include "Generated files/resource.h"
|
||||
#include "hotkey_conflict_detector.h"
|
||||
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include "powertoy_module.h"
|
||||
@@ -204,11 +205,15 @@ void apply_general_settings(const json::JsonObject& general_configs, bool save)
|
||||
{
|
||||
Logger::info(L"apply_general_settings: Enabling powertoy {}", name);
|
||||
powertoy->enable();
|
||||
auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance();
|
||||
hkmng.EnableHotkeyByModule(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info(L"apply_general_settings: Disabling powertoy {}", name);
|
||||
powertoy->disable();
|
||||
auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance();
|
||||
hkmng.DisableHotkeyByModule(name);
|
||||
}
|
||||
// Sync the hotkey state with the module state, so it can be removed for disabled modules.
|
||||
powertoy.UpdateHotkeyEx();
|
||||
@@ -315,6 +320,8 @@ void start_enabled_powertoys()
|
||||
{
|
||||
Logger::info(L"start_enabled_powertoys: Enabling powertoy {}", name);
|
||||
powertoy->enable();
|
||||
auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance();
|
||||
hkmng.EnableHotkeyByModule(name);
|
||||
powertoy.UpdateHotkeyEx();
|
||||
}
|
||||
}
|
||||
|
||||
471
src/runner/hotkey_conflict_detector.cpp
Normal file
471
src/runner/hotkey_conflict_detector.cpp
Normal file
@@ -0,0 +1,471 @@
|
||||
#include "pch.h"
|
||||
#include "hotkey_conflict_detector.h"
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <windows.h>
|
||||
#include <unordered_map>
|
||||
#include <cwchar>
|
||||
|
||||
namespace HotkeyConflictDetector
|
||||
{
|
||||
Hotkey ShortcutToHotkey(const CentralizedHotkeys::Shortcut& shortcut)
|
||||
{
|
||||
Hotkey hotkey;
|
||||
|
||||
hotkey.win = (shortcut.modifiersMask & MOD_WIN) != 0;
|
||||
hotkey.ctrl = (shortcut.modifiersMask & MOD_CONTROL) != 0;
|
||||
hotkey.shift = (shortcut.modifiersMask & MOD_SHIFT) != 0;
|
||||
hotkey.alt = (shortcut.modifiersMask & MOD_ALT) != 0;
|
||||
|
||||
hotkey.key = shortcut.vkCode > 255 ? 0 : static_cast<unsigned char>(shortcut.vkCode);
|
||||
|
||||
return hotkey;
|
||||
}
|
||||
|
||||
HotkeyConflictManager* HotkeyConflictManager::instance = nullptr;
|
||||
std::mutex HotkeyConflictManager::instanceMutex;
|
||||
|
||||
HotkeyConflictManager& HotkeyConflictManager::GetInstance()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(instanceMutex);
|
||||
if (instance == nullptr)
|
||||
{
|
||||
instance = new HotkeyConflictManager();
|
||||
}
|
||||
return *instance;
|
||||
}
|
||||
|
||||
HotkeyConflictType HotkeyConflictManager::HasConflict(Hotkey const& _hotkey, const wchar_t* _moduleName, const int _hotkeyID)
|
||||
{
|
||||
if (disabledHotkeys.find(_moduleName) != disabledHotkeys.end())
|
||||
{
|
||||
return HotkeyConflictType::NoConflict;
|
||||
}
|
||||
|
||||
uint16_t handle = GetHotkeyHandle(_hotkey);
|
||||
|
||||
if (handle == 0)
|
||||
{
|
||||
return HotkeyConflictType::NoConflict;
|
||||
}
|
||||
|
||||
// The order is important, first to check sys conflict and then inapp conflict
|
||||
if (sysConflictHotkeyMap.find(handle) != sysConflictHotkeyMap.end())
|
||||
{
|
||||
return HotkeyConflictType::SystemConflict;
|
||||
}
|
||||
|
||||
if (inAppConflictHotkeyMap.find(handle) != inAppConflictHotkeyMap.end())
|
||||
{
|
||||
return HotkeyConflictType::InAppConflict;
|
||||
}
|
||||
|
||||
auto it = hotkeyMap.find(handle);
|
||||
|
||||
if (it == hotkeyMap.end())
|
||||
{
|
||||
return HasConflictWithSystemHotkey(_hotkey) ?
|
||||
HotkeyConflictType::SystemConflict :
|
||||
HotkeyConflictType::NoConflict;
|
||||
}
|
||||
|
||||
if (wcscmp(it->second.moduleName.c_str(), _moduleName) == 0 && it->second.hotkeyID == _hotkeyID)
|
||||
{
|
||||
// A shortcut matching its own assignment is not considered a conflict.
|
||||
return HotkeyConflictType::NoConflict;
|
||||
}
|
||||
|
||||
return HotkeyConflictType::InAppConflict;
|
||||
}
|
||||
|
||||
HotkeyConflictType HotkeyConflictManager::HasConflict(Hotkey const& _hotkey)
|
||||
{
|
||||
uint16_t handle = GetHotkeyHandle(_hotkey);
|
||||
|
||||
if (handle == 0)
|
||||
{
|
||||
return HotkeyConflictType::NoConflict;
|
||||
}
|
||||
|
||||
// The order is important, first to check sys conflict and then inapp conflict
|
||||
if (sysConflictHotkeyMap.find(handle) != sysConflictHotkeyMap.end())
|
||||
{
|
||||
return HotkeyConflictType::SystemConflict;
|
||||
}
|
||||
|
||||
if (inAppConflictHotkeyMap.find(handle) != inAppConflictHotkeyMap.end())
|
||||
{
|
||||
return HotkeyConflictType::InAppConflict;
|
||||
}
|
||||
|
||||
auto it = hotkeyMap.find(handle);
|
||||
|
||||
if (it == hotkeyMap.end())
|
||||
{
|
||||
return HasConflictWithSystemHotkey(_hotkey) ?
|
||||
HotkeyConflictType::SystemConflict :
|
||||
HotkeyConflictType::NoConflict;
|
||||
}
|
||||
|
||||
return HotkeyConflictType::InAppConflict;
|
||||
}
|
||||
|
||||
// This function should only be called when a conflict has already been identified.
|
||||
// It returns a list of all conflicting shortcuts.
|
||||
std::vector<HotkeyConflictInfo> HotkeyConflictManager::GetAllConflicts(Hotkey const& _hotkey)
|
||||
{
|
||||
std::vector<HotkeyConflictInfo> conflicts;
|
||||
uint16_t handle = GetHotkeyHandle(_hotkey);
|
||||
|
||||
// Check in-app conflicts first
|
||||
auto inAppIt = inAppConflictHotkeyMap.find(handle);
|
||||
if (inAppIt != inAppConflictHotkeyMap.end())
|
||||
{
|
||||
// Add all in-app conflicts
|
||||
for (const auto& conflict : inAppIt->second)
|
||||
{
|
||||
conflicts.push_back(conflict);
|
||||
}
|
||||
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
// Check system conflicts
|
||||
auto sysIt = sysConflictHotkeyMap.find(handle);
|
||||
if (sysIt != sysConflictHotkeyMap.end())
|
||||
{
|
||||
HotkeyConflictInfo systemConflict;
|
||||
systemConflict.hotkey = _hotkey;
|
||||
systemConflict.moduleName = L"System";
|
||||
systemConflict.hotkeyID = 0;
|
||||
|
||||
conflicts.push_back(systemConflict);
|
||||
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
// Check if there's a successfully registered hotkey that would conflict
|
||||
auto registeredIt = hotkeyMap.find(handle);
|
||||
if (registeredIt != hotkeyMap.end())
|
||||
{
|
||||
conflicts.push_back(registeredIt->second);
|
||||
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
// If all the above conditions are ruled out, a system-level conflict is the only remaining explanation.
|
||||
HotkeyConflictInfo systemConflict;
|
||||
systemConflict.hotkey = _hotkey;
|
||||
systemConflict.moduleName = L"System";
|
||||
systemConflict.hotkeyID = 0;
|
||||
conflicts.push_back(systemConflict);
|
||||
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
bool HotkeyConflictManager::AddHotkey(Hotkey const& _hotkey, const wchar_t* _moduleName, const int _hotkeyID, bool isEnabled)
|
||||
{
|
||||
if (!isEnabled)
|
||||
{
|
||||
disabledHotkeys[_moduleName].push_back({ _hotkey, _moduleName, _hotkeyID });
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t handle = GetHotkeyHandle(_hotkey);
|
||||
|
||||
if (handle == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
HotkeyConflictType conflictType = HasConflict(_hotkey, _moduleName, _hotkeyID);
|
||||
if (conflictType != HotkeyConflictType::NoConflict)
|
||||
{
|
||||
if (conflictType == HotkeyConflictType::InAppConflict)
|
||||
{
|
||||
auto hotkeyFound = hotkeyMap.find(handle);
|
||||
inAppConflictHotkeyMap[handle].insert({ _hotkey, _moduleName, _hotkeyID });
|
||||
|
||||
if (hotkeyFound != hotkeyMap.end())
|
||||
{
|
||||
inAppConflictHotkeyMap[handle].insert(hotkeyFound->second);
|
||||
hotkeyMap.erase(hotkeyFound);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sysConflictHotkeyMap[handle].insert({ _hotkey, _moduleName, _hotkeyID });
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
HotkeyConflictInfo hotkeyInfo;
|
||||
hotkeyInfo.moduleName = _moduleName;
|
||||
hotkeyInfo.hotkeyID = _hotkeyID;
|
||||
hotkeyInfo.hotkey = _hotkey;
|
||||
hotkeyMap[handle] = hotkeyInfo;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<HotkeyConflictInfo> HotkeyConflictManager::RemoveHotkeyByModule(const std::wstring& moduleName)
|
||||
{
|
||||
std::vector<HotkeyConflictInfo> removedHotkeys;
|
||||
|
||||
if (disabledHotkeys.find(moduleName) != disabledHotkeys.end())
|
||||
{
|
||||
disabledHotkeys.erase(moduleName);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(hotkeyMutex);
|
||||
bool foundRecord = false;
|
||||
|
||||
for (auto it = sysConflictHotkeyMap.begin(); it != sysConflictHotkeyMap.end();)
|
||||
{
|
||||
auto& conflictSet = it->second;
|
||||
for (auto setIt = conflictSet.begin(); setIt != conflictSet.end();)
|
||||
{
|
||||
if (setIt->moduleName == moduleName)
|
||||
{
|
||||
removedHotkeys.push_back(*setIt);
|
||||
setIt = conflictSet.erase(setIt);
|
||||
foundRecord = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
++setIt;
|
||||
}
|
||||
}
|
||||
if (conflictSet.empty())
|
||||
{
|
||||
it = sysConflictHotkeyMap.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = inAppConflictHotkeyMap.begin(); it != inAppConflictHotkeyMap.end();)
|
||||
{
|
||||
auto& conflictSet = it->second;
|
||||
uint16_t handle = it->first;
|
||||
|
||||
for (auto setIt = conflictSet.begin(); setIt != conflictSet.end();)
|
||||
{
|
||||
if (setIt->moduleName == moduleName)
|
||||
{
|
||||
removedHotkeys.push_back(*setIt);
|
||||
setIt = conflictSet.erase(setIt);
|
||||
foundRecord = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
++setIt;
|
||||
}
|
||||
}
|
||||
|
||||
if (conflictSet.empty())
|
||||
{
|
||||
it = inAppConflictHotkeyMap.erase(it);
|
||||
}
|
||||
else if (conflictSet.size() == 1)
|
||||
{
|
||||
// Move the only remaining conflict to main map
|
||||
const auto& onlyConflict = *conflictSet.begin();
|
||||
hotkeyMap[handle] = onlyConflict;
|
||||
it = inAppConflictHotkeyMap.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = hotkeyMap.begin(); it != hotkeyMap.end();)
|
||||
{
|
||||
if (it->second.moduleName == moduleName)
|
||||
{
|
||||
uint16_t handle = it->first;
|
||||
removedHotkeys.push_back(it->second);
|
||||
it = hotkeyMap.erase(it);
|
||||
foundRecord = true;
|
||||
|
||||
auto inAppIt = inAppConflictHotkeyMap.find(handle);
|
||||
if (inAppIt != inAppConflictHotkeyMap.end() && inAppIt->second.size() == 1)
|
||||
{
|
||||
// Move the only in-app conflict to main map
|
||||
const auto& onlyConflict = *inAppIt->second.begin();
|
||||
hotkeyMap[handle] = onlyConflict;
|
||||
inAppConflictHotkeyMap.erase(inAppIt);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
return removedHotkeys;
|
||||
}
|
||||
|
||||
void HotkeyConflictManager::EnableHotkeyByModule(const std::wstring& moduleName)
|
||||
{
|
||||
if (disabledHotkeys.find(moduleName) == disabledHotkeys.end())
|
||||
{
|
||||
return; // No disabled hotkeys for this module
|
||||
}
|
||||
|
||||
auto hotkeys = disabledHotkeys[moduleName];
|
||||
disabledHotkeys.erase(moduleName);
|
||||
|
||||
for (const auto& hotkeyInfo : hotkeys)
|
||||
{
|
||||
// Re-add the hotkey as enabled
|
||||
AddHotkey(hotkeyInfo.hotkey, moduleName.c_str(), hotkeyInfo.hotkeyID, true);
|
||||
}
|
||||
}
|
||||
|
||||
void HotkeyConflictManager::DisableHotkeyByModule(const std::wstring& moduleName)
|
||||
{
|
||||
auto hotkeys = RemoveHotkeyByModule(moduleName);
|
||||
disabledHotkeys[moduleName] = hotkeys;
|
||||
}
|
||||
|
||||
bool HotkeyConflictManager::HasConflictWithSystemHotkey(const Hotkey& hotkey)
|
||||
{
|
||||
// Convert PowerToys Hotkey format to Win32 RegisterHotKey format
|
||||
UINT modifiers = 0;
|
||||
if (hotkey.win)
|
||||
{
|
||||
modifiers |= MOD_WIN;
|
||||
}
|
||||
if (hotkey.ctrl)
|
||||
{
|
||||
modifiers |= MOD_CONTROL;
|
||||
}
|
||||
if (hotkey.alt)
|
||||
{
|
||||
modifiers |= MOD_ALT;
|
||||
}
|
||||
if (hotkey.shift)
|
||||
{
|
||||
modifiers |= MOD_SHIFT;
|
||||
}
|
||||
|
||||
// No modifiers or no key is not a valid hotkey
|
||||
if (modifiers == 0 || hotkey.key == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use a unique ID for this test registration
|
||||
const int hotkeyId = 0x0FFF; // Arbitrary ID for temporary registration
|
||||
|
||||
// Try to register the hotkey with Windows, using nullptr instead of a window handle
|
||||
if (!RegisterHotKey(nullptr, hotkeyId, modifiers, hotkey.key))
|
||||
{
|
||||
// If registration fails with ERROR_HOTKEY_ALREADY_REGISTERED, it means the hotkey
|
||||
// is already in use by the system or another application
|
||||
if (GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If registration succeeds, unregister it immediately
|
||||
UnregisterHotKey(nullptr, hotkeyId);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
json::JsonObject HotkeyConflictManager::GetHotkeyConflictsAsJson()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(hotkeyMutex);
|
||||
|
||||
using namespace json;
|
||||
JsonObject root;
|
||||
|
||||
// Serialize hotkey to a unique string format for grouping
|
||||
auto serializeHotkey = [](const Hotkey& hotkey) -> JsonObject {
|
||||
JsonObject obj;
|
||||
obj.Insert(L"win", value(hotkey.win));
|
||||
obj.Insert(L"ctrl", value(hotkey.ctrl));
|
||||
obj.Insert(L"shift", value(hotkey.shift));
|
||||
obj.Insert(L"alt", value(hotkey.alt));
|
||||
obj.Insert(L"key", value(static_cast<int>(hotkey.key)));
|
||||
return obj;
|
||||
};
|
||||
|
||||
// New format: Group conflicts by hotkey
|
||||
JsonArray inAppConflictsArray;
|
||||
JsonArray sysConflictsArray;
|
||||
|
||||
// Process in-app conflicts - only include hotkeys that are actually in conflict
|
||||
for (const auto& [handle, conflicts] : inAppConflictHotkeyMap)
|
||||
{
|
||||
if (!conflicts.empty())
|
||||
{
|
||||
JsonObject conflictGroup;
|
||||
|
||||
// All entries have the same hotkey, so use the first one for the key
|
||||
conflictGroup.Insert(L"hotkey", serializeHotkey(conflicts.begin()->hotkey));
|
||||
|
||||
// Create an array of module info without repeating the hotkey
|
||||
JsonArray modules;
|
||||
for (const auto& info : conflicts)
|
||||
{
|
||||
JsonObject moduleInfo;
|
||||
moduleInfo.Insert(L"moduleName", value(info.moduleName));
|
||||
moduleInfo.Insert(L"hotkeyID", value(info.hotkeyID));
|
||||
modules.Append(moduleInfo);
|
||||
}
|
||||
|
||||
conflictGroup.Insert(L"modules", modules);
|
||||
inAppConflictsArray.Append(conflictGroup);
|
||||
}
|
||||
}
|
||||
|
||||
// Process system conflicts - only include hotkeys that are actually in conflict
|
||||
for (const auto& [handle, conflicts] : sysConflictHotkeyMap)
|
||||
{
|
||||
if (!conflicts.empty())
|
||||
{
|
||||
JsonObject conflictGroup;
|
||||
|
||||
// All entries have the same hotkey, so use the first one for the key
|
||||
conflictGroup.Insert(L"hotkey", serializeHotkey(conflicts.begin()->hotkey));
|
||||
|
||||
// Create an array of module info without repeating the hotkey
|
||||
JsonArray modules;
|
||||
for (const auto& info : conflicts)
|
||||
{
|
||||
JsonObject moduleInfo;
|
||||
moduleInfo.Insert(L"moduleName", value(info.moduleName));
|
||||
moduleInfo.Insert(L"hotkeyID", value(info.hotkeyID));
|
||||
modules.Append(moduleInfo);
|
||||
}
|
||||
|
||||
conflictGroup.Insert(L"modules", modules);
|
||||
sysConflictsArray.Append(conflictGroup);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the grouped conflicts to the root object
|
||||
root.Insert(L"inAppConflicts", inAppConflictsArray);
|
||||
root.Insert(L"sysConflicts", sysConflictsArray);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
uint16_t HotkeyConflictManager::GetHotkeyHandle(const Hotkey& hotkey)
|
||||
{
|
||||
uint16_t handle = hotkey.key;
|
||||
handle |= hotkey.win << 8;
|
||||
handle |= hotkey.ctrl << 9;
|
||||
handle |= hotkey.shift << 10;
|
||||
handle |= hotkey.alt << 11;
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
100
src/runner/hotkey_conflict_detector.h
Normal file
100
src/runner/hotkey_conflict_detector.h
Normal file
@@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <string>
|
||||
|
||||
#include "../modules/interface/powertoy_module_interface.h"
|
||||
#include "centralized_hotkeys.h"
|
||||
#include "common/utils/json.h"
|
||||
|
||||
namespace HotkeyConflictDetector
|
||||
{
|
||||
using Hotkey = PowertoyModuleIface::Hotkey;
|
||||
using HotkeyEx = PowertoyModuleIface::HotkeyEx;
|
||||
using Shortcut = CentralizedHotkeys::Shortcut;
|
||||
|
||||
struct HotkeyConflictInfo
|
||||
{
|
||||
Hotkey hotkey;
|
||||
std::wstring moduleName;
|
||||
int hotkeyID = 0;
|
||||
|
||||
inline bool operator==(const HotkeyConflictInfo& other) const
|
||||
{
|
||||
return hotkey == other.hotkey &&
|
||||
moduleName == other.moduleName &&
|
||||
hotkeyID == other.hotkeyID;
|
||||
}
|
||||
};
|
||||
|
||||
Hotkey ShortcutToHotkey(const CentralizedHotkeys::Shortcut& shortcut);
|
||||
|
||||
enum HotkeyConflictType
|
||||
{
|
||||
NoConflict = 0,
|
||||
SystemConflict = 1,
|
||||
InAppConflict = 2,
|
||||
};
|
||||
|
||||
class HotkeyConflictManager
|
||||
{
|
||||
public:
|
||||
static HotkeyConflictManager& GetInstance();
|
||||
|
||||
HotkeyConflictType HasConflict(const Hotkey& hotkey, const wchar_t* moduleName, const int hotkeyID);
|
||||
HotkeyConflictType HotkeyConflictManager::HasConflict(Hotkey const& _hotkey);
|
||||
std::vector<HotkeyConflictInfo> HotkeyConflictManager::GetAllConflicts(Hotkey const& hotkey);
|
||||
bool AddHotkey(const Hotkey& hotkey, const wchar_t* moduleName, const int hotkeyID, bool isEnabled);
|
||||
std::vector<HotkeyConflictInfo> RemoveHotkeyByModule(const std::wstring& moduleName);
|
||||
|
||||
void EnableHotkeyByModule(const std::wstring& moduleName);
|
||||
void DisableHotkeyByModule(const std::wstring& moduleName);
|
||||
|
||||
json::JsonObject GetHotkeyConflictsAsJson();
|
||||
|
||||
private:
|
||||
static std::mutex instanceMutex;
|
||||
static HotkeyConflictManager* instance;
|
||||
|
||||
std::mutex hotkeyMutex;
|
||||
// Hotkey in hotkeyMap means the hotkey has been registered successfully
|
||||
std::unordered_map<uint16_t, HotkeyConflictInfo> hotkeyMap;
|
||||
// Hotkey in sysConflictHotkeyMap means the hotkey has conflict with system defined hotkeys
|
||||
std::unordered_map<uint16_t, std::unordered_set<HotkeyConflictInfo>> sysConflictHotkeyMap;
|
||||
// Hotkey in inAppConflictHotkeyMap means the hotkey has conflict with other modules
|
||||
std::unordered_map<uint16_t, std::unordered_set<HotkeyConflictInfo>> inAppConflictHotkeyMap;
|
||||
|
||||
std::unordered_map<std::wstring, std::vector<HotkeyConflictInfo>> disabledHotkeys;
|
||||
|
||||
uint16_t GetHotkeyHandle(const Hotkey&);
|
||||
bool HasConflictWithSystemHotkey(const Hotkey&);
|
||||
|
||||
HotkeyConflictManager() = default;
|
||||
};
|
||||
};
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
struct hash<HotkeyConflictDetector::HotkeyConflictInfo>
|
||||
{
|
||||
size_t operator()(const HotkeyConflictDetector::HotkeyConflictInfo& info) const
|
||||
{
|
||||
|
||||
size_t hotkeyHash =
|
||||
(info.hotkey.win ? 1ULL : 0ULL) |
|
||||
((info.hotkey.ctrl ? 1ULL : 0ULL) << 1) |
|
||||
((info.hotkey.shift ? 1ULL : 0ULL) << 2) |
|
||||
((info.hotkey.alt ? 1ULL : 0ULL) << 3) |
|
||||
(static_cast<size_t>(info.hotkey.key) << 4);
|
||||
|
||||
size_t moduleHash = std::hash<std::wstring>{}(info.moduleName);
|
||||
size_t idHash = std::hash<int>{}(info.hotkeyID);
|
||||
|
||||
return hotkeyHash ^
|
||||
((moduleHash << 1) | (moduleHash >> (sizeof(size_t) * 8 - 1))) ^ // rotate left 1 bit
|
||||
((idHash << 2) | (idHash >> (sizeof(size_t) * 8 - 2))); // rotate left 2 bits
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -177,7 +177,6 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
|
||||
L"PowerToys.WorkspacesModuleInterface.dll",
|
||||
L"PowerToys.CmdPalModuleInterface.dll",
|
||||
L"PowerToys.ZoomItModuleInterface.dll",
|
||||
L"PowerToys.LightSwitchModuleInterface.dll",
|
||||
};
|
||||
|
||||
for (auto moduleSubdir : knownModules)
|
||||
|
||||
@@ -40,13 +40,14 @@ json::JsonObject PowertoyModule::json_config() const
|
||||
}
|
||||
|
||||
PowertoyModule::PowertoyModule(PowertoyModuleIface* pt_module, HMODULE handle) :
|
||||
handle(handle), pt_module(pt_module)
|
||||
handle(handle), pt_module(pt_module), hkmng(HotkeyConflictDetector::HotkeyConflictManager::GetInstance())
|
||||
{
|
||||
if (!pt_module)
|
||||
{
|
||||
throw std::runtime_error("Module not initialized");
|
||||
}
|
||||
|
||||
remove_hotkey_records();
|
||||
update_hotkeys();
|
||||
UpdateHotkeyEx();
|
||||
}
|
||||
@@ -63,19 +64,27 @@ void PowertoyModule::update_hotkeys()
|
||||
|
||||
for (size_t i = 0; i < hotkeyCount; i++)
|
||||
{
|
||||
CentralizedKeyboardHook::SetHotkeyAction(pt_module->get_key(), hotkeys[i], [modulePtr, i] {
|
||||
Logger::trace(L"{} hotkey is invoked from Centralized keyboard hook", modulePtr->get_key());
|
||||
return modulePtr->on_hotkey(i);
|
||||
});
|
||||
if (hotkeys[i].isShown)
|
||||
{
|
||||
hkmng.AddHotkey(hotkeys[i], pt_module->get_key(), static_cast<int>(i), pt_module->is_enabled());
|
||||
|
||||
CentralizedKeyboardHook::SetHotkeyAction(pt_module->get_key(), hotkeys[i], [modulePtr, i] {
|
||||
Logger::trace(L"{} hotkey is invoked from Centralized keyboard hook", modulePtr->get_key());
|
||||
return modulePtr->on_hotkey(i);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PowertoyModule::UpdateHotkeyEx()
|
||||
{
|
||||
CentralizedHotkeys::UnregisterHotkeysForModule(pt_module->get_key());
|
||||
|
||||
auto container = pt_module->GetHotkeyEx();
|
||||
if (container.has_value() && pt_module->is_enabled())
|
||||
{
|
||||
hkmng.RemoveHotkeyByModule(pt_module->get_key());
|
||||
|
||||
auto hotkey = container.value();
|
||||
auto modulePtr = pt_module.get();
|
||||
auto action = [modulePtr](WORD /*modifiersMask*/, WORD /*vkCode*/) {
|
||||
@@ -83,6 +92,9 @@ void PowertoyModule::UpdateHotkeyEx()
|
||||
modulePtr->OnHotkeyEx();
|
||||
};
|
||||
|
||||
HotkeyConflictDetector::Hotkey _hotkey = HotkeyConflictDetector::ShortcutToHotkey({ hotkey.modifiersMask, hotkey.vkCode });
|
||||
hkmng.AddHotkey(_hotkey, pt_module->get_key(), 0, pt_module->is_enabled()); // This is the only one activation hotkey, so we use "0" as the name.
|
||||
|
||||
CentralizedHotkeys::AddHotkeyAction({ hotkey.modifiersMask, hotkey.vkCode }, { pt_module->get_key(), action });
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include "hotkey_conflict_detector.h"
|
||||
|
||||
#include <common/utils/json.h>
|
||||
|
||||
@@ -44,9 +45,17 @@ public:
|
||||
|
||||
void UpdateHotkeyEx();
|
||||
|
||||
inline void remove_hotkey_records()
|
||||
{
|
||||
hkmng.RemoveHotkeyByModule(pt_module->get_key());
|
||||
}
|
||||
|
||||
private:
|
||||
HotkeyConflictDetector::HotkeyConflictManager& hkmng;
|
||||
std::unique_ptr<HMODULE, PowertoyModuleDLLDeleter> handle;
|
||||
std::unique_ptr<PowertoyModuleIface, PowertoyModuleDeleter> pt_module;
|
||||
|
||||
|
||||
};
|
||||
|
||||
PowertoyModule load_powertoy(const std::wstring_view filename);
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
<ClCompile Include="bug_report.cpp" />
|
||||
<ClCompile Include="centralized_hotkeys.cpp" />
|
||||
<ClCompile Include="general_settings.cpp" />
|
||||
<ClCompile Include="hotkey_conflict_detector.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
@@ -71,6 +72,7 @@
|
||||
<ClInclude Include="bug_report.h" />
|
||||
<ClInclude Include="centralized_hotkeys.h" />
|
||||
<ClInclude Include="general_settings.h" />
|
||||
<ClInclude Include="hotkey_conflict_detector.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="centralized_kb_hook.h" />
|
||||
<ClInclude Include="settings_telemetry.h" />
|
||||
|
||||
@@ -45,6 +45,9 @@
|
||||
<ClCompile Include="bug_report.cpp">
|
||||
<Filter>Utils</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hotkey_conflict_detector.cpp">
|
||||
<Filter>Utils</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
@@ -93,6 +96,9 @@
|
||||
<ClInclude Include="bug_report.h">
|
||||
<Filter>Utils</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hotkey_conflict_detector.h">
|
||||
<Filter>Utils</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Utils">
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "UpdateUtils.h"
|
||||
#include "centralized_kb_hook.h"
|
||||
#include "Generated files/resource.h"
|
||||
#include "hotkey_conflict_detector.h"
|
||||
|
||||
#include <common/utils/json.h>
|
||||
#include <common/SettingsAPI/settings_helpers.cpp>
|
||||
@@ -153,6 +154,8 @@ void send_json_config_to_module(const std::wstring& module_key, const std::wstri
|
||||
if (moduleIt != modules().end())
|
||||
{
|
||||
moduleIt->second->set_config(settings.c_str());
|
||||
|
||||
moduleIt->second.remove_hotkey_records();
|
||||
moduleIt->second.update_hotkeys();
|
||||
moduleIt->second.UpdateHotkeyEx();
|
||||
}
|
||||
@@ -249,6 +252,77 @@ void dispatch_received_json(const std::wstring& json_to_parse)
|
||||
const std::wstring save_file_location = PTSettingsHelper::get_root_save_folder_location() + language_filename;
|
||||
json::to_file(save_file_location, j);
|
||||
}
|
||||
else if (name == L"check_hotkey_conflict")
|
||||
{
|
||||
try
|
||||
{
|
||||
PowertoyModuleIface::Hotkey hotkey;
|
||||
hotkey.win = value.GetObjectW().GetNamedBoolean(L"win", false);
|
||||
hotkey.ctrl = value.GetObjectW().GetNamedBoolean(L"ctrl", false);
|
||||
hotkey.shift = value.GetObjectW().GetNamedBoolean(L"shift", false);
|
||||
hotkey.alt = value.GetObjectW().GetNamedBoolean(L"alt", false);
|
||||
hotkey.key = static_cast<unsigned char>(value.GetObjectW().GetNamedNumber(L"key", 0));
|
||||
|
||||
std::wstring requestId = value.GetObjectW().GetNamedString(L"request_id", L"").c_str();
|
||||
|
||||
auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance();
|
||||
bool hasConflict = hkmng.HasConflict(hotkey);
|
||||
|
||||
json::JsonObject response;
|
||||
response.SetNamedValue(L"response_type", json::JsonValue::CreateStringValue(L"hotkey_conflict_result"));
|
||||
response.SetNamedValue(L"request_id", json::JsonValue::CreateStringValue(requestId));
|
||||
response.SetNamedValue(L"has_conflict", json::JsonValue::CreateBooleanValue(hasConflict));
|
||||
|
||||
if (hasConflict)
|
||||
{
|
||||
auto conflicts = hkmng.GetAllConflicts(hotkey);
|
||||
if (!conflicts.empty())
|
||||
{
|
||||
// Include all conflicts in the response
|
||||
json::JsonArray allConflicts;
|
||||
for (const auto& conflict : conflicts)
|
||||
{
|
||||
json::JsonObject conflictObj;
|
||||
conflictObj.SetNamedValue(L"module", json::JsonValue::CreateStringValue(conflict.moduleName));
|
||||
conflictObj.SetNamedValue(L"hotkeyID", json::JsonValue::CreateNumberValue(conflict.hotkeyID));
|
||||
allConflicts.Append(conflictObj);
|
||||
}
|
||||
response.SetNamedValue(L"all_conflicts", allConflicts);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_lock lock{ ipc_mutex };
|
||||
if (current_settings_ipc)
|
||||
{
|
||||
current_settings_ipc->send(response.Stringify().c_str());
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"Failed to process hotkey conflict check request");
|
||||
}
|
||||
}
|
||||
else if (name == L"get_all_hotkey_conflicts")
|
||||
{
|
||||
try
|
||||
{
|
||||
auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance();
|
||||
auto conflictsJson = hkmng.GetHotkeyConflictsAsJson();
|
||||
|
||||
// Add response type identifier
|
||||
conflictsJson.SetNamedValue(L"response_type", json::JsonValue::CreateStringValue(L"all_hotkey_conflicts"));
|
||||
|
||||
std::unique_lock lock{ ipc_mutex };
|
||||
if (current_settings_ipc)
|
||||
{
|
||||
current_settings_ipc->send(conflictsJson.Stringify().c_str());
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"Failed to process get all hotkey conflicts request");
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -683,8 +757,6 @@ std::string ESettingsWindowNames_to_string(ESettingsWindowNames value)
|
||||
return "ColorPicker";
|
||||
case ESettingsWindowNames::CmdNotFound:
|
||||
return "CmdNotFound";
|
||||
case ESettingsWindowNames::LightSwitch:
|
||||
return "LightSwitch";
|
||||
case ESettingsWindowNames::FancyZones:
|
||||
return "FancyZones";
|
||||
case ESettingsWindowNames::FileLocksmith:
|
||||
@@ -770,10 +842,6 @@ ESettingsWindowNames ESettingsWindowNames_from_string(std::string value)
|
||||
{
|
||||
return ESettingsWindowNames::CmdNotFound;
|
||||
}
|
||||
else if (value == "LightSwitch")
|
||||
{
|
||||
return ESettingsWindowNames::LightSwitch;
|
||||
}
|
||||
else if (value == "FancyZones")
|
||||
{
|
||||
return ESettingsWindowNames::FancyZones;
|
||||
|
||||
@@ -10,7 +10,6 @@ enum class ESettingsWindowNames
|
||||
Awake,
|
||||
ColorPicker,
|
||||
CmdNotFound,
|
||||
LightSwitch,
|
||||
FancyZones,
|
||||
FileLocksmith,
|
||||
Run,
|
||||
|
||||
@@ -12,7 +12,9 @@ namespace Microsoft.PowerToys.Settings.UI.Library;
|
||||
public sealed partial class AdvancedPasteAdditionalAction : Observable, IAdvancedPasteAction
|
||||
{
|
||||
private HotkeySettings _shortcut = new();
|
||||
private bool _isShown = true;
|
||||
private bool _isShown;
|
||||
private bool _hasConflict;
|
||||
private string _tooltip;
|
||||
|
||||
[JsonPropertyName("shortcut")]
|
||||
public HotkeySettings Shortcut
|
||||
@@ -38,6 +40,20 @@ public sealed partial class AdvancedPasteAdditionalAction : Observable, IAdvance
|
||||
set => Set(ref _isShown, value);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool HasConflict
|
||||
{
|
||||
get => _hasConflict;
|
||||
set => Set(ref _hasConflict, value);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public string Tooltip
|
||||
{
|
||||
get => _tooltip;
|
||||
set => Set(ref _tooltip, value);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public IEnumerable<IAdvancedPasteAction> SubActions => [];
|
||||
}
|
||||
|
||||
@@ -28,16 +28,23 @@ public sealed class AdvancedPasteAdditionalActions
|
||||
|
||||
public IEnumerable<IAdvancedPasteAction> GetAllActions()
|
||||
{
|
||||
Queue<IAdvancedPasteAction> queue = new([ImageToText, PasteAsFile, Transcode]);
|
||||
return GetAllActionsRecursive([ImageToText, PasteAsFile, Transcode]);
|
||||
}
|
||||
|
||||
while (queue.Count != 0)
|
||||
/// <summary>
|
||||
/// Changed to depth-first traversal to ensure ordered output
|
||||
/// </summary>
|
||||
/// <param name="actions">The collection of actions to traverse</param>
|
||||
/// <returns>All actions returned in depth-first order</returns>
|
||||
private static IEnumerable<IAdvancedPasteAction> GetAllActionsRecursive(IEnumerable<IAdvancedPasteAction> actions)
|
||||
{
|
||||
foreach (var action in actions)
|
||||
{
|
||||
var action = queue.Dequeue();
|
||||
yield return action;
|
||||
|
||||
foreach (var subAction in action.SubActions)
|
||||
foreach (var subAction in GetAllActionsRecursive(action.SubActions))
|
||||
{
|
||||
queue.Enqueue(subAction);
|
||||
yield return subAction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.HotkeyConflicts;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library;
|
||||
|
||||
@@ -20,6 +20,8 @@ public sealed class AdvancedPasteCustomAction : Observable, IAdvancedPasteAction
|
||||
private bool _canMoveUp;
|
||||
private bool _canMoveDown;
|
||||
private bool _isValid;
|
||||
private bool _hasConflict;
|
||||
private string _tooltip;
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
public int Id
|
||||
@@ -65,7 +67,6 @@ public sealed class AdvancedPasteCustomAction : Observable, IAdvancedPasteAction
|
||||
// We null-coalesce here rather than outside this branch as we want to raise PropertyChanged when the setter is called
|
||||
// with null; the ShortcutControl depends on this.
|
||||
_shortcut = value ?? new();
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
@@ -99,6 +100,20 @@ public sealed class AdvancedPasteCustomAction : Observable, IAdvancedPasteAction
|
||||
private set => Set(ref _isValid, value);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool HasConflict
|
||||
{
|
||||
get => _hasConflict;
|
||||
set => Set(ref _hasConflict, value);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public string Tooltip
|
||||
{
|
||||
get => _tooltip;
|
||||
set => Set(ref _tooltip, value);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public IEnumerable<IAdvancedPasteAction> SubActions => [];
|
||||
|
||||
@@ -118,6 +133,8 @@ public sealed class AdvancedPasteCustomAction : Observable, IAdvancedPasteAction
|
||||
IsShown = other.IsShown;
|
||||
CanMoveUp = other.CanMoveUp;
|
||||
CanMoveDown = other.CanMoveDown;
|
||||
HasConflict = other.HasConflict;
|
||||
Tooltip = other.Tooltip;
|
||||
}
|
||||
|
||||
private HotkeySettings GetShortcutClone()
|
||||
|
||||
@@ -3,14 +3,16 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class AdvancedPasteSettings : BasePTModuleSettings, ISettingsConfig
|
||||
public class AdvancedPasteSettings : BasePTModuleSettings, ISettingsConfig, IHotkeyConfig
|
||||
{
|
||||
public const string ModuleName = "AdvancedPaste";
|
||||
|
||||
@@ -39,6 +41,64 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
settingsUtils.SaveSettings(JsonSerializer.Serialize(this, options), ModuleName);
|
||||
}
|
||||
|
||||
public ModuleType GetModuleType() => ModuleType.AdvancedPaste;
|
||||
|
||||
public HotkeyAccessor[] GetAllHotkeyAccessors()
|
||||
{
|
||||
var hotkeyAccessors = new List<HotkeyAccessor>
|
||||
{
|
||||
new HotkeyAccessor(
|
||||
() => Properties.PasteAsPlainTextShortcut,
|
||||
value => Properties.PasteAsPlainTextShortcut = value ?? AdvancedPasteProperties.DefaultPasteAsPlainTextShortcut,
|
||||
"PasteAsPlainText_Shortcut"),
|
||||
new HotkeyAccessor(
|
||||
() => Properties.AdvancedPasteUIShortcut,
|
||||
value => Properties.AdvancedPasteUIShortcut = value ?? AdvancedPasteProperties.DefaultAdvancedPasteUIShortcut,
|
||||
"AdvancedPasteUI_Shortcut"),
|
||||
new HotkeyAccessor(
|
||||
() => Properties.PasteAsMarkdownShortcut,
|
||||
value => Properties.PasteAsMarkdownShortcut = value ?? new HotkeySettings(),
|
||||
"PasteAsMarkdown_Shortcut"),
|
||||
new HotkeyAccessor(
|
||||
() => Properties.PasteAsJsonShortcut,
|
||||
value => Properties.PasteAsJsonShortcut = value ?? new HotkeySettings(),
|
||||
"PasteAsJson_Shortcut"),
|
||||
};
|
||||
|
||||
string[] additionalActionHeaderKeys =
|
||||
[
|
||||
"ImageToText",
|
||||
"PasteAsTxtFile",
|
||||
"PasteAsPngFile",
|
||||
"PasteAsHtmlFile",
|
||||
"TranscodeToMp3",
|
||||
"TranscodeToMp4",
|
||||
];
|
||||
int index = 0;
|
||||
foreach (var action in Properties.AdditionalActions.GetAllActions())
|
||||
{
|
||||
if (action is AdvancedPasteAdditionalAction additionalAction)
|
||||
{
|
||||
hotkeyAccessors.Add(new HotkeyAccessor(
|
||||
() => additionalAction.Shortcut,
|
||||
value => additionalAction.Shortcut = value ?? new HotkeySettings(),
|
||||
additionalActionHeaderKeys[index]));
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
// Custom actions do not have localization header, just use the action name.
|
||||
foreach (var customAction in Properties.CustomActions.Value)
|
||||
{
|
||||
hotkeyAccessors.Add(new HotkeyAccessor(
|
||||
() => customAction.Shortcut,
|
||||
value => customAction.Shortcut = value ?? new HotkeySettings(),
|
||||
customAction.Name));
|
||||
}
|
||||
|
||||
return hotkeyAccessors.ToArray();
|
||||
}
|
||||
|
||||
public string GetModuleName()
|
||||
=> Name;
|
||||
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class AlwaysOnTopSettings : BasePTModuleSettings, ISettingsConfig
|
||||
public class AlwaysOnTopSettings : BasePTModuleSettings, ISettingsConfig, IHotkeyConfig
|
||||
{
|
||||
public const string ModuleName = "AlwaysOnTop";
|
||||
public const string ModuleVersion = "0.0.1";
|
||||
@@ -28,6 +30,21 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
return Name;
|
||||
}
|
||||
|
||||
public ModuleType GetModuleType() => ModuleType.AlwaysOnTop;
|
||||
|
||||
public HotkeyAccessor[] GetAllHotkeyAccessors()
|
||||
{
|
||||
var hotkeyAccessors = new List<HotkeyAccessor>
|
||||
{
|
||||
new HotkeyAccessor(
|
||||
() => Properties.Hotkey.Value,
|
||||
value => Properties.Hotkey.Value = value ?? AlwaysOnTopProperties.DefaultHotkeyValue,
|
||||
"AlwaysOnTop_ActivationShortcut"),
|
||||
};
|
||||
|
||||
return hotkeyAccessors.ToArray();
|
||||
}
|
||||
|
||||
public bool UpgradeSettingsConfiguration()
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -7,14 +7,14 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Enumerations;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class ColorPickerSettings : BasePTModuleSettings, ISettingsConfig
|
||||
public class ColorPickerSettings : BasePTModuleSettings, ISettingsConfig, IHotkeyConfig
|
||||
{
|
||||
public const string ModuleName = "ColorPicker";
|
||||
|
||||
@@ -64,6 +64,21 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
return false;
|
||||
}
|
||||
|
||||
public ModuleType GetModuleType() => ModuleType.ColorPicker;
|
||||
|
||||
public HotkeyAccessor[] GetAllHotkeyAccessors()
|
||||
{
|
||||
var hotkeyAccessors = new List<HotkeyAccessor>
|
||||
{
|
||||
new HotkeyAccessor(
|
||||
() => Properties.ActivationShortcut,
|
||||
value => Properties.ActivationShortcut = value ?? Properties.DefaultActivationShortcut,
|
||||
"Activation_Shortcut"),
|
||||
};
|
||||
|
||||
return hotkeyAccessors.ToArray();
|
||||
}
|
||||
|
||||
public static object UpgradeSettings(object oldSettingsObject)
|
||||
{
|
||||
ColorPickerSettingsVersion1 oldSettings = (ColorPickerSettingsVersion1)oldSettingsObject;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class CropAndLockSettings : BasePTModuleSettings, ISettingsConfig
|
||||
public class CropAndLockSettings : BasePTModuleSettings, ISettingsConfig, IHotkeyConfig
|
||||
{
|
||||
public const string ModuleName = "CropAndLock";
|
||||
public const string ModuleVersion = "0.0.1";
|
||||
@@ -28,6 +30,25 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
return Name;
|
||||
}
|
||||
|
||||
public ModuleType GetModuleType() => ModuleType.CropAndLock;
|
||||
|
||||
public HotkeyAccessor[] GetAllHotkeyAccessors()
|
||||
{
|
||||
var hotkeyAccessors = new List<HotkeyAccessor>
|
||||
{
|
||||
new HotkeyAccessor(
|
||||
() => Properties.ReparentHotkey.Value,
|
||||
value => Properties.ReparentHotkey.Value = value ?? CropAndLockProperties.DefaultReparentHotkeyValue,
|
||||
"CropAndLock_ReparentActivation_Shortcut"),
|
||||
new HotkeyAccessor(
|
||||
() => Properties.ThumbnailHotkey.Value,
|
||||
value => Properties.ThumbnailHotkey.Value = value ?? CropAndLockProperties.DefaultThumbnailHotkeyValue,
|
||||
"CropAndLock_ThumbnailActivation_Shortcut"),
|
||||
};
|
||||
|
||||
return hotkeyAccessors.ToArray();
|
||||
}
|
||||
|
||||
public bool UpgradeSettingsConfiguration()
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -513,23 +513,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
}
|
||||
}
|
||||
|
||||
private bool lightSwitch;
|
||||
|
||||
[JsonPropertyName("LightSwitch")]
|
||||
public bool LightSwitch
|
||||
{
|
||||
get => lightSwitch;
|
||||
set
|
||||
{
|
||||
if (lightSwitch != value)
|
||||
{
|
||||
LogTelemetryEvent(value);
|
||||
lightSwitch = value;
|
||||
NotifyChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void NotifyChange()
|
||||
{
|
||||
notifyEnabledChangedAction?.Invoke();
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class FindMyMouseSettings : BasePTModuleSettings, ISettingsConfig
|
||||
public class FindMyMouseSettings : BasePTModuleSettings, ISettingsConfig, IHotkeyConfig
|
||||
{
|
||||
public const string ModuleName = "FindMyMouse";
|
||||
|
||||
@@ -27,6 +29,21 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
return Name;
|
||||
}
|
||||
|
||||
public ModuleType GetModuleType() => ModuleType.FindMyMouse;
|
||||
|
||||
public HotkeyAccessor[] GetAllHotkeyAccessors()
|
||||
{
|
||||
var hotkeyAccessors = new List<HotkeyAccessor>
|
||||
{
|
||||
new HotkeyAccessor(
|
||||
() => Properties.ActivationShortcut,
|
||||
value => Properties.ActivationShortcut = value ?? Properties.DefaultActivationShortcut,
|
||||
"MouseUtils_FindMyMouse_ActivationShortcut"),
|
||||
};
|
||||
|
||||
return hotkeyAccessors.ToArray();
|
||||
}
|
||||
|
||||
// This can be utilized in the future if the settings.json file is to be modified/deleted.
|
||||
public bool UpgradeSettingsConfiguration()
|
||||
{
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Settings.UI.Library.Helpers;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Helpers
|
||||
{
|
||||
public static class CityLoader
|
||||
{
|
||||
/// <summary>
|
||||
/// Loads all cities from a world_cities.csv file.
|
||||
/// Expected columns: city, city_ascii, lat, lng, country
|
||||
/// </summary>
|
||||
public static IEnumerable<City> LoadCities(string path)
|
||||
{
|
||||
using StreamReader reader = new(path);
|
||||
|
||||
// Read header
|
||||
string header = reader.ReadLine();
|
||||
if (header is null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
List<string> headerCols = SplitCsvLine(header);
|
||||
int idxCity = headerCols.FindIndex(h => string.Equals(h, "city", StringComparison.OrdinalIgnoreCase));
|
||||
int idxCityAscii = headerCols.FindIndex(h => string.Equals(h, "city_ascii", StringComparison.OrdinalIgnoreCase));
|
||||
int idxLat = headerCols.FindIndex(h => string.Equals(h, "lat", StringComparison.OrdinalIgnoreCase));
|
||||
int idxLng = headerCols.FindIndex(h => string.Equals(h, "lng", StringComparison.OrdinalIgnoreCase));
|
||||
int idxCountry = headerCols.FindIndex(h => string.Equals(h, "country", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
string line;
|
||||
while ((line = reader.ReadLine()) is not null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
List<string> cols = SplitCsvLine(line);
|
||||
|
||||
string rawCity = idxCity >= 0 && idxCity < cols.Count ? cols[idxCity] : string.Empty;
|
||||
string cityAscii = idxCityAscii >= 0 && idxCityAscii < cols.Count ? cols[idxCityAscii] : string.Empty;
|
||||
string cityName = string.IsNullOrWhiteSpace(cityAscii) ? rawCity : cityAscii;
|
||||
string country = idxCountry >= 0 && idxCountry < cols.Count ? cols[idxCountry] : string.Empty;
|
||||
|
||||
if (!(idxLat >= 0 && idxLat < cols.Count && idxLng >= 0 && idxLng < cols.Count))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!double.TryParse(cols[idxLat], NumberStyles.Float, CultureInfo.InvariantCulture, out double lat))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!double.TryParse(cols[idxLng], NumberStyles.Float, CultureInfo.InvariantCulture, out double lng))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cityName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return new City(cityName, country, lat, lng);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits a CSV line, handling commas inside quotes and escaped quotes.
|
||||
/// </summary>
|
||||
private static List<string> SplitCsvLine(string line)
|
||||
{
|
||||
List<string> result = new();
|
||||
if (string.IsNullOrEmpty(line))
|
||||
{
|
||||
result.Add(string.Empty);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool inQuotes = false;
|
||||
StringBuilder current = new();
|
||||
|
||||
for (int i = 0; i < line.Length; i++)
|
||||
{
|
||||
char c = line[i];
|
||||
if (c == '"')
|
||||
{
|
||||
if (inQuotes && i + 1 < line.Length && line[i + 1] == '"')
|
||||
{
|
||||
current.Append('"');
|
||||
i++; // skip escaped quote
|
||||
}
|
||||
else
|
||||
{
|
||||
inQuotes = !inQuotes;
|
||||
}
|
||||
}
|
||||
else if (c == ',' && !inQuotes)
|
||||
{
|
||||
result.Add(current.ToString());
|
||||
current.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
current.Append(c);
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(current.ToString());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library.Helpers
|
||||
{
|
||||
public class HotkeyAccessor
|
||||
{
|
||||
public Func<HotkeySettings> Getter { get; }
|
||||
|
||||
public Action<HotkeySettings> Setter { get; }
|
||||
|
||||
public HotkeyAccessor(Func<HotkeySettings> getter, Action<HotkeySettings> setter, string localizationHeaderKey = "")
|
||||
{
|
||||
Getter = getter ?? throw new ArgumentNullException(nameof(getter));
|
||||
Setter = setter ?? throw new ArgumentNullException(nameof(setter));
|
||||
LocalizationHeaderKey = localizationHeaderKey;
|
||||
}
|
||||
|
||||
public HotkeySettings Value
|
||||
{
|
||||
get => Getter();
|
||||
set => Setter(value);
|
||||
}
|
||||
|
||||
public string LocalizationHeaderKey { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
// 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;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library.Helpers
|
||||
{
|
||||
public static class SunCalc
|
||||
{
|
||||
public static SunTimes CalculateSunriseSunset(double latitude, double longitude, int year, int month, int day)
|
||||
{
|
||||
double zenith = 90.833; // official sunrise/sunset
|
||||
|
||||
int n1 = (int)Math.Floor(275.0 * month / 9.0);
|
||||
int n2 = (int)Math.Floor((month + 9.0) / 12.0);
|
||||
int n3 = (int)Math.Floor(1.0 + Math.Floor((year - (4.0 * Math.Floor(year / 4.0)) + 2.0) / 3.0));
|
||||
int n = n1 - (n2 * n3) + day - 30;
|
||||
|
||||
double? riseUT = CalcTime(isSunrise: true);
|
||||
double? setUT = CalcTime(isSunrise: false);
|
||||
|
||||
var riseLocal = ToLocal(riseUT, year, month, day);
|
||||
var setLocal = ToLocal(setUT, year, month, day);
|
||||
|
||||
var result = new SunTimes
|
||||
{
|
||||
HasSunrise = riseLocal.HasValue,
|
||||
HasSunset = setLocal.HasValue,
|
||||
SunriseHour = riseLocal?.Hour ?? -1,
|
||||
SunriseMinute = riseLocal?.Minute ?? -1,
|
||||
SunsetHour = setLocal?.Hour ?? -1,
|
||||
SunsetMinute = setLocal?.Minute ?? -1,
|
||||
};
|
||||
|
||||
return result;
|
||||
|
||||
// Local functions
|
||||
double? CalcTime(bool isSunrise)
|
||||
{
|
||||
double lngHour = longitude / 15.0;
|
||||
double t = isSunrise ? n + ((6 - lngHour) / 24.0) : n + ((18 - lngHour) / 24.0);
|
||||
|
||||
double m1 = (0.9856 * t) - 3.289;
|
||||
double l = m1 + (1.916 * Math.Sin(Deg2Rad(m1))) + (0.020 * Math.Sin(2 * Deg2Rad(m1))) + 282.634;
|
||||
l = NormalizeDegrees(l);
|
||||
|
||||
double rA = Rad2Deg(Math.Atan(0.91764 * Math.Tan(Deg2Rad(l))));
|
||||
rA = NormalizeDegrees(rA);
|
||||
|
||||
double lquadrant = Math.Floor(l / 90.0) * 90.0;
|
||||
double rAquadrant = Math.Floor(rA / 90.0) * 90.0;
|
||||
rA = rA + (lquadrant - rAquadrant);
|
||||
rA /= 15.0;
|
||||
|
||||
double sinDec = 0.39782 * Math.Sin(Deg2Rad(l));
|
||||
double cosDec = Math.Cos(Math.Asin(sinDec));
|
||||
|
||||
double cosH = (Math.Cos(Deg2Rad(zenith)) - (sinDec * Math.Sin(Deg2Rad(latitude))))
|
||||
/ (cosDec * Math.Cos(Deg2Rad(latitude)));
|
||||
|
||||
if (cosH > 1.0 || cosH < -1.0)
|
||||
{
|
||||
// Sun never rises or never sets on this date at this location
|
||||
return null;
|
||||
}
|
||||
|
||||
double h = isSunrise ? 360.0 - Rad2Deg(Math.Acos(cosH)) : Rad2Deg(Math.Acos(cosH));
|
||||
h /= 15.0;
|
||||
|
||||
double t1 = h + rA - (0.06571 * t) - 6.622;
|
||||
double uT = t1 - lngHour;
|
||||
uT = NormalizeHours(uT);
|
||||
|
||||
return uT;
|
||||
}
|
||||
|
||||
static (int Hour, int Minute)? ToLocal(double? ut, int y, int m, int d)
|
||||
{
|
||||
if (!ut.HasValue)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Convert fractional hours to hh:mm with proper rounding
|
||||
int hours = (int)Math.Floor(ut.Value);
|
||||
int minutes = (int)((ut.Value - hours) * 60.0);
|
||||
|
||||
// Normalize minute overflow
|
||||
if (minutes == 60)
|
||||
{
|
||||
minutes = 0;
|
||||
hours = (hours + 1) % 24;
|
||||
}
|
||||
|
||||
// Build a UTC DateTime on the given date
|
||||
var utc = new DateTime(y, m, d, hours, minutes, 0, DateTimeKind.Utc);
|
||||
|
||||
// Convert to local time using system time zone rules for that date
|
||||
var local = TimeZoneInfo.ConvertTimeFromUtc(utc, TimeZoneInfo.Local);
|
||||
|
||||
return (local.Hour, local.Minute);
|
||||
}
|
||||
|
||||
static double Deg2Rad(double deg) => deg * Math.PI / 180.0;
|
||||
static double Rad2Deg(double rad) => rad * 180.0 / Math.PI;
|
||||
|
||||
static double NormalizeDegrees(double angle)
|
||||
{
|
||||
angle %= 360.0;
|
||||
if (angle < 0)
|
||||
{
|
||||
angle += 360.0;
|
||||
}
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
static double NormalizeHours(double hours)
|
||||
{
|
||||
hours %= 24.0;
|
||||
if (hours < 0)
|
||||
{
|
||||
hours += 24.0;
|
||||
}
|
||||
|
||||
return hours;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library.HotkeyConflicts
|
||||
{
|
||||
public class AllHotkeyConflictsData
|
||||
{
|
||||
public List<HotkeyConflictGroupData> InAppConflicts { get; set; } = new List<HotkeyConflictGroupData>();
|
||||
|
||||
public List<HotkeyConflictGroupData> SystemConflicts { get; set; } = new List<HotkeyConflictGroupData>();
|
||||
}
|
||||
}
|
||||
@@ -8,17 +8,15 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library.Helpers
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library.HotkeyConflicts
|
||||
{
|
||||
public struct SunTimes
|
||||
public class AllHotkeyConflictsEventArgs : EventArgs
|
||||
{
|
||||
public int SunriseHour;
|
||||
public int SunriseMinute;
|
||||
public int SunsetHour;
|
||||
public int SunsetMinute;
|
||||
public string Text;
|
||||
public AllHotkeyConflictsData Conflicts { get; }
|
||||
|
||||
public bool HasSunrise;
|
||||
public bool HasSunset;
|
||||
public AllHotkeyConflictsEventArgs(AllHotkeyConflictsData conflicts)
|
||||
{
|
||||
Conflicts = conflicts;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,12 +8,14 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Settings.UI.Library.Helpers
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library.HotkeyConflicts
|
||||
{
|
||||
public sealed record City(string Name, string Country, double Latitude, double Longitude)
|
||||
public class HotkeyConflictGroupData
|
||||
{
|
||||
public string Display => string.IsNullOrWhiteSpace(Country)
|
||||
? Name
|
||||
: $"{Name}, {Country}";
|
||||
public HotkeyData Hotkey { get; set; }
|
||||
|
||||
public bool IsSystemConflict { get; set; }
|
||||
|
||||
public List<ModuleHotkeyData> Modules { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library.HotkeyConflicts
|
||||
{
|
||||
public class HotkeyConflictInfo
|
||||
{
|
||||
public bool IsSystemConflict { get; set; }
|
||||
|
||||
public string ConflictingModuleName { get; set; }
|
||||
|
||||
public int ConflictingHotkeyID { get; set; }
|
||||
|
||||
public List<string> AllConflictingModules { get; set; } = new List<string>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library.HotkeyConflicts
|
||||
{
|
||||
public class HotkeyData
|
||||
{
|
||||
public bool Win { get; set; }
|
||||
|
||||
public bool Ctrl { get; set; }
|
||||
|
||||
public bool Shift { get; set; }
|
||||
|
||||
public bool Alt { get; set; }
|
||||
|
||||
public int Key { get; set; }
|
||||
|
||||
public List<object> GetKeysList()
|
||||
{
|
||||
List<object> shortcutList = new List<object>();
|
||||
|
||||
if (Win)
|
||||
{
|
||||
shortcutList.Add(92); // The Windows key or button.
|
||||
}
|
||||
|
||||
if (Ctrl)
|
||||
{
|
||||
shortcutList.Add("Ctrl");
|
||||
}
|
||||
|
||||
if (Alt)
|
||||
{
|
||||
shortcutList.Add("Alt");
|
||||
}
|
||||
|
||||
if (Shift)
|
||||
{
|
||||
shortcutList.Add(16); // The Shift key or button.
|
||||
}
|
||||
|
||||
if (Key > 0)
|
||||
{
|
||||
switch (Key)
|
||||
{
|
||||
// https://learn.microsoft.com/uwp/api/windows.system.virtualkey?view=winrt-20348
|
||||
case 38: // The Up Arrow key or button.
|
||||
case 40: // The Down Arrow key or button.
|
||||
case 37: // The Left Arrow key or button.
|
||||
case 39: // The Right Arrow key or button.
|
||||
shortcutList.Add(Key);
|
||||
break;
|
||||
default:
|
||||
var localKey = Helper.GetKeyName((uint)Key);
|
||||
shortcutList.Add(localKey);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return shortcutList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library.HotkeyConflicts
|
||||
{
|
||||
public class ModuleConflictsData
|
||||
{
|
||||
public List<HotkeyConflictGroupData> InAppConflicts { get; set; } = new List<HotkeyConflictGroupData>();
|
||||
|
||||
public List<HotkeyConflictGroupData> SystemConflicts { get; set; } = new List<HotkeyConflictGroupData>();
|
||||
|
||||
public bool HasConflicts => InAppConflicts.Count > 0 || SystemConflicts.Count > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
// 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.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
using Windows.Web.AtomPub;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library.HotkeyConflicts
|
||||
{
|
||||
public class ModuleHotkeyData : INotifyPropertyChanged
|
||||
{
|
||||
private string _moduleName;
|
||||
private int _hotkeyID;
|
||||
private HotkeySettings _hotkeySettings;
|
||||
private bool _isSystemConflict;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public string IconPath { get; set; }
|
||||
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
public string Header { get; set; }
|
||||
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
public string ModuleName
|
||||
{
|
||||
get => _moduleName;
|
||||
set
|
||||
{
|
||||
if (_moduleName != value)
|
||||
{
|
||||
_moduleName = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int HotkeyID
|
||||
{
|
||||
get => _hotkeyID;
|
||||
set
|
||||
{
|
||||
if (_hotkeyID != value)
|
||||
{
|
||||
_hotkeyID = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public HotkeySettings HotkeySettings
|
||||
{
|
||||
get => _hotkeySettings;
|
||||
set
|
||||
{
|
||||
if (_hotkeySettings != value)
|
||||
{
|
||||
_hotkeySettings = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSystemConflict
|
||||
{
|
||||
get => _isSystemConflict;
|
||||
set
|
||||
{
|
||||
if (_isSystemConflict != value)
|
||||
{
|
||||
_isSystemConflict = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ModuleType ModuleType { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -4,17 +4,29 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public record HotkeySettings : ICmdLineRepresentable
|
||||
public record HotkeySettings : ICmdLineRepresentable, INotifyPropertyChanged
|
||||
{
|
||||
private const int VKTAB = 0x09;
|
||||
private bool _hasConflict;
|
||||
private string _conflictDescription;
|
||||
private bool _isSystemConflict;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
public HotkeySettings()
|
||||
{
|
||||
@@ -23,6 +35,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
Alt = false;
|
||||
Shift = false;
|
||||
Code = 0;
|
||||
|
||||
HasConflict = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -40,6 +54,51 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
Alt = alt;
|
||||
Shift = shift;
|
||||
Code = code;
|
||||
HasConflict = false;
|
||||
}
|
||||
|
||||
public bool HasConflict
|
||||
{
|
||||
get => _hasConflict;
|
||||
set
|
||||
{
|
||||
if (_hasConflict != value)
|
||||
{
|
||||
_hasConflict = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string ConflictDescription
|
||||
{
|
||||
get => _conflictDescription ?? string.Empty;
|
||||
set
|
||||
{
|
||||
if (_conflictDescription != value)
|
||||
{
|
||||
_conflictDescription = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSystemConflict
|
||||
{
|
||||
get => _isSystemConflict;
|
||||
set
|
||||
{
|
||||
if (_isSystemConflict != value)
|
||||
{
|
||||
_isSystemConflict = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void UpdateConflictStatus()
|
||||
{
|
||||
Logger.LogInfo($"{this.ToString()}");
|
||||
}
|
||||
|
||||
[JsonPropertyName("win")]
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// 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.Collections.Generic;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library.Interfaces
|
||||
{
|
||||
public interface IHotkeyConfig
|
||||
{
|
||||
HotkeyAccessor[] GetAllHotkeyAccessors();
|
||||
|
||||
ModuleType GetModuleType();
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
// 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.Text.Json.Serialization;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class LightSwitchProperties
|
||||
{
|
||||
public const bool DefaultChangeSystem = false;
|
||||
public const bool DefaultChangeApps = false;
|
||||
public const int DefaultLightTime = 480; // 08:00
|
||||
public const int DefaultDarkTime = 1200; // 20:001
|
||||
public const int DefaultOffset = 0;
|
||||
public const string DefaultLatitude = "0.0";
|
||||
public const string DefaultLongitude = "0.0";
|
||||
public const string DefaultScheduleMode = "FixedHours";
|
||||
public static readonly HotkeySettings DefaultForceLightModeValue = new HotkeySettings(true, true, false, true, 0x4C); // Ctrl+Win+Shift+L
|
||||
public static readonly HotkeySettings DefaultForceDarkModeValue = new HotkeySettings(true, true, false, true, 0x44); // Ctrl+Win+Shift+D
|
||||
|
||||
public LightSwitchProperties()
|
||||
{
|
||||
ChangeSystem = new BoolProperty(DefaultChangeSystem);
|
||||
ChangeApps = new BoolProperty(DefaultChangeApps);
|
||||
LightTime = new IntProperty(DefaultLightTime);
|
||||
DarkTime = new IntProperty(DefaultDarkTime);
|
||||
Latitude = new StringProperty(DefaultLatitude);
|
||||
Longitude = new StringProperty(DefaultLongitude);
|
||||
Offset = new IntProperty(DefaultOffset);
|
||||
ScheduleMode = new StringProperty(DefaultScheduleMode);
|
||||
ForceLightModeHotkey = new KeyboardKeysProperty(DefaultForceLightModeValue);
|
||||
ForceDarkModeHotkey = new KeyboardKeysProperty(DefaultForceDarkModeValue);
|
||||
}
|
||||
|
||||
[JsonPropertyName("changeSystem")]
|
||||
public BoolProperty ChangeSystem { get; set; }
|
||||
|
||||
[JsonPropertyName("changeApps")]
|
||||
public BoolProperty ChangeApps { get; set; }
|
||||
|
||||
[JsonPropertyName("lightTime")]
|
||||
public IntProperty LightTime { get; set; }
|
||||
|
||||
[JsonPropertyName("darkTime")]
|
||||
public IntProperty DarkTime { get; set; }
|
||||
|
||||
[JsonPropertyName("offset")]
|
||||
public IntProperty Offset { get; set; }
|
||||
|
||||
[JsonPropertyName("latitude")]
|
||||
public StringProperty Latitude { get; set; }
|
||||
|
||||
[JsonPropertyName("longitude")]
|
||||
public StringProperty Longitude { get; set; }
|
||||
|
||||
[JsonPropertyName("scheduleMode")]
|
||||
public StringProperty ScheduleMode { get; set; }
|
||||
|
||||
[JsonPropertyName("force-light-mode-hotkey")]
|
||||
public KeyboardKeysProperty ForceLightModeHotkey { get; set; }
|
||||
|
||||
[JsonPropertyName("force-dark-mode-hotkey")]
|
||||
public KeyboardKeysProperty ForceDarkModeHotkey { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
// 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.Reflection;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
|
||||
namespace Settings.UI.Library
|
||||
{
|
||||
public class LightSwitchSettings : BasePTModuleSettings, ISettingsConfig, ICloneable
|
||||
{
|
||||
public const string ModuleName = "LightSwitch";
|
||||
|
||||
public LightSwitchSettings()
|
||||
{
|
||||
Name = ModuleName;
|
||||
Version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
||||
Properties = new LightSwitchProperties();
|
||||
}
|
||||
|
||||
[JsonPropertyName("properties")]
|
||||
public LightSwitchProperties Properties { get; set; }
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
return new LightSwitchSettings()
|
||||
{
|
||||
Name = Name,
|
||||
Version = Version,
|
||||
Properties = new LightSwitchProperties()
|
||||
{
|
||||
ChangeSystem = new BoolProperty(Properties.ChangeSystem.Value),
|
||||
ChangeApps = new BoolProperty(Properties.ChangeApps.Value),
|
||||
ScheduleMode = new StringProperty(Properties.ScheduleMode.Value),
|
||||
LightTime = new IntProperty((int)Properties.LightTime.Value),
|
||||
DarkTime = new IntProperty((int)Properties.DarkTime.Value),
|
||||
Offset = new IntProperty((int)Properties.Offset.Value),
|
||||
Latitude = new StringProperty(Properties.Latitude.Value),
|
||||
Longitude = new StringProperty(Properties.Longitude.Value),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public string GetModuleName()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
public bool UpgradeSettingsConfiguration()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,15 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class MeasureToolSettings : BasePTModuleSettings, ISettingsConfig
|
||||
public class MeasureToolSettings : BasePTModuleSettings, ISettingsConfig, IHotkeyConfig
|
||||
{
|
||||
public const string ModuleName = "Measure Tool";
|
||||
|
||||
@@ -25,6 +27,21 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
public string GetModuleName()
|
||||
=> Name;
|
||||
|
||||
public ModuleType GetModuleType() => ModuleType.MeasureTool;
|
||||
|
||||
public HotkeyAccessor[] GetAllHotkeyAccessors()
|
||||
{
|
||||
var hotkeyAccessors = new List<HotkeyAccessor>
|
||||
{
|
||||
new HotkeyAccessor(
|
||||
() => Properties.ActivationShortcut,
|
||||
value => Properties.ActivationShortcut = value ?? Properties.DefaultActivationShortcut,
|
||||
"MeasureTool_ActivationShortcut"),
|
||||
};
|
||||
|
||||
return hotkeyAccessors.ToArray();
|
||||
}
|
||||
|
||||
// This can be utilized in the future if the settings.json file is to be modified/deleted.
|
||||
public bool UpgradeSettingsConfiguration()
|
||||
=> false;
|
||||
|
||||
@@ -2,15 +2,17 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class MouseHighlighterSettings : BasePTModuleSettings, ISettingsConfig
|
||||
public class MouseHighlighterSettings : BasePTModuleSettings, ISettingsConfig, IHotkeyConfig
|
||||
{
|
||||
public const string ModuleName = "MouseHighlighter";
|
||||
|
||||
@@ -29,6 +31,21 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
return Name;
|
||||
}
|
||||
|
||||
public ModuleType GetModuleType() => ModuleType.MouseHighlighter;
|
||||
|
||||
public HotkeyAccessor[] GetAllHotkeyAccessors()
|
||||
{
|
||||
var hotkeyAccessors = new List<HotkeyAccessor>
|
||||
{
|
||||
new HotkeyAccessor(
|
||||
() => Properties.ActivationShortcut,
|
||||
value => Properties.ActivationShortcut = value ?? Properties.DefaultActivationShortcut,
|
||||
"MouseUtils_MouseHighlighter_ActivationShortcut"),
|
||||
};
|
||||
|
||||
return hotkeyAccessors.ToArray();
|
||||
}
|
||||
|
||||
// This can be utilized in the future if the settings.json file is to be modified/deleted.
|
||||
public bool UpgradeSettingsConfiguration()
|
||||
{
|
||||
|
||||
@@ -3,16 +3,18 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
using MouseJump.Common.Helpers;
|
||||
using MouseJump.Common.Models.Settings;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class MouseJumpSettings : BasePTModuleSettings, ISettingsConfig
|
||||
public class MouseJumpSettings : BasePTModuleSettings, ISettingsConfig, IHotkeyConfig
|
||||
{
|
||||
public const string ModuleName = "MouseJump";
|
||||
|
||||
@@ -46,6 +48,21 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
return Name;
|
||||
}
|
||||
|
||||
public ModuleType GetModuleType() => ModuleType.MouseJump;
|
||||
|
||||
public HotkeyAccessor[] GetAllHotkeyAccessors()
|
||||
{
|
||||
var hotkeyAccessors = new List<HotkeyAccessor>
|
||||
{
|
||||
new HotkeyAccessor(
|
||||
() => Properties.ActivationShortcut,
|
||||
value => Properties.ActivationShortcut = value ?? Properties.DefaultActivationShortcut,
|
||||
"MouseUtils_MouseJump_ActivationShortcut"),
|
||||
};
|
||||
|
||||
return hotkeyAccessors.ToArray();
|
||||
}
|
||||
|
||||
// This can be utilized in the future if the settings.json file is to be modified/deleted.
|
||||
public bool UpgradeSettingsConfiguration()
|
||||
{
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class MousePointerCrosshairsSettings : BasePTModuleSettings, ISettingsConfig
|
||||
public class MousePointerCrosshairsSettings : BasePTModuleSettings, ISettingsConfig, IHotkeyConfig
|
||||
{
|
||||
public const string ModuleName = "MousePointerCrosshairs";
|
||||
|
||||
@@ -27,6 +29,21 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
return Name;
|
||||
}
|
||||
|
||||
public ModuleType GetModuleType() => ModuleType.MousePointerCrosshairs;
|
||||
|
||||
public HotkeyAccessor[] GetAllHotkeyAccessors()
|
||||
{
|
||||
var hotkeyAccessors = new List<HotkeyAccessor>
|
||||
{
|
||||
new HotkeyAccessor(
|
||||
() => Properties.ActivationShortcut,
|
||||
value => Properties.ActivationShortcut = value ?? Properties.DefaultActivationShortcut,
|
||||
"MouseUtils_MousePointerCrosshairs_ActivationShortcut"),
|
||||
};
|
||||
|
||||
return hotkeyAccessors.ToArray();
|
||||
}
|
||||
|
||||
// This can be utilized in the future if the settings.json file is to be modified/deleted.
|
||||
public bool UpgradeSettingsConfiguration()
|
||||
{
|
||||
|
||||
@@ -3,15 +3,17 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class MouseWithoutBordersSettings : BasePTModuleSettings, ISettingsConfig
|
||||
public class MouseWithoutBordersSettings : BasePTModuleSettings, ISettingsConfig, IHotkeyConfig
|
||||
{
|
||||
public const string ModuleName = "MouseWithoutBorders";
|
||||
|
||||
@@ -37,6 +39,33 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
return Name;
|
||||
}
|
||||
|
||||
public ModuleType GetModuleType() => ModuleType.MouseWithoutBorders;
|
||||
|
||||
public HotkeyAccessor[] GetAllHotkeyAccessors()
|
||||
{
|
||||
var hotkeyAccessors = new List<HotkeyAccessor>
|
||||
{
|
||||
new HotkeyAccessor(
|
||||
() => Properties.ToggleEasyMouseShortcut,
|
||||
value => Properties.ToggleEasyMouseShortcut = value ?? MouseWithoutBordersProperties.DefaultHotKeyToggleEasyMouse,
|
||||
"MouseWithoutBorders_ToggleEasyMouseShortcut"),
|
||||
new HotkeyAccessor(
|
||||
() => Properties.LockMachineShortcut,
|
||||
value => Properties.LockMachineShortcut = value ?? MouseWithoutBordersProperties.DefaultHotKeyLockMachine,
|
||||
"MouseWithoutBorders_LockMachinesShortcut"),
|
||||
new HotkeyAccessor(
|
||||
() => Properties.Switch2AllPCShortcut,
|
||||
value => Properties.Switch2AllPCShortcut = value ?? MouseWithoutBordersProperties.DefaultHotKeySwitch2AllPC,
|
||||
"MouseWithoutBorders_Switch2AllPcShortcut"),
|
||||
new HotkeyAccessor(
|
||||
() => Properties.ReconnectShortcut,
|
||||
value => Properties.ReconnectShortcut = value ?? MouseWithoutBordersProperties.DefaultHotKeyReconnect,
|
||||
"MouseWithoutBorders_ReconnectShortcut"),
|
||||
};
|
||||
|
||||
return hotkeyAccessors.ToArray();
|
||||
}
|
||||
|
||||
public HotkeySettings ConvertMouseWithoutBordersHotKeyToPowerToys(int value)
|
||||
{
|
||||
// VK_A <= value <= VK_Z
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user