Compare commits
29 commits
dev/crutka
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
72ea4ff8b3 | ||
|
991124c9e4 | ||
|
47b5386c0c | ||
|
5381486c25 | ||
|
375ce4c798 | ||
|
d2c6148662 | ||
|
84101ab821 | ||
|
bd0db76e31 | ||
|
8743c2329e | ||
|
46244e8e84 | ||
|
8afac77841 | ||
|
6452369351 | ||
|
641d838140 | ||
|
2d5276f742 | ||
|
0dae5d0402 | ||
|
022dde4754 | ||
|
0aaf00dc5e | ||
|
dfb5736ac0 | ||
|
04a72ed947 | ||
|
105f94690d | ||
|
36bbce78d7 | ||
|
5a9f52fb11 | ||
|
5a4822f89e | ||
|
c934127d84 | ||
|
2128b88571 | ||
|
84d361e8a9 | ||
|
c7381cf1d5 | ||
|
11354a45ce | ||
|
7703991f4c |
8
.github/actions/spell-check/expect.txt
vendored
|
@ -699,6 +699,7 @@ gdi
|
|||
gdiplus
|
||||
GDISCALED
|
||||
generatesqlfromuserquery
|
||||
GETDESKWALLPAPER
|
||||
GETDISPINFO
|
||||
GETDLGCODE
|
||||
GETDPISCALEDSIZE
|
||||
|
@ -762,8 +763,10 @@ hglobal
|
|||
hhk
|
||||
HHmmss
|
||||
HHOOK
|
||||
hhx
|
||||
HICON
|
||||
HIDEWINDOW
|
||||
highlighter
|
||||
HIMAGELIST
|
||||
himl
|
||||
hinst
|
||||
|
@ -787,7 +790,7 @@ hmonitor
|
|||
HOLDENTER
|
||||
HOLDESC
|
||||
homljgmgpmcbpjbnjpfijnhipfkiclkd
|
||||
Homepage
|
||||
homepage
|
||||
HOOKPROC
|
||||
hostname
|
||||
hotkeycontrol
|
||||
|
@ -2083,6 +2086,7 @@ Switchbetweenvirtualdesktops
|
|||
SWP
|
||||
swprintf
|
||||
SWRESTORE
|
||||
swscanf
|
||||
SYMED
|
||||
SYMOPT
|
||||
SYNCMFT
|
||||
|
@ -2334,7 +2338,7 @@ VTABLE
|
|||
Vtbl
|
||||
wav
|
||||
WBounds
|
||||
Wca
|
||||
wca
|
||||
wcautil
|
||||
WCE
|
||||
wcex
|
||||
|
|
|
@ -138,24 +138,24 @@ build:
|
|||
- 'modules\launcher\Microsoft.Launcher.dll'
|
||||
- 'modules\launcher\Plugins\Calculator\Microsoft.PowerToys.Run.Plugin.Calculator.dll'
|
||||
- 'modules\launcher\Plugins\Calculator\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Folder\Microsoft.Plugin.Folder.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Folder\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Indexer\Microsoft.Plugin.Indexer.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Indexer\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Program\Microsoft.Plugin.Program.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Program\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\Microsoft.PowerToys.Run.Plugin.Registry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\Microsoft.PowerToys.Run.Plugin.WindowsSettings.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\WindowsSettings.json'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Shell\Microsoft.Plugin.Shell.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Shell\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Uri\Microsoft.Plugin.Uri.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Uri\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\Microsoft.Plugin.WindowWalker.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Community.UnitConverter\Community.PowerToys.Run.Plugin.UnitConverter.dll'
|
||||
- 'modules\launcher\Plugins\Folder\Microsoft.Plugin.Folder.dll'
|
||||
- 'modules\launcher\Plugins\Folder\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Indexer\Microsoft.Plugin.Indexer.dll'
|
||||
- 'modules\launcher\Plugins\Indexer\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Program\Microsoft.Plugin.Program.dll'
|
||||
- 'modules\launcher\Plugins\Program\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Registry\Microsoft.PowerToys.Run.Plugin.Registry.dll'
|
||||
- 'modules\launcher\Plugins\Registry\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\WindowsSettings\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\WindowsSettings\Microsoft.PowerToys.Run.Plugin.WindowsSettings.dll'
|
||||
- 'modules\launcher\Plugins\WindowsSettings\WindowsSettings.json'
|
||||
- 'modules\launcher\Plugins\Shell\Microsoft.Plugin.Shell.dll'
|
||||
- 'modules\launcher\Plugins\Shell\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Uri\Microsoft.Plugin.Uri.dll'
|
||||
- 'modules\launcher\Plugins\Uri\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\WindowWalker\Microsoft.Plugin.WindowWalker.dll'
|
||||
- 'modules\launcher\Plugins\WindowWalker\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\UnitConverter\Community.PowerToys.Run.Plugin.UnitConverter.dll'
|
||||
- 'modules\launcher\Plugins\VSCodeWorkspaces\Community.PowerToys.Run.Plugin.VSCodeWorkspaces.dll'
|
||||
- 'modules\launcher\Plugins\Service\Microsoft.PowerToys.Run.Plugin.Service.dll'
|
||||
- 'modules\launcher\Plugins\System\Microsoft.PowerToys.Run.Plugin.System.dll'
|
||||
|
@ -171,6 +171,7 @@ build:
|
|||
- 'modules\launcher\Wox.Infrastructure.dll'
|
||||
- 'modules\launcher\Wox.Plugin.dll'
|
||||
- 'modules\MouseUtils\FindMyMouse.dll'
|
||||
- 'modules\MouseUtils\MouseHighlighter.dll'
|
||||
- 'modules\PowerRename\PowerRenameExt.dll'
|
||||
- 'modules\PowerRename\PowerRenameUILib.dll'
|
||||
- 'modules\PowerRename\PowerRename.exe'
|
||||
|
@ -254,6 +255,7 @@ static_analysis_options:
|
|||
exclude:
|
||||
- 'WiX.*/**/*.dll'
|
||||
- 'Wix.*/**/*.exe'
|
||||
- 'Microsoft.Windows.CppWinRT.*/**/*.exe'
|
||||
moderncop_options:
|
||||
files_to_scan:
|
||||
- from: 'src'
|
||||
|
|
|
@ -262,6 +262,7 @@ EndProject
|
|||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "utils", "utils", "{B39DC643-4663-475E-B329-03F0C9918D48}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
src\common\utils\appMutex.h = src\common\utils\appMutex.h
|
||||
src\common\utils\color.h = src\common\utils\color.h
|
||||
src\common\utils\com_object_factory.h = src\common\utils\com_object_factory.h
|
||||
src\common\utils\elevation.h = src\common\utils\elevation.h
|
||||
src\common\utils\EventLocker.h = src\common\utils\EventLocker.h
|
||||
|
@ -371,6 +372,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MouseUtils", "MouseUtils",
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FindMyMouse", "src\modules\MouseUtils\FindMyMouse\FindMyMouse.vcxproj", "{E94FD11C-0591-456F-899F-EFC0CA548336}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MouseHighlighter", "src\modules\MouseUtils\MouseHighlighter\MouseHighlighter.vcxproj", "{782A61BE-9D85-4081-B35C-1CCC9DCC1E88}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
|
@ -986,6 +989,12 @@ Global
|
|||
{E94FD11C-0591-456F-899F-EFC0CA548336}.Release|x64.ActiveCfg = Release|x64
|
||||
{E94FD11C-0591-456F-899F-EFC0CA548336}.Release|x64.Build.0 = Release|x64
|
||||
{E94FD11C-0591-456F-899F-EFC0CA548336}.Release|x86.ActiveCfg = Release|x64
|
||||
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88}.Debug|x64.Build.0 = Debug|x64
|
||||
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88}.Release|x64.ActiveCfg = Release|x64
|
||||
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88}.Release|x64.Build.0 = Release|x64
|
||||
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88}.Release|x86.ActiveCfg = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -1105,6 +1114,7 @@ Global
|
|||
{4642D596-723F-4BFC-894C-46811219AC4A} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
|
||||
{322566EF-20DC-43A6-B9F8-616AF942579A} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{E94FD11C-0591-456F-899F-EFC0CA548336} = {322566EF-20DC-43A6-B9F8-616AF942579A}
|
||||
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88} = {322566EF-20DC-43A6-B9F8-616AF942579A}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Microsoft PowerToys
|
||||
|
||||
<img src="./doc/images/overview/PT%20hero%20image.png"/>
|
||||
![Hero image for Microsoft PowerToys](doc/images/overview/PT_hero_image.png)
|
||||
|
||||
[How to use PowerToys][usingPowerToys-docs-link] | [Downloads & Release notes][github-release-link] | [Contributing to PowerToys](#contributing) | [What's Happening](#whats-happening) | [Roadmap](#powertoys-roadmap)
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|----------|----------|
|
||||
| getpowertoys | ms-windows-store://pdp/?productid=XP89DCGQ3K6VLD |
|
||||
| installpowertoys | https://github.com/microsoft/PowerToys/releases/latest |
|
||||
| powertoys-license | https://github.com/microsoft/PowerToys/blob/master/LICENSE |
|
||||
| powertoys-license | https://github.com/microsoft/PowerToys/blob/main/LICENSE |
|
||||
| powertoys | https://github.com/microsoft/PowerToys |
|
||||
| PowerToysAppCompat | https://github.com/microsoft/PowerToys/wiki/Application-Compatibility |
|
||||
| powerToysCannotRemapKeys | https://docs.microsoft.com/windows/powertoys/keyboard-manager#keys-that-cannot-be-remapped |
|
||||
|
|
|
@ -15,7 +15,7 @@ TODO
|
|||
#### [`ZoneSet.cpp`](/src/modules/fancyzones/lib/ZoneSet.cpp)
|
||||
TODO
|
||||
|
||||
#### [`ZoneWindow.cpp`](/src/modules/fancyzones/lib/ZoneWindow.cpp)
|
||||
#### [`WorkArea.cpp`](/src/modules/fancyzones/lib/WorkArea.cpp)
|
||||
TODO
|
||||
|
||||
## FancyZones Editor
|
||||
|
|
BIN
doc/images/icons/Find My Mouse.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
doc/images/icons/Mouse Highlighter.png
Normal file
After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 447 KiB After Width: | Height: | Size: 447 KiB |
|
@ -2,17 +2,17 @@
|
|||
---
|
||||
|
||||
1. `Zone` - Class which is basically wrapper around rectangle structure, representing one zone inside applied zone layout. ZoneSet is holding array of these which represent zone layout.
|
||||
2. `ZoneSet` - Class implementing actual zone layout applied. What this means is that ZoneSet is responsible for actual calculation of rectangle coordinates (whether is grid or canvas layout) and moving window through them. ZoneWindow holds ZoneSet structure which represents currently active zone set.
|
||||
3. `ZoneWindow` - Class representing work area, which is defined by monitor and current virtual desktop. For an example, if You have two monitors connected and two virtual desktops, You have 4 work areas available, and each of them can have separate zone layout. ZoneWindow is describing single work area. As mentioned before it holds active ZoneSet.
|
||||
2. `ZoneSet` - Class implementing actual zone layout applied. What this means is that ZoneSet is responsible for actual calculation of rectangle coordinates (whether is grid or canvas layout) and moving window through them. WorkArea holds ZoneSet structure which represents currently active zone set.
|
||||
3. `WorkArea` - Class representing work area, which is defined by monitor and current virtual desktop. For an example, if You have two monitors connected and two virtual desktops, You have 4 work areas available, and each of them can have separate zone layout. WorkArea is describing single work area. As mentioned before it holds active ZoneSet.
|
||||
4. `FancyZones` - Top level entity and entry point for all user actions (which goes through actual module interface). Some of the main responsibilities of FancyZones class:
|
||||
|
||||
1. Starting FancyZones Editor (C#) with appropriate command line arguments on user request.
|
||||
2. Keeping track of ZoneWindow per monitor (currently active work area on each connected monitor).
|
||||
2. Keeping track of WorkArea per monitor (currently active work area on each connected monitor).
|
||||
3. Keeping track of active virtual desktops. This is performed in separate thread by polling VirtualDesktopIDs registry key and parsing its content.
|
||||
4. Detecting every change in work environment, such as creating / destroying / switching between virtual desktops, closing FancyZones Editor, changing display settings and handling those changes.
|
||||
|
||||
### Proposal for modifications of handling described in 4.4:
|
||||
|
||||
Currently after each of the mentioned changes in work environment we are calling EnumDisplayMonitors windows API, and passing callback function to it. EnumDisplayMonitors works asynchronous and triggers that callback for each work area available (as mentioned in previous example, for two monitors and two virtual desktops, we have this callback triggered four times). As mentioned previously, we have ZoneWindow class as our representation of this work area. And what we do, every time this callback is triggered we destroy previous ZoneWindow object for that work area and create new one, even though that it is most likely that nothing has changed (e.g. just switching back and forth between virtual desktops). This constant creation and deletion of ZoneWindow has caused some problems in the past and it's not ideal for some other fixes we would like to make in the multi-monitor/multi-desktop scenario.
|
||||
Currently after each of the mentioned changes in work environment we are calling EnumDisplayMonitors windows API, and passing callback function to it. EnumDisplayMonitors works asynchronous and triggers that callback for each work area available (as mentioned in previous example, for two monitors and two virtual desktops, we have this callback triggered four times). As mentioned previously, we have WorkArea class as our representation of this work area. And what we do, every time this callback is triggered we destroy previous WorkArea object for that work area and create new one, even though that it is most likely that nothing has changed (e.g. just switching back and forth between virtual desktops). This constant creation and deletion of WorkArea has caused some problems in the past and it's not ideal for some other fixes we would like to make in the multi-monitor/multi-desktop scenario.
|
||||
|
||||
As mentioned in 4.3 we already have tracker of virtual desktops implemented. Idea is to use this functionality and to extend it bit more, so we can track if work area (ZoneWindow) is new one, or already processed and skip creating new ZoneWindow objects and deleting old ones every time, even if nothing changed in it. We will keep map, where virtual desktop id is the key, and values are already processed monitors (virtual desktop exists across all monitors). Once we receive callback from EnumDisplayMonitors, indicating work area (defined by virtual desktop id and monitor) we can check if it’s new or not, and act accordingly (create new ZoneWindow for it or not). Deleting virtual desktop (which is also registered in 4.3), will trigger updates in this map, and also updates in our JSON storage.
|
||||
As mentioned in 4.3 we already have tracker of virtual desktops implemented. Idea is to use this functionality and to extend it bit more, so we can track if work area (WorkArea) is new one, or already processed and skip creating new WorkArea objects and deleting old ones every time, even if nothing changed in it. We will keep map, where virtual desktop id is the key, and values are already processed monitors (virtual desktop exists across all monitors). Once we receive callback from EnumDisplayMonitors, indicating work area (defined by virtual desktop id and monitor) we can check if it’s new or not, and act accordingly (create new WorkArea for it or not). Deleting virtual desktop (which is also registered in 4.3), will trigger updates in this map, and also updates in our JSON storage.
|
||||
|
|
|
@ -316,27 +316,27 @@
|
|||
<Directory Id="CalculatorImagesFolder" Name="Images" />
|
||||
<Directory Id="CalculatorLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
<Directory Id="FolderPluginFolder" Name="Microsoft.Plugin.Folder">
|
||||
<Directory Id="FolderPluginFolder" Name="Folder">
|
||||
<Directory Id="FolderPluginImagesFolder" Name="Images" />
|
||||
<Directory Id="FolderPluginLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
<Directory Id="ProgramPluginFolder" Name="Microsoft.Plugin.Program">
|
||||
<Directory Id="ProgramPluginFolder" Name="Program">
|
||||
<Directory Id="ProgramImagesFolder" Name="Images" />
|
||||
<Directory Id="ProgramLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
<Directory Id="ShellPluginFolder" Name="Microsoft.Plugin.Shell">
|
||||
<Directory Id="ShellPluginFolder" Name="Shell">
|
||||
<Directory Id="ShellImagesFolder" Name="Images" />
|
||||
<Directory Id="ShellLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
<Directory Id="IndexerPluginFolder" Name="Microsoft.Plugin.Indexer">
|
||||
<Directory Id="IndexerPluginFolder" Name="Indexer">
|
||||
<Directory Id="IndexerImagesFolder" Name="Images" />
|
||||
<Directory Id="IndexerLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
<Directory Id="UriPluginFolder" Name="Microsoft.Plugin.Uri">
|
||||
<Directory Id="UriPluginFolder" Name="Uri">
|
||||
<Directory Id="UriImagesFolder" Name="Images" />
|
||||
<Directory Id="UriLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
<Directory Id="UnitConverterPluginFolder" Name="Community.UnitConverter">
|
||||
<Directory Id="UnitConverterPluginFolder" Name="UnitConverter">
|
||||
<Directory Id="UnitConverterImagesFolder" Name="Images" />
|
||||
<Directory Id="UnitConverterLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
|
@ -344,11 +344,11 @@
|
|||
<Directory Id="VSCodeWorkspaceImagesFolder" Name="Images" />
|
||||
<Directory Id="VSCodeWorkspaceLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
<Directory Id="WindowWalkerPluginFolder" Name="Microsoft.Plugin.WindowWalker">
|
||||
<Directory Id="WindowWalkerPluginFolder" Name="WindowWalker">
|
||||
<Directory Id="WindowWalkerImagesFolder" Name="Images" />
|
||||
<Directory Id="WindowWalkerLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
<Directory Id="RegistryPluginFolder" Name="Microsoft.PowerToys.Run.Plugin.Registry">
|
||||
<Directory Id="RegistryPluginFolder" Name="Registry">
|
||||
<Directory Id="RegistryImagesFolder" Name="Images" />
|
||||
<Directory Id="RegistryLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
|
@ -361,7 +361,7 @@
|
|||
<Directory Id="SystemPluginFolder" Name="System">
|
||||
<Directory Id="SystemImagesFolder" Name="Images" />
|
||||
</Directory>
|
||||
<Directory Id="WindowsSettingsPluginFolder" Name="Microsoft.PowerToys.Run.Plugin.WindowsSettings">
|
||||
<Directory Id="WindowsSettingsPluginFolder" Name="WindowsSettings">
|
||||
<Directory Id="WindowsSettingsImagesFolder" Name="Images" />
|
||||
<Directory Id="WindowsSettingsLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
|
@ -657,6 +657,9 @@
|
|||
<Component Id="Module_FindMyMouse" Guid="60D0E4AE-188F-4403-BF06-1465AACC1BC5" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.MouseUtilsProjectName)\FindMyMouse.dll" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="Module_MouseHighlighter" Guid="3BAEA39F-A73D-48D2-9616-BBED5B8C86D3" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.MouseUtilsProjectName)\MouseHighlighter.dll" KeyPath="yes" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- Shortcut guide -->
|
||||
|
@ -971,6 +974,7 @@
|
|||
<ComponentRef Id="Module_Awake_runtime_netcoreapp30"/>
|
||||
<ComponentRef Id="Module_Awake_runtime_netcoreapp21"/>
|
||||
<ComponentRef Id="Module_FindMyMouse"/>
|
||||
<ComponentRef Id="Module_MouseHighlighter"/>
|
||||
<ComponentRef Id="SettingsV2" />
|
||||
<ComponentRef Id="SettingsV2Assets" />
|
||||
<ComponentRef Id="SettingsV2AssetsModules" />
|
||||
|
@ -1059,28 +1063,28 @@
|
|||
<File Id="Launcher_Calculator_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Calculator\$(var.Language)\Microsoft.PowerToys.Run.Plugin.Calculator.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_Folder_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)FolderPluginFolder">
|
||||
<File Id="Launcher_Folder_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Folder\$(var.Language)\Microsoft.Plugin.Folder.resources.dll" />
|
||||
<File Id="Launcher_Folder_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Folder\$(var.Language)\Microsoft.Plugin.Folder.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_Program_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)ProgramPluginFolder">
|
||||
<File Id="Launcher_Program_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Program\$(var.Language)\Microsoft.Plugin.Program.resources.dll" />
|
||||
<File Id="Launcher_Program_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Program\$(var.Language)\Microsoft.Plugin.Program.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_Shell_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)ShellPluginFolder">
|
||||
<File Id="Launcher_Shell_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Shell\$(var.Language)\Microsoft.Plugin.Shell.resources.dll" />
|
||||
<File Id="Launcher_Shell_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Shell\$(var.Language)\Microsoft.Plugin.Shell.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_Indexer_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)IndexerPluginFolder">
|
||||
<File Id="Launcher_Indexer_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Indexer\$(var.Language)\Microsoft.Plugin.Indexer.resources.dll" />
|
||||
<File Id="Launcher_Indexer_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Indexer\$(var.Language)\Microsoft.Plugin.Indexer.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_Uri_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)UriPluginFolder">
|
||||
<File Id="Launcher_Uri_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Uri\$(var.Language)\Microsoft.Plugin.Uri.resources.dll" />
|
||||
<File Id="Launcher_Uri_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Uri\$(var.Language)\Microsoft.Plugin.Uri.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_VSCodeWorkspaces_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)VSCodeWorkspacesPluginFolder">
|
||||
<File Id="Launcher_VSCodeWorkspaces_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\VSCodeWorkspaces\$(var.Language)\Community.PowerToys.Run.Plugin.VSCodeWorkspaces.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_WindowWalker_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)WindowWalkerPluginFolder">
|
||||
<File Id="Launcher_WindowWalker_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\$(var.Language)\Microsoft.Plugin.WindowWalker.resources.dll" />
|
||||
<File Id="Launcher_WindowWalker_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowWalker\$(var.Language)\Microsoft.Plugin.WindowWalker.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_Registry_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)RegistryPluginFolder">
|
||||
<File Id="Launcher_Registry_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\$(var.Language)\Microsoft.PowerToys.Run.Plugin.Registry.resources.dll" />
|
||||
<File Id="Launcher_Registry_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Registry\$(var.Language)\Microsoft.PowerToys.Run.Plugin.Registry.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_Service_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)ServicePluginFolder">
|
||||
<File Id="Launcher_Service_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Service\$(var.Language)\Microsoft.PowerToys.Run.Plugin.Service.resources.dll" />
|
||||
|
@ -1089,7 +1093,7 @@
|
|||
<File Id="Launcher_System_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\System\$(var.Language)\Microsoft.PowerToys.Run.Plugin.System.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_WindowsSettings_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)WindowsSettingsPluginFolder">
|
||||
<File Id="Launcher_WindowsSettings_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\$(var.Language)\Microsoft.PowerToys.Run.Plugin.WindowsSettings.resources.dll" />
|
||||
<File Id="Launcher_WindowsSettings_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowsSettings\$(var.Language)\Microsoft.PowerToys.Run.Plugin.WindowsSettings.resources.dll" />
|
||||
</Component>
|
||||
<!-- Uncomment after Plugin receives the localization files.
|
||||
<Component Id="Launcher_WindowsTerminal_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)WindowsTerminalFolder">
|
||||
|
@ -1143,71 +1147,71 @@
|
|||
<!-- Folder Plugin -->
|
||||
<Component Id="FolderComponent" Directory="FolderPluginFolder" Guid="453D6C29-8F0D-46EC-B210-82E6AF547039">
|
||||
<?foreach File in plugin.json;Microsoft.Plugin.Folder.deps.json;Microsoft.Plugin.Folder.dll;ManagedTelemetry.dll?>
|
||||
<File Id="Folder_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Folder\$(var.File)" />
|
||||
<File Id="Folder_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Folder\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="FolderImagesComponent" Directory="FolderPluginImagesFolder" Guid="6C5226EB-E312-4768-B4D1-B1D3ACFCCBDF">
|
||||
<?foreach File in copy.dark.png;copy.light.png;delete.dark.png;delete.light.png;file.dark.png;file.light.png;folder.dark.png;folder.light.png;user.dark.png;user.light.png;Warning.dark.png;Warning.light.png?>
|
||||
<File Id="FolderPlugin_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Folder\Images\$(var.File)" />
|
||||
<File Id="FolderPlugin_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Folder\Images\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
|
||||
<!-- Program Plugin -->
|
||||
<Component Id="ProgramComponent" Directory="ProgramPluginFolder" Guid="3C5CA6E6-3D36-4F4E-B40E-38AA5E5CB799">
|
||||
<?foreach File in plugin.json;Microsoft.Plugin.Program.deps.json;Microsoft.Plugin.Program.dll;ManagedTelemetry.dll?>
|
||||
<File Id="Program_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Program\$(var.File)" />
|
||||
<File Id="Program_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Program\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="ProgramImagesComponent" Directory="ProgramImagesFolder" Guid="30D357F5-406F-47D1-BEFE-6022746469B4">
|
||||
<?foreach File in app.dark.png;app.light.png;disable.light.png;disable.dark.png;folder.light.png;folder.dark.png;shell.light.png;shell.dark.png;user.light.png;user.dark.png?>
|
||||
<File Id="Program_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Program\Images\$(var.File)" />
|
||||
<File Id="Program_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Program\Images\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
|
||||
<!-- Shell Plugin -->
|
||||
<Component Id="ShellComponent" Directory="ShellPluginFolder" Guid="6D3D7294-1804-47C9-83E5-47A8867F3801">
|
||||
<?foreach File in plugin.json;Microsoft.Plugin.Shell.deps.json;Microsoft.Plugin.Shell.dll;ManagedTelemetry.dll?>
|
||||
<File Id="Shell_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Shell\$(var.File)" />
|
||||
<File Id="Shell_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Shell\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="ShellImagesComponent" Directory="ShellImagesFolder" Guid="15B5DBAE-E7C1-4BF7-A29E-6CE76242F8F4">
|
||||
<?foreach File in shell.light.png;shell.dark.png;user.light.png;user.dark.png?>
|
||||
<File Id="Shell_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Shell\Images\$(var.File)" />
|
||||
<File Id="Shell_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Shell\Images\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
|
||||
<!-- Indexer Plugin -->
|
||||
<Component Id="IndexerComponent" Directory="IndexerPluginFolder" Guid="FEA9816A-B4F7-42CC-99AF-B05F3E7F7EBF">
|
||||
<?foreach File in Microsoft.Plugin.Indexer.deps.json;Microsoft.Plugin.Indexer.dll;plugin.json;ManagedTelemetry.dll?>
|
||||
<File Id="Indexer_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Indexer\$(var.File)" />
|
||||
<File Id="Indexer_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Indexer\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="IndexerImagesComponent" Directory="IndexerImagesFolder" Guid="DB2E8D49-D104-425B-9616-952AC8CAB676">
|
||||
<?foreach File in indexer.dark.png;indexer.light.png;Warning.light.png;Warning.dark.png?>
|
||||
<File Id="Indexer_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Indexer\Images\$(var.File)" />
|
||||
<File Id="Indexer_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Indexer\Images\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
|
||||
<!-- UnitConverter Plugin -->
|
||||
<Component Id="UnitConverterComponent" Directory="UnitConverterPluginFolder" Guid="D4F429E3-C619-49D6-9416-88A757D18E02">
|
||||
<?foreach File in plugin.json;Community.PowerToys.Run.Plugin.UnitConverter.deps.json;Community.PowerToys.Run.Plugin.UnitConverter.dll?>
|
||||
<File Id="UnitConverter_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Community.UnitConverter\$(var.File)" />
|
||||
<File Id="UnitConverter_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\UnitConverter\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="UnitConverterImagesComponent" Directory="UnitConverterImagesFolder" Guid="16ABD217-0898-47B2-89D9-AF1ABF00F543">
|
||||
<File Id="UnitConverterLight" Source="$(var.BinX64Dir)modules\launcher\Plugins\Community.UnitConverter\Images\unitconverter.light.png" />
|
||||
<File Id="UnitConverterDark" Source="$(var.BinX64Dir)modules\launcher\Plugins\Community.UnitConverter\Images\unitconverter.dark.png" />
|
||||
<File Id="UnitConverterLight" Source="$(var.BinX64Dir)modules\launcher\Plugins\UnitConverter\Images\unitconverter.light.png" />
|
||||
<File Id="UnitConverterDark" Source="$(var.BinX64Dir)modules\launcher\Plugins\UnitConverter\Images\unitconverter.dark.png" />
|
||||
</Component>
|
||||
|
||||
<!-- Uri Plugin -->
|
||||
<Component Id="UriComponent" Directory="UriPluginFolder" Guid="C7DC8F88-554C-4375-9510-9435399B5D3D">
|
||||
<?foreach File in plugin.json;Microsoft.Plugin.Uri.deps.json;Microsoft.Plugin.Uri.dll;ManagedTelemetry.dll?>
|
||||
<File Id="Uri_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Uri\$(var.File)" />
|
||||
<File Id="Uri_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Uri\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="UriImagesComponent" Directory="UriImagesFolder" Guid="8C9C1634-28C8-45C4-A8EA-8D4C9B4810D0">
|
||||
<File Id="UriDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Uri\Images\Uri.dark.png" />
|
||||
<File Id="UriLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Uri\Images\Uri.light.png" />
|
||||
<File Id="UriDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Uri\Images\Uri.dark.png" />
|
||||
<File Id="UriLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Uri\Images\Uri.light.png" />
|
||||
</Component>
|
||||
|
||||
<!-- VSCodeWorkspaces Plugin -->
|
||||
|
@ -1227,23 +1231,23 @@
|
|||
<!-- WindowWalker Plugin -->
|
||||
<Component Id="WindowWalkerComponent" Directory="WindowWalkerPluginFolder" Guid="EB1391C9-B701-421F-80FC-ABB2FEDFAD19">
|
||||
<?foreach File in plugin.json;Microsoft.Plugin.WindowWalker.deps.json;Microsoft.Plugin.WindowWalker.dll;ManagedTelemetry.dll?>
|
||||
<File Id="WindowWalker_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\$(var.File)" />
|
||||
<File Id="WindowWalker_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowWalker\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="WindowWalkerImagesComponent" Directory="WindowWalkerImagesFolder" Guid="3944A7F5-77F4-4979-9911-EDE709B2F509">
|
||||
<File Id="WindowWalkerDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\Images\windowwalker.dark.png" />
|
||||
<File Id="WindowWalkerLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\Images\windowwalker.light.png" />
|
||||
<File Id="WindowWalkerDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowWalker\Images\windowwalker.dark.png" />
|
||||
<File Id="WindowWalkerLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowWalker\Images\windowwalker.light.png" />
|
||||
</Component>
|
||||
|
||||
<!-- Registry Plugin -->
|
||||
<Component Id="RegistryComponent" Directory="RegistryPluginFolder" Guid="186FDFDC-12F1-4221-BEF6-DE6763F54B18">
|
||||
<?foreach File in plugin.json;Microsoft.PowerToys.Run.Plugin.Registry.deps.json;Microsoft.PowerToys.Run.Plugin.Registry.dll;ManagedTelemetry.dll?>
|
||||
<File Id="Registry_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\$(var.File)" />
|
||||
<File Id="Registry_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Registry\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="RegistryImagesComponent" Directory="RegistryImagesFolder" Guid="2E2C91A2-9F53-40C6-BBE9-E6FD6D6E94EB">
|
||||
<File Id="RegistryDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\Images\reg.dark.png" />
|
||||
<File Id="RegistryLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\Images\reg.light.png" />
|
||||
<File Id="RegistryDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Registry\Images\reg.dark.png" />
|
||||
<File Id="RegistryLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Registry\Images\reg.light.png" />
|
||||
</Component>
|
||||
|
||||
<!-- Service Plugin -->
|
||||
|
@ -1281,12 +1285,12 @@
|
|||
<!-- WindowsSettings Plugin -->
|
||||
<Component Id="WindowsSettingsComponent" Directory="WindowsSettingsPluginFolder" Guid="ACEC2B6D-8E95-43BF-A1E4-137E95F07C96">
|
||||
<?foreach File in plugin.json;Microsoft.PowerToys.Run.Plugin.WindowsSettings.deps.json;Microsoft.PowerToys.Run.Plugin.WindowsSettings.dll;ManagedTelemetry.dll?>
|
||||
<File Id="WindowsSettings_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\$(var.File)" />
|
||||
<File Id="WindowsSettings_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowsSettings\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="WindowsSettingsImagesComponent" Directory="WindowsSettingsImagesFolder" Guid="E1CE33A7-6318-4FA6-A46B-9302A00BD6AA">
|
||||
<File Id="WindowsSettingsDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\Images\WindowsSettings.dark.png" />
|
||||
<File Id="WindowsSettingsLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\Images\WindowsSettings.light.png" />
|
||||
<File Id="WindowsSettingsDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowsSettings\Images\WindowsSettings.dark.png" />
|
||||
<File Id="WindowsSettingsLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowsSettings\Images\WindowsSettings.light.png" />
|
||||
</Component>
|
||||
|
||||
<!-- WindowsTerminal Plugin -->
|
||||
|
|
|
@ -26,6 +26,7 @@ struct LogSettings
|
|||
inline const static std::string keyboardManagerLoggerName = "keyboard-manager";
|
||||
inline const static std::wstring keyboardManagerLogPath = L"Logs\\keyboard-manager-log.txt";
|
||||
inline const static std::string findMyMouseLoggerName = "find-my-mouse";
|
||||
inline const static std::string mouseHighlighterLoggerName = "mouse-highlighter";
|
||||
inline const static std::string powerRenameLoggerName = "powerrename";
|
||||
inline const static int retention = 30;
|
||||
std::wstring logLevel;
|
||||
|
|
|
@ -9,10 +9,7 @@
|
|||
#include "winapi_error.h"
|
||||
#include "../logger/logger.h"
|
||||
|
||||
static IMAGEHLP_SYMBOL64* pSymbol = (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + MAX_PATH * sizeof(TCHAR));
|
||||
static IMAGEHLP_LINE64 line;
|
||||
static BOOLEAN processingException = FALSE;
|
||||
static CHAR modulePath[MAX_PATH];
|
||||
|
||||
static inline const char* exceptionDescription(const DWORD& code)
|
||||
{
|
||||
|
@ -64,15 +61,15 @@ static inline const char* exceptionDescription(const DWORD& code)
|
|||
}
|
||||
|
||||
/* Returns the index of the last backslash in the file path */
|
||||
inline int GetFilenameStart(CHAR* path)
|
||||
inline int GetFilenameStart(wchar_t* path)
|
||||
{
|
||||
int pos = 0;
|
||||
int found = 0;
|
||||
if (path != NULL)
|
||||
{
|
||||
while (path[pos] != '\0' && pos < MAX_PATH)
|
||||
while (path[pos] != L'\0' && pos < MAX_PATH)
|
||||
{
|
||||
if (path[pos] == '\\')
|
||||
if (path[pos] == L'\\')
|
||||
{
|
||||
found = pos + 1;
|
||||
}
|
||||
|
@ -83,22 +80,73 @@ inline int GetFilenameStart(CHAR* path)
|
|||
return found;
|
||||
}
|
||||
|
||||
inline void LogStackTrace()
|
||||
inline std::wstring GetModuleName(HANDLE process, const STACKFRAME64& stack)
|
||||
{
|
||||
BOOL result;
|
||||
HANDLE thread;
|
||||
HANDLE process;
|
||||
CONTEXT context;
|
||||
STACKFRAME64 stack;
|
||||
ULONG frame;
|
||||
DWORD64 dw64Displacement;
|
||||
DWORD dwDisplacement;
|
||||
static wchar_t modulePath[MAX_PATH]{};
|
||||
const size_t size = sizeof(modulePath);
|
||||
memset(&modulePath[0], '\0', size);
|
||||
|
||||
DWORD64 moduleBase = SymGetModuleBase64(process, stack.AddrPC.Offset);
|
||||
if (!moduleBase)
|
||||
{
|
||||
Logger::error(L"Failed to get a module. {}", get_last_error_or_default(GetLastError()));
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
if (!GetModuleFileNameW((HINSTANCE)moduleBase, modulePath, MAX_PATH))
|
||||
{
|
||||
Logger::error(L"Failed to get a module path. {}", get_last_error_or_default(GetLastError()));
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
const int start = GetFilenameStart(modulePath);
|
||||
return std::wstring(modulePath, start);
|
||||
}
|
||||
|
||||
inline std::wstring GetName(HANDLE process, const STACKFRAME64& stack)
|
||||
{
|
||||
static IMAGEHLP_SYMBOL64* pSymbol = (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + MAX_PATH * sizeof(TCHAR));
|
||||
if (!pSymbol)
|
||||
{
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
memset(&stack, 0, sizeof(STACKFRAME64));
|
||||
memset(pSymbol, '\0', sizeof(*pSymbol) + MAX_PATH);
|
||||
memset(&modulePath[0], '\0', sizeof(modulePath));
|
||||
pSymbol->MaxNameLength = MAX_PATH;
|
||||
pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
|
||||
DWORD64 dw64Displacement = 0;
|
||||
if (!SymGetSymFromAddr64(process, stack.AddrPC.Offset, &dw64Displacement, pSymbol))
|
||||
{
|
||||
Logger::error(L"Failed to get a symbol. {}", get_last_error_or_default(GetLastError()));
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
std::string str = pSymbol->Name;
|
||||
return std::wstring(str.begin(), str.end());
|
||||
}
|
||||
|
||||
inline std::wstring GetLine(HANDLE process, const STACKFRAME64& stack)
|
||||
{
|
||||
static IMAGEHLP_LINE64 line{};
|
||||
|
||||
memset(&line, '\0', sizeof(IMAGEHLP_LINE64));
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
line.LineNumber = 0;
|
||||
|
||||
DWORD dwDisplacement = 0;
|
||||
if (!SymGetLineFromAddr64(process, stack.AddrPC.Offset, &dwDisplacement, &line))
|
||||
{
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
std::string fileName(line.FileName);
|
||||
return L"(" + std::wstring(fileName.begin(), fileName.end()) + L":" + std::to_wstring(line.LineNumber) + L")";
|
||||
}
|
||||
|
||||
inline void LogStackTrace()
|
||||
{
|
||||
CONTEXT context;
|
||||
try
|
||||
{
|
||||
RtlCaptureContext(&context);
|
||||
|
@ -109,9 +157,11 @@ inline void LogStackTrace()
|
|||
return;
|
||||
}
|
||||
|
||||
process = GetCurrentProcess();
|
||||
thread = GetCurrentThread();
|
||||
dw64Displacement = 0;
|
||||
STACKFRAME64 stack;
|
||||
memset(&stack, 0, sizeof(STACKFRAME64));
|
||||
|
||||
HANDLE process = GetCurrentProcess();
|
||||
HANDLE thread = GetCurrentThread();
|
||||
stack.AddrPC.Offset = context.Rip;
|
||||
stack.AddrPC.Mode = AddrModeFlat;
|
||||
stack.AddrStack.Offset = context.Rsp;
|
||||
|
@ -119,8 +169,9 @@ inline void LogStackTrace()
|
|||
stack.AddrFrame.Offset = context.Rbp;
|
||||
stack.AddrFrame.Mode = AddrModeFlat;
|
||||
|
||||
std::stringstream ss;
|
||||
for (frame = 0;; frame++)
|
||||
BOOL result = false;
|
||||
std::wstringstream ss;
|
||||
for (;;)
|
||||
{
|
||||
result = StackWalk64(
|
||||
IMAGE_FILE_MACHINE_AMD64,
|
||||
|
@ -138,34 +189,10 @@ inline void LogStackTrace()
|
|||
break;
|
||||
}
|
||||
|
||||
pSymbol->MaxNameLength = MAX_PATH;
|
||||
pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
|
||||
if (!SymGetSymFromAddr64(process, stack.AddrPC.Offset, &dw64Displacement, pSymbol))
|
||||
{
|
||||
Logger::error(L"Failed to get a symbol. {}", get_last_error_or_default(GetLastError()));
|
||||
}
|
||||
|
||||
line.LineNumber = 0;
|
||||
SymGetLineFromAddr64(process, stack.AddrPC.Offset, &dwDisplacement, &line);
|
||||
|
||||
DWORD64 moduleBase = SymGetModuleBase64(process, stack.AddrPC.Offset);
|
||||
if (moduleBase)
|
||||
{
|
||||
if (!GetModuleFileNameA((HINSTANCE)moduleBase, modulePath, MAX_PATH))
|
||||
{
|
||||
Logger::error(L"Failed to get a module path. {}", get_last_error_or_default(GetLastError()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error(L"Failed to get a module. {}", get_last_error_or_default(GetLastError()));
|
||||
}
|
||||
|
||||
ss << std::string(modulePath).substr(GetFilenameStart(modulePath)) << "!" << pSymbol->Name << "(" << line.FileName << ":" << line.LineNumber << std::endl;
|
||||
ss << GetModuleName(process, stack) << "!" << GetName(process, stack) << GetLine(process, stack) << std::endl;
|
||||
}
|
||||
|
||||
Logger::error("STACK TRACE\r\n{}", ss.str());
|
||||
Logger::error(L"STACK TRACE\r\n{}", ss.str());
|
||||
Logger::flush();
|
||||
}
|
||||
|
||||
|
@ -218,7 +245,6 @@ inline void InitSymbols()
|
|||
{
|
||||
// Preload symbols so they will be available in case of out-of-memory exception
|
||||
SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
HANDLE process = GetCurrentProcess();
|
||||
if (!SymInitialize(process, NULL, TRUE))
|
||||
{
|
||||
|
|
21
src/common/utils/color.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
// helper function to get the RGB from a #FFFFFF string.
|
||||
inline bool checkValidRGB(std::wstring_view hex, uint8_t* R, uint8_t* G, uint8_t* B)
|
||||
{
|
||||
if (hex.length() != 7)
|
||||
return false;
|
||||
hex = hex.substr(1, 6); // remove #
|
||||
for (auto& c : hex)
|
||||
{
|
||||
if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (swscanf_s(hex.data(), L"%2hhx%2hhx%2hhx", R, G, B) != 3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
#include <vector>
|
||||
#include <optional>
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
|
||||
#include "../logger/logger.h"
|
||||
#include "../utils/winapi_error.h"
|
||||
|
|
|
@ -19,8 +19,6 @@ namespace ABI
|
|||
}
|
||||
#endif
|
||||
|
||||
bool m_doNotActivateOnGameMode = true;
|
||||
|
||||
#pragma region Super_Sonar_Base_Code
|
||||
|
||||
template<typename D>
|
||||
|
@ -58,11 +56,13 @@ protected:
|
|||
// At actual check, time a fifth of the current double click setting might be used instead to take into account users who might have low values.
|
||||
static const int MIN_DOUBLE_CLICK_TIME = 100;
|
||||
|
||||
static constexpr int SonarRadius = 100;
|
||||
static constexpr int SonarZoomFactor = 9;
|
||||
static constexpr DWORD FadeDuration = 500;
|
||||
static constexpr int FinalAlphaNumerator = 1;
|
||||
static constexpr int FinalAlphaDenominator = 2;
|
||||
bool m_destroyed = false;
|
||||
bool m_doNotActivateOnGameMode = true;
|
||||
int m_sonarRadius = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_RADIUS;
|
||||
int m_sonarZoomFactor = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_INITIAL_ZOOM;
|
||||
DWORD m_fadeDuration = FIND_MY_MOUSE_DEFAULT_ANIMATION_DURATION_MS;
|
||||
int m_finalAlphaNumerator = FIND_MY_MOUSE_DEFAULT_OVERLAY_OPACITY;
|
||||
static constexpr int FinalAlphaDenominator = 100;
|
||||
winrt::DispatcherQueueController m_dispatcherQueueController{ nullptr };
|
||||
|
||||
private:
|
||||
|
@ -141,7 +141,7 @@ bool SuperSonar<D>::Initialize(HINSTANCE hinst)
|
|||
|
||||
m_hwndOwner = CreateWindow(L"static", nullptr, WS_POPUP, 0, 0, 0, 0, nullptr, nullptr, hinst, nullptr);
|
||||
|
||||
DWORD exStyle = WS_EX_TRANSPARENT | WS_EX_LAYERED | Shim()->GetExtendedStyle();
|
||||
DWORD exStyle = WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOOLWINDOW | Shim()->GetExtendedStyle();
|
||||
return CreateWindowExW(exStyle, className, windowTitle, WS_POPUP, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, m_hwndOwner, nullptr, hinst, this) != nullptr;
|
||||
}
|
||||
|
||||
|
@ -150,6 +150,7 @@ void SuperSonar<D>::Terminate()
|
|||
{
|
||||
auto dispatcherQueue = m_dispatcherQueueController.DispatcherQueue();
|
||||
bool enqueueSucceeded = dispatcherQueue.TryEnqueue([=]() {
|
||||
m_destroyed = true;
|
||||
DestroyWindow(m_hwndOwner);
|
||||
});
|
||||
if (!enqueueSucceeded)
|
||||
|
@ -457,7 +458,7 @@ void SuperSonar<D>::UpdateMouseSnooping()
|
|||
struct CompositionSpotlight : SuperSonar<CompositionSpotlight>
|
||||
{
|
||||
static constexpr UINT WM_OPACITY_ANIMATION_COMPLETED = WM_APP;
|
||||
static constexpr float SonarRadiusFloat = static_cast<float>(SonarRadius);
|
||||
float m_sonarRadiusFloat = static_cast<float>(m_sonarRadius);
|
||||
|
||||
DWORD GetExtendedStyle()
|
||||
{
|
||||
|
@ -489,7 +490,7 @@ struct CompositionSpotlight : SuperSonar<CompositionSpotlight>
|
|||
m_batch.Completed([hwnd = m_hwnd](auto&&, auto&&) {
|
||||
PostMessage(hwnd, WM_OPACITY_ANIMATION_COMPLETED, 0, 0);
|
||||
});
|
||||
m_root.Opacity(visible ? static_cast<float>(FinalAlphaNumerator) / FinalAlphaDenominator : 0.0f);
|
||||
m_root.Opacity(visible ? static_cast<float>(m_finalAlphaNumerator) / FinalAlphaDenominator : 0.0f);
|
||||
if (visible)
|
||||
{
|
||||
ShowWindow(m_hwnd, SW_SHOWNOACTIVATE);
|
||||
|
@ -531,38 +532,38 @@ private:
|
|||
layer.RelativeSizeAdjustment({ 1.0f, 1.0f }); // fill the parent
|
||||
m_root.Children().InsertAtTop(layer);
|
||||
|
||||
auto backdrop = m_compositor.CreateSpriteVisual();
|
||||
backdrop.RelativeSizeAdjustment({ 1.0f, 1.0f }); // fill the parent
|
||||
backdrop.Brush(m_compositor.CreateColorBrush({ 255, 0, 0, 0 }));
|
||||
layer.Children().InsertAtTop(backdrop);
|
||||
m_backdrop = m_compositor.CreateSpriteVisual();
|
||||
m_backdrop.RelativeSizeAdjustment({ 1.0f, 1.0f }); // fill the parent
|
||||
m_backdrop.Brush(m_compositor.CreateColorBrush(m_backgroundColor));
|
||||
layer.Children().InsertAtTop(m_backdrop);
|
||||
|
||||
m_circleGeometry = m_compositor.CreateEllipseGeometry(); // radius set via expression animation
|
||||
auto circleShape = m_compositor.CreateSpriteShape(m_circleGeometry);
|
||||
circleShape.FillBrush(m_compositor.CreateColorBrush({ 255, 255, 255, 255 }));
|
||||
circleShape.Offset({ SonarRadiusFloat * SonarZoomFactor, SonarRadiusFloat * SonarZoomFactor });
|
||||
m_circleShape = m_compositor.CreateSpriteShape(m_circleGeometry);
|
||||
m_circleShape.FillBrush(m_compositor.CreateColorBrush(m_spotlightColor));
|
||||
m_circleShape.Offset({ m_sonarRadiusFloat * m_sonarZoomFactor, m_sonarRadiusFloat * m_sonarZoomFactor });
|
||||
m_spotlight = m_compositor.CreateShapeVisual();
|
||||
m_spotlight.Size({ SonarRadiusFloat * 2 * SonarZoomFactor, SonarRadiusFloat * 2 * SonarZoomFactor });
|
||||
m_spotlight.Size({ m_sonarRadiusFloat * 2 * m_sonarZoomFactor, m_sonarRadiusFloat * 2 * m_sonarZoomFactor });
|
||||
m_spotlight.AnchorPoint({ 0.5f, 0.5f });
|
||||
m_spotlight.Shapes().Append(circleShape);
|
||||
m_spotlight.Shapes().Append(m_circleShape);
|
||||
|
||||
layer.Children().InsertAtTop(m_spotlight);
|
||||
|
||||
// Implicitly animate the alpha.
|
||||
auto animation = m_compositor.CreateScalarKeyFrameAnimation();
|
||||
animation.Target(L"Opacity");
|
||||
animation.InsertExpressionKeyFrame(1.0f, L"this.FinalValue");
|
||||
animation.Duration(std::chrono::milliseconds{ FadeDuration });
|
||||
m_animation = m_compositor.CreateScalarKeyFrameAnimation();
|
||||
m_animation.Target(L"Opacity");
|
||||
m_animation.InsertExpressionKeyFrame(1.0f, L"this.FinalValue");
|
||||
m_animation.Duration(std::chrono::milliseconds{ m_fadeDuration });
|
||||
auto collection = m_compositor.CreateImplicitAnimationCollection();
|
||||
collection.Insert(L"Opacity", animation);
|
||||
collection.Insert(L"Opacity", m_animation);
|
||||
m_root.ImplicitAnimations(collection);
|
||||
|
||||
// Radius of spotlight shrinks as opacity increases.
|
||||
// At opacity zero, it is SonarRadius * SonarZoomFactor.
|
||||
// At maximum opacity, it is SonarRadius.
|
||||
// At opacity zero, it is m_sonarRadius * SonarZoomFactor.
|
||||
// At maximum opacity, it is m_sonarRadius.
|
||||
auto radiusExpression = m_compositor.CreateExpressionAnimation();
|
||||
radiusExpression.SetReferenceParameter(L"Root", m_root);
|
||||
wchar_t expressionText[256];
|
||||
winrt::check_hresult(StringCchPrintfW(expressionText, ARRAYSIZE(expressionText), L"Lerp(Vector2(%d, %d), Vector2(%d, %d), Root.Opacity * %d / %d)", SonarRadius * SonarZoomFactor, SonarRadius * SonarZoomFactor, SonarRadius, SonarRadius, FinalAlphaDenominator, FinalAlphaNumerator));
|
||||
winrt::check_hresult(StringCchPrintfW(expressionText, ARRAYSIZE(expressionText), L"Lerp(Vector2(%d, %d), Vector2(%d, %d), Root.Opacity * %d / %d)", m_sonarRadius * m_sonarZoomFactor, m_sonarRadius * m_sonarZoomFactor, m_sonarRadius, m_sonarRadius, FinalAlphaDenominator, m_finalAlphaNumerator));
|
||||
radiusExpression.Expression(expressionText);
|
||||
m_circleGeometry.StartAnimation(L"Radius", radiusExpression);
|
||||
|
||||
|
@ -581,6 +582,62 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void ApplySettings(const FindMyMouseSettings& settings, bool applyToRuntimeObjects) {
|
||||
if (!applyToRuntimeObjects)
|
||||
{
|
||||
// Runtime objects not created yet. Just update fields.
|
||||
m_sonarRadius = settings.spotlightRadius;
|
||||
m_sonarRadiusFloat = static_cast<float>(m_sonarRadius);
|
||||
m_backgroundColor = settings.backgroundColor;
|
||||
m_spotlightColor = settings.spotlightColor;
|
||||
m_doNotActivateOnGameMode = settings.doNotActivateOnGameMode;
|
||||
m_fadeDuration = settings.animationDurationMs > 0 ? settings.animationDurationMs : 1;
|
||||
m_finalAlphaNumerator = settings.overlayOpacity;
|
||||
m_sonarZoomFactor = settings.spotlightInitialZoom;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Runtime objects already created. Should update in the owner thread.
|
||||
auto dispatcherQueue = m_dispatcherQueueController.DispatcherQueue();
|
||||
FindMyMouseSettings localSettings = settings;
|
||||
bool enqueueSucceeded = dispatcherQueue.TryEnqueue([=]() {
|
||||
if (!m_destroyed)
|
||||
{
|
||||
// Runtime objects not created yet. Just update fields.
|
||||
m_sonarRadius = localSettings.spotlightRadius;
|
||||
m_sonarRadiusFloat = static_cast<float>(m_sonarRadius);
|
||||
m_backgroundColor = localSettings.backgroundColor;
|
||||
m_spotlightColor = localSettings.spotlightColor;
|
||||
m_doNotActivateOnGameMode = localSettings.doNotActivateOnGameMode;
|
||||
m_fadeDuration = localSettings.animationDurationMs > 0 ? localSettings.animationDurationMs : 1;
|
||||
m_finalAlphaNumerator = localSettings.overlayOpacity;
|
||||
m_sonarZoomFactor = localSettings.spotlightInitialZoom;
|
||||
|
||||
// Apply new settings to runtime composition objects.
|
||||
m_backdrop.Brush().as<winrt::CompositionColorBrush>().Color(m_backgroundColor);
|
||||
m_circleShape.FillBrush().as<winrt::CompositionColorBrush>().Color(m_spotlightColor);
|
||||
m_circleShape.Offset({ m_sonarRadiusFloat * m_sonarZoomFactor, m_sonarRadiusFloat * m_sonarZoomFactor });
|
||||
m_spotlight.Size({ m_sonarRadiusFloat * 2 * m_sonarZoomFactor, m_sonarRadiusFloat * 2 * m_sonarZoomFactor });
|
||||
m_animation.Duration(std::chrono::milliseconds{ m_fadeDuration });
|
||||
m_circleGeometry.StopAnimation(L"Radius");
|
||||
|
||||
// Update animation
|
||||
auto radiusExpression = m_compositor.CreateExpressionAnimation();
|
||||
radiusExpression.SetReferenceParameter(L"Root", m_root);
|
||||
wchar_t expressionText[256];
|
||||
winrt::check_hresult(StringCchPrintfW(expressionText, ARRAYSIZE(expressionText), L"Lerp(Vector2(%d, %d), Vector2(%d, %d), Root.Opacity * %d / %d)", m_sonarRadius * m_sonarZoomFactor, m_sonarRadius * m_sonarZoomFactor, m_sonarRadius, m_sonarRadius, FinalAlphaDenominator, m_finalAlphaNumerator));
|
||||
radiusExpression.Expression(expressionText);
|
||||
m_circleGeometry.StartAnimation(L"Radius", radiusExpression);
|
||||
}
|
||||
});
|
||||
if (!enqueueSucceeded)
|
||||
{
|
||||
Logger::error("Couldn't enqueue message to update the sonar settings.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
winrt::Compositor m_compositor{ nullptr };
|
||||
winrt::Desktop::DesktopWindowTarget m_target{ nullptr };
|
||||
|
@ -588,6 +645,11 @@ private:
|
|||
winrt::CompositionEllipseGeometry m_circleGeometry{ nullptr };
|
||||
winrt::ShapeVisual m_spotlight{ nullptr };
|
||||
winrt::CompositionCommitBatch m_batch{ nullptr };
|
||||
winrt::SpriteVisual m_backdrop{ nullptr };
|
||||
winrt::CompositionSpriteShape m_circleShape{ nullptr };
|
||||
winrt::Windows::UI::Color m_backgroundColor = FIND_MY_MOUSE_DEFAULT_BACKGROUND_COLOR;
|
||||
winrt::Windows::UI::Color m_spotlightColor = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_COLOR;
|
||||
winrt::ScalarKeyFrameAnimation m_animation{ nullptr };
|
||||
};
|
||||
|
||||
template<typename D>
|
||||
|
@ -631,7 +693,7 @@ struct GdiSonar : SuperSonar<D>
|
|||
void OnFadeTimer()
|
||||
{
|
||||
auto now = GetTickCount();
|
||||
auto step = (int)((now - m_fadeStart) * MaxAlpha / this->FadeDuration);
|
||||
auto step = (int)((now - m_fadeStart) * MaxAlpha / this->m_fadeDuration);
|
||||
|
||||
this->Shim()->InvalidateSonar();
|
||||
if (m_alpha < m_alphaTarget)
|
||||
|
@ -666,13 +728,13 @@ protected:
|
|||
int CurrentSonarRadius()
|
||||
{
|
||||
int range = MaxAlpha - m_alpha;
|
||||
int radius = this->SonarRadius + this->SonarRadius * range * (this->SonarZoomFactor - 1) / MaxAlpha;
|
||||
int radius = this->m_sonarRadius + this->m_sonarRadius * range * (this->m_sonarZoomFactor - 1) / MaxAlpha;
|
||||
return radius;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr DWORD FadeFramePeriod = 10;
|
||||
static constexpr int MaxAlpha = SuperSonar<D>::FinalAlphaNumerator * 255 / SuperSonar<D>::FinalAlphaDenominator;
|
||||
int MaxAlpha = SuperSonar<D>::m_finalAlphaNumerator * 255 / SuperSonar<D>::FinalAlphaDenominator;
|
||||
static constexpr DWORD TIMER_ID_FADE = 101;
|
||||
|
||||
private:
|
||||
|
@ -792,6 +854,14 @@ struct GdiCrosshairs : GdiSonar<GdiCrosshairs>
|
|||
#pragma region Super_Sonar_API
|
||||
|
||||
CompositionSpotlight* m_sonar = nullptr;
|
||||
void FindMyMouseApplySettings(const FindMyMouseSettings& settings)
|
||||
{
|
||||
if (m_sonar != nullptr)
|
||||
{
|
||||
Logger::info("Applying settings.");
|
||||
m_sonar->ApplySettings(settings, true);
|
||||
}
|
||||
}
|
||||
|
||||
void FindMyMouseDisable()
|
||||
{
|
||||
|
@ -807,13 +877,8 @@ bool FindMyMouseIsEnabled()
|
|||
return (m_sonar != nullptr);
|
||||
}
|
||||
|
||||
void FindMyMouseSetDoNotActivateOnGameMode(bool doNotActivate)
|
||||
{
|
||||
m_doNotActivateOnGameMode = doNotActivate;
|
||||
}
|
||||
|
||||
// Based on SuperSonar's original wWinMain.
|
||||
int FindMyMouseMain(HINSTANCE hinst)
|
||||
int FindMyMouseMain(HINSTANCE hinst, const FindMyMouseSettings& settings)
|
||||
{
|
||||
Logger::info("Starting a sonar instance.");
|
||||
if (m_sonar != nullptr)
|
||||
|
@ -823,6 +888,7 @@ int FindMyMouseMain(HINSTANCE hinst)
|
|||
}
|
||||
|
||||
CompositionSpotlight sonar;
|
||||
sonar.ApplySettings(settings, false);
|
||||
if (!sonar.Initialize(hinst))
|
||||
{
|
||||
Logger::error("Couldn't initialize a sonar instance.");
|
||||
|
|
|
@ -1,6 +1,26 @@
|
|||
#pragma once
|
||||
#include "pch.h"
|
||||
int FindMyMouseMain(HINSTANCE hinst);
|
||||
|
||||
constexpr bool FIND_MY_MOUSE_DEFAULT_DO_NOT_ACTIVATE_ON_GAME_MODE = true;
|
||||
const winrt::Windows::UI::Color FIND_MY_MOUSE_DEFAULT_BACKGROUND_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(255, 0, 0, 0);
|
||||
const winrt::Windows::UI::Color FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(255, 255, 255, 255);
|
||||
constexpr int FIND_MY_MOUSE_DEFAULT_OVERLAY_OPACITY = 50;
|
||||
constexpr int FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_RADIUS = 100;
|
||||
constexpr int FIND_MY_MOUSE_DEFAULT_ANIMATION_DURATION_MS = 500;
|
||||
constexpr int FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_INITIAL_ZOOM = 9;
|
||||
|
||||
struct FindMyMouseSettings
|
||||
{
|
||||
bool doNotActivateOnGameMode = FIND_MY_MOUSE_DEFAULT_DO_NOT_ACTIVATE_ON_GAME_MODE;
|
||||
winrt::Windows::UI::Color backgroundColor = FIND_MY_MOUSE_DEFAULT_BACKGROUND_COLOR;
|
||||
winrt::Windows::UI::Color spotlightColor = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_COLOR;
|
||||
int overlayOpacity = FIND_MY_MOUSE_DEFAULT_OVERLAY_OPACITY;
|
||||
int spotlightRadius = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_RADIUS;
|
||||
int animationDurationMs = FIND_MY_MOUSE_DEFAULT_ANIMATION_DURATION_MS;
|
||||
int spotlightInitialZoom = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_INITIAL_ZOOM;
|
||||
};
|
||||
|
||||
int FindMyMouseMain(HINSTANCE hinst, const FindMyMouseSettings& settings);
|
||||
void FindMyMouseDisable();
|
||||
bool FindMyMouseIsEnabled();
|
||||
void FindMyMouseSetDoNotActivateOnGameMode(bool doNotActivate);
|
||||
void FindMyMouseApplySettings(const FindMyMouseSettings& settings);
|
||||
|
|
|
@ -5,13 +5,19 @@
|
|||
#include "FindMyMouse.h"
|
||||
#include <thread>
|
||||
#include <common/utils/logger_helper.h>
|
||||
|
||||
#include <common/utils/color.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
const wchar_t JSON_KEY_PROPERTIES[] = L"properties";
|
||||
const wchar_t JSON_KEY_VALUE[] = L"value";
|
||||
const wchar_t JSON_KEY_DO_NOT_ACTIVATE_ON_GAME_MODE[] = L"do_not_activate_on_game_mode";
|
||||
const wchar_t JSON_KEY_BACKGROUND_COLOR[] = L"background_color";
|
||||
const wchar_t JSON_KEY_SPOTLIGHT_COLOR[] = L"spotlight_color";
|
||||
const wchar_t JSON_KEY_OVERLAY_OPACITY[] = L"overlay_opacity";
|
||||
const wchar_t JSON_KEY_SPOTLIGHT_RADIUS[] = L"spotlight_radius";
|
||||
const wchar_t JSON_KEY_ANIMATION_DURATION_MS[] = L"animation_duration_ms";
|
||||
const wchar_t JSON_KEY_SPOTLIGHT_INITIAL_ZOOM[] = L"spotlight_initial_zoom";
|
||||
}
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
@ -48,6 +54,9 @@ private:
|
|||
// The PowerToy state.
|
||||
bool m_enabled = false;
|
||||
|
||||
// Find My Mouse specific settings
|
||||
FindMyMouseSettings m_findMyMouseSettings;
|
||||
|
||||
// Load initial settings from the persisted values.
|
||||
void init_settings();
|
||||
|
||||
|
@ -109,7 +118,7 @@ public:
|
|||
|
||||
parse_settings(values);
|
||||
|
||||
values.save_to_settings_file();
|
||||
FindMyMouseApplySettings(m_findMyMouseSettings);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
|
@ -122,7 +131,7 @@ public:
|
|||
{
|
||||
m_enabled = true;
|
||||
Trace::EnableFindMyMouse(true);
|
||||
std::thread([]() { FindMyMouseMain(m_hModule); }).detach();
|
||||
std::thread([=]() { FindMyMouseMain(m_hModule, m_findMyMouseSettings); }).detach();
|
||||
}
|
||||
|
||||
// Disable the powertoy
|
||||
|
@ -158,25 +167,103 @@ void FindMyMouse::init_settings()
|
|||
|
||||
void FindMyMouse::parse_settings(PowerToysSettings::PowerToyValues& settings)
|
||||
{
|
||||
FindMyMouseSetDoNotActivateOnGameMode(true);
|
||||
|
||||
auto settingsObject = settings.get_raw_json();
|
||||
FindMyMouseSettings findMyMouseSettings;
|
||||
if (settingsObject.GetView().Size())
|
||||
{
|
||||
try
|
||||
{
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_DO_NOT_ACTIVATE_ON_GAME_MODE);
|
||||
FindMyMouseSetDoNotActivateOnGameMode((bool)jsonPropertiesObject.GetNamedBoolean(JSON_KEY_VALUE));
|
||||
findMyMouseSettings.doNotActivateOnGameMode = (bool)jsonPropertiesObject.GetNamedBoolean(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to get 'do not activate on game mode' setting");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse background color
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_BACKGROUND_COLOR);
|
||||
auto backgroundColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE);
|
||||
uint8_t r, g, b;
|
||||
if (!checkValidRGB(backgroundColor, &r, &g, &b))
|
||||
{
|
||||
Logger::error("Background color RGB value is invalid. Will use default value");
|
||||
}
|
||||
else
|
||||
{
|
||||
findMyMouseSettings.backgroundColor = winrt::Windows::UI::ColorHelper::FromArgb(255, r, g, b);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize background color from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse spotlight color
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_SPOTLIGHT_COLOR);
|
||||
auto spotlightColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE);
|
||||
uint8_t r, g, b;
|
||||
if (!checkValidRGB(spotlightColor, &r, &g, &b))
|
||||
{
|
||||
Logger::error("Spotlight color RGB value is invalid. Will use default value");
|
||||
}
|
||||
else
|
||||
{
|
||||
findMyMouseSettings.spotlightColor = winrt::Windows::UI::ColorHelper::FromArgb(255, r, g, b);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize spotlight color from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Overlay Opacity
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_OVERLAY_OPACITY);
|
||||
findMyMouseSettings.overlayOpacity = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Overlay Opacity from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Spotlight Radius
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_SPOTLIGHT_RADIUS);
|
||||
findMyMouseSettings.spotlightRadius = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Spotlight Radius from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Animation Duration
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_ANIMATION_DURATION_MS);
|
||||
findMyMouseSettings.animationDurationMs = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Animation Duration from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Spotlight Initial Zoom
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_SPOTLIGHT_INITIAL_ZOOM);
|
||||
findMyMouseSettings.spotlightInitialZoom = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Spotlight Initial Zoom from settings. Will use default value");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info("Find My Mouse settings are empty");
|
||||
}
|
||||
m_findMyMouseSettings = findMyMouseSettings;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
|
||||
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 .\ resource.base.h resource.h MouseHighlighter.base.rc MouseHighlighter.rc" />
|
||||
</Target>
|
||||
</Project>
|
|
@ -0,0 +1,40 @@
|
|||
#include <windows.h>
|
||||
#include "resource.h"
|
||||
#include "../../../../common/version/version.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
#include "winres.h"
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION FILE_VERSION
|
||||
PRODUCTVERSION PRODUCT_VERSION
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
|
||||
BEGIN
|
||||
VALUE "CompanyName", COMPANY_NAME
|
||||
VALUE "FileDescription", FILE_DESCRIPTION
|
||||
VALUE "FileVersion", FILE_VERSION_STRING
|
||||
VALUE "InternalName", INTERNAL_NAME
|
||||
VALUE "LegalCopyright", COPYRIGHT_NOTE
|
||||
VALUE "OriginalFilename", ORIGINAL_FILENAME
|
||||
VALUE "ProductName", PRODUCT_NAME
|
||||
VALUE "ProductVersion", PRODUCT_VERSION_STRING
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
|
||||
END
|
||||
END
|
443
src/modules/MouseUtils/MouseHighlighter/MouseHighlighter.cpp
Normal file
|
@ -0,0 +1,443 @@
|
|||
// MouseHighlighter.cpp : Defines the entry point for the application.
|
||||
//
|
||||
|
||||
#include "pch.h"
|
||||
#include "MouseHighlighter.h"
|
||||
#include "trace.h"
|
||||
|
||||
#ifdef COMPOSITION
|
||||
namespace winrt
|
||||
{
|
||||
using namespace winrt::Windows::System;
|
||||
using namespace winrt::Windows::UI::Composition;
|
||||
}
|
||||
|
||||
namespace ABI
|
||||
{
|
||||
using namespace ABI::Windows::System;
|
||||
using namespace ABI::Windows::UI::Composition::Desktop;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct Highlighter
|
||||
{
|
||||
bool MyRegisterClass(HINSTANCE hInstance);
|
||||
static Highlighter* instance;
|
||||
void Terminate();
|
||||
void SwitchActivationMode();
|
||||
void ApplySettings(MouseHighlighterSettings settings);
|
||||
|
||||
private:
|
||||
enum class MouseButton
|
||||
{
|
||||
Left,
|
||||
Right
|
||||
};
|
||||
|
||||
void DestroyHighlighter();
|
||||
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) noexcept;
|
||||
void StartDrawing();
|
||||
void StopDrawing();
|
||||
bool CreateHighlighter();
|
||||
void AddDrawingPoint(MouseButton button);
|
||||
void UpdateDrawingPointPosition(MouseButton button);
|
||||
void StartDrawingPointFading(MouseButton button);
|
||||
void ClearDrawing();
|
||||
HHOOK m_mouseHook = NULL;
|
||||
static LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) noexcept;
|
||||
|
||||
static constexpr auto m_className = L"MouseHighlighter";
|
||||
static constexpr auto m_windowTitle = L"MouseHighlighter";
|
||||
HWND m_hwndOwner = NULL;
|
||||
HWND m_hwnd = NULL;
|
||||
HINSTANCE m_hinstance = NULL;
|
||||
static constexpr DWORD WM_SWITCH_ACTIVATION_MODE = WM_APP;
|
||||
|
||||
winrt::DispatcherQueueController m_dispatcherQueueController{ nullptr };
|
||||
winrt::Compositor m_compositor{ nullptr };
|
||||
winrt::Desktop::DesktopWindowTarget m_target{ nullptr };
|
||||
winrt::ContainerVisual m_root{ nullptr };
|
||||
winrt::LayerVisual m_layer{ nullptr };
|
||||
winrt::ShapeVisual m_shape{ nullptr };
|
||||
|
||||
winrt::CompositionSpriteShape m_leftPointer{ nullptr };
|
||||
winrt::CompositionSpriteShape m_rightPointer{ nullptr };
|
||||
bool m_leftButtonPressed = false;
|
||||
bool m_rightButtonPressed = false;
|
||||
|
||||
bool m_visible = false;
|
||||
|
||||
// Possible configurable settings
|
||||
float m_radius = MOUSE_HIGHLIGHTER_DEFAULT_RADIUS;
|
||||
|
||||
int m_fadeDelay_ms = MOUSE_HIGHLIGHTER_DEFAULT_DELAY_MS;
|
||||
int m_fadeDuration_ms = MOUSE_HIGHLIGHTER_DEFAULT_DURATION_MS;
|
||||
|
||||
winrt::Windows::UI::Color m_leftClickColor = MOUSE_HIGHLIGHTER_DEFAULT_LEFT_BUTTON_COLOR;
|
||||
winrt::Windows::UI::Color m_rightClickColor = MOUSE_HIGHLIGHTER_DEFAULT_RIGHT_BUTTON_COLOR;
|
||||
};
|
||||
|
||||
Highlighter* Highlighter::instance = nullptr;
|
||||
|
||||
bool Highlighter::CreateHighlighter()
|
||||
{
|
||||
try
|
||||
{
|
||||
// We need a dispatcher queue.
|
||||
DispatcherQueueOptions options =
|
||||
{
|
||||
sizeof(options),
|
||||
DQTYPE_THREAD_CURRENT,
|
||||
DQTAT_COM_ASTA,
|
||||
};
|
||||
ABI::IDispatcherQueueController* controller;
|
||||
winrt::check_hresult(CreateDispatcherQueueController(options, &controller));
|
||||
*winrt::put_abi(m_dispatcherQueueController) = controller;
|
||||
|
||||
// Create the compositor for our window.
|
||||
m_compositor = winrt::Compositor();
|
||||
ABI::IDesktopWindowTarget* target;
|
||||
winrt::check_hresult(m_compositor.as<ABI::ICompositorDesktopInterop>()->CreateDesktopWindowTarget(m_hwnd, false, &target));
|
||||
*winrt::put_abi(m_target) = target;
|
||||
|
||||
// Create visual root
|
||||
m_root = m_compositor.CreateContainerVisual();
|
||||
m_root.RelativeSizeAdjustment({ 1.0f, 1.0f });
|
||||
m_target.Root(m_root);
|
||||
|
||||
// Create the shapes container visual and add it to root.
|
||||
m_shape = m_compositor.CreateShapeVisual();
|
||||
m_shape.RelativeSizeAdjustment({ 1.0f, 1.0f });
|
||||
m_root.Children().InsertAtTop(m_shape);
|
||||
|
||||
return true;
|
||||
} catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Highlighter::AddDrawingPoint(MouseButton button)
|
||||
{
|
||||
POINT pt;
|
||||
|
||||
// Applies DPIs.
|
||||
GetCursorPos(&pt);
|
||||
|
||||
// Converts to client area of the Windows.
|
||||
ScreenToClient(m_hwnd, &pt);
|
||||
|
||||
// Create circle and add it.
|
||||
auto circleGeometry = m_compositor.CreateEllipseGeometry();
|
||||
circleGeometry.Radius({ m_radius, m_radius });
|
||||
auto circleShape = m_compositor.CreateSpriteShape(circleGeometry);
|
||||
circleShape.Offset({ (float)pt.x, (float)pt.y });
|
||||
if (button == MouseButton::Left)
|
||||
{
|
||||
circleShape.FillBrush(m_compositor.CreateColorBrush(m_leftClickColor));
|
||||
m_leftPointer = circleShape;
|
||||
}
|
||||
else
|
||||
{
|
||||
//right
|
||||
circleShape.FillBrush(m_compositor.CreateColorBrush(m_rightClickColor));
|
||||
m_rightPointer = circleShape;
|
||||
}
|
||||
m_shape.Shapes().Append(circleShape);
|
||||
|
||||
// TODO: We're leaking shapes for long drawing sessions.
|
||||
// Perhaps add a task to the Dispatcher every X circles to clean up.
|
||||
|
||||
// Get back on top in case other Window is now the topmost.
|
||||
SetWindowPos(m_hwnd, HWND_TOPMOST, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN),
|
||||
GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN), 0);
|
||||
}
|
||||
|
||||
void Highlighter::UpdateDrawingPointPosition(MouseButton button)
|
||||
{
|
||||
POINT pt;
|
||||
|
||||
// Applies DPIs.
|
||||
GetCursorPos(&pt);
|
||||
|
||||
// Converts to client area of the Windows.
|
||||
ScreenToClient(m_hwnd, &pt);
|
||||
|
||||
if (button == MouseButton::Left)
|
||||
{
|
||||
m_leftPointer.Offset({ (float)pt.x, (float)pt.y });
|
||||
}
|
||||
else
|
||||
{
|
||||
//right
|
||||
m_rightPointer.Offset({ (float)pt.x, (float)pt.y });
|
||||
}
|
||||
}
|
||||
void Highlighter::StartDrawingPointFading(MouseButton button)
|
||||
{
|
||||
winrt::Windows::UI::Composition::CompositionSpriteShape circleShape{ nullptr };
|
||||
if (button == MouseButton::Left)
|
||||
{
|
||||
circleShape = m_leftPointer;
|
||||
}
|
||||
else
|
||||
{
|
||||
//right
|
||||
circleShape = m_rightPointer;
|
||||
}
|
||||
|
||||
auto brushColor = circleShape.FillBrush().as<winrt::Windows::UI::Composition::CompositionColorBrush>().Color();
|
||||
|
||||
// Animate opacity to simulate a fade away effect.
|
||||
auto animation = m_compositor.CreateColorKeyFrameAnimation();
|
||||
animation.InsertKeyFrame(1, winrt::Windows::UI::ColorHelper::FromArgb(0, brushColor.R, brushColor.G, brushColor.B));
|
||||
using timeSpan = std::chrono::duration<int, std::ratio<1, 1000>>;
|
||||
std::chrono::milliseconds duration(m_fadeDuration_ms);
|
||||
std::chrono::milliseconds delay(m_fadeDelay_ms);
|
||||
animation.Duration(timeSpan(duration));
|
||||
animation.DelayTime(timeSpan(delay));
|
||||
|
||||
circleShape.FillBrush().StartAnimation(L"Color", animation);
|
||||
}
|
||||
|
||||
|
||||
void Highlighter::ClearDrawing()
|
||||
{
|
||||
m_shape.Shapes().Clear();
|
||||
}
|
||||
|
||||
LRESULT CALLBACK Highlighter::MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
if (nCode >= 0)
|
||||
{
|
||||
MSLLHOOKSTRUCT* hookData = (MSLLHOOKSTRUCT*)lParam;
|
||||
switch (wParam)
|
||||
{
|
||||
case WM_LBUTTONDOWN:
|
||||
instance->AddDrawingPoint(MouseButton::Left);
|
||||
instance->m_leftButtonPressed = true;
|
||||
break;
|
||||
case WM_RBUTTONDOWN:
|
||||
instance->AddDrawingPoint(MouseButton::Right);
|
||||
instance->m_rightButtonPressed = true;
|
||||
break;
|
||||
case WM_MOUSEMOVE:
|
||||
if (instance->m_leftButtonPressed)
|
||||
{
|
||||
instance->UpdateDrawingPointPosition(MouseButton::Left);
|
||||
}
|
||||
if (instance->m_rightButtonPressed)
|
||||
{
|
||||
instance->UpdateDrawingPointPosition(MouseButton::Right);
|
||||
}
|
||||
break;
|
||||
case WM_LBUTTONUP:
|
||||
if (instance->m_leftButtonPressed)
|
||||
{
|
||||
instance->StartDrawingPointFading(MouseButton::Left);
|
||||
instance->m_leftButtonPressed = false;
|
||||
}
|
||||
break;
|
||||
case WM_RBUTTONUP:
|
||||
if (instance->m_rightButtonPressed)
|
||||
{
|
||||
instance->StartDrawingPointFading(MouseButton::Right);
|
||||
instance->m_rightButtonPressed = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return CallNextHookEx(0, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
|
||||
void Highlighter::StartDrawing()
|
||||
{
|
||||
Logger::info("Starting draw mode.");
|
||||
Trace::StartHighlightingSession();
|
||||
m_visible = true;
|
||||
SetWindowPos(m_hwnd, HWND_TOPMOST, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN),
|
||||
GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN), 0);
|
||||
ClearDrawing();
|
||||
ShowWindow(m_hwnd, SW_SHOWNOACTIVATE);
|
||||
m_mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, m_hinstance, 0);
|
||||
}
|
||||
|
||||
void Highlighter::StopDrawing()
|
||||
{
|
||||
Logger::info("Stopping draw mode.");
|
||||
m_visible = false;
|
||||
m_leftButtonPressed = false;
|
||||
m_rightButtonPressed = false;
|
||||
m_leftPointer = nullptr;
|
||||
m_rightPointer = nullptr;
|
||||
ShowWindow(m_hwnd, SW_HIDE);
|
||||
UnhookWindowsHookEx(m_mouseHook);
|
||||
ClearDrawing();
|
||||
m_mouseHook = NULL;
|
||||
}
|
||||
|
||||
void Highlighter::SwitchActivationMode()
|
||||
{
|
||||
PostMessage(m_hwnd, WM_SWITCH_ACTIVATION_MODE, 0, 0);
|
||||
}
|
||||
|
||||
void Highlighter::ApplySettings(MouseHighlighterSettings settings) {
|
||||
m_radius = (float)settings.radius;
|
||||
m_fadeDelay_ms = settings.fadeDelayMs;
|
||||
m_fadeDuration_ms = settings.fadeDurationMs;
|
||||
m_leftClickColor = settings.leftButtonColor;
|
||||
m_rightClickColor = settings.rightButtonColor;
|
||||
}
|
||||
|
||||
void Highlighter::DestroyHighlighter()
|
||||
{
|
||||
StopDrawing();
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK Highlighter::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_NCCREATE:
|
||||
instance->m_hwnd = hWnd;
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
case WM_CREATE:
|
||||
return instance->CreateHighlighter() ? 0 : -1;
|
||||
case WM_NCHITTEST:
|
||||
return HTTRANSPARENT;
|
||||
case WM_SWITCH_ACTIVATION_MODE:
|
||||
if (instance->m_visible)
|
||||
{
|
||||
instance->StopDrawing();
|
||||
}
|
||||
else
|
||||
{
|
||||
instance->StartDrawing();
|
||||
}
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
instance->DestroyHighlighter();
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Highlighter::MyRegisterClass(HINSTANCE hInstance)
|
||||
{
|
||||
WNDCLASS wc{};
|
||||
|
||||
m_hinstance = hInstance;
|
||||
|
||||
SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
if (!GetClassInfoW(hInstance, m_className, &wc))
|
||||
{
|
||||
wc.lpfnWndProc = WndProc;
|
||||
wc.hInstance = hInstance;
|
||||
wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
|
||||
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
|
||||
wc.lpszClassName = m_className;
|
||||
|
||||
if (!RegisterClassW(&wc))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_hwndOwner = CreateWindow(L"static", nullptr, WS_POPUP, 0, 0, 0, 0, nullptr, nullptr, hInstance, nullptr);
|
||||
|
||||
DWORD exStyle = WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_NOREDIRECTIONBITMAP | WS_EX_TOOLWINDOW;
|
||||
return CreateWindowExW(exStyle, m_className, m_windowTitle, WS_POPUP,
|
||||
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, m_hwndOwner, nullptr, hInstance, nullptr) != nullptr;
|
||||
}
|
||||
|
||||
void Highlighter::Terminate()
|
||||
{
|
||||
auto dispatcherQueue = m_dispatcherQueueController.DispatcherQueue();
|
||||
bool enqueueSucceeded = dispatcherQueue.TryEnqueue([=]() {
|
||||
DestroyWindow(m_hwndOwner);
|
||||
});
|
||||
if (!enqueueSucceeded)
|
||||
{
|
||||
Logger::error("Couldn't enqueue message to destroy the window.");
|
||||
}
|
||||
}
|
||||
|
||||
#pragma region MouseHighlighter_API
|
||||
|
||||
void MouseHighlighterApplySettings(MouseHighlighterSettings settings)
|
||||
{
|
||||
if (Highlighter::instance != nullptr)
|
||||
{
|
||||
Logger::info("Applying settings.");
|
||||
Highlighter::instance->ApplySettings(settings);
|
||||
}
|
||||
}
|
||||
|
||||
void MouseHighlighterSwitch()
|
||||
{
|
||||
if (Highlighter::instance != nullptr)
|
||||
{
|
||||
Logger::info("Switching activation mode.");
|
||||
Highlighter::instance->SwitchActivationMode();
|
||||
}
|
||||
}
|
||||
|
||||
void MouseHighlighterDisable()
|
||||
{
|
||||
if (Highlighter::instance != nullptr)
|
||||
{
|
||||
Logger::info("Terminating the highlighter instance.");
|
||||
Highlighter::instance->Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
bool MouseHighlighterIsEnabled()
|
||||
{
|
||||
return (Highlighter::instance != nullptr);
|
||||
}
|
||||
|
||||
int MouseHighlighterMain(HINSTANCE hInstance, MouseHighlighterSettings settings)
|
||||
{
|
||||
Logger::info("Starting a highlighter instance.");
|
||||
if (Highlighter::instance != nullptr)
|
||||
{
|
||||
Logger::error("A highlighter instance was still working when trying to start a new one.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Perform application initialization:
|
||||
Highlighter highlighter;
|
||||
Highlighter::instance = &highlighter;
|
||||
highlighter.ApplySettings(settings);
|
||||
if (!highlighter.MyRegisterClass(hInstance))
|
||||
{
|
||||
Logger::error("Couldn't initialize a highlighter instance.");
|
||||
Highlighter::instance = nullptr;
|
||||
return FALSE;
|
||||
}
|
||||
Logger::info("Initialized the highlighter instance.");
|
||||
|
||||
MSG msg;
|
||||
|
||||
// Main message loop:
|
||||
while (GetMessage(&msg, nullptr, 0, 0))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
Logger::info("Mouse highlighter message loop ended.");
|
||||
Highlighter::instance = nullptr;
|
||||
|
||||
return (int)msg.wParam;
|
||||
}
|
||||
|
||||
#pragma endregion MouseHighlighter_API
|
24
src/modules/MouseUtils/MouseHighlighter/MouseHighlighter.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
#include "pch.h"
|
||||
|
||||
constexpr int MOUSE_HIGHLIGHTER_DEFAULT_OPACITY = 160;
|
||||
const winrt::Windows::UI::Color MOUSE_HIGHLIGHTER_DEFAULT_LEFT_BUTTON_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(MOUSE_HIGHLIGHTER_DEFAULT_OPACITY, 255, 255, 0);
|
||||
const winrt::Windows::UI::Color MOUSE_HIGHLIGHTER_DEFAULT_RIGHT_BUTTON_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(MOUSE_HIGHLIGHTER_DEFAULT_OPACITY, 0, 0, 255);
|
||||
constexpr int MOUSE_HIGHLIGHTER_DEFAULT_RADIUS = 20;
|
||||
constexpr int MOUSE_HIGHLIGHTER_DEFAULT_DELAY_MS = 500;
|
||||
constexpr int MOUSE_HIGHLIGHTER_DEFAULT_DURATION_MS = 250;
|
||||
|
||||
struct MouseHighlighterSettings
|
||||
{
|
||||
winrt::Windows::UI::Color leftButtonColor = MOUSE_HIGHLIGHTER_DEFAULT_LEFT_BUTTON_COLOR;
|
||||
winrt::Windows::UI::Color rightButtonColor = MOUSE_HIGHLIGHTER_DEFAULT_RIGHT_BUTTON_COLOR;
|
||||
int radius = MOUSE_HIGHLIGHTER_DEFAULT_RADIUS;
|
||||
int fadeDelayMs = MOUSE_HIGHLIGHTER_DEFAULT_DELAY_MS;
|
||||
int fadeDurationMs = MOUSE_HIGHLIGHTER_DEFAULT_DURATION_MS;
|
||||
};
|
||||
|
||||
int MouseHighlighterMain(HINSTANCE hinst, MouseHighlighterSettings settings);
|
||||
void MouseHighlighterDisable();
|
||||
bool MouseHighlighterIsEnabled();
|
||||
void MouseHighlighterSwitch();
|
||||
void MouseHighlighterApplySettings(MouseHighlighterSettings settings);
|
145
src/modules/MouseUtils/MouseHighlighter/MouseHighlighter.vcxproj
Normal file
|
@ -0,0 +1,145 @@
|
|||
<?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.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\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>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{782a61be-9d85-4081-b35c-1ccc9dcc1e88}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>MouseHighlighter</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>MouseHighlighter</ProjectName>
|
||||
</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>
|
||||
<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>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\MouseUtils\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\MouseUtils\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<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>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<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>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(CIBuild)'!='true'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="MouseHighlighter.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="Generated Files\resource.h" />
|
||||
<None Include="resource.base.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="MouseHighlighter.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp" />
|
||||
<None Include="MouseHighlighter.base.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Generated Files\MouseHighlighter.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SetttingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\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.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="trace.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MouseHighlighter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Generated Files\resource.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MouseHighlighter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<None Include="MouseHighlighter.base.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resource.base.h">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{b012a2c8-5ccb-47fc-9429-4ebf877928e2}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{c8345550-9836-40a0-b473-0f4bf6129568}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{7934ee5b-8427-486d-9324-73b6bcf60eed}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Generated Files">
|
||||
<UniqueIdentifier>{e1083d6b-b856-42a6-bd1f-1710e96170ba}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Generated Files\MouseHighlighter.rc">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
304
src/modules/MouseUtils/MouseHighlighter/dllmain.cpp
Normal file
|
@ -0,0 +1,304 @@
|
|||
#include "pch.h"
|
||||
#include <interface/powertoy_module_interface.h>
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include "trace.h"
|
||||
#include "MouseHighlighter.h"
|
||||
#include "common/utils/color.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
const wchar_t JSON_KEY_PROPERTIES[] = L"properties";
|
||||
const wchar_t JSON_KEY_VALUE[] = L"value";
|
||||
const wchar_t JSON_KEY_ACTIVATION_SHORTCUT[] = L"activation_shortcut";
|
||||
const wchar_t JSON_KEY_LEFT_BUTTON_CLICK_COLOR[] = L"left_button_click_color";
|
||||
const wchar_t JSON_KEY_RIGHT_BUTTON_CLICK_COLOR[] = L"right_button_click_color";
|
||||
const wchar_t JSON_KEY_HIGHLIGHT_OPACITY[] = L"highlight_opacity";
|
||||
const wchar_t JSON_KEY_HIGHLIGHT_RADIUS[] = L"highlight_radius";
|
||||
const wchar_t JSON_KEY_HIGHLIGHT_FADE_DELAY_MS[] = L"highlight_fade_delay_ms";
|
||||
const wchar_t JSON_KEY_HIGHLIGHT_FADE_DURATION_MS[] = L"highlight_fade_duration_ms";
|
||||
}
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
HMODULE m_hModule;
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
m_hModule = hModule;
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
Trace::RegisterProvider();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
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"MouseHighlighter";
|
||||
// Add a description that will we shown in the module settings page.
|
||||
const static wchar_t* MODULE_DESC = L"<no description>";
|
||||
|
||||
// Implement the PowerToy Module Interface and all the required methods.
|
||||
class MouseHighlighter : public PowertoyModuleIface
|
||||
{
|
||||
private:
|
||||
// The PowerToy state.
|
||||
bool m_enabled = false;
|
||||
|
||||
// Hotkey to invoke the module
|
||||
HotkeyEx m_hotkey;
|
||||
|
||||
// Mouse Highlighter specific settings
|
||||
MouseHighlighterSettings m_highlightSettings;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
MouseHighlighter()
|
||||
{
|
||||
LoggerHelpers::init_logger(MODULE_NAME, L"ModuleInterface", LogSettings::mouseHighlighterLoggerName);
|
||||
init_settings();
|
||||
};
|
||||
|
||||
// Destroy the powertoy and free memory
|
||||
virtual void destroy() override
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
// Return the localized display name of the powertoy
|
||||
virtual const wchar_t* get_name() override
|
||||
{
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
// Return the non localized key of the powertoy, this will be cached by the runner
|
||||
virtual const wchar_t* get_key() override
|
||||
{
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
// Return JSON with the configuration options.
|
||||
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
|
||||
{
|
||||
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||
PowerToysSettings::Settings settings(hinstance, get_name());
|
||||
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||
}
|
||||
|
||||
// Signal from the Settings editor to call a custom action.
|
||||
// This can be used to spawn more complex editors.
|
||||
virtual void call_custom_action(const wchar_t* action) override
|
||||
{
|
||||
}
|
||||
|
||||
// Called by the runner to pass the updated settings values as a serialized JSON.
|
||||
virtual void set_config(const wchar_t* config) override
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse the input JSON string.
|
||||
PowerToysSettings::PowerToyValues values =
|
||||
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
||||
|
||||
parse_settings(values);
|
||||
|
||||
MouseHighlighterApplySettings(m_highlightSettings);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
Logger::error("Invalid json when trying to parse Mouse Highlighter settings json.");
|
||||
}
|
||||
}
|
||||
|
||||
// Enable the powertoy
|
||||
virtual void enable()
|
||||
{
|
||||
m_enabled = true;
|
||||
Trace::EnableMouseHighlighter(true);
|
||||
std::thread([=]() { MouseHighlighterMain(m_hModule, m_highlightSettings); }).detach();
|
||||
}
|
||||
|
||||
// Disable the powertoy
|
||||
virtual void disable()
|
||||
{
|
||||
m_enabled = false;
|
||||
Trace::EnableMouseHighlighter(false);
|
||||
MouseHighlighterDisable();
|
||||
}
|
||||
|
||||
// Returns if the powertoys is enabled
|
||||
virtual bool is_enabled() override
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
virtual std::optional<HotkeyEx> GetHotkeyEx() override
|
||||
{
|
||||
return m_hotkey;
|
||||
}
|
||||
|
||||
virtual void OnHotkeyEx() override
|
||||
{
|
||||
MouseHighlighterSwitch();
|
||||
}
|
||||
|
||||
// Load the settings file.
|
||||
void init_settings()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Load and parse the settings file for this PowerToy.
|
||||
PowerToysSettings::PowerToyValues settings =
|
||||
PowerToysSettings::PowerToyValues::load_from_settings_file(MouseHighlighter::get_key());
|
||||
parse_settings(settings);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
Logger::error("Invalid json when trying to load the Mouse Highlighter settings json from file.");
|
||||
}
|
||||
}
|
||||
|
||||
void parse_settings(PowerToysSettings::PowerToyValues& settings)
|
||||
{
|
||||
// TODO: refactor to use common/utils/json.h instead
|
||||
auto settingsObject = settings.get_raw_json();
|
||||
MouseHighlighterSettings highlightSettings;
|
||||
if (settingsObject.GetView().Size())
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse HotKey
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_ACTIVATION_SHORTCUT);
|
||||
auto hotkey = PowerToysSettings::HotkeyObject::from_json(jsonPropertiesObject);
|
||||
m_hotkey = HotkeyEx();
|
||||
if (hotkey.win_pressed())
|
||||
{
|
||||
m_hotkey.modifiersMask |= MOD_WIN;
|
||||
}
|
||||
|
||||
if (hotkey.ctrl_pressed())
|
||||
{
|
||||
m_hotkey.modifiersMask |= MOD_CONTROL;
|
||||
}
|
||||
|
||||
if (hotkey.shift_pressed())
|
||||
{
|
||||
m_hotkey.modifiersMask |= MOD_SHIFT;
|
||||
}
|
||||
|
||||
if (hotkey.alt_pressed())
|
||||
{
|
||||
m_hotkey.modifiersMask |= MOD_ALT;
|
||||
}
|
||||
|
||||
m_hotkey.vkCode = hotkey.get_code();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Mouse Highlighter activation shortcut");
|
||||
}
|
||||
uint8_t opacity = MOUSE_HIGHLIGHTER_DEFAULT_OPACITY;
|
||||
try
|
||||
{
|
||||
// Parse Opacity
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_HIGHLIGHT_OPACITY);
|
||||
opacity = (uint8_t)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Opacity from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse left button click color
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_LEFT_BUTTON_CLICK_COLOR);
|
||||
auto leftColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE);
|
||||
uint8_t r, g, b;
|
||||
if (!checkValidRGB(leftColor,&r,&g,&b))
|
||||
{
|
||||
Logger::error("Left click color RGB value is invalid. Will use default value");
|
||||
}
|
||||
else
|
||||
{
|
||||
highlightSettings.leftButtonColor = winrt::Windows::UI::ColorHelper::FromArgb(opacity, r, g, b);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize left click color from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse right button click color
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_RIGHT_BUTTON_CLICK_COLOR);
|
||||
auto rightColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE);
|
||||
uint8_t r, g, b;
|
||||
if (!checkValidRGB(rightColor, &r, &g, &b))
|
||||
{
|
||||
Logger::error("Right click color RGB value is invalid. Will use default value");
|
||||
}
|
||||
else
|
||||
{
|
||||
highlightSettings.rightButtonColor = winrt::Windows::UI::ColorHelper::FromArgb(opacity, r, g, b);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize right click color from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Radius
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_HIGHLIGHT_RADIUS);
|
||||
highlightSettings.radius = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Radius from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Fade Delay
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_HIGHLIGHT_FADE_DELAY_MS);
|
||||
highlightSettings.fadeDelayMs = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Fade Delay from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Fade Duration
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_HIGHLIGHT_FADE_DURATION_MS);
|
||||
highlightSettings.fadeDurationMs = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Fade Duration from settings. Will use default value");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info("Mouse Highlighter settings are empty");
|
||||
}
|
||||
if (!m_hotkey.modifiersMask)
|
||||
{
|
||||
Logger::info("Mouse Highlighter is going to use default shortcut");
|
||||
m_hotkey.modifiersMask = MOD_SHIFT | MOD_WIN;
|
||||
m_hotkey.vkCode = 0x48; // H key
|
||||
}
|
||||
m_highlightSettings = highlightSettings;
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
{
|
||||
return new MouseHighlighter();
|
||||
}
|
4
src/modules/MouseUtils/MouseHighlighter/packages.config
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" />
|
||||
</packages>
|
1
src/modules/MouseUtils/MouseHighlighter/pch.cpp
Normal file
|
@ -0,0 +1 @@
|
|||
#include "pch.h"
|
22
src/modules/MouseUtils/MouseHighlighter/pch.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#define COMPOSITION
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <strsafe.h>
|
||||
#include <hIdUsage.h>
|
||||
#include <thread>
|
||||
|
||||
#ifdef COMPOSITION
|
||||
#include <windows.ui.composition.interop.h>
|
||||
#include <DispatcherQueue.h>
|
||||
#include <winrt/Windows.System.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.UI.Composition.Desktop.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#endif
|
||||
|
||||
#include <ProjectTelemetry.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/utils/logger_helper.h>
|
14
src/modules/MouseUtils/MouseHighlighter/resource.base.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by MouseHighlighter.rc
|
||||
|
||||
//////////////////////////////
|
||||
// Non-localizable
|
||||
|
||||
#define FILE_DESCRIPTION "PowerToys MouseHighlighter"
|
||||
#define INTERNAL_NAME "MouseHighlighter"
|
||||
#define ORIGINAL_FILENAME "MouseHighlighter.dll"
|
||||
#define IDS_KEYBOARDMANAGER_ICON 1001
|
||||
|
||||
// Non-localizable
|
||||
//////////////////////////////
|
40
src/modules/MouseUtils/MouseHighlighter/trace.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
#include "pch.h"
|
||||
#include "trace.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() noexcept
|
||||
{
|
||||
TraceLoggingRegister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::UnregisterProvider() noexcept
|
||||
{
|
||||
TraceLoggingUnregister(g_hProvider);
|
||||
}
|
||||
|
||||
// Log if the user has MouseHighlighter enabled or disabled
|
||||
void Trace::EnableMouseHighlighter(const bool enabled) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"MouseHighlighter_EnableMouseHighlighter",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingBoolean(enabled, "Enabled"));
|
||||
}
|
||||
|
||||
// Log that the user activated the module by starting a highlighting session
|
||||
void Trace::StartHighlightingSession() noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"MouseHighlighter_StartHighlightingSession",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
14
src/modules/MouseUtils/MouseHighlighter/trace.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
class Trace
|
||||
{
|
||||
public:
|
||||
static void RegisterProvider() noexcept;
|
||||
static void UnregisterProvider() noexcept;
|
||||
|
||||
// Log if the user has MouseHighlighter enabled or disabled
|
||||
static void EnableMouseHighlighter(const bool enabled) noexcept;
|
||||
|
||||
// Log that the user activated the module by starting a highlighting session
|
||||
static void StartHighlightingSession() noexcept;
|
||||
};
|
|
@ -177,7 +177,7 @@ namespace Awake.Core
|
|||
// No keep-awake menu item.
|
||||
CheckButtonToolStripMenuItem? passiveMenuItem = new CheckButtonToolStripMenuItem
|
||||
{
|
||||
Text = "Off (Passive)",
|
||||
Text = "Off (Keep using the selected power plan)",
|
||||
};
|
||||
|
||||
passiveMenuItem.Checked = mode == AwakeMode.PASSIVE;
|
||||
|
|
|
@ -291,7 +291,7 @@ namespace ColorPicker.Controls
|
|||
var newValue = (sender as TextBox).Text;
|
||||
|
||||
// support hex with 3 and 6 characters
|
||||
var reg = new Regex("^#([0-9A-F]{3}){1,2}$");
|
||||
var reg = new Regex("^#([0-9A-Fa-f]{3}){1,2}$");
|
||||
|
||||
if (!reg.IsMatch(newValue))
|
||||
{
|
||||
|
|
|
@ -44,6 +44,14 @@ namespace ColorPicker.Helpers
|
|||
return (cyan, magenta, yellow, blackKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a given <see cref="Color"/> to a float color styling(0.1f, 0.1f, 0.1f)
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="Color"/> to convert</param>
|
||||
/// <returns>The int / 255d for each value to get value between 0 and 1</returns>
|
||||
internal static (double red, double green, double blue) ConvertToDouble(Color color)
|
||||
=> (color.R / 255d, color.G / 255d, color.B / 255d);
|
||||
|
||||
/// <summary>
|
||||
/// Convert a given <see cref="Color"/> to a HSB color (hue, saturation, brightness)
|
||||
/// </summary>
|
||||
|
|
|
@ -46,6 +46,8 @@ namespace ColorPicker.Helpers
|
|||
ColorRepresentationType.RGB => ColorToRGB(color),
|
||||
ColorRepresentationType.CIELAB => ColorToCIELAB(color),
|
||||
ColorRepresentationType.CIEXYZ => ColorToCIEXYZ(color),
|
||||
ColorRepresentationType.VEC4 => ColorToFloat(color),
|
||||
ColorRepresentationType.DecimalValue => ColorToDecimal(color),
|
||||
|
||||
// Fall-back value, when "_userSettings.CopiedColorRepresentation.Value" is incorrect
|
||||
_ => ColorToHex(color),
|
||||
|
@ -99,6 +101,29 @@ namespace ColorPicker.Helpers
|
|||
+ $", {brightness.ToString(CultureInfo.InvariantCulture)}%)";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a <see cref="string"/> representation float color styling(0.1f, 0.1f, 0.1f)
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="Color"/> to convert</param>
|
||||
/// <returns>a string value (0.1f, 0.1f, 0.1f)</returns>
|
||||
private static string ColorToFloat(Color color)
|
||||
{
|
||||
var (red, green, blue) = ColorHelper.ConvertToDouble(color);
|
||||
var precision = 2;
|
||||
|
||||
return $"({Math.Round(red, precision).ToString("0.##", CultureInfo.InvariantCulture)}f, {Math.Round(green, precision).ToString("0.##", CultureInfo.InvariantCulture)}f, {Math.Round(blue, precision).ToString("0.##", CultureInfo.InvariantCulture)}f, 1f)";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a <see cref="string"/> representation decimal color value
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="Color"/> to convert</param>
|
||||
/// <returns>a string value number</returns>
|
||||
private static string ColorToDecimal(Color color)
|
||||
{
|
||||
return $"{color.R + (color.G * 256) + (color.B * 65536)}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a <see cref="string"/> representation of a HSI color
|
||||
/// </summary>
|
||||
|
|
|
@ -216,6 +216,18 @@ namespace ColorPicker.ViewModels
|
|||
FormatName = ColorRepresentationType.CIEXYZ.ToString(),
|
||||
Convert = (Color color) => { return ColorRepresentationHelper.GetStringRepresentationFromMediaColor(color, ColorRepresentationType.CIEXYZ); },
|
||||
});
|
||||
_allColorRepresentations.Add(
|
||||
new ColorFormatModel()
|
||||
{
|
||||
FormatName = ColorRepresentationType.VEC4.ToString(),
|
||||
Convert = (Color color) => { return ColorRepresentationHelper.GetStringRepresentationFromMediaColor(color, ColorRepresentationType.VEC4); },
|
||||
});
|
||||
_allColorRepresentations.Add(
|
||||
new ColorFormatModel()
|
||||
{
|
||||
FormatName = "Decimal",
|
||||
Convert = (Color color) => { return ColorRepresentationHelper.GetStringRepresentationFromMediaColor(color, ColorRepresentationType.DecimalValue); },
|
||||
});
|
||||
|
||||
_userSettings.VisibleColorFormats.CollectionChanged += VisibleColorFormats_CollectionChanged;
|
||||
|
||||
|
|
|
@ -24,6 +24,8 @@ namespace Microsoft.ColorPicker.UnitTests
|
|||
[DataRow(ColorRepresentationType.RGB, "rgb(0, 0, 0)")]
|
||||
[DataRow(ColorRepresentationType.CIELAB, "CIELab(0, 0, 0)")]
|
||||
[DataRow(ColorRepresentationType.CIEXYZ, "xyz(0, 0, 0)")]
|
||||
[DataRow(ColorRepresentationType.VEC4, "(0f, 0f, 0f, 1f)")]
|
||||
[DataRow(ColorRepresentationType.DecimalValue, "0")]
|
||||
|
||||
public void GetStringRepresentationTest(ColorRepresentationType type, string expected)
|
||||
{
|
||||
|
|
|
@ -25,9 +25,8 @@ const std::wstring instanceMutexName = L"Local\\PowerToys_FancyZones_InstanceMut
|
|||
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ PWSTR lpCmdLine, _In_ int nCmdShow)
|
||||
{
|
||||
winrt::init_apartment();
|
||||
InitUnhandledExceptionHandler_x64();
|
||||
|
||||
LoggerHelpers::init_logger(moduleName, internalPath, LogSettings::fancyZonesLoggerName);
|
||||
InitUnhandledExceptionHandler_x64();
|
||||
|
||||
auto mutex = CreateMutex(nullptr, true, instanceMutexName.c_str());
|
||||
if (mutex == nullptr)
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
<ClInclude Include="ZoneColors.h" />
|
||||
<ClInclude Include="ZoneSet.h" />
|
||||
<ClInclude Include="WorkArea.h" />
|
||||
<ClInclude Include="ZoneWindowDrawing.h" />
|
||||
<ClInclude Include="ZonesOverlay.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="FancyZones.cpp" />
|
||||
|
@ -84,7 +84,7 @@
|
|||
<ClCompile Include="Zone.cpp" />
|
||||
<ClCompile Include="ZoneSet.cpp" />
|
||||
<ClCompile Include="WorkArea.cpp" />
|
||||
<ClCompile Include="ZoneWindowDrawing.cpp" />
|
||||
<ClCompile Include="ZonesOverlay.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="fancyzones.base.rc" />
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
<ClInclude Include="KeyState.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ZoneWindowDrawing.h">
|
||||
<ClInclude Include="ZonesOverlay.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MonitorUtils.h">
|
||||
|
@ -140,7 +140,7 @@
|
|||
<ClCompile Include="FancyZonesDataTypes.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZoneWindowDrawing.cpp">
|
||||
<ClCompile Include="ZonesOverlay.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="OnThreadExecutor.cpp">
|
||||
|
|
|
@ -101,12 +101,12 @@ void WindowMoveHandler::MoveSizeStart(HWND window, HMONITOR monitor, POINT const
|
|||
{
|
||||
for (auto [keyMonitor, workArea] : workAreaMap)
|
||||
{
|
||||
// Skip calling ShowZoneWindow for iter->second (m_draggedWindowWorkArea) since it
|
||||
// Skip calling ShowZonesOverlay for iter->second (m_draggedWindowWorkArea) since it
|
||||
// was already called in MoveSizeEnter
|
||||
const bool moveSizeEnterCalled = workArea == m_draggedWindowWorkArea;
|
||||
if (workArea && !moveSizeEnterCalled)
|
||||
{
|
||||
workArea->ShowZoneWindow();
|
||||
workArea->ShowZonesOverlay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ void WindowMoveHandler::MoveSizeStart(HWND window, HMONITOR monitor, POINT const
|
|||
{
|
||||
if (workArea)
|
||||
{
|
||||
workArea->HideZoneWindow();
|
||||
workArea->HideZonesOverlay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ void WindowMoveHandler::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen,
|
|||
{
|
||||
if (workArea)
|
||||
{
|
||||
workArea->HideZoneWindow();
|
||||
workArea->HideZonesOverlay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ void WindowMoveHandler::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen,
|
|||
m_draggedWindowWorkArea->ClearSelectedZones();
|
||||
if (!m_settings->GetSettings()->showZonesOnAllMonitors)
|
||||
{
|
||||
m_draggedWindowWorkArea->HideZoneWindow();
|
||||
m_draggedWindowWorkArea->HideZonesOverlay();
|
||||
}
|
||||
|
||||
m_draggedWindowWorkArea = iter->second;
|
||||
|
@ -279,7 +279,7 @@ void WindowMoveHandler::MoveSizeEnd(HWND window, POINT const& ptScreen, const st
|
|||
{
|
||||
if (workArea)
|
||||
{
|
||||
workArea->HideZoneWindow();
|
||||
workArea->HideZonesOverlay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include "FancyZonesData.h"
|
||||
#include "FancyZonesDataTypes.h"
|
||||
#include "ZoneWindowDrawing.h"
|
||||
#include "ZonesOverlay.h"
|
||||
#include "trace.h"
|
||||
#include "util.h"
|
||||
#include "on_thread_executor.h"
|
||||
|
@ -21,7 +21,7 @@
|
|||
// Non-Localizable strings
|
||||
namespace NonLocalizable
|
||||
{
|
||||
const wchar_t ToolWindowClassName[] = L"SuperFancyZones_ZoneWindow";
|
||||
const wchar_t ToolWindowClassName[] = L"FancyZones_ZonesOverlay";
|
||||
}
|
||||
|
||||
using namespace FancyZonesUtils;
|
||||
|
@ -57,13 +57,13 @@ namespace
|
|||
|
||||
public:
|
||||
|
||||
HWND NewZoneWindow(Rect position, HINSTANCE hinstance, WorkArea* owner)
|
||||
HWND NewZonesOverlayWindow(Rect position, HINSTANCE hinstance, WorkArea* owner)
|
||||
{
|
||||
HWND windowFromPool = ExtractWindow();
|
||||
if (windowFromPool == NULL)
|
||||
{
|
||||
HWND window = CreateWindowExW(WS_EX_TOOLWINDOW, NonLocalizable::ToolWindowClassName, L"", WS_POPUP, position.left(), position.top(), position.width(), position.height(), nullptr, nullptr, hinstance, owner);
|
||||
Logger::info("Creating new zone window, hWnd = {}", (void*)window);
|
||||
Logger::info("Creating new ZonesOverlay window, hWnd = {}", (void*)window);
|
||||
MakeWindowTransparent(window);
|
||||
|
||||
// According to ShowWindow docs, we must call it with SW_SHOWNORMAL the first time
|
||||
|
@ -73,17 +73,17 @@ namespace
|
|||
}
|
||||
else
|
||||
{
|
||||
Logger::info("Reusing zone window from pool, hWnd = {}", (void*)windowFromPool);
|
||||
Logger::info("Reusing ZonesOverlay window from pool, hWnd = {}", (void*)windowFromPool);
|
||||
SetWindowLongPtrW(windowFromPool, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(owner));
|
||||
MoveWindow(windowFromPool, position.left(), position.top(), position.width(), position.height(), TRUE);
|
||||
return windowFromPool;
|
||||
}
|
||||
}
|
||||
|
||||
void FreeZoneWindow(HWND window)
|
||||
void FreeZonesOverlayWindow(HWND window)
|
||||
{
|
||||
_TRACER_;
|
||||
Logger::info("Freeing zone window, hWnd = {}", (void*)window);
|
||||
Logger::info("Freeing ZonesOverlay window into pool, hWnd = {}", (void*)window);
|
||||
SetWindowLongPtrW(window, GWLP_USERDATA, 0);
|
||||
ShowWindow(window, SW_HIDE);
|
||||
|
||||
|
@ -133,9 +133,9 @@ public:
|
|||
IFACEMETHODIMP_(ZoneIndexSet)
|
||||
GetWindowZoneIndexes(HWND window) const noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
ShowZoneWindow() noexcept;
|
||||
ShowZonesOverlay() noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
HideZoneWindow() noexcept;
|
||||
HideZonesOverlay() noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
UpdateActiveZoneSet() noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
|
@ -169,7 +169,7 @@ private:
|
|||
ZoneIndexSet m_highlightZone;
|
||||
WPARAM m_keyLast{};
|
||||
size_t m_keyCycle{};
|
||||
std::unique_ptr<ZoneWindowDrawing> m_zoneWindowDrawing;
|
||||
std::unique_ptr<ZonesOverlay> m_zonesOverlay;
|
||||
ZoneColors m_zoneColors;
|
||||
OverlappingZonesAlgorithm m_overlappingAlgorithm;
|
||||
};
|
||||
|
@ -187,7 +187,7 @@ WorkArea::WorkArea(HINSTANCE hinstance)
|
|||
|
||||
WorkArea::~WorkArea()
|
||||
{
|
||||
windowPool.FreeZoneWindow(m_window);
|
||||
windowPool.FreeZonesOverlayWindow(m_window);
|
||||
}
|
||||
|
||||
bool WorkArea::Init(HINSTANCE hinstance, HMONITOR monitor, const FancyZonesDataTypes::DeviceIdData& uniqueId, const FancyZonesDataTypes::DeviceIdData& parentUniqueId, const ZoneColors& zoneColors, OverlappingZonesAlgorithm overlappingAlgorithm)
|
||||
|
@ -215,14 +215,14 @@ bool WorkArea::Init(HINSTANCE hinstance, HMONITOR monitor, const FancyZonesDataT
|
|||
m_uniqueId = uniqueId;
|
||||
InitializeZoneSets(parentUniqueId);
|
||||
|
||||
m_window = windowPool.NewZoneWindow(workAreaRect, hinstance, this);
|
||||
m_window = windowPool.NewZonesOverlayWindow(workAreaRect, hinstance, this);
|
||||
|
||||
if (!m_window)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_zoneWindowDrawing = std::make_unique<ZoneWindowDrawing>(m_window);
|
||||
m_zonesOverlay = std::make_unique<ZonesOverlay>(m_window);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ IFACEMETHODIMP WorkArea::MoveSizeEnter(HWND window) noexcept
|
|||
m_windowMoveSize = window;
|
||||
m_highlightZone = {};
|
||||
m_initialHighlightZone = {};
|
||||
ShowZoneWindow();
|
||||
ShowZonesOverlay();
|
||||
Trace::WorkArea::MoveOrResizeStarted(m_zoneSet);
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -275,7 +275,7 @@ IFACEMETHODIMP WorkArea::MoveSizeUpdate(POINT const& ptScreen, bool dragEnabled,
|
|||
|
||||
if (redraw)
|
||||
{
|
||||
m_zoneWindowDrawing->DrawActiveZoneSet(m_zoneSet->GetZones(), m_highlightZone, m_zoneColors);
|
||||
m_zonesOverlay->DrawActiveZoneSet(m_zoneSet->GetZones(), m_highlightZone, m_zoneColors);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
|
@ -301,7 +301,7 @@ IFACEMETHODIMP WorkArea::MoveSizeEnd(HWND window, POINT const& ptScreen) noexcep
|
|||
}
|
||||
Trace::WorkArea::MoveOrResizeEnd(m_zoneSet);
|
||||
|
||||
HideZoneWindow();
|
||||
HideZonesOverlay();
|
||||
m_windowMoveSize = nullptr;
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -400,22 +400,22 @@ WorkArea::GetWindowZoneIndexes(HWND window) const noexcept
|
|||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
WorkArea::ShowZoneWindow() noexcept
|
||||
WorkArea::ShowZonesOverlay() noexcept
|
||||
{
|
||||
if (m_window)
|
||||
{
|
||||
SetAsTopmostWindow();
|
||||
m_zoneWindowDrawing->DrawActiveZoneSet(m_zoneSet->GetZones(), m_highlightZone, m_zoneColors);
|
||||
m_zoneWindowDrawing->Show();
|
||||
m_zonesOverlay->DrawActiveZoneSet(m_zoneSet->GetZones(), m_highlightZone, m_zoneColors);
|
||||
m_zonesOverlay->Show();
|
||||
}
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
WorkArea::HideZoneWindow() noexcept
|
||||
WorkArea::HideZonesOverlay() noexcept
|
||||
{
|
||||
if (m_window)
|
||||
{
|
||||
m_zoneWindowDrawing->Hide();
|
||||
m_zonesOverlay->Hide();
|
||||
m_keyLast = 0;
|
||||
m_windowMoveSize = nullptr;
|
||||
m_highlightZone = {};
|
||||
|
@ -429,7 +429,7 @@ WorkArea::UpdateActiveZoneSet() noexcept
|
|||
if (m_window)
|
||||
{
|
||||
m_highlightZone.clear();
|
||||
m_zoneWindowDrawing->DrawActiveZoneSet(m_zoneSet->GetZones(), m_highlightZone, m_zoneColors);
|
||||
m_zonesOverlay->DrawActiveZoneSet(m_zoneSet->GetZones(), m_highlightZone, m_zoneColors);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -448,7 +448,7 @@ WorkArea::ClearSelectedZones() noexcept
|
|||
if (m_highlightZone.size())
|
||||
{
|
||||
m_highlightZone.clear();
|
||||
m_zoneWindowDrawing->DrawActiveZoneSet(m_zoneSet->GetZones(), m_highlightZone, m_zoneColors);
|
||||
m_zonesOverlay->DrawActiveZoneSet(m_zoneSet->GetZones(), m_highlightZone, m_zoneColors);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -458,8 +458,8 @@ WorkArea::FlashZones() noexcept
|
|||
if (m_window)
|
||||
{
|
||||
SetAsTopmostWindow();
|
||||
m_zoneWindowDrawing->DrawActiveZoneSet(m_zoneSet->GetZones(), {}, m_zoneColors);
|
||||
m_zoneWindowDrawing->Flash();
|
||||
m_zonesOverlay->DrawActiveZoneSet(m_zoneSet->GetZones(), {}, m_zoneColors);
|
||||
m_zonesOverlay->Flash();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -108,8 +108,14 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IWorkArea :
|
|||
* @returns Zone index of the window
|
||||
*/
|
||||
IFACEMETHOD_(ZoneIndexSet, GetWindowZoneIndexes)(HWND window) const = 0;
|
||||
IFACEMETHOD_(void, ShowZoneWindow)() = 0;
|
||||
IFACEMETHOD_(void, HideZoneWindow)() = 0;
|
||||
/**
|
||||
* Show a drawing of the zones in the work area.
|
||||
*/
|
||||
IFACEMETHOD_(void, ShowZonesOverlay)() = 0;
|
||||
/**
|
||||
* Hide the drawing of the zones in the work area.
|
||||
*/
|
||||
IFACEMETHOD_(void, HideZonesOverlay)() = 0;
|
||||
/**
|
||||
* Update currently active zone layout for this work area.
|
||||
*/
|
||||
|
|
|
@ -594,19 +594,17 @@ ZoneSet::CycleTabs(HWND window, bool reverse) noexcept
|
|||
for (;;)
|
||||
{
|
||||
auto next = GetNextTab(indexSet, window, reverse);
|
||||
if (next == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
auto success = SetForegroundWindow(next);
|
||||
if (!success && GetLastError() == ERROR_INVALID_WINDOW_HANDLE)
|
||||
// Determine whether the window still exists
|
||||
if (!IsWindow(next))
|
||||
{
|
||||
// Dismiss the encountered window since it was probably closed
|
||||
DismissWindow(next);
|
||||
continue;
|
||||
}
|
||||
|
||||
SwitchToWindow(next);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "pch.h"
|
||||
#include "ZoneWindowDrawing.h"
|
||||
#include "ZonesOverlay.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
@ -7,7 +7,6 @@
|
|||
#include <vector>
|
||||
|
||||
#include <common/logger/call_tracer.h>
|
||||
#include <common/logger/logger.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -20,7 +19,7 @@ namespace NonLocalizable
|
|||
const wchar_t SegoeUiFont[] = L"Segoe ui";
|
||||
}
|
||||
|
||||
float ZoneWindowDrawing::GetAnimationAlpha()
|
||||
float ZonesOverlay::GetAnimationAlpha()
|
||||
{
|
||||
// Lock is held by the caller
|
||||
|
||||
|
@ -41,7 +40,7 @@ float ZoneWindowDrawing::GetAnimationAlpha()
|
|||
return std::clamp(millis / FadeInDurationMillis, 0.001f, 1.f);
|
||||
}
|
||||
|
||||
ID2D1Factory* ZoneWindowDrawing::GetD2DFactory()
|
||||
ID2D1Factory* ZonesOverlay::GetD2DFactory()
|
||||
{
|
||||
static auto pD2DFactory = [] {
|
||||
ID2D1Factory* res = nullptr;
|
||||
|
@ -51,7 +50,7 @@ ID2D1Factory* ZoneWindowDrawing::GetD2DFactory()
|
|||
return pD2DFactory;
|
||||
}
|
||||
|
||||
IDWriteFactory* ZoneWindowDrawing::GetWriteFactory()
|
||||
IDWriteFactory* ZonesOverlay::GetWriteFactory()
|
||||
{
|
||||
static auto pDWriteFactory = [] {
|
||||
IUnknown* res = nullptr;
|
||||
|
@ -61,7 +60,7 @@ IDWriteFactory* ZoneWindowDrawing::GetWriteFactory()
|
|||
return pDWriteFactory;
|
||||
}
|
||||
|
||||
D2D1_COLOR_F ZoneWindowDrawing::ConvertColor(COLORREF color)
|
||||
D2D1_COLOR_F ZonesOverlay::ConvertColor(COLORREF color)
|
||||
{
|
||||
return D2D1::ColorF(GetRValue(color) / 255.f,
|
||||
GetGValue(color) / 255.f,
|
||||
|
@ -69,12 +68,12 @@ D2D1_COLOR_F ZoneWindowDrawing::ConvertColor(COLORREF color)
|
|||
1.f);
|
||||
}
|
||||
|
||||
D2D1_RECT_F ZoneWindowDrawing::ConvertRect(RECT rect)
|
||||
D2D1_RECT_F ZonesOverlay::ConvertRect(RECT rect)
|
||||
{
|
||||
return D2D1::RectF((float)rect.left + 0.5f, (float)rect.top + 0.5f, (float)rect.right - 0.5f, (float)rect.bottom - 0.5f);
|
||||
}
|
||||
|
||||
ZoneWindowDrawing::ZoneWindowDrawing(HWND window)
|
||||
ZonesOverlay::ZonesOverlay(HWND window)
|
||||
{
|
||||
HRESULT hr;
|
||||
m_window = window;
|
||||
|
@ -84,7 +83,7 @@ ZoneWindowDrawing::ZoneWindowDrawing(HWND window)
|
|||
// Obtain the size of the drawing area.
|
||||
if (!GetClientRect(window, &m_clientRect))
|
||||
{
|
||||
Logger::error("couldn't initialize ZoneWindowDrawing: GetClientRect failed");
|
||||
Logger::error("couldn't initialize ZonesOverlay: GetClientRect failed");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -103,14 +102,14 @@ ZoneWindowDrawing::ZoneWindowDrawing(HWND window)
|
|||
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
Logger::error("couldn't initialize ZoneWindowDrawing: CreateHwndRenderTarget failed with {}", hr);
|
||||
Logger::error("couldn't initialize ZonesOverlay: CreateHwndRenderTarget failed with {}", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
m_renderThread = std::thread([this]() { RenderLoop(); });
|
||||
}
|
||||
|
||||
ZoneWindowDrawing::RenderResult ZoneWindowDrawing::Render()
|
||||
ZonesOverlay::RenderResult ZonesOverlay::Render()
|
||||
{
|
||||
std::unique_lock lock(m_mutex);
|
||||
|
||||
|
@ -193,7 +192,7 @@ ZoneWindowDrawing::RenderResult ZoneWindowDrawing::Render()
|
|||
return RenderResult::Ok;
|
||||
}
|
||||
|
||||
void ZoneWindowDrawing::RenderLoop()
|
||||
void ZonesOverlay::RenderLoop()
|
||||
{
|
||||
while (!m_abortThread)
|
||||
{
|
||||
|
@ -212,7 +211,7 @@ void ZoneWindowDrawing::RenderLoop()
|
|||
}
|
||||
}
|
||||
|
||||
void ZoneWindowDrawing::Hide()
|
||||
void ZonesOverlay::Hide()
|
||||
{
|
||||
_TRACER_;
|
||||
bool shouldHideWindow = true;
|
||||
|
@ -229,7 +228,7 @@ void ZoneWindowDrawing::Hide()
|
|||
}
|
||||
}
|
||||
|
||||
void ZoneWindowDrawing::Show()
|
||||
void ZonesOverlay::Show()
|
||||
{
|
||||
_TRACER_;
|
||||
bool shouldShowWindow = true;
|
||||
|
@ -257,7 +256,7 @@ void ZoneWindowDrawing::Show()
|
|||
m_cv.notify_all();
|
||||
}
|
||||
|
||||
void ZoneWindowDrawing::Flash()
|
||||
void ZonesOverlay::Flash()
|
||||
{
|
||||
_TRACER_;
|
||||
bool shouldShowWindow = true;
|
||||
|
@ -277,9 +276,9 @@ void ZoneWindowDrawing::Flash()
|
|||
m_cv.notify_all();
|
||||
}
|
||||
|
||||
void ZoneWindowDrawing::DrawActiveZoneSet(const IZoneSet::ZonesMap& zones,
|
||||
const ZoneIndexSet& highlightZones,
|
||||
const ZoneColors& colors)
|
||||
void ZonesOverlay::DrawActiveZoneSet(const IZoneSet::ZonesMap& zones,
|
||||
const ZoneIndexSet& highlightZones,
|
||||
const ZoneColors& colors)
|
||||
{
|
||||
_TRACER_;
|
||||
std::unique_lock lock(m_mutex);
|
||||
|
@ -345,7 +344,7 @@ void ZoneWindowDrawing::DrawActiveZoneSet(const IZoneSet::ZonesMap& zones,
|
|||
}
|
||||
}
|
||||
|
||||
ZoneWindowDrawing::~ZoneWindowDrawing()
|
||||
ZonesOverlay::~ZonesOverlay()
|
||||
{
|
||||
{
|
||||
std::unique_lock lock(m_mutex);
|
|
@ -13,7 +13,7 @@
|
|||
#include "FancyZones.h"
|
||||
#include "ZoneColors.h"
|
||||
|
||||
class ZoneWindowDrawing
|
||||
class ZonesOverlay
|
||||
{
|
||||
struct DrawableRect
|
||||
{
|
||||
|
@ -60,8 +60,8 @@ class ZoneWindowDrawing
|
|||
|
||||
public:
|
||||
|
||||
~ZoneWindowDrawing();
|
||||
ZoneWindowDrawing(HWND window);
|
||||
~ZonesOverlay();
|
||||
ZonesOverlay(HWND window);
|
||||
void Hide();
|
||||
void Show();
|
||||
void Flash();
|
|
@ -369,6 +369,22 @@ namespace FancyZonesUtils
|
|||
::SetWindowPlacement(window, &placement);
|
||||
}
|
||||
|
||||
void SwitchToWindow(HWND window) noexcept
|
||||
{
|
||||
// Check if the window is minimized
|
||||
if (IsIconic(window))
|
||||
{
|
||||
// Show the window since SetForegroundWindow fails on minimized windows
|
||||
ShowWindow(window, SW_RESTORE);
|
||||
}
|
||||
|
||||
// This is a hack to bypass the restriction on setting the foreground window
|
||||
INPUT inputs[1] = { { .type = INPUT_MOUSE } };
|
||||
SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
|
||||
|
||||
SetForegroundWindow(window);
|
||||
}
|
||||
|
||||
bool HasNoVisibleOwner(HWND window) noexcept
|
||||
{
|
||||
auto owner = GetWindow(window, GW_OWNER);
|
||||
|
|
|
@ -195,6 +195,8 @@ namespace FancyZonesUtils
|
|||
// Parameter rect must be in screen coordinates (e.g. obtained from GetWindowRect)
|
||||
void SizeWindowToRect(HWND window, RECT rect) noexcept;
|
||||
|
||||
void SwitchToWindow(HWND window) noexcept;
|
||||
|
||||
bool HasNoVisibleOwner(HWND window) noexcept;
|
||||
bool IsStandardWindow(HWND window);
|
||||
bool IsCandidateForLastKnownZone(HWND window, const std::vector<std::wstring>& excludedApps) noexcept;
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace ImageResizer.Extensions
|
||||
|
@ -43,7 +45,14 @@ namespace ImageResizer.Extensions
|
|||
|
||||
try
|
||||
{
|
||||
return metadata.GetQuery(query);
|
||||
if (metadata.ContainsQuery(query))
|
||||
{
|
||||
return metadata.GetQuery(query);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
|
@ -51,5 +60,179 @@ namespace ImageResizer.Extensions
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveQuerySafe(this BitmapMetadata metadata, string query)
|
||||
{
|
||||
if (metadata == null || string.IsNullOrWhiteSpace(query))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (metadata.ContainsQuery(query))
|
||||
{
|
||||
metadata.RemoveQuery(query);
|
||||
}
|
||||
}
|
||||
#pragma warning disable CA1031 // Do not catch general exception types
|
||||
catch (Exception ex)
|
||||
#pragma warning restore CA1031 // Do not catch general exception types
|
||||
{
|
||||
Debug.WriteLine($"Exception while trying to remove metadata entry at position: {query}");
|
||||
Debug.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetQuerySafe(this BitmapMetadata metadata, string query, object value)
|
||||
{
|
||||
if (metadata == null || string.IsNullOrWhiteSpace(query) || value == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
metadata.SetQuery(query, value);
|
||||
}
|
||||
#pragma warning disable CA1031 // Do not catch general exception types
|
||||
catch (Exception ex)
|
||||
#pragma warning restore CA1031 // Do not catch general exception types
|
||||
{
|
||||
Debug.WriteLine($"Exception while trying to set metadata {value} at position: {query}");
|
||||
Debug.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all metadata
|
||||
/// Iterates recursively through all metadata
|
||||
/// </summary>
|
||||
public static List<(string metadataPath, object value)> GetListOfMetadata(this BitmapMetadata metadata)
|
||||
{
|
||||
var listOfAllMetadata = new List<(string metadataPath, object value)>();
|
||||
|
||||
GetMetadataRecursively(metadata, string.Empty);
|
||||
|
||||
return listOfAllMetadata;
|
||||
|
||||
void GetMetadataRecursively(BitmapMetadata metadata, string query)
|
||||
{
|
||||
foreach (string relativeQuery in metadata)
|
||||
{
|
||||
string absolutePath = query + relativeQuery;
|
||||
|
||||
object metadataQueryReader = null;
|
||||
|
||||
try
|
||||
{
|
||||
metadataQueryReader = GetQueryWithPreCheck(metadata, relativeQuery);
|
||||
}
|
||||
#pragma warning disable CA1031 // Do not catch general exception types
|
||||
catch (Exception ex)
|
||||
#pragma warning restore CA1031 // Do not catch general exception types
|
||||
{
|
||||
Debug.WriteLine($"Removing corrupt metadata property {absolutePath}. Skipping metadata entry | {ex.Message}");
|
||||
Debug.WriteLine(ex);
|
||||
}
|
||||
|
||||
if (metadataQueryReader != null)
|
||||
{
|
||||
listOfAllMetadata.Add((absolutePath, metadataQueryReader));
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.WriteLine($"No metadata found for query {absolutePath}. Skipping empty null entry because its invalid.");
|
||||
}
|
||||
|
||||
if (metadataQueryReader is BitmapMetadata innerMetadata)
|
||||
{
|
||||
GetMetadataRecursively(innerMetadata, absolutePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object GetQueryWithPreCheck(BitmapMetadata metadata, string query)
|
||||
{
|
||||
if (metadata == null || string.IsNullOrWhiteSpace(query))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (metadata.ContainsQuery(query))
|
||||
{
|
||||
return metadata.GetQuery(query);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prints all metadata to debug console
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Intented for debug only!!!
|
||||
/// </remarks>
|
||||
public static void PrintsAllMetadataToDebugOutput(this BitmapMetadata metadata)
|
||||
{
|
||||
if (metadata == null)
|
||||
{
|
||||
Debug.WriteLine($"Metadata was null.");
|
||||
}
|
||||
|
||||
var listOfMetadata = metadata.GetListOfMetadataForDebug();
|
||||
foreach (var metadataItem in listOfMetadata)
|
||||
{
|
||||
// Debug.WriteLine($"modifiableMetadata.RemoveQuerySafe(\"{metadataItem.metadataPath}\");");
|
||||
Debug.WriteLine($"{metadataItem.metadataPath} | {metadataItem.value}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all metadata
|
||||
/// Iterates recursively through all metadata
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Intented for debug only!!!
|
||||
/// </remarks>
|
||||
public static List<(string metadataPath, object value)> GetListOfMetadataForDebug(this BitmapMetadata metadata)
|
||||
{
|
||||
var listOfAllMetadata = new List<(string metadataPath, object value)>();
|
||||
|
||||
GetMetadataRecursively(metadata, string.Empty);
|
||||
|
||||
return listOfAllMetadata;
|
||||
|
||||
void GetMetadataRecursively(BitmapMetadata metadata, string query)
|
||||
{
|
||||
foreach (string relativeQuery in metadata)
|
||||
{
|
||||
string absolutePath = query + relativeQuery;
|
||||
|
||||
object metadataQueryReader = null;
|
||||
|
||||
try
|
||||
{
|
||||
metadataQueryReader = metadata.GetQuerySafe(relativeQuery);
|
||||
listOfAllMetadata.Add((absolutePath, metadataQueryReader));
|
||||
}
|
||||
#pragma warning disable CA1031 // Do not catch general exception types
|
||||
catch (Exception ex)
|
||||
#pragma warning restore CA1031 // Do not catch general exception types
|
||||
{
|
||||
listOfAllMetadata.Add((absolutePath, $"######## INVALID METADATA: {ex.Message}"));
|
||||
Debug.WriteLine(ex);
|
||||
}
|
||||
|
||||
if (metadataQueryReader is BitmapMetadata innerMetadata)
|
||||
{
|
||||
GetMetadataRecursively(innerMetadata, absolutePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
|
@ -83,11 +84,36 @@ namespace ImageResizer.Models
|
|||
try
|
||||
{
|
||||
// Detect whether metadata can copied successfully
|
||||
_ = metadata.Clone();
|
||||
var modifiableMetadata = metadata.Clone();
|
||||
|
||||
#if DEBUG
|
||||
Debug.WriteLine($"### Processing metadata of file {_file}");
|
||||
modifiableMetadata.PrintsAllMetadataToDebugOutput();
|
||||
#endif
|
||||
|
||||
// read all metadata and build up metadata object from the scratch. Discard invalid (unreadable/unwritable) metadata.
|
||||
var newMetadata = new BitmapMetadata(metadata.Format);
|
||||
var listOfMetadata = modifiableMetadata.GetListOfMetadata();
|
||||
foreach (var (metadataPath, value) in listOfMetadata)
|
||||
{
|
||||
if (value is BitmapMetadata bitmapMetadata)
|
||||
{
|
||||
var innerMetadata = new BitmapMetadata(bitmapMetadata.Format);
|
||||
newMetadata.SetQuerySafe(metadataPath, innerMetadata);
|
||||
}
|
||||
else
|
||||
{
|
||||
newMetadata.SetQuerySafe(metadataPath, value);
|
||||
}
|
||||
}
|
||||
|
||||
metadata = newMetadata;
|
||||
}
|
||||
catch (ArgumentException)
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
metadata = null;
|
||||
|
||||
Debug.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,9 +131,9 @@ namespace ImageResizer.Models
|
|||
encoder.Frames.Add(
|
||||
BitmapFrame.Create(
|
||||
Transform(originalFrame),
|
||||
thumbnail: null,
|
||||
originalFrame.Thumbnail,
|
||||
metadata,
|
||||
colorContexts: null));
|
||||
originalFrame.ColorContexts));
|
||||
}
|
||||
|
||||
path = GetDestinationPath(encoder);
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Community.UnitConverter\</OutputPath>
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\UnitConverter\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -30,7 +30,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Community.UnitConverter\</OutputPath>
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\UnitConverter\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.Plugin.Folder\</OutputPath>
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Folder\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -30,7 +30,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Microsoft.Plugin.Folder\</OutputPath>
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Folder\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.Plugin.Indexer\</OutputPath>
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Indexer\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -30,7 +30,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Microsoft.Plugin.Indexer\</OutputPath>
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Indexer\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.Plugin.Program\</OutputPath>
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Program\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -31,7 +31,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Microsoft.Plugin.Program\</OutputPath>
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Program\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.Plugin.Shell\</OutputPath>
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Shell\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -29,7 +29,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Microsoft.Plugin.Shell\</OutputPath>
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Shell\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
|
|
|
@ -11,62 +11,85 @@ namespace Microsoft.Plugin.Uri.UnitTests.UriHelper
|
|||
public class ExtendedUriParserTests
|
||||
{
|
||||
[DataTestMethod]
|
||||
[DataRow("google.com", true, "https://google.com/")]
|
||||
[DataRow("http://google.com", true, "http://google.com/")]
|
||||
[DataRow("localhost", true, "https://localhost/")]
|
||||
[DataRow("http://localhost", true, "http://localhost/")]
|
||||
[DataRow("127.0.0.1", true, "https://127.0.0.1/")]
|
||||
[DataRow("http://127.0.0.1", true, "http://127.0.0.1/")]
|
||||
[DataRow("http://127.0.0.1:80", true, "http://127.0.0.1/")]
|
||||
[DataRow("127", false, null)]
|
||||
[DataRow("", false, null)]
|
||||
[DataRow("https://google.com", true, "https://google.com/")]
|
||||
[DataRow("ftps://google.com", true, "ftps://google.com/")]
|
||||
[DataRow(null, false, null)]
|
||||
[DataRow("bing.com/search?q=gmx", true, "https://bing.com/search?q=gmx")]
|
||||
[DataRow("http://bing.com/search?q=gmx", true, "http://bing.com/search?q=gmx")]
|
||||
[DataRow("h", true, "https://h/")]
|
||||
[DataRow("http://h", true, "http://h/")]
|
||||
[DataRow("ht", true, "https://ht/")]
|
||||
[DataRow("http://ht", true, "http://ht/")]
|
||||
[DataRow("htt", true, "https://htt/")]
|
||||
[DataRow("http://htt", true, "http://htt/")]
|
||||
[DataRow("http", true, "https://http/")]
|
||||
[DataRow("http://http", true, "http://http/")]
|
||||
[DataRow("http:", false, null)]
|
||||
[DataRow("http:/", false, null)]
|
||||
[DataRow("http://", false, null)]
|
||||
[DataRow("http://t", true, "http://t/")]
|
||||
[DataRow("http://te", true, "http://te/")]
|
||||
[DataRow("http://tes", true, "http://tes/")]
|
||||
[DataRow("http://test", true, "http://test/")]
|
||||
[DataRow("http://test.", false, null)]
|
||||
[DataRow("http://test.c", true, "http://test.c/")]
|
||||
[DataRow("http://test.co", true, "http://test.co/")]
|
||||
[DataRow("http://test.com", true, "http://test.com/")]
|
||||
[DataRow("http:3", true, "https://http:3/")]
|
||||
[DataRow("http://http:3", true, "http://http:3/")]
|
||||
[DataRow("[::]", true, "https://[::]/")]
|
||||
[DataRow("http://[::]", true, "http://[::]/")]
|
||||
[DataRow("[2001:0DB8::1]", true, "https://[2001:db8::1]/")]
|
||||
[DataRow("http://[2001:0DB8::1]", true, "http://[2001:db8::1]/")]
|
||||
[DataRow("[2001:0DB8::1]:80", true, "https://[2001:db8::1]/")]
|
||||
[DataRow("http://[2001:0DB8::1]:80", true, "http://[2001:db8::1]/")]
|
||||
[DataRow("mailto:example@mail.com", true, "mailto:example@mail.com")]
|
||||
[DataRow("tel:411", true, "tel:411")]
|
||||
[DataRow("ftp://example.com", true, "ftp://example.com/")]
|
||||
[DataRow("example.com:443", true, "example.com:443")]
|
||||
[DataRow("google.com", true, "https://google.com/", true)]
|
||||
[DataRow("http://google.com", true, "http://google.com/", true)]
|
||||
[DataRow("localhost", true, "https://localhost/", true)]
|
||||
[DataRow("http://localhost", true, "http://localhost/", true)]
|
||||
[DataRow("127.0.0.1", true, "https://127.0.0.1/", true)]
|
||||
[DataRow("http://127.0.0.1", true, "http://127.0.0.1/", true)]
|
||||
[DataRow("http://127.0.0.1:80", true, "http://127.0.0.1/", true)]
|
||||
[DataRow("127", false, null, false)]
|
||||
[DataRow("", false, null, false)]
|
||||
[DataRow("https://google.com", true, "https://google.com/", true)]
|
||||
[DataRow("ftps://google.com", true, "ftps://google.com/", false)]
|
||||
[DataRow(null, false, null, false)]
|
||||
[DataRow("bing.com/search?q=gmx", true, "https://bing.com/search?q=gmx", true)]
|
||||
[DataRow("http://bing.com/search?q=gmx", true, "http://bing.com/search?q=gmx", true)]
|
||||
[DataRow("h", true, "https://h/", true)]
|
||||
[DataRow("http://h", true, "http://h/", true)]
|
||||
[DataRow("ht", true, "https://ht/", true)]
|
||||
[DataRow("http://ht", true, "http://ht/", true)]
|
||||
[DataRow("htt", true, "https://htt/", true)]
|
||||
[DataRow("http://htt", true, "http://htt/", true)]
|
||||
[DataRow("http", true, "https://http/", true)]
|
||||
[DataRow("http://http", true, "http://http/", true)]
|
||||
[DataRow("http:", false, null, false)]
|
||||
[DataRow("http:/", false, null, false)]
|
||||
[DataRow("http://", false, null, false)]
|
||||
[DataRow("http://t", true, "http://t/", true)]
|
||||
[DataRow("http://te", true, "http://te/", true)]
|
||||
[DataRow("http://tes", true, "http://tes/", true)]
|
||||
[DataRow("http://test", true, "http://test/", true)]
|
||||
[DataRow("http://test.", false, null, false)]
|
||||
[DataRow("http://test.c", true, "http://test.c/", true)]
|
||||
[DataRow("http://test.co", true, "http://test.co/", true)]
|
||||
[DataRow("http://test.com", true, "http://test.com/", true)]
|
||||
[DataRow("http:3", true, "https://http:3/", true)]
|
||||
[DataRow("http://http:3", true, "http://http:3/", true)]
|
||||
[DataRow("[::]", true, "https://[::]/", true)]
|
||||
[DataRow("http://[::]", true, "http://[::]/", true)]
|
||||
[DataRow("[2001:0DB8::1]", true, "https://[2001:db8::1]/", true)]
|
||||
[DataRow("http://[2001:0DB8::1]", true, "http://[2001:db8::1]/", true)]
|
||||
[DataRow("[2001:0DB8::1]:80", true, "https://[2001:db8::1]/", true)]
|
||||
[DataRow("http://[2001:0DB8::1]:80", true, "http://[2001:db8::1]/", true)]
|
||||
[DataRow("mailto:example@mail.com", true, "mailto:example@mail.com", false)]
|
||||
[DataRow("tel:411", true, "tel:411", false)]
|
||||
[DataRow("ftp://example.com", true, "ftp://example.com/", false)]
|
||||
|
||||
public void TryParseCanParseHostName(string query, bool expectedSuccess, string expectedResult)
|
||||
// This has been parsed as an application URI. Linked issue: #14260
|
||||
[DataRow("example.com:443", true, "example.com:443", false)]
|
||||
[DataRow("mailto:", true, "mailto:", false)]
|
||||
[DataRow("mailto:/", false, null, false)]
|
||||
[DataRow("ms-settings:", true, "ms-settings:", false)]
|
||||
[DataRow("ms-settings:/", false, null, false)]
|
||||
[DataRow("ms-settings://", false, null, false)]
|
||||
[DataRow("ms-settings://privacy", true, "ms-settings://privacy/", false)]
|
||||
[DataRow("ms-settings://privacy/", true, "ms-settings://privacy/", false)]
|
||||
[DataRow("ms-settings:privacy", true, "ms-settings:privacy", false)]
|
||||
[DataRow("ms-settings:powersleep", true, "ms-settings:powersleep", false)]
|
||||
[DataRow("microsoft-edge:http://google.com", true, "microsoft-edge:http://google.com", false)]
|
||||
[DataRow("microsoft-edge:https://google.com", true, "microsoft-edge:https://google.com", false)]
|
||||
[DataRow("microsoft-edge:google.com", true, "microsoft-edge:google.com", false)]
|
||||
[DataRow("microsoft-edge:google.com/", true, "microsoft-edge:google.com/", false)]
|
||||
[DataRow("microsoft-edge:https://google.com/", true, "microsoft-edge:https://google.com/", false)]
|
||||
[DataRow("ftp://user:password@localhost:8080", true, "ftp://user:password@localhost:8080/", false)]
|
||||
[DataRow("ftp://user:password@localhost:8080/", true, "ftp://user:password@localhost:8080/", false)]
|
||||
[DataRow("ftp://user:password@google.com", true, "ftp://user:password@google.com/", false)]
|
||||
[DataRow("ftp://user:password@google.com:2121", true, "ftp://user:password@google.com:2121/", false)]
|
||||
[DataRow("ftp://user:password@1.1.1.1", true, "ftp://user:password@1.1.1.1/", false)]
|
||||
[DataRow("ftp://user:password@1.1.1.1:2121", true, "ftp://user:password@1.1.1.1:2121/", false)]
|
||||
|
||||
public void TryParseCanParseHostName(string query, bool expectedSuccess, string expectedResult, bool expectedIsWebUri)
|
||||
{
|
||||
// Arrange
|
||||
var parser = new ExtendedUriParser();
|
||||
|
||||
// Act
|
||||
var success = parser.TryParse(query, out var result);
|
||||
var success = parser.TryParse(query, out var result, out var isWebUriResult);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(expectedResult, result?.ToString());
|
||||
Assert.AreEqual(expectedIsWebUri, isWebUriResult);
|
||||
Assert.AreEqual(expectedSuccess, success);
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.8 KiB |
|
@ -6,6 +6,6 @@ namespace Microsoft.Plugin.Uri.Interfaces
|
|||
{
|
||||
public interface IUriParser
|
||||
{
|
||||
bool TryParse(string input, out System.Uri result);
|
||||
bool TryParse(string input, out System.Uri result, out bool isWebUri);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,17 +63,15 @@ namespace Microsoft.Plugin.Uri
|
|||
{
|
||||
results.Add(new Result
|
||||
{
|
||||
Title = Properties.Resources.Microsoft_plugin_uri_default_browser,
|
||||
Title = Properties.Resources.Microsoft_plugin_uri_open,
|
||||
SubTitle = BrowserPath,
|
||||
IcoPath = _uriSettings.ShowBrowserIcon
|
||||
? BrowserIconPath
|
||||
: DefaultIconPath,
|
||||
IcoPath = DefaultIconPath,
|
||||
Action = action =>
|
||||
{
|
||||
if (!Helper.OpenInShell(BrowserPath))
|
||||
{
|
||||
var title = $"Plugin: {Properties.Resources.Microsoft_plugin_uri_plugin_name}";
|
||||
var message = $"{Properties.Resources.Microsoft_plugin_default_browser_open_failed}: ";
|
||||
var message = $"{Properties.Resources.Microsoft_plugin_uri_open_failed}: ";
|
||||
Context.API.ShowMsg(title, message);
|
||||
return false;
|
||||
}
|
||||
|
@ -85,16 +83,19 @@ namespace Microsoft.Plugin.Uri
|
|||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(query?.Search)
|
||||
&& _uriParser.TryParse(query.Search, out var uriResult)
|
||||
&& _uriParser.TryParse(query.Search, out var uriResult, out var isWebUri)
|
||||
&& _uriResolver.IsValidHost(uriResult))
|
||||
{
|
||||
var uriResultString = uriResult.ToString();
|
||||
var isWebUriBool = isWebUri;
|
||||
|
||||
results.Add(new Result
|
||||
{
|
||||
Title = uriResultString,
|
||||
SubTitle = Properties.Resources.Microsoft_plugin_uri_website,
|
||||
IcoPath = _uriSettings.ShowBrowserIcon
|
||||
SubTitle = isWebUriBool
|
||||
? Properties.Resources.Microsoft_plugin_uri_website
|
||||
: Properties.Resources.Microsoft_plugin_uri_open,
|
||||
IcoPath = isWebUriBool
|
||||
? BrowserIconPath
|
||||
: DefaultIconPath,
|
||||
Action = action =>
|
||||
|
@ -118,7 +119,7 @@ namespace Microsoft.Plugin.Uri
|
|||
private static bool IsActivationKeyword(Query query)
|
||||
{
|
||||
return !string.IsNullOrEmpty(query?.ActionKeyword)
|
||||
&& query?.ActionKeyword == query?.RawQuery;
|
||||
&& query?.ActionKeyword == query?.RawQuery;
|
||||
}
|
||||
|
||||
private bool IsDefaultBrowserSet()
|
||||
|
@ -155,16 +156,23 @@ namespace Microsoft.Plugin.Uri
|
|||
UpdateBrowserIconPath(newTheme);
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alive but will log the exception")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage(
|
||||
"Design",
|
||||
"CA1031:Do not catch general exception types",
|
||||
Justification = "We want to keep the process alive but will log the exception")]
|
||||
private void UpdateBrowserIconPath(Theme newTheme)
|
||||
{
|
||||
try
|
||||
{
|
||||
var progId = _registryWrapper.GetRegistryValue("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice", "ProgId");
|
||||
var progId = _registryWrapper.GetRegistryValue(
|
||||
"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
|
||||
"ProgId");
|
||||
var programLocation =
|
||||
|
||||
// Resolve App Icon (UWP)
|
||||
_registryWrapper.GetRegistryValue("HKEY_CLASSES_ROOT\\" + progId + "\\Application", "ApplicationIcon")
|
||||
_registryWrapper.GetRegistryValue(
|
||||
"HKEY_CLASSES_ROOT\\" + progId + "\\Application",
|
||||
"ApplicationIcon")
|
||||
|
||||
// Resolves default file association icon (UWP + Normal)
|
||||
?? _registryWrapper.GetRegistryValue("HKEY_CLASSES_ROOT\\" + progId + "\\DefaultIcon", null);
|
||||
|
@ -174,14 +182,21 @@ namespace Microsoft.Plugin.Uri
|
|||
if (programLocation.StartsWith("@", StringComparison.Ordinal))
|
||||
{
|
||||
var directProgramLocationStringBuilder = new StringBuilder(128);
|
||||
if (NativeMethods.SHLoadIndirectString(programLocation, directProgramLocationStringBuilder, (uint)directProgramLocationStringBuilder.Capacity, IntPtr.Zero) ==
|
||||
if (NativeMethods.SHLoadIndirectString(
|
||||
programLocation,
|
||||
directProgramLocationStringBuilder,
|
||||
(uint)directProgramLocationStringBuilder.Capacity,
|
||||
IntPtr.Zero) ==
|
||||
NativeMethods.Hresult.Ok)
|
||||
{
|
||||
// Check if there's a postfix with contract-white/contrast-black icon is available and use that instead
|
||||
var directProgramLocation = directProgramLocationStringBuilder.ToString();
|
||||
var themeIcon = newTheme == Theme.Light || newTheme == Theme.HighContrastWhite ? "contrast-white" : "contrast-black";
|
||||
var themeIcon = newTheme == Theme.Light || newTheme == Theme.HighContrastWhite
|
||||
? "contrast-white"
|
||||
: "contrast-black";
|
||||
var extension = Path.GetExtension(directProgramLocation);
|
||||
var themedProgLocation = $"{directProgramLocation.Substring(0, directProgramLocation.Length - extension.Length)}_{themeIcon}{extension}";
|
||||
var themedProgLocation =
|
||||
$"{directProgramLocation.Substring(0, directProgramLocation.Length - extension.Length)}_{themeIcon}{extension}";
|
||||
BrowserIconPath = File.Exists(themedProgLocation)
|
||||
? themedProgLocation
|
||||
: directProgramLocation;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.Plugin.Uri\</OutputPath>
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Uri\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -30,7 +30,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Microsoft.Plugin.Uri\</OutputPath>
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Uri\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace Microsoft.Plugin.Uri.Properties {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Open Default Browser.
|
||||
/// Looks up a localized string similar to Open default browser.
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_uri_default_browser {
|
||||
get {
|
||||
|
@ -79,7 +79,16 @@ namespace Microsoft.Plugin.Uri.Properties {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Failed to open URL.
|
||||
/// Looks up a localized string similar to Open URI.
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_uri_open {
|
||||
get {
|
||||
return ResourceManager.GetString("Microsoft_plugin_uri_open", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Failed to open URI.
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_uri_open_failed {
|
||||
get {
|
||||
|
|
|
@ -123,8 +123,11 @@
|
|||
<data name="Microsoft_plugin_uri_default_browser" xml:space="preserve">
|
||||
<value>Open default browser</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_uri_open" xml:space="preserve">
|
||||
<value>Open URI</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_uri_open_failed" xml:space="preserve">
|
||||
<value>Failed to open URL</value>
|
||||
<value>Failed to open URI</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_uri_plugin_description" xml:space="preserve">
|
||||
<value>Opens URLs and UNC network shares.</value>
|
||||
|
@ -135,4 +138,4 @@
|
|||
<data name="Microsoft_plugin_uri_website" xml:space="preserve">
|
||||
<value>Open in default browser</value>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
|
@ -10,22 +10,37 @@ namespace Microsoft.Plugin.Uri.UriHelper
|
|||
{
|
||||
public class ExtendedUriParser : IUriParser
|
||||
{
|
||||
public bool TryParse(string input, out System.Uri result)
|
||||
public bool TryParse(string input, out System.Uri result, out bool isWebUri)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
result = default;
|
||||
isWebUri = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handling URL with only scheme, typically mailto or application uri.
|
||||
// Do nothing, return the result without urlBuilder
|
||||
if (input.EndsWith(":", StringComparison.OrdinalIgnoreCase)
|
||||
&& !input.StartsWith("http", StringComparison.OrdinalIgnoreCase)
|
||||
&& !input.Contains("/", StringComparison.OrdinalIgnoreCase)
|
||||
&& !input.All(char.IsDigit))
|
||||
{
|
||||
result = new System.Uri(input);
|
||||
isWebUri = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle common cases UriBuilder does not handle
|
||||
// Using CurrentCulture since this is a user typed string
|
||||
if (input.EndsWith(":", StringComparison.CurrentCulture)
|
||||
|| input.EndsWith(".", StringComparison.CurrentCulture)
|
||||
|| input.EndsWith(":/", StringComparison.CurrentCulture)
|
||||
|| input.EndsWith("://", StringComparison.CurrentCulture)
|
||||
|| input.All(char.IsDigit))
|
||||
{
|
||||
result = default;
|
||||
isWebUri = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -35,27 +50,31 @@ namespace Microsoft.Plugin.Uri.UriHelper
|
|||
var hadDefaultPort = urlBuilder.Uri.IsDefaultPort;
|
||||
urlBuilder.Port = hadDefaultPort ? -1 : urlBuilder.Port;
|
||||
|
||||
if (input.Contains("HTTP://", StringComparison.OrdinalIgnoreCase))
|
||||
if (input.StartsWith("HTTP://", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
urlBuilder.Scheme = System.Uri.UriSchemeHttp;
|
||||
isWebUri = true;
|
||||
}
|
||||
else if (input.Contains(":", StringComparison.OrdinalIgnoreCase) &&
|
||||
!input.Contains("http", StringComparison.OrdinalIgnoreCase) &&
|
||||
!input.StartsWith("http", StringComparison.OrdinalIgnoreCase) &&
|
||||
!input.Contains("[", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Do nothing, leave unchanged
|
||||
isWebUri = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
urlBuilder.Scheme = System.Uri.UriSchemeHttps;
|
||||
isWebUri = true;
|
||||
}
|
||||
|
||||
result = urlBuilder.Uri;
|
||||
return true;
|
||||
}
|
||||
catch (System.UriFormatException)
|
||||
catch (UriFormatException)
|
||||
{
|
||||
result = default;
|
||||
isWebUri = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\</OutputPath>
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\WindowWalker\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -29,7 +29,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\</OutputPath>
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\WindowWalker\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\</OutputPath>
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Registry\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -27,7 +27,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\</OutputPath>
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Registry\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\</OutputPath>
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\WindowsSettings\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<Optimize>false</Optimize>
|
||||
<DebugType>full</DebugType>
|
||||
|
@ -31,7 +31,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\</OutputPath>
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\WindowsSettings\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
|
|
|
@ -134,6 +134,7 @@ bool AppWindow::OnCreate(HWND, LPCREATESTRUCT) noexcept
|
|||
try
|
||||
{
|
||||
PopulateExplorerItems();
|
||||
UpdateCounts();
|
||||
SetHandlers();
|
||||
ReadSettings();
|
||||
}
|
||||
|
@ -246,11 +247,6 @@ void AppWindow::PopulateExplorerItems()
|
|||
m_prManager->GetVisibleItemCount(&count);
|
||||
Logger::debug(L"Number of visible items: {}", count);
|
||||
|
||||
UINT currDepth = 0;
|
||||
std::stack<UINT> parents{};
|
||||
UINT prevId = 0;
|
||||
parents.push(0);
|
||||
|
||||
for (UINT i = 0; i < count; ++i)
|
||||
{
|
||||
CComPtr<IPowerRenameItem> renameItem;
|
||||
|
@ -274,23 +270,8 @@ void AppWindow::PopulateExplorerItems()
|
|||
bool isSubFolderContent = false;
|
||||
winrt::check_hresult(renameItem->GetIsFolder(&isFolder));
|
||||
|
||||
if (depth > currDepth)
|
||||
{
|
||||
parents.push(prevId);
|
||||
currDepth = depth;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (currDepth > depth)
|
||||
{
|
||||
parents.pop();
|
||||
currDepth--;
|
||||
}
|
||||
currDepth = depth;
|
||||
}
|
||||
m_mainUserControl.AddExplorerItem(
|
||||
id, originalName, newName == nullptr ? hstring{} : hstring{ newName }, isFolder ? 0 : 1, parents.top(), selected);
|
||||
prevId = id;
|
||||
id, originalName, newName == nullptr ? hstring{} : hstring{ newName }, isFolder ? 0 : 1, depth, selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -638,6 +619,7 @@ void AppWindow::SwitchView()
|
|||
|
||||
m_prManager->SwitchFilter(0);
|
||||
PopulateExplorerItems();
|
||||
UpdateCounts();
|
||||
}
|
||||
|
||||
void AppWindow::Rename(bool closeWindow)
|
||||
|
@ -851,11 +833,12 @@ void AppWindow::UpdateCounts()
|
|||
m_selectedCount = selectedCount;
|
||||
m_renamingCount = renamingCount;
|
||||
|
||||
// Update counts UI elements if/when added
|
||||
|
||||
// Update Rename button state
|
||||
m_mainUserControl.UIUpdatesItem().ButtonRenameEnabled(renamingCount > 0);
|
||||
}
|
||||
|
||||
m_mainUserControl.UIUpdatesItem().OriginalCount(std::to_wstring(m_mainUserControl.ExplorerItems().Size()));
|
||||
m_mainUserControl.UIUpdatesItem().RenamedCount(std::to_wstring(m_renamingCount));
|
||||
}
|
||||
|
||||
HRESULT AppWindow::OnItemAdded(_In_ IPowerRenameItem* renameItem)
|
||||
|
@ -878,7 +861,6 @@ HRESULT AppWindow::OnUpdate(_In_ IPowerRenameItem* renameItem)
|
|||
}
|
||||
}
|
||||
|
||||
UpdateCounts();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -935,6 +917,7 @@ HRESULT AppWindow::OnRegExCompleted(_In_ DWORD threadId)
|
|||
}
|
||||
}
|
||||
|
||||
UpdateCounts();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//Microsoft Visual C++ generated resource script.
|
||||
⼀⼀ഀ<EFBFBD>
|
||||
⌀椀渀挀氀甀搀攀 ∀爀攀猀漀甀爀挀攀⸀栀∀ഀ<EFBFBD>
|
||||
|