Compare commits

..

5 commits

Author SHA1 Message Date
Andrey Nekrasov f51ee065c2
[VCM] Activate the module (#13662) 2021-10-12 19:05:08 +03:00
Seraphima Zykova afdefa2428 [FancyZones] Reset layouts after screen locking fix (#13703) 2021-10-11 11:43:11 +01:00
Seraphima Zykova 45d2752dbb [FancyZones] Change layout using a shortcut (#13616) 2021-10-11 11:42:59 +01:00
Jaime Bernardo 52c9f35369 [PT Run] Add setting to use centralized keyboard hook (#13557)
* [PT Run] Add setting to use centralized hook

* Add UI separator
2021-10-11 11:39:46 +01:00
Jaime Bernardo 03e5e77171 [Shortcut Guide] Suppress Windows Menu appearing (#13553)
* Get the new settings values

* Suppress windows menu appearing

* Send new settings telemetry

* Address PR comments
2021-10-11 11:39:30 +01:00
510 changed files with 15643 additions and 20705 deletions

View file

@ -39,7 +39,6 @@ body:
- Image Resizer
- Keyboard Manager
- MD Preview
- Mouse Utilities
- PDF Preview
- PDF Thumbnail
- PowerRename
@ -48,7 +47,6 @@ body:
- SVG Preview
- SVG Thumbnail
- Settings
- Video Conference Mute
- Welcome / PowerToys Tour window
- System tray interaction
- Installer

View file

@ -1,5 +1,8 @@
blank_issues_enabled: false
blank_issues_enabled: true
contact_links:
- name: "\U0001F4F7 Video Conference Mute Issue"
url: https://github.com/microsoft/PowerToys/issues/6246
about: Report Bug for the Video Conference Mute utility
- name: "\U0001F6A8 Microsoft Security Response Center (MSRC)"
url: https://msrc.microsoft.com/create-report
about: Report security bugs
@ -7,6 +10,6 @@ contact_links:
url: https://github.com/microsoft/PowerToys/wiki
about: Documentation for users of PowerToys utilities
- name: "\U0001F4DA PowerToys dev documentation"
url: https://github.com/microsoft/PowerToys/tree/main/doc/devdocs
url: https://github.com/microsoft/PowerToys/tree/master/doc/devdocs
about: Documentation for people interested in developing and contributing for PowerToys

View file

@ -5,9 +5,7 @@ abcdef
abcdefgh
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abgr
abi
ABlocked
ABOUTBOX
Abug
accctrl
Acceleratorkeys
@ -130,7 +128,6 @@ AUTOSIZECOLUMNS
AUTOUPDATE
available
AValid
awakeness
awakeversion
AWAYMODE
AYUV
@ -186,7 +183,6 @@ Browsable
bsd
bstr
bti
btn
BTNFACE
Bto
buf
@ -206,7 +202,6 @@ CANRENAME
Captureascreenshot
CAPTURECHANGED
CASESENSITIVE
cassert
CAtl
CCDDEE
ccf
@ -385,7 +380,6 @@ CXVIRTUALSCREEN
cxx
cxxopts
CYSMICON
CYVIRTUALSCREEN
cziplib
Dac
dacl
@ -435,7 +429,6 @@ Delimarsky
delims
dend
DENORMAL
Deondre
depersist
deprioritized
deps
@ -497,8 +490,6 @@ DPICHANGED
DPolicy
DPopup
DPSAPI
DQTAT
DQTYPE
DRAWFRAME
drawingcolor
dreamsofameaningfullife
@ -578,7 +569,6 @@ errc
errorlevel
ERRORMESSAGE
ERRORTITLE
ESettings
esize
estdir
etcore
@ -631,7 +621,6 @@ Farbraum
FARPROC
fdw
feimage
FFAA
ffcd
FFDDDDDD
fff
@ -677,7 +666,6 @@ FRAMEDOWNLOAD
franky
Froml
fstream
ftp
ftps
FTYPE
FULLNAME
@ -699,7 +687,6 @@ gdi
gdiplus
GDISCALED
generatesqlfromuserquery
GETDESKWALLPAPER
GETDISPINFO
GETDLGCODE
GETDPISCALEDSIZE
@ -734,7 +721,6 @@ Hardlines
HARDWAREINPUT
hashcode
Hashset
Hashtable
HASHVAL
hbitmap
hbmp
@ -763,10 +749,8 @@ hglobal
hhk
HHmmss
HHOOK
hhx
HICON
HIDEWINDOW
highlighter
HIMAGELIST
himl
hinst
@ -790,7 +774,6 @@ hmonitor
HOLDENTER
HOLDESC
homljgmgpmcbpjbnjpfijnhipfkiclkd
homepage
HOOKPROC
hostname
hotkeycontrol
@ -800,7 +783,6 @@ hotspot
HPAINTBUFFER
hpj
hpp
HRAWINPUT
hread
HREDRAW
href
@ -820,7 +802,6 @@ Htmdid
html
htt
http
HTTRANSPARENT
hwb
HWINEVENTHOOK
hwnd
@ -854,7 +835,6 @@ ICollection
IColor
ICommand
IComparer
ICompositor
ICONERROR
ICONINFORMATION
IContext
@ -869,7 +849,6 @@ IDesktop
IDictionary
IDirectory
IDispatch
IDispatcher
IDisposable
idl
IDLIST
@ -884,7 +863,6 @@ IEasing
IEnum
IEnumerable
IEnumerator
IEnvironment
IEquality
IEquatable
IEvent
@ -957,7 +935,6 @@ INPUTHARDWARE
INPUTKEYBOARD
INPUTLANGCHANGED
INPUTMOUSE
INPUTSINK
INPUTTYPE
INSTALLDESKTOPSHORTCUT
INSTALLDIR
@ -1025,7 +1002,6 @@ IShell
ISingle
ISmart
isocpp
iss
IStorage
IStream
istreambuf
@ -1036,7 +1012,6 @@ ITab
ITask
ITemplate
ITEMSTATEICONCLICK
ITerminal
ITest
ith
IThrottled
@ -1056,7 +1031,6 @@ IWeb
IWIC
IWindows
IWork
IXaml
IXml
ixx
IYUV
@ -1089,7 +1063,6 @@ KBDLLHOOKSTRUCT
kbm
KERNELBASE
KEYBDINPUT
keybindings
keyboardeventhandlers
keyboardmanager
keyboardmanagercommon
@ -1166,7 +1139,6 @@ lmcons
LMEM
LMENU
lnk
LOADSTRING
LOCALAPPDATA
LOCALDISPLAY
localhost
@ -1188,7 +1160,6 @@ lowlevel
LOWORD
lparam
LPBYTE
LPCITEMIDLIST
LPCMINVOKECOMMANDINFO
LPCREATESTRUCT
LPCTSTR
@ -1235,7 +1206,6 @@ LVS
LVSIL
LWA
lwin
LZero
lzw
mailto
MAINICON
@ -1349,7 +1319,6 @@ msedge
MSGFLT
mshtmdid
msi
msiexec
MSIFASTINSTALL
MSIHANDLE
MSIINSTALLER
@ -1592,7 +1561,6 @@ phwnd
pici
pid
pidl
PIDLIST
PINDIR
pinfo
pinvoke
@ -1625,7 +1593,6 @@ powerlauncher
powerpreview
powerrename
POWERRENAMETEST
POWERRENAMEUIHOST
powershell
powertoy
powertoysinterop
@ -1665,9 +1632,7 @@ prgms
pri
PRINTCLIENT
printf
pritudev
prm
proactively
PROCESSKEY
PRODUCTVERSION
PROGDLG
@ -1720,7 +1685,6 @@ QUERYOPEN
QUEUESYNC
Quickime
QUICKLAYOUTSWITCH
QUNS
qwertyuiopasdfghjklzxcvbnm
qword
qwrtyuiopsghjklzxvnm
@ -1728,9 +1692,6 @@ Radiobuttons
RAII
RAlt
randyrants
RAWINPUT
RAWINPUTDEVICE
RAWINPUTHEADER
RAWPATH
rbegin
Rbp
@ -1741,7 +1702,6 @@ RBUTTONUP
rclsid
RCONTROL
RCtrl
rdeveen
RDW
readme
READMODE
@ -1815,7 +1775,6 @@ rgs
rhs
ricardosantos
Richtext
RIDEV
RIGHTSCROLLBAR
riid
riverar
@ -1862,7 +1821,6 @@ scancode
scanled
schedtasks
Scn
SCOOBE
SCOPEID
screenshot
scrollable
@ -2040,7 +1998,6 @@ stdlib
STDMETHODCALLTYPE
STDMETHODIMP
stdout
stefan
STEPIT
stgm
STGMEDIUM
@ -2086,7 +2043,6 @@ Switchbetweenvirtualdesktops
SWP
swprintf
SWRESTORE
swscanf
SYMED
SYMOPT
SYNCMFT
@ -2196,9 +2152,7 @@ tsx
TYMED
typedef
TYPEKEY
TYPEKEYBOARD
TYPELIB
TYPEMOUSE
typename
typeof
typeparam
@ -2338,7 +2292,7 @@ VTABLE
Vtbl
wav
WBounds
wca
Wca
wcautil
WCE
wcex
@ -2443,7 +2397,6 @@ workaround
Workflow
workspaces
wostream
wostringstream
wox
wparam
wpf
@ -2502,7 +2455,6 @@ XSmall
XStr
XToolset
xunit
XVIRTUALSCREEN
Yaml
YDiff
YIncrement
@ -2513,7 +2465,6 @@ YStr
YUY
yuyoyuppe
YUYV
YVIRTUALSCREEN
YVU
YVYU
ZEROINIT

View file

@ -16,8 +16,8 @@
- [ ] **Docs:** Added/ updated
- [ ] **Binaries:** Any new files are added to WXS / YML
- [ ] No new binaries
- [ ] [YML for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/pipeline.user.windows.yml#L68) for new binaries
- [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries
- [ ] [YML for signing](https://github.com/microsoft/PowerToys/blob/master/.pipelines/pipeline.user.windows.yml#L68) for new binaries
- [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/master/installer/PowerToysSetup/Product.wxs) for new binaries
## Contributor License Agreement (CLA)
A CLA must be signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/PowerToys) and sign the CLA.

View file

@ -2,7 +2,7 @@ trigger:
batch: true
branches:
include:
- main
- master
- stable
paths:
exclude:
@ -13,7 +13,7 @@ trigger:
pr:
branches:
include:
- main
- master
- stable
# 0.0.yyMM.dd##

View file

@ -138,8 +138,7 @@ steps:
**\Microsoft.PowerToys.Run.Plugin.Calculator.UnitTest.dll
**\Microsoft.Plugin.Uri.UnitTests.dll
**\Wox.Test.dll
**\Microsoft.PowerToys.Run.Plugin.System.UnitTests.dll
**\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.UnitTests.dll
**\Microsoft.PowerToys.Run.Plugin.System.UnitTests.dll
!**\obj\**
# Native dlls

View file

@ -66,8 +66,6 @@ build:
to: 'Build_Output'
include:
- 'modules\VideoConference\VideoConferenceProxyFilter_x86.dll'
signing_options:
sign_inline: true # This does signing as soon as this command completes
- from: 'x64/Release'
to: 'Build_Output'
include:
@ -138,29 +136,27 @@ 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\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\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\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'
- 'modules\launcher\Plugins\WindowsTerminal\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.dll'
- 'modules\launcher\Plugins\WindowsTerminal\ManagedTelemetry.dll'
- 'modules\launcher\PowerLauncher.dll'
- 'modules\launcher\PowerLauncher.exe'
- 'modules\launcher\PowerLauncher.Telemetry.dll'
@ -170,15 +166,12 @@ build:
- 'modules\launcher\Wox.dll'
- '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'
- 'modules\ShortcutGuide\ShortcutGuide\PowerToys.ShortcutGuide.exe'
- 'modules\ShortcutGuide\ShortcutGuideModuleInterface\ShortcutGuideModuleInterface.dll'
- 'modules\VideoConference\VideoConferenceModule.dll'
- 'modules\VideoConference\VideoConferenceProxyFilter_x64.dll'
- 'modules\VideoConference\VideoConferenceProxyFilter_x86.dll'
- 'Settings\ManagedTelemetry.dll'
- 'Settings\Microsoft.PowerToys.Settings.UI.exe'
- 'Settings\Microsoft.PowerToys.Settings.UI.Lib.dll'
@ -255,7 +248,6 @@ static_analysis_options:
exclude:
- 'WiX.*/**/*.dll'
- 'Wix.*/**/*.exe'
- 'Microsoft.Windows.CppWinRT.*/**/*.exe'
moderncop_options:
files_to_scan:
- from: 'src'

View file

@ -1,6 +1,6 @@
# not using this but keeping around in case we need it in the future.
# good use case here could be to set up a new machine, we just point people at it.
# https://github.com/microsoft/PowerToys/tree/main/doc/devdocs#prerequisites-for-compiling-powertoys
# https://github.com/microsoft/PowerToys/tree/master/doc/devdocs#prerequisites-for-compiling-powertoys
# improvements if this script is used to replace the snippet
# Add in a param for passive versus quiet. Could be a IsSettingUpDevComputer true/false flag

View file

@ -72,10 +72,6 @@ PowerToys Awake is a tool to keep your computer awake.
Color Picker is from Martin.
### [@oldnewthing](https://github.com/oldnewthing) - Raymond Chen
Find My Mouse is based on Raymond Chen's SuperSonar.
### Microsoft InVEST team
This amazing team helped PowerToys develop PowerToys Run and Keyboard manager as well as update our Settings to v2. @alekhyareddy28, @arjunbalgovind, @jyuwono @laviusmotileng-ms, @ryanbodrug-microsoft, @saahmedm, @somil55, @traies, @udit3333

View file

@ -49,7 +49,7 @@ Once the team has approved an issue/spec approach to solving, development can pr
## Development
Follow the [development guidelines](https://github.com/microsoft/PowerToys/blob/main/doc/devdocs/readme.md).
Follow the [development guidelines](https://github.com/microsoft/PowerToys/blob/master/doc/devdocs/readme.md).
### Naming of features and functionality

View file

@ -76,7 +76,7 @@
<!-- Global props -->
<PropertyGroup Label="Globals" Condition="'$(OverrideWindowsTargetPlatformVersion)'!='True'">
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<!-- Props that are constant for both Debug and Release configurations -->
@ -84,6 +84,7 @@
<PlatformToolset Condition="'$(OverridePlatformToolset)'!='True'">v142</PlatformToolset>
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>Spectre</SpectreMitigation>
</PropertyGroup>
<!-- Debug/Release props -->

View file

@ -5,6 +5,7 @@ MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "src\runner\runner.vcxproj", "{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}"
ProjectSection(ProjectDependencies) = postProject
{217DF501-135C-4E38-BFC8-99D4821032EA} = {217DF501-135C-4E38-BFC8-99D4821032EA}
{0E072714-D127-460B-AFAD-B4C40B412798} = {0E072714-D127-460B-AFAD-B4C40B412798}
{48804216-2A0E-4168-A6D8-9CD068D14227} = {48804216-2A0E-4168-A6D8-9CD068D14227}
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB} = {6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}
@ -56,18 +57,26 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "powerrename", "powerrename"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameExt", "src\modules\powerrename\dll\PowerRenameExt.vcxproj", "{B25AC7A5-FB9F-4789-B392-D5C85E948670}"
ProjectSection(ProjectDependencies) = postProject
{0E072714-D127-460B-AFAD-B4C40B412798} = {0E072714-D127-460B-AFAD-B4C40B412798}
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameLib", "src\modules\powerrename\lib\PowerRenameLib.vcxproj", "{51920F1F-C28C-4ADF-8660-4238766796C2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameUI", "src\modules\powerrename\ui\PowerRenameUI.vcxproj", "{0E072714-D127-460B-AFAD-B4C40B412798}"
ProjectSection(ProjectDependencies) = postProject
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameTest", "src\modules\powerrename\testapp\PowerRenameTest.vcxproj", "{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}"
ProjectSection(ProjectDependencies) = postProject
{0E072714-D127-460B-AFAD-B4C40B412798} = {0E072714-D127-460B-AFAD-B4C40B412798}
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameUnitTests", "src\modules\powerrename\unittests\PowerRenameLibUnitTests.vcxproj", "{2151F984-E006-4A9F-92EF-C6DDE3DC8413}"
ProjectSection(ProjectDependencies) = postProject
{0E072714-D127-460B-AFAD-B4C40B412798} = {0E072714-D127-460B-AFAD-B4C40B412798}
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
{B25AC7A5-FB9F-4789-B392-D5C85E948670} = {B25AC7A5-FB9F-4789-B392-D5C85E948670}
EndProjectSection
@ -75,6 +84,9 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ModuleTemplateCompileTest", "tools\project_template\ModuleTemplate\ModuleTemplateCompileTest.vcxproj", "{64A80062-4D8B-4229-8A38-DFA1D7497749}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameUWPUI", "src\modules\powerrename\UWPui\PowerRenameUWPUI.vcxproj", "{0485F45C-EA7A-4BB5-804B-3E8D14699387}"
ProjectSection(ProjectDependencies) = postProject
{0E072714-D127-460B-AFAD-B4C40B412798} = {0E072714-D127-460B-AFAD-B4C40B412798}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManager", "src\modules\keyboardmanager\dll\KeyboardManager.vcxproj", "{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}"
EndProject
@ -141,7 +153,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerLauncher", "src\module
{5043CECE-E6A7-4867-9CBE-02D27D83747A} = {5043CECE-E6A7-4867-9CBE-02D27D83747A}
{F8B870EB-D5F5-45BA-9CF7-A5C459818820} = {F8B870EB-D5F5-45BA-9CF7-A5C459818820}
{74F1B9ED-F59C-4FE7-B473-7B453E30837E} = {74F1B9ED-F59C-4FE7-B473-7B453E30837E}
{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85} = {A2D583F0-B70C-4462-B1F0-8E81AFB7BA85}
{4BABF3FE-3451-42FD-873F-3C332E18DCEF} = {4BABF3FE-3451-42FD-873F-3C332E18DCEF}
EndProjectSection
EndProject
@ -169,6 +180,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "powerpreview", "src\modules
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF} = {CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "powerpreviewTest", "src\modules\previewpane\powerpreviewTest\powerpreviewTest.vcxproj", "{47310AB4-9034-4BD1-8D8B-E88AD21A171B}"
ProjectSection(ProjectDependencies) = postProject
{217DF501-135C-4E38-BFC8-99D4821032EA} = {217DF501-135C-4E38-BFC8-99D4821032EA}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "settings-ui", "settings-ui", "{C3081D9A-1586-441A-B5F4-ED815B3719C1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerToys.Settings.UI", "src\settings-ui\Microsoft.PowerToys.Settings.UI\Microsoft.PowerToys.Settings.UI.csproj", "{A7D5099E-F0FD-4BF3-8522-5A682759F915}"
@ -177,7 +193,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
src\.editorconfig = src\.editorconfig
src\tests\win-app-driver\packages.config = src\tests\win-app-driver\packages.config
Solution.props = Solution.props
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Settings.UI.Library", "src\settings-ui\Microsoft.PowerToys.Settings.UI.Library\Microsoft.PowerToys.Settings.UI.Library.csproj", "{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}"
@ -262,23 +277,18 @@ 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
src\common\utils\EventWaiter.h = src\common\utils\EventWaiter.h
src\common\utils\exec.h = src\common\utils\exec.h
src\common\utils\game_mode.h = src\common\utils\game_mode.h
src\common\utils\HDropIterator.h = src\common\utils\HDropIterator.h
src\common\utils\HttpClient.h = src\common\utils\HttpClient.h
src\common\utils\json.h = src\common\utils\json.h
src\common\utils\logger_helper.h = src\common\utils\logger_helper.h
src\common\utils\modulesRegistry.h = src\common\utils\modulesRegistry.h
src\common\utils\MsiUtils.h = src\common\utils\MsiUtils.h
src\common\utils\os-detect.h = src\common\utils\os-detect.h
src\common\utils\process_path.h = src\common\utils\process_path.h
src\common\utils\ProcessWaiter.h = src\common\utils\ProcessWaiter.h
src\common\utils\registry.h = src\common\utils\registry.h
src\common\utils\resources.h = src\common\utils\resources.h
src\common\utils\string_utils.h = src\common\utils\string_utils.h
src\common\utils\timeutil.h = src\common\utils\timeutil.h
@ -357,23 +367,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfThumbnailProvider", "src
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-PdfThumbnailProvider", "src\modules\previewpane\UnitTests-PdfThumbnailProvider\UnitTests-PdfThumbnailProvider.csproj", "{F40C3397-1834-4530-B2D9-8F8B8456BCDF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.WindowsTerminal", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsTerminal\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.csproj", "{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.WindowsTerminal.UnitTests", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.UnitTests\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.UnitTests.csproj", "{4ED320BC-BA04-4D42-8D15-CBE62151F08B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameUIHost", "src\modules\powerrename\PowerRenameUIHost\PowerRenameUIHost.vcxproj", "{F7EC4E6C-19CA-4FBD-9918-B8AC5FEF4F63}"
ProjectSection(ProjectDependencies) = postProject
{4642D596-723F-4BFC-894C-46811219AC4A} = {4642D596-723F-4BFC-894C-46811219AC4A}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameUILib", "src\modules\powerrename\PowerRenameUILib\PowerRenameUILib.vcxproj", "{4642D596-723F-4BFC-894C-46811219AC4A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MouseUtils", "MouseUtils", "{322566EF-20DC-43A6-B9F8-616AF942579A}"
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
@ -424,6 +417,12 @@ Global
{51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x64.ActiveCfg = Release|x64
{51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x64.Build.0 = Release|x64
{51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x86.ActiveCfg = Release|x64
{0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x64.ActiveCfg = Debug|x64
{0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x64.Build.0 = Debug|x64
{0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x86.ActiveCfg = Debug|x64
{0E072714-D127-460B-AFAD-B4C40B412798}.Release|x64.ActiveCfg = Release|x64
{0E072714-D127-460B-AFAD-B4C40B412798}.Release|x64.Build.0 = Release|x64
{0E072714-D127-460B-AFAD-B4C40B412798}.Release|x86.ActiveCfg = Release|x64
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x64.ActiveCfg = Debug|x64
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x64.Build.0 = Debug|x64
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x86.ActiveCfg = Debug|x64
@ -598,9 +597,17 @@ Global
{217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x64.ActiveCfg = Release|x64
{217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x64.Build.0 = Release|x64
{217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x86.ActiveCfg = Release|x64
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x64.ActiveCfg = Debug|x64
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x64.Build.0 = Debug|x64
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x86.ActiveCfg = Debug|x64
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x64.ActiveCfg = Release|x64
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x64.Build.0 = Release|x64
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x86.ActiveCfg = Release|x64
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x64.ActiveCfg = Debug|x64
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x64.Build.0 = Debug|x64
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x86.ActiveCfg = Debug|x64
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x86.ActiveCfg = Debug|Win32
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x86.Build.0 = Debug|Win32
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x86.Deploy.0 = Debug|Win32
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x64.ActiveCfg = Release|x64
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x64.Build.0 = Release|x64
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x86.ActiveCfg = Release|Win32
@ -958,43 +965,6 @@ Global
{F40C3397-1834-4530-B2D9-8F8B8456BCDF}.Release|x64.ActiveCfg = Release|x64
{F40C3397-1834-4530-B2D9-8F8B8456BCDF}.Release|x64.Build.0 = Release|x64
{F40C3397-1834-4530-B2D9-8F8B8456BCDF}.Release|x86.ActiveCfg = Release|x64
{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85}.Debug|x64.ActiveCfg = Debug|x64
{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85}.Debug|x64.Build.0 = Debug|x64
{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85}.Debug|x86.ActiveCfg = Debug|x64
{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85}.Release|x64.ActiveCfg = Release|x64
{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85}.Release|x64.Build.0 = Release|x64
{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85}.Release|x86.ActiveCfg = Release|x64
{4ED320BC-BA04-4D42-8D15-CBE62151F08B}.Debug|x64.ActiveCfg = Debug|x64
{4ED320BC-BA04-4D42-8D15-CBE62151F08B}.Debug|x64.Build.0 = Debug|x64
{4ED320BC-BA04-4D42-8D15-CBE62151F08B}.Debug|x86.ActiveCfg = Debug|x64
{4ED320BC-BA04-4D42-8D15-CBE62151F08B}.Release|x64.ActiveCfg = Release|x64
{4ED320BC-BA04-4D42-8D15-CBE62151F08B}.Release|x64.Build.0 = Release|x64
{4ED320BC-BA04-4D42-8D15-CBE62151F08B}.Release|x86.ActiveCfg = Release|Any CPU
{4ED320BC-BA04-4D42-8D15-CBE62151F08B}.Release|x86.Build.0 = Release|Any CPU
{F7EC4E6C-19CA-4FBD-9918-B8AC5FEF4F63}.Debug|x64.ActiveCfg = Debug|x64
{F7EC4E6C-19CA-4FBD-9918-B8AC5FEF4F63}.Debug|x64.Build.0 = Debug|x64
{F7EC4E6C-19CA-4FBD-9918-B8AC5FEF4F63}.Debug|x86.ActiveCfg = Debug|x64
{F7EC4E6C-19CA-4FBD-9918-B8AC5FEF4F63}.Release|x64.ActiveCfg = Release|x64
{F7EC4E6C-19CA-4FBD-9918-B8AC5FEF4F63}.Release|x64.Build.0 = Release|x64
{F7EC4E6C-19CA-4FBD-9918-B8AC5FEF4F63}.Release|x86.ActiveCfg = Release|x64
{4642D596-723F-4BFC-894C-46811219AC4A}.Debug|x64.ActiveCfg = Debug|x64
{4642D596-723F-4BFC-894C-46811219AC4A}.Debug|x64.Build.0 = Debug|x64
{4642D596-723F-4BFC-894C-46811219AC4A}.Debug|x86.ActiveCfg = Debug|x64
{4642D596-723F-4BFC-894C-46811219AC4A}.Release|x64.ActiveCfg = Release|x64
{4642D596-723F-4BFC-894C-46811219AC4A}.Release|x64.Build.0 = Release|x64
{4642D596-723F-4BFC-894C-46811219AC4A}.Release|x86.ActiveCfg = Release|x64
{E94FD11C-0591-456F-899F-EFC0CA548336}.Debug|x64.ActiveCfg = Debug|x64
{E94FD11C-0591-456F-899F-EFC0CA548336}.Debug|x64.Build.0 = Debug|x64
{E94FD11C-0591-456F-899F-EFC0CA548336}.Debug|x86.ActiveCfg = Debug|x64
{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
@ -1009,6 +979,7 @@ Global
{89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{B25AC7A5-FB9F-4789-B392-D5C85E948670} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{51920F1F-C28C-4ADF-8660-4238766796C2} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{0E072714-D127-460B-AFAD-B4C40B412798} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{2151F984-E006-4A9F-92EF-C6DDE3DC8413} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{0485F45C-EA7A-4BB5-804B-3E8D14699387} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
@ -1041,6 +1012,7 @@ Global
{060D75DA-2D1C-48E6-A4A1-6F0718B64661} = {2F305555-C296-497E-AC20-5FA1B237996A}
{748417CA-F17E-487F-9411-CAFB6D3F4877} = {2F305555-C296-497E-AC20-5FA1B237996A}
{217DF501-135C-4E38-BFC8-99D4821032EA} = {2F305555-C296-497E-AC20-5FA1B237996A}
{47310AB4-9034-4BD1-8D8B-E88AD21A171B} = {2F305555-C296-497E-AC20-5FA1B237996A}
{A7D5099E-F0FD-4BF3-8522-5A682759F915} = {C3081D9A-1586-441A-B5F4-ED815B3719C1}
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A} = {C3081D9A-1586-441A-B5F4-ED815B3719C1}
{F055103B-F80B-4D0C-BF48-057C55620033} = {5A7818A8-109C-4E1C-850D-1A654E234B0E}
@ -1108,13 +1080,6 @@ Global
{470FBAF9-E1F8-4F3E-8786-198A1C81C8A8} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{11491FD8-F921-48BF-880C-7FEA185B80A1} = {2F305555-C296-497E-AC20-5FA1B237996A}
{F40C3397-1834-4530-B2D9-8F8B8456BCDF} = {2F305555-C296-497E-AC20-5FA1B237996A}
{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{4ED320BC-BA04-4D42-8D15-CBE62151F08B} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{F7EC4E6C-19CA-4FBD-9918-B8AC5FEF4F63} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{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}

174
README.md
View file

@ -1,50 +1,53 @@
# Microsoft PowerToys
![Hero image for Microsoft PowerToys](doc/images/overview/PT_hero_image.png)
<img src="./doc/images/overview/PT%20hero%20image.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)
[Downloads & Release notes][github-release-link] | [Contributing to PowerToys](#contributing) | [What's Happening](#whats-happening) | [Roadmap](#powertoys-roadmap)
## Build status
| Architecture | Main | Stable | Installer |
|--------------|------|--------|-----------|
| x64 | [![Build Status for Main](https://dev.azure.com/ms/PowerToys/_apis/build/status/microsoft.PowerToys?branchName=main)](https://dev.azure.com/ms/PowerToys/_build/latest?definitionId=219&branchName=main) | [![Build Status for Stable](https://dev.azure.com/ms/PowerToys/_apis/build/status/microsoft.PowerToys?branchName=stable)](https://dev.azure.com/ms/PowerToys/_build/latest?definitionId=219&branchName=stable) | [![Build Status for Installer](https://github-private.visualstudio.com/microsoft/_apis/build/status/CDPX/powertoys/powertoys-Windows-Official-master-Test?branchName=main)](https://github-private.visualstudio.com/microsoft/_build/latest?definitionId=61&branchName=main) |
| Architecture | Master | Stable | Installer |
|--------------|--------|--------|-----------|
| x64 | [![Build Status for Master](https://dev.azure.com/ms/PowerToys/_apis/build/status/microsoft.PowerToys?branchName=master)](https://dev.azure.com/ms/PowerToys/_build/latest?definitionId=219&branchName=master) | [![Build Status for Stable](https://dev.azure.com/ms/PowerToys/_apis/build/status/microsoft.PowerToys?branchName=stable)](https://dev.azure.com/ms/PowerToys/_build/latest?definitionId=219&branchName=stable) | [![Build Status for Installer](https://github-private.visualstudio.com/microsoft/_apis/build/status/CDPX/powertoys/powertoys-Windows-Official-master-Test?branchName=master)](https://github-private.visualstudio.com/microsoft/_build/latest?definitionId=61&branchName=master) |
## About
Microsoft PowerToys is a set of utilities for power users to tune and streamline their Windows experience for greater productivity. For more info on [PowerToys overviews and how to use the utilities][usingPowerToys-docs-link], or any other tools and resources for [Windows development environments](https://docs.microsoft.com/windows/dev-environment/overview), head over to [docs.microsoft.com][usingPowerToys-docs-link]!
Microsoft PowerToys is a set of utilities for power users to tune and streamline their Windows 10 experience for greater productivity. For more info on [PowerToys overviews and guides][usingPowerToys-docs-link], or any other tools and resources for [Windows development environments](https://docs.microsoft.com/windows/dev-environment/overview), head over to [docs.microsoft.com][usingPowerToys-docs-link]!
| | Current utilities: | |
|--------------|--------------------|--------------|
| [PowerToys Awake](https://aka.ms/PowerToysOverview_Awake) | [Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) | [FancyZones](https://aka.ms/PowerToysOverview_FancyZones) |
| [File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) | [Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) |
| [Mouse utilities](https://aka.ms/PowerToysOverview_MouseUtilities) | [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) |
| [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) | [Video Conference Mute](https://aka.ms/PowerToysOverview_VideoConference) | |
| [Awake](https://aka.ms/PowerToysOverview_Awake) | [Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) | [FancyZones](https://aka.ms/PowerToysOverview_FancyZones) |
| [File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) | [Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) |
| [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) | [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) |
| [Video Conference Mute (Experimental)](https://aka.ms/PowerToysOverview_VideoConference) | | |
## Installing and running Microsoft PowerToys
### Requirements
- Windows 11 or Windows 10 v1903 (18362) or newer.
- [.NET Core 3.1.20 Desktop Runtime](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-desktop-3.1.20-windows-x64-installer) or a newer 3.1.x runtime. The installer will handle this if not present.
- ⚠️ PowerToys (v0.37.0 and newer) requires Windows 10 v1903 (18362) or newer.
- Have [.NET Core 3.1.15 Desktop Runtime](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-desktop-3.1.15-windows-x64-installer). The installer should handle this but we want to directly make people aware.
### Via GitHub with EXE [Recommended]
#### Stable version
[Microsoft PowerToys GitHub releases page][github-release-link], click on `Assets` at the bottom to show the files available in the release and then click on `PowerToysSetup-0.49.0-x64.exe` to download the PowerToys installer.
Install from the [Microsoft Store's PowerToys page][microsoft-store-link] or use [Microsoft PowerToys GitHub releases page][github-release-link].
- For GitHub, click on `Assets` to show the files available in the release and then click on `PowerToysSetup-0.45.0-x64.exe` to download the PowerToys installer.
- For Microsoft Store, you must be using the [new Microsoft Store](https://blogs.windows.com/windowsExperience/2021/06/24/building-a-new-open-microsoft-store-on-windows-11/) which will be available for both Windows 11 and Windows 10.
This is our preferred method.
### Via Microsoft Store
Install from the [Microsoft Store's PowerToys page][microsoft-store-link]. You must be using the [new Microsoft Store](https://blogs.windows.com/windowsExperience/2021/06/24/building-a-new-open-microsoft-store-on-windows-11/) which will be available for both Windows 11 and Windows 10.
#### Experimental version
To install the Video Conference mute, please use the [v0.46 experimental version of PowerToys][github-prerelease-link] to try out this version. It includes all improvements from v0.45 in addition to the Video conference utility. Click on `Assets` to show the files available in the release and then download the .exe installer.
### Via WinGet (Preview)
Download PowerToys from [WinGet](https://github.com/microsoft/winget-cli#installing-the-client). To install PowerToys, run the following command from the command line / PowerShell:
```powershell
winget install Microsoft.PowerToys -s winget
WinGet install powertoys
```
### Other install methods
@ -75,74 +78,114 @@ For guidance on developing for PowerToys, please read the [developer docs](/doc/
Our [prioritized roadmap][roadmap] of features and utilities that the core team is focusing on.
### 0.49 - October 2021 Update
### 0.45 - August 2021 Update
The [v0.49 release cycle](https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F25) introduces exciting new updates primarily centered around modernizing PowerRename's UI, adding a brand new mouse utility, and merging Video Conference Mute into the stable releases!
Our goals for the [v0.45 release cycle](https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F23) primarily centered around stability updates and optimizations, installer updates, general bug fixes, and accessibility improvements.
PowerRename's new UI brings a refreshed experience that reflects the modern UI theming of Windows 11, along with helpful regular expression guidance and file formatting tips.
We also worked extensively with the community to build an updated settings menu UI. This UI update takes advantage of the latest styling elements to provide users with a refreshed, modern experience navigating the various utilities and their settings.
With the new mouse utility, PowerToys introduces functionality to quickly find your mouse position by double pressing the left <kbd>ctrl</kbd> key. This is ideal for large, high-resolution displays and low-vision users, with additional features and enhancements planned for future releases. Special thanks to [Raymond Chen](https://github.com/oldnewthing) for providing the base code PowerToys used to develop this feature. To learn more, check out our [Mouse Utilities documentation](https://aka.ms/PowerToysOverview_MouseUtilities) on Microsoft Docs!
An experimental version of [PowerToys (v0.46)][github-prerelease-link] was released the week of September 13th. Download and install it to try out the latest improvements to our Video Conference Mute utility! All updates from the v0.45.0 release will still apply in v0.46.0.
As Video Conference Mute becomes available in the stable releases, there are still known quirks that we are actively working to address. These bugs are [tracked on our GitHub](https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+label%3A%22Product-Video+Conference+Mute%22), and we welcome any and all feedback as we work to isolate and resolve the cause.
Color Picker's HEX format will no longer have the `#` character. This addresses issues with various color inputs that only accept six characters cutting off the last value. We apologize for any inconvenience this causes as we understand it impacts users who may prefer having `#` included. However, we believe this is the best solution while the custom string functionality ([#8305](https://github.com/microsoft/PowerToys/issues/8305)) is in development.
Additional work in this release include stability updates and optimizations, installer updates, general bug fixes, and accessibility improvements.
#### Highlights from v0.49
#### Highlights from v0.45
**General**
- **Change of Behavior:** Color Picker's HEX format will no longer have the `#` character. Custom string functionality for color picker ([#8305](https://github.com/microsoft/PowerToys/issues/8305)) is in development and will allow someone to use this again.
- Find My Mouse utility added! Utilize the functionality to quickly locate the cursor on your displays! Learn more on our [Mouse Utility docs](https://aka.ms/PowerToysOverview_MouseUtilities).
- Accessibility and minor UI improvements to the settings page. Thanks [@niels9001](https://github.com/niels9001)!
- Added deep links to the Settings menus for various utilities within their respective editors. Thanks [@niels9001](https://github.com/niels9001)!
- Settings improvements to improve clarity for various options. Thanks [@niels9001](https://github.com/niels9001)!
- Improved settings window to adjust size and position as needed when multi-monitor conditions change. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
**PowerToys Awake**
- Screen reader improvements for accessibility.
- Settings and OOBE windows updated with Fluent UX! We hope you enjoy the new modern feel of the application menus as we align our product with upcoming Windows 11 interfaces. Special thanks to @niels9001 for driving the development of this UI, along with many thanks to the various community members who offered constant feedback and adjustments to make this a truly spectacular update!
- Added button to settings which displays version history. Thanks @niels9001!
- Signed PowerToysSetupCustomActions.dll.
- Improved auto-update experience. Thanks @niels9001!
- Aligned OOBE theme color with Settings theme color. Thanks @niels9001!
- Adjusted labeling of "Restart as Administrator" button to "Restart PowerToys as Administrator" to avoid ambiguity in meaning. Thanks @niels9001!
- Added colored icons to settings sidebar. Thanks @niels9001!
- Fixed accessibility issue in OOBE where Microsoft Docs and PowerToys release notes links could not be navigated to via keyboard. Thanks @niels9001!
- Fixed settings header alignment. Thanks @niels9001!
- Fixed text under updates section to be visible when in light mode. Thanks @niels9001!
- Updated "Learn More" text to be more descriptive. Thanks @niels9001!
- Updated "Read more" text on updates to be more descriptive. Thanks @niels9001!
- Added link to documentation in system tray. Thanks @BenConstable9!
- Fixed error caused by file in use issues when installing PowerToys.
- Fixed issue where opening settings from start menu didn't work when PowerToys was run as admin. Thanks @davidegiacometti!
### Awake
**Color Picker**
- Color Picker's HEX format was changed to remove the `#` character. Thanks [@niels9001](https://github.com/niels9001)!
- Accessibility improvements for screen reader and UI to distinguish colors from the border when matching. Thanks [@niels9001](https://github.com/niels9001)!
- Added PowerToys Awake as option in translation bug template. Thanks @Aaron-Junker!
- Adjusted description of inactive setting to improve distinguishing between the utility being disabled vs inactive. Thanks @niels9001!
**FancyZones**
- Fixed Color Picker and OOBE windows from being snapped by FancyZones. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
- Fixed regression with layouts not being changed via shortcuts.
- Fixed crashing issue with FancyZones editor.
- Fixed zone layouts resetting after screen locking.
- Accessibility improvements for screen reader in editor.
### Color Picker
**Keyboard Manager**
- Fixed crashing issue when the editor is opened at high zoom on 4k monitors.
- Fixed bug where changing RGB values doesn't update color's HEX value. Thanks @martinchrzan!
- Fixed accessibility issue with screen reader not announcing when "Copied to Clipboard" is activated.
- Fixed accessibility issue where user could not hover the content of the info icon using a mouse. Thanks @niels9001!
- Fixed color picker format order not being accessible via keyboard. Thanks @niels9001!
- Fixed accessibility issue where screen reader announces incorrect name for "Editor color format" button and not announcing "Toggle switch" button at all. Thanks @niels9001!
**PowerRename**
- New UI update! We hope you enjoy the modern experience and take advantage of new tool-tips to describe common regular expressions and text/file formatting. Thanks to [@niels9001](https://github.com/niels9001) for all the support on this redesign!
### FancyZones
**PowerToys Run**
- Windows Terminal Plugin added. Open shells through Windows Terminal via `_` activation command by default. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
- Added environment variables to Folder plugin search. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
- Fixed certain schemas that were overwritten with HTTPS. Thanks [@franky920920](https://github.com/franky920920)!
- Fixed issue with program plugin getting caught in infinite loops as certain file paths are recursively searched.
- Adjusted "Save and apply" editor button to adjust with text size for localizations. Thanks @niels9001!
- Fixed "Create new layout" button visibility when in high contrast mode. Thanks @niels9001!
- Fixed scaling quirks related to editor UI. Thanks @niels9001!
- Fixed editor crashing when double clicking the "edit layout" button.
- Fixed issue with editor crashing immediately after displaying zones.
- Fixed bug when navigating editor options via keyboard where pressing enter on unselected Canvas option launches Grid editor instead.
- Fixed issue where FancyZones would not restore Console Applications.
- Fixed Canvas editor and Grid editor window heights. Thanks @niels9001!
- Fixed crash due to KERNELBASE.dll.
- Fixed FancyZone icons to be smoother at higher DPI settings. Thanks @niels9001!
- Fixed crash when changing between zone layouts.
- Fixed regression where FancyZones does not resize windows on layout change.
- Adjusted layout settings to reset shortcut key after canceling changes on a particular layout.
**Video Conference Mute**
- VCM added to stable releases of PowerToys!
### File Explorer add-ons
- Fixed issue where markdown files were still previewed even when "Enable Markdown" was turned off.
### Image Resizer
- Added warning that GIF files with animations may not correctly resize if the encoding used for the files is incompatible.
### Keyboard Manager
- Improved UI for KBM re-mappings list. Thanks @niels9001!
### PowerRename
- Expanding a plugin option in settings can now be toggled. Thanks @niels9001!
- Fixed race condition causing PowerRename to crash File Explorer. Thanks @ianjoneill!
### PowerToys Run
- Fixed lag caused from PowerToys running in background and invoking Alt-Tab.
- Resolved file not found exception when loading "System.Windows.Controls.Ribbon".
- Fixed null reference exception crash.
- Fixed registry plugin load crash.
- Fixed unauthorized access exception crash when setting registry keys for the utility.
- Added search for Plugin Manager. Thanks @davidegiacometti!
- Fixed VSCode workspace plugin not working. Thanks @BenConstable9!
### Video Conference Mute
- Fixed toolbar top right vertical offset to allow users to close other app windows.
- Fixed compatibility issues for certain systems when compiling from source.
- Fixed toolbox from persisting on screen.
- Fixed microphone un-muting when changing Video Conference Mute toolbar position.
- Added Video Conference Mute to OOBE.
## Community contributions
We'd like to directly mention certain contributors (in alphabetical order) for their continued community support this month and helping directly make PowerToys a better piece of software.
[@Aaron-Junker](https://github.com/Aaron-Junker), [@davidegiacometti](https://github.com/davidegiacometti), [@franky920920](https://github.com/franky920920), [@htcfreek](https://github.com/htcfreek), [@Jay-o-Way](https://github.com/Jay-o-Way), [@martinchrzan](https://github.com/martinchrzan), [@niels9001](https://github.com/niels9001), [@pritudev](https://github.com/pritudev), and [@TobiasSekan](https://github.com/TobiasSekan)
[@Aaron-Junker](https://github.com/Aaron-Junker), [@BenConstable9](https://github.com/BenConstable9), [@davidegiacometti](https://github.com/davidegiacometti), [@dchristensen](https://github.com/dchristensen), [@dend](https://github.com/dend), [@franky920920](https://github.com/franky920920), [@htcfreek](https://github.com/htcfreek), [@ianjoneill](https://github.com/ianjoneill), [@jakeoeding](https://github.com/jakeoeding), [@Jay-o-Way](https://github.com/Jay-o-Way), [@jsoref](https://github.com/jsoref), [@martinchrzan](https://github.com/martinchrzan), [@niels9001](https://github.com/niels9001) and [@royvou](https://github.com/royvou)
#### What is being planned for v0.51
#### What is being planned for v0.47
For [v0.51][github-next-release-work], we are planning to work on:
For [v0.47][github-next-release-work], we are planning to work on:
- Initial development of Always on Top utility to allow users to persist desired windows in the foreground of their displays
- We are working to heavily reduce / remove the UAC prompt over the next few releases on install. This is a big shift so it is spanning multiple releases so we can isolate issues if they do occur. Work is tracked in [#10126](https://github.com/microsoft/PowerToys/issues/10126)
- UI/UX investigations to adopt WinUI and improve accessibility
- Stability and bug fixes
- Update the PowerToys Build Pipeline to allow .NET 5 integration
- Upgrading PowerToys Run to .NET 5
- Preliminary UI/UX investigations to adopt WinUI and improve accessibility
- Configuring Shortcut guide to re-enable long `Win` key press to activate
- Testing PDF preview functionality for File Explorer add-ons
- Planning for new utilities and enhancements
## PowerToys Community
@ -165,7 +208,8 @@ The application logs basic telemetry. Our Telemetry Data page (Coming Soon) has
[privacy-link]: http://go.microsoft.com/fwlink/?LinkId=521839
[vidConfOverview]: https://aka.ms/PowerToysOverview_VideoConference
[loc-bug]: https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=&template=translation_issue.md&title=
[usingPowerToys-docs-link]: https://aka.ms/powertoys-docs
[usingPowerToys-docs-link]: https://docs.microsoft.com/windows/powertoys/
<!-- items that need to be updated release to release -->
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F26
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F21
[github-prerelease-link]: https://github.com/microsoft/PowerToys/releases/tag/v0.46.0

View file

@ -1,10 +1,5 @@
# Support
## How to use Microsoft PowerToys
For more info on [PowerToys overviews and how to use the utilities][usingPowerToys-docs-link], or any other tools and resources for [Windows development environments](https://docs.microsoft.com/windows/dev-environment/overview), head over to [docs.microsoft.com][usingPowerToys-docs-link]!
## How to file issues and get help
This project uses [GitHub Issues][gh-issue] to [track bugs][gh-bug] and [feature requests][gh-feature]. Please search the existing issues before filing new issues to avoid duplicates. For new issues, file your bug or
@ -20,5 +15,4 @@ Support for PowerToys is limited to the resources listed above.
[gh-bug]: https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=Issue-Bug&template=bug_report.md&title=
[gh-feature]: https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=&template=feature_request.md&title=
[wiki]: https://github.com/microsoft/PowerToys/wiki
[contributor]: https://github.com/microsoft/PowerToys/blob/main/CONTRIBUTING.md
[usingPowerToys-docs-link]: https://aka.ms/powertoys-docs
[contributor]: https://github.com/microsoft/PowerToys/blob/master/CONTRIBUTING.md

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<GeneratedFilesDir>$(IntDir)Generated Files\</GeneratedFilesDir>
</PropertyGroup>
</Project>

View file

@ -4,44 +4,43 @@
|----------|----------|
| getpowertoys | ms-windows-store://pdp/?productid=XP89DCGQ3K6VLD |
| installpowertoys | https://github.com/microsoft/PowerToys/releases/latest |
| powertoys-license | https://github.com/microsoft/PowerToys/blob/main/LICENSE |
| powertoys-license | https://github.com/microsoft/PowerToys/blob/master/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 |
| powerToysColorPickerImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/ColorPicker_small.png |
| powerToysColorPickerSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/ColorPicker_large.png |
| powerToysColorPickerSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/overview/ColorPicker_large.png |
| powertoysDetectedElevatedHelp | https://docs.microsoft.com/windows/powertoys/administrator |
| powertoys-docs | https://docs.microsoft.com/windows/powertoys/?WT.mc_id=twitter-0000-docsmsft |
| powerToysFancyZoneImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/FancyZones_small.png |
| powerToysFancyZoneSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/FancyZones_large.png |
| powerToysFancyZoneSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/overview/FancyZones_large.png |
| powerToysGiveFeedback | https://github.com/microsoft/PowerToys/issues |
| powerToysImageResizerImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/ImageResizer_small.png |
| powerToysImageResizerSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/ImageResizer_large.png |
| powerToysImageResizerSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/overview/ImageResizer_large.png |
| powerToysKBMImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/KBM_small.png |
| powerToysKBMSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/KBM_large.png |
| powerToysKBMSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/overview/KBM_large.png |
| PowerToysOverview | https://docs.microsoft.com/windows/powertoys/ |
| PowerToysOverview_ColorPicker | https://docs.microsoft.com/windows/powertoys/color-picker |
| PowerToysOverview_FancyZones | https://docs.microsoft.com/windows/powertoys/fancyzones |
| PowerToysOverview_FileExplorerAddOns | https://docs.microsoft.com/windows/powertoys/file-explorer |
| PowerToysOverview_ImageResizer | https://docs.microsoft.com/windows/powertoys/image-resizer |
| PowerToysOverview_KeyboardManager | https://docs.microsoft.com/windows/powertoys/keyboard-manager |
| PowerToysOverview_MouseUtilities | https://docs.microsoft.com/windows/powertoys/mouse-utilities |
| PowerToysOverview_PowerRename | https://docs.microsoft.com/windows/powertoys/powerrename |
| PowerToysOverview_PowerToysRun | https://docs.microsoft.com/windows/powertoys/run |
| PowerToysOverview_ShortcutGuide | https://docs.microsoft.com/windows/powertoys/shortcut-guide |
| PowerToysOverview_VideoConference | https://docs.microsoft.com/windows/powertoys/video-conference-mute |
| powerToysPowerLauncherImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/PowerLauncher_small.png |
| powerToysPowerLauncherSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/PowerLauncher_large.png |
| powerToysPowerLauncherSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/overview/PowerLauncher_large.png |
| powerToysPowerPreviewImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/PowerPreview_small.png |
| powerToysPowerPreviewSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/PowerPreview_large.png |
| powerToysPowerPreviewSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/overview/PowerPreview_large.png |
| powerToysPowerRenameImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/PowerRename_small.png |
| powerToysPowerRenameSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/PowerRename_large.png |
| powerToysPowerRenameSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/overview/PowerRename_large.png |
| powerToysPTImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/PT_small.png |
| powerToysPTSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/PT_large.png |
| powerToysPTSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/overview/PT_large.png |
| powerToysReportBug | https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=Issue-Bug%2CTriage-Needed&template=bug_report.yml&title= |
| powerToysRequestFeature | https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=&template=feature_request.md&title= |
| powerToysShortcutGuideImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/ShortcutGuide_small.png |
| powerToysShortcutGuideSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/ShortcutGuide_large.png |
| powerToysShortcutGuideSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/overview/ShortcutGuide_large.png |
| powerToysVideoConferenceImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/VideoConference_small.png |
| powerToysVideoConferenceSettingImage | https://github.com/microsoft/PowerToys/wiki/images/overview/VideoConference_large.png |
| powertoyswiki | https://github.com/microsoft/PowerToys/wiki |

View file

@ -1,30 +0,0 @@
# How to integrate new MSIX module with PowerToys Settings and WiX installer
[`issue_11705_with_example` branch](https://github.com/microsoft/PowerToys/tree/issue_11705_with_example) contains HelloWorld UWP C# MSIX application which reads its module settings and is installed along PowerToys.
## Steps
- uncomment everything near "TODO: Use to activate embedded MSIX" comments
- build PowerToys solution
- deploy HelloModule module and sign it with a self-signed certificate (don't forget to put it into a trusted store)
- build PowerToysSetup solution and install it
Type HelloModule into start search and observe that it was installed:
<img src="../images/msix/hello-module-start.png">
Open PowerToys settings and change the stub setting to something:
<img src="../images/msix/hello-module-settings-page.png">
Open HelloModule:
<img src="../images/msix/hello-module-screen.png">
First time you press "Load Settings", it'll detect that it doesn't have permissions to access local file system and open its system settings window, toggle it there:
<img src="../images/msix/hello-module-app-permissions.png">
(it's a known uwp limitation, see https://stackoverflow.com/a/53533414/657390)
HelloModule will close then, restart it, press "Load Settings" and you should see that the application was able to load the setting string which was set by the settings app:
<img src="../images/msix/hello-module-loaded-settings.png">

View file

@ -12,11 +12,11 @@
5. [Enabling localized MSI for a new project](#enabling-localized-msi-for-a-new-project)
## Localization on the pipeline (CDPX)
[The localization step](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L45-L52) is run on the pipeline before the solution is built. This step runs the [build-localization](https://github.com/microsoft/PowerToys/blob/main/.pipelines/build-localization.cmd) script, which generates resx files for all the projects with localization enabled using the `Localization.XLoc` package.
[The localization step](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L45-L52) is run on the pipeline before the solution is built. This step runs the [build-localization](https://github.com/microsoft/PowerToys/blob/master/.pipelines/build-localization.cmd) script, which generates resx files for all the projects with localization enabled using the `Localization.XLoc` package.
The [`Localization.XLoc`](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/build-localization.cmd#L24-L25) tool is run on the repo root, and it checks for all occurrences of `LocProject.json`. Each localized project has a `LocProject.json` file in the project root, which contains the location of the English resx file, list of languages for localization, and the output path where the localized resx files are to be copied to. In addition to this, some other parameters can be set, such as whether the language ID should be added as a folder in the file path or in the file name. When the CDPX pipeline is run, the localization team is notified of changes in the English resx files. For each project with localization enabled, a `loc` folder (see [this](https://github.com/microsoft/PowerToys/tree/main/src/modules/launcher/Microsoft.Launcher/loc) for example) is created in the same directory as the `LocProject.json` file. The folder contains language specific folders which in turn have a nested folder path equivalent to `OutputPath` in the `LocProject.json`. Each of these folders contain one `lcl` file. The `lcl` files contain the English resources along with their translation for that language. These are described in more detail [here](#lcl-files). Once the `.resx` files are generated, they will be used during the `Build PowerToys` step for localized versions of the modules.
The [`Localization.XLoc`](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/build-localization.cmd#L24-L25) tool is run on the repo root, and it checks for all occurrences of `LocProject.json`. Each localized project has a `LocProject.json` file in the project root, which contains the location of the English resx file, list of languages for localization, and the output path where the localized resx files are to be copied to. In addition to this, some other parameters can be set, such as whether the language ID should be added as a folder in the file path or in the file name. When the CDPX pipeline is run, the localization team is notified of changes in the English resx files. For each project with localization enabled, a `loc` folder (see [this](https://github.com/microsoft/PowerToys/tree/master/src/modules/launcher/Microsoft.Launcher/loc) for example) is created in the same directory as the `LocProject.json` file. The folder contains language specific folders which in turn have a nested folder path equivalent to `OutputPath` in the `LocProject.json`. Each of these folders contain one `lcl` file. The `lcl` files contain the English resources along with their translation for that language. These are described in more detail [here](#lcl-files). Once the `.resx` files are generated, they will be used during the `Build PowerToys` step for localized versions of the modules.
Since the localization script requires certain nuget packages, the [`restore-localization`](https://github.com/microsoft/PowerToys/blob/main/.pipelines/restore-localization.cmd) script is run before running `build-localization` to install all the required packages. This script must [run in the `restore` step](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L37-L39) of pipeline because [the host is network isolated](https://onebranch.visualstudio.com/Pipeline/_wiki/wikis/Pipeline.wiki/2066/Consuming-Packages-in-a-CDPx-Pipelinhttps://onebranch.visualstudio.com/Pipeline/_wiki/wikis/Pipeline.wiki/2066/Consuming-Packages-in-a-CDPx-Pipeline?anchor=overview) at the `build` step. The [Toolset package source](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L23) is used for this.
Since the localization script requires certain nuget packages, the [`restore-localization`](https://github.com/microsoft/PowerToys/blob/master/.pipelines/restore-localization.cmd) script is run before running `build-localization` to install all the required packages. This script must [run in the `restore` step](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L37-L39) of pipeline because [the host is network isolated](https://onebranch.visualstudio.com/Pipeline/_wiki/wikis/Pipeline.wiki/2066/Consuming-Packages-in-a-CDPx-Pipelinhttps://onebranch.visualstudio.com/Pipeline/_wiki/wikis/Pipeline.wiki/2066/Consuming-Packages-in-a-CDPx-Pipeline?anchor=overview) at the `build` step. The [Toolset package source](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L23) is used for this.
The process and variables that can be tweaked on the pipeline are described in more detail [here](https://onebranch.visualstudio.com/Pipeline/_wiki/wikis/Pipeline.wiki/290/Localization).
@ -31,7 +31,7 @@ UWP differs from this as it expects the resources to have the same Resources.res
For example, `path\en-us\Resources.resw` for English and `path\fr-fr\Resources.resw` for French.
Since the pipeline generates it in this format, [a script is run](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/build-localization.cmd#L29-L31) to move these resw files to the correct format expected by all UWP projects. Currently the only UWP project is [Microsoft.PowerToys.Settings.UI](https://github.com/microsoft/PowerToys/tree/main/src/core/Microsoft.PowerToys.Settings.UI). The script used for moving the resources can be [found here](https://github.com/microsoft/PowerToys/blob/main/tools/localization/move_uwp_resources.ps1). The equivalent full language IDs for each shortened language ID obtained from the pipeline has been hardcoded in the script.
Since the pipeline generates it in this format, [a script is run](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/build-localization.cmd#L29-L31) to move these resw files to the correct format expected by all UWP projects. Currently the only UWP project is [Microsoft.PowerToys.Settings.UI](https://github.com/microsoft/PowerToys/tree/master/src/core/Microsoft.PowerToys.Settings.UI). The script used for moving the resources can be [found here](https://github.com/microsoft/PowerToys/blob/master/tools/localization/move_uwp_resources.ps1). The equivalent full language IDs for each shortened language ID obtained from the pipeline has been hardcoded in the script.
## Enabling localization on a new project
To enable localization on a new project, the first step is to create a file `LocProject.json` in the project root.
@ -58,7 +58,7 @@ The rest of the steps depend on the project type and are covered in the sections
### C++
C++ projects do not support `resx` files, and instead use `rc` files along with `resource.h` files. The CDPX pipeline however doesn't support localizing `rc` files and the other alternative they support is directly translating the resources from the binary which makes it harder to maintain resources. To avoid this, a custom script has been added which expects a resx file and converts the entries to an rc file with a string table and adds resource declarations to a resource.h file so that the resources can be compiled with the C++ project.
If you already have a .rc file, copy the string table to a separate txt file and run the [convert-stringtable-to-resx.ps1](https://github.com/microsoft/PowerToys/blob/main/tools/build/convert-stringtable-to-resx.ps1) script on it. This script is not very robust to input, and requires the data in a specific format, where `IDS_ResName L"ResourceValue"` and any number of spaces can be present in between. The script converts this file to the format expected by [`resgen`](https://docs.microsoft.com/en-us/dotnet/framework/tools/resgen-exe-resource-file-generator#Convert), which will convert it to resx. The resource names are changed from all uppercase to title case, and the `IDS_` prefix is removed. Escape characters might have to be manually replaced, for example .rc files would have escaped double quotes as `""`, so this should be replaced with just `"` before converting to the resx files.
If you already have a .rc file, copy the string table to a separate txt file and run the [convert-stringtable-to-resx.ps1](https://github.com/microsoft/PowerToys/blob/master/tools/build/convert-stringtable-to-resx.ps1) script on it. This script is not very robust to input, and requires the data in a specific format, where `IDS_ResName L"ResourceValue"` and any number of spaces can be present in between. The script converts this file to the format expected by [`resgen`](https://docs.microsoft.com/en-us/dotnet/framework/tools/resgen-exe-resource-file-generator#Convert), which will convert it to resx. The resource names are changed from all uppercase to title case, and the `IDS_` prefix is removed. Escape characters might have to be manually replaced, for example .rc files would have escaped double quotes as `""`, so this should be replaced with just `"` before converting to the resx files.
After generating the resx file, rename the existing rc and h files to ProjName.base.rc and resource.base.h. In the rc file remove the string table which is to be localized and in the .h file remove all `#define`s corresponding to localized resources. In the vcxproj of the C++ project, add the following build event:
```
@ -67,7 +67,7 @@ After generating the resx file, rename the existing rc and h files to ProjName.b
</Target>
```
This event runs a script which generates a resource.h and ProjName.rc in the `Generated Files` folder using the strings in all the resx files along with the existing information in resource.base.h and ProjName.base.rc. The script can be found [here](https://github.com/microsoft/PowerToys/blob/main/tools/build/convert-resx-to-rc.ps1). The script uses [`resgen`](https://docs.microsoft.com/en-us/dotnet/framework/tools/resgen-exe-resource-file-generator#Convert) to convert the resx file to a string table expected in the .rc file format. When the resources are added to the rc file the `IDS_` prefix is added and resource names are in upper case (as it was originally). Any occurrences of `"` in the string resource is escaped as `""` to prevent build errors. The string tables are added to the rc file in the following format:
This event runs a script which generates a resource.h and ProjName.rc in the `Generated Files` folder using the strings in all the resx files along with the existing information in resource.base.h and ProjName.base.rc. The script can be found [here](https://github.com/microsoft/PowerToys/blob/master/tools/build/convert-resx-to-rc.ps1). The script uses [`resgen`](https://docs.microsoft.com/en-us/dotnet/framework/tools/resgen-exe-resource-file-generator#Convert) to convert the resx file to a string table expected in the .rc file format. When the resources are added to the rc file the `IDS_` prefix is added and resource names are in upper case (as it was originally). Any occurrences of `"` in the string resource is escaped as `""` to prevent build errors. The string tables are added to the rc file in the following format:
```
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
@ -84,7 +84,7 @@ Since there is no API to identify the `AFX_TARG_*`, `LANG_*` or `SUBLANG_*` valu
<None Include="Resources.resx" />
```
Some rc/resource.h files might be used in multiple projects (for example, KBM). To ensure the projects build for these cases, the build event can be added to the entire directory so that the rc files are generated before any project is built. See [Directory.Build.targets](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/Directory.Build.targets) for an example.
Some rc/resource.h files might be used in multiple projects (for example, KBM). To ensure the projects build for these cases, the build event can be added to the entire directory so that the rc files are generated before any project is built. See [Directory.Build.targets](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/Directory.Build.targets) for an example.
Check [this PR](https://github.com/microsoft/PowerToys/pull/6104) for an example for making these changes for a C++ project.

View file

@ -15,7 +15,7 @@ TODO
#### [`ZoneSet.cpp`](/src/modules/fancyzones/lib/ZoneSet.cpp)
TODO
#### [`WorkArea.cpp`](/src/modules/fancyzones/lib/WorkArea.cpp)
#### [`ZoneWindow.cpp`](/src/modules/fancyzones/lib/ZoneWindow.cpp)
TODO
## FancyZones Editor

View file

@ -66,10 +66,10 @@ This file contains documentation for all the methods involved in key/shortcut re
[This method](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/KeyboardEventHandlers.cpp#L126-L176) was added to support a feature for converting the behavior of a key from behaving like a toggle (like Caps Lock/Num Lock) to a modifier (like Ctrl), such that when you hold Caps Lock it would behave as if Caps Lock was active, and when it was not pressed Caps Lock would be off. For Caps Lock this would be similar to behaving like Shift, but for Num Lock there is no existing key which can substitute for this. This was added while testing out remapping for the KBM PoC, but wasn't added as a feature since it wasn't a priority.
## Tests
In order to test the remapping logic, a mocked keyboard input handler had to be created because otherwise the tests would process and send actual key events. For this the [`InputInterface`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/InputInterface.h) was made, and in production code the methods are implemented using [`SendInput`](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput) and [`GetAsyncKeyState`](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate). In addition to this, [`GetCurrentApplication`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Helpers.cpp#L226-L268) had to be mocked so that app-specific remapping can be tested.
In order to test the remapping logic, a mocked keyboard input handler had to be created because otherwise the tests would process and send actual key events. For this the [`InputInterface`](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/common/InputInterface.h) was made, and in production code the methods are implemented using [`SendInput`](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput) and [`GetAsyncKeyState`](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate). In addition to this, [`GetCurrentApplication`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Helpers.cpp#L226-L268) had to be mocked so that app-specific remapping can be tested.
### MockedInput
The [`MockedInput`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/MockedInput.h) class uses a 256 size `bool` vector to store the key state for each key code. Identifying the foreground process is mocked by simply setting and getting a string value for the name of the current process.
The [`MockedInput`](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/test/MockedInput.h) class uses a 256 size `bool` vector to store the key state for each key code. Identifying the foreground process is mocked by simply setting and getting a string value for the name of the current process.
[To mock the `SendInput` method](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/test/MockedInput.cpp#L10-L110), the steps for processing the input are as follows. This implementation is based on public documentation for SendInput and the behavior of key messages and keyboard hooks:
- Iterate over all the inputs in the INPUT array argument
@ -81,4 +81,4 @@ The [`MockedInput`](https://github.com/microsoft/PowerToys/blob/main/src/modules
- For modifiers the behavior is slightly different as if the key state of the L/R version is modified, it should also modify the common version, and if a common version is released, it should release both the L and R versions.
### Tests for single key remaps and shortcut remaps
Using the MockedInput handler, all the expected (and known) key scenarios that can occur for while pressing a [remapped key](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/SingleKeyRemappingTests.cpp) or [remapped shortcut](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/OSLevelShortcutRemappingTests.cpp) are tested. The foreground app behavior which is specific to app-specific shortcuts is tested [here](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/AppSpecificShortcutRemappingTests.cpp).
Using the MockedInput handler, all the expected (and known) key scenarios that can occur for while pressing a [remapped key](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/test/SingleKeyRemappingTests.cpp) or [remapped shortcut](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/test/OSLevelShortcutRemappingTests.cpp) are tested. The foreground app behavior which is specific to app-specific shortcuts is tested [here](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/test/AppSpecificShortcutRemappingTests.cpp).

View file

@ -185,7 +185,7 @@ This method is used by [SharpKeys](https://github.com/randyrants/sharpkeys) and
Using a driver approach has the benefit of not depending on precedence orders as KBM could always run before low level hooks, and it also has the benefit of differentiating between different keyboards, allowing [multi keyboard-specific remaps](https://github.com/microsoft/PowerToys/issues/1460). The disadvantages are however that any bug or crash could have system level consequences. [Interception](https://github.com/oblitum/Interception) is an open source driver that could be used for implementing this. The approach was deprioritized due to the potential side effects.
## Telemetry
Keyboard Manager emits the following telemetry events (implemented in [trace.h](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/trace.h) and [trace.cpp](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/trace.cpp)):
Keyboard Manager emits the following telemetry events (implemented in [trace.h](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/common/trace.h) and [trace.cpp](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/common/trace.cpp)):
- **`KeyboardManager_EnableKeyboardManager`:** Logs a `boolean` value storing the KBM toggle state. It is logged whenever KBM is enabled or disabled (emitted [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L305-L316)).
- **`KeyboardManager_KeyRemapCount`:** Logs the number of key to key and key to shortcut remaps (i.e. all the remaps on the Remap a key window). This gets logged on saving new settings in the Remap a key window (emitted [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/LoadingAndSavingRemappingHelper.cpp#L159-L163)).
- **`KeyboardManager_OSLevelShortcutRemapCount`:** Logs the number of global shortcut to shortcut and shortcut to key remaps. This gets logged on saving new settings in the Remap a shortcut window (emitted [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/LoadingAndSavingRemappingHelper.cpp#L220)).

View file

@ -17,7 +17,7 @@ This project contains any code that is to be shared between the backend and UI p
1. [Foreground App Detection](#Foreground-App-Detection)
## KeyboardManagerState
[This class](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/KeyboardManagerState.cpp) stores all the data related to remappings and is also used in the sense of a View Model as it used to communicate common data that is shared between the KBM UI and the backend. They are accessed on the UI controls using static class members of `SingleKeyRemapControl` and `ShortcutControl`.
[This class](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/common/KeyboardManagerState.cpp) stores all the data related to remappings and is also used in the sense of a View Model as it used to communicate common data that is shared between the KBM UI and the backend. They are accessed on the UI controls using static class members of `SingleKeyRemapControl` and `ShortcutControl`.
### UI States
[UI states](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyboardManagerState.h#L27-L42) are used to keep track in which step of the UI flow is the user at, such as which Remap window they are on, or if they have one of the Type windows open. This is required because the hook needs to suppress input and update UI in some cases, and in some cases remappings have to be disabled altogether.
@ -37,12 +37,12 @@ The [`SaveConfigToFile`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a
To prevent the UI thread and low level hook thread from concurrently accessing the remap tables we use an [`atomic bool` variable](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyboardManagerState.h#L91-L92), which is set to `true` while the tables are getting updated. When this is `true` the hook will skip all remappings. Use of mutexes in the hook were removed to prevent re-entrant mutex bugs.
## KeyDelay
[This class](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/KeyDelay.cpp) implements a queue based approach for processing key events and based on the time difference between key down and key up events [executes separate methods for `ShortPress`, `LongPress` or `LongPressReleased`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyDelay.h#L69-L72). The class is used for the hold Enter/Esc functionality required for making the Type window accessible and prevent keyboard traps (see [this](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp#L273-L292) for an example of it's usage). The `KeyEvents` are added to the queue from the hook thread of KBM, and a separate [`DelayThread`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyDelay.cpp#L142-L166) is used to process the key events by checking the `time` member in the key event. The thresholds for short vs long press and hold wait timeouts are `static` constants, but if the module is extended for other purposes these could be made into arguments.
[This class](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/common/KeyDelay.cpp) implements a queue based approach for processing key events and based on the time difference between key down and key up events [executes separate methods for `ShortPress`, `LongPress` or `LongPressReleased`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyDelay.h#L69-L72). The class is used for the hold Enter/Esc functionality required for making the Type window accessible and prevent keyboard traps (see [this](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp#L273-L292) for an example of it's usage). The `KeyEvents` are added to the queue from the hook thread of KBM, and a separate [`DelayThread`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyDelay.cpp#L142-L166) is used to process the key events by checking the `time` member in the key event. The thresholds for short vs long press and hold wait timeouts are `static` constants, but if the module is extended for other purposes these could be made into arguments.
**Note:** [Deletion of the `KeyDelay`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyDelay.cpp#L4-L12) object should never be called from the `DelayThread` i.e. from within one of the 3 handlers, as it can re-enter the mutex and would lead to a deadlock. This can be avoided by either deleting it on a separate thread or as done in the KBM UI, on the dispatcher thread. See [this PR](https://github.com/microsoft/PowerToys/pull/6959#issue-496583547) for more details on this issue.
## Shortcut and RemapShortcut classes
The [`Shortcut` class](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/Shortcut.h) is a data structure for storing key combinations which are valid shortcuts and it contains several methods which are used for shortcut specific operations. [`RemapShortcut`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/RemapShortcut.h) consists of a shortcut/key union (`std::variant`), along with other boolean flags which are required on the hook side for storing any relevant keyboard states mid-execution.
The [`Shortcut` class](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/common/Shortcut.h) is a data structure for storing key combinations which are valid shortcuts and it contains several methods which are used for shortcut specific operations. [`RemapShortcut`](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/common/RemapShortcut.h) consists of a shortcut/key union (`std::variant`), along with other boolean flags which are required on the hook side for storing any relevant keyboard states mid-execution.
### IsKeyboardStateClearExceptShortcut
[This method](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Shortcut.cpp#L665-L813) is used by the `HandleShortcutRemapEvent` to check if any other keys on the keyboard have been pressed apart from the keys in the shortcut. This is required because shortcut to shortcut remaps should not be applied if the shortcut is pressed with other keys. The method iterates over all the possible key codes, except any keys that are considered reserved, unassigned, OEM-specific or undefined, as well as mouse buttons (see list [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Shortcut.cpp#L628-L663)).
@ -51,13 +51,13 @@ The [`Shortcut` class](https://github.com/microsoft/PowerToys/blob/main/src/modu
[This method](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Shortcut.cpp#L517-L614) uses `GetVirtualKeyState` (internally calls `GetAsyncKeyState` in production code), to check if all the modifiers of the current shortcut are being pressed. Since Win doesn't have a non-L/R key code we check this by checking both LWIN and RWIN.
### Tests
Tests for some methods in the `Shortcut` class can be found [here](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/ShortcutTests.cpp).
Tests for some methods in the `Shortcut` class can be found [here](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/test/ShortcutTests.cpp).
## Helpers
[This namespace](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/Helpers.cpp) has any methods which are used across either UI or the backend which aren't specific to either. Some of these methods have tests [here](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/SetKeyEventTests.cpp).
[This namespace](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/common/Helpers.cpp) has any methods which are used across either UI or the backend which aren't specific to either. Some of these methods have tests [here](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/test/SetKeyEventTests.cpp).
### Foreground App Detection
[`GetCurrentApplication`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Helpers.cpp#L226-L268) is used for detecting the foreground process for App-specific shortcuts. The logic is very similar to that used for FZ's app exception feature, involving `GetForegroundWindow` and `get_process_path`. The one additional case which has been added is for full-screen UWP apps, where the above method fails and returns `ApplicationFrameHost.exe`. The [`GetFullscreenUWPWindowHandle`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Helpers.cpp#L210-L224) uses `GetGUIThreadInfo` API to find the window linked to the GUI thread. This logic is based on [this stackoverflow answer](https://stackoverflow.com/questions/39702704/connecting-uwp-apps-hosted-by-applicationframehost-to-their-real-processes/55353165#55353165).
**Note:** The [`GetForegroundProcess` method](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/Input.cpp#L17-L21) performs string allocation in a weird way because of exceptions that were occurring while running tests as a result of memory being allocated or deallocated across dll boundaries. Here's the comment from the PR where this was added
> To make app-specific logic test-able, a GetForegroundProcess was added to the input interface which internally calls GetCurrentApplication. This allows us to mock this method in the test project by just setting some process name as the foreground process for that function. When I set this to just return the string name, it would goes runtime errors on the test project in debug_heap with `__acrt_first_block == header`. Based on [this stackoverflow answer](https://stackoverflow.com/a/35311928), this would happen if allocation happens in one dll's code space and deallocation happens in another. One way to avoid this is to change both the projects to MD (multi threaded dll) instead of MT(multi threaded), however that results in many compile-time errors since all the PT projects are configured as MT. To solve this, the GetForegroundProcess was rewritten such that its argument is the output variable, and we allocate memory for that string within the AppSpecificHandler method rather than in that function.
> To make app-specific logic test-able, a GetForegroundProcess was added to the input interface which internally calls GetCurrentApplication. This allows us to mock this method in the test project by just setting some process name as the foreground process for that function. When I set this to just return the string name, it would goes runtime errors on the test project in debug_heap with `__acrt_first_block == header`. Based on [this stackoverflow answer](https://stackoverflow.com/a/35311928), this would happen if allocation happens in one dll's code space and deallocation happens in another. One way to avoid this is to change both the projects to MD (multi threaded dll) instead of MT(multi threaded), however that results in many compile-time errors since all the PT projects are configured as MT. To solve this, the GetForegroundProcess was rewritten such that its argument is the output variable, and we allocate memory for that string within the AppSpecificHandler method rather than in that function.

View file

@ -24,7 +24,7 @@ The KBM UI is implemented as a C++ XAML Island, but all the controls are impleme
The windows are [created as C++ windows](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L128-L140) and the window sizes are set to default by [scaling them as per DPI](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L120-L126) using the `DPIAware::Convert` API from common lib. Since the UI is launched on a new thread, the window may not be in the foreground, so [we call `SetForegroundWindow`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L146-L150).
`DesktopWindowXamlSource` has to be declared and [it is initialized](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L159-L162) using the [`XamlBridge`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/XamlBridge.cpp), and [a second window handle](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L161-L162) is generated for the internal Xaml Island window. Most of the code was based on the [Xaml Island Sample](https://github.com/microsoft/Xaml-Islands-Samples/blob/master/Samples/Win32/SampleCppApp/XamlBridge.cpp). The `XamlBridge` class contains code which handles initializing the Xaml Island containers as well as handling special messages like keyboard navigation, and focus between islands and between the C++ window and the island. It also has methods for clearing the xaml islands and closing the window.
`DesktopWindowXamlSource` has to be declared and [it is initialized](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L159-L162) using the [`XamlBridge`](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/ui/XamlBridge.cpp), and [a second window handle](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L161-L162) is generated for the internal Xaml Island window. Most of the code was based on the [Xaml Island Sample](https://github.com/microsoft/Xaml-Islands-Samples/blob/master/Samples/Win32/SampleCppApp/XamlBridge.cpp). The `XamlBridge` class contains code which handles initializing the Xaml Island containers as well as handling special messages like keyboard navigation, and focus between islands and between the C++ window and the island. It also has methods for clearing the xaml islands and closing the window.
Once the UI controls are created, the parent container is set as the content for the `DesktopWindowXamlSource` and the `XamlBridge.MessageLoop` is executed. Messages are processed by the C++ window handler like [`EditKeyboardWindowProc`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L364-L404). The general structure we use for this is, for any `WM_PAINT` or `WM_SIZE` message we resize the Xaml Island window. For `WM_GETMINMAXINFO` we set minimum widths so that the window cannot be resized beyond a minimum height and width. This is done to prevent the WinUI elements from overlapping and getting cropped. If it is neither of these cases we send the message to the [`XamlBridge.MessageHandler`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/XamlBridge.cpp#L291-L301) which handles Destroy, Activation and Focus. If `WM_NCDESTROY` is received when the `XamlBridge` is `nullptr`, the window thread is terminated.
@ -41,7 +41,7 @@ To access the brushes available on C# Xaml, it has to be done with the `Resource
`primaryButton.Background(Windows::UI::Xaml::Application::Current().Resources().Lookup(box_value(L"SystemControlBackgroundBaseMediumLowBrush")).as<Windows::UI::Xaml::Media::SolidColorBrush>());`
## UI Structure
The KBM UI consists of a [`Grid` with several columns](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L200-L218). Rows are added dynamically when [the add button is pressed](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L305-L309). [A vector of vector of unique pointers to `SingleKeyRemapControl`/`ShortcutControl`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L248-L249) is created so that references to the UI components and their data are not lost until the window is closed. [`SingleKeyRemapControl`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp) is the UI class for each row of the Remap keys table, and [`ShortcutControl`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/ShortcutControl.cpp) is the UI class for each row of the Remap shortcuts table. [`KeyDropDownControl`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/KeyDropDownControl.cpp) is used for handling the ComboBox operations. Each of these two classes [have vectors of unique pointers to the `KeyDropDownControl` objects](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/ShortcutControl.h#L44-L45) so that references to the objects are active until the control is deleted.
The KBM UI consists of a [`Grid` with several columns](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L200-L218). Rows are added dynamically when [the add button is pressed](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L305-L309). [A vector of vector of unique pointers to `SingleKeyRemapControl`/`ShortcutControl`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L248-L249) is created so that references to the UI components and their data are not lost until the window is closed. [`SingleKeyRemapControl`](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp) is the UI class for each row of the Remap keys table, and [`ShortcutControl`](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/ui/ShortcutControl.cpp) is the UI class for each row of the Remap shortcuts table. [`KeyDropDownControl`](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/ui/KeyDropDownControl.cpp) is used for handling the ComboBox operations. Each of these two classes [have vectors of unique pointers to the `KeyDropDownControl` objects](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/ShortcutControl.h#L44-L45) so that references to the objects are active until the control is deleted.
When the UI windows are activated the `KeyboardManagerState` object [sets the `UIState` variable](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L251-L252) which is used for distinguishing if the UI is up from the keyboard hook thread. The [states are also updated](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp#L53) on opening and closing the Type window.
@ -89,7 +89,7 @@ On making a selection in the drop down, [the selection handler](https://github.c
- Conflicting modifier previously remapped (Ctrl->A and Ctrl(left)->B, since Ctrl also includes Ctrl(left))
If the selection is found to be valid, the `singleKeyRemapBuffer` is updated accordingly.
For handling `Shortcut` and key in the remap buffer for the right column, we use `std::variant`, which allows us to store either of the two types and check which one of them is present in the buffer by using the `index` method.
[`ValidateAndUpdateKeyBufferElement`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/BufferValidationHelpers.cpp#L8-L66) does not reference any UI components and instead takes all the relevant data as arguments. This method [has tests](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/BufferValidationTests.cpp) which covers all the cases that could arise from making selections on the UI.
[`ValidateAndUpdateKeyBufferElement`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/BufferValidationHelpers.cpp#L8-L66) does not reference any UI components and instead takes all the relevant data as arguments. This method [has tests](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/test/BufferValidationTests.cpp) which covers all the cases that could arise from making selections on the UI.
### Shortcut ComboBox Selection Handler
On making a selection in the drop down, [the selection handler](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/KeyDropDownControl.cpp#L215-L295) validates the input with the buffer from the other column and other rows. Error messages are shown using flyouts if the selection is not considered valid and the drop down and buffer for that entry are reset to empty selection.
@ -115,7 +115,7 @@ Unlike the Single Key handler, there is a different set of errors that can occur
- Conflicting shortcut previously remapped for same target app (Ctrl+A->B and Ctrl(left)+A->C, since Ctrl also includes Ctrl(left))
- Illegal shortcut remaps like Win+L or Ctrl+Alt+Del (since these cannot be remapped using LL hooks)
[`ValidateShortcutBufferElement`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/BufferValidationHelpers.cpp#L68-L304) does not reference any UI components and instead takes all the relevant data as arguments. This method [has tests](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/BufferValidationTests.cpp) which covers all the cases that could arise from making selections on the UI.
[`ValidateShortcutBufferElement`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/BufferValidationHelpers.cpp#L68-L304) does not reference any UI components and instead takes all the relevant data as arguments. This method [has tests](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/test/BufferValidationTests.cpp) which covers all the cases that could arise from making selections on the UI.
**Note:** After updating the buffer we have [code to handle a special case](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/KeyDropDownControl.cpp#L269-L279), which was required to prevent scenarios where a drop down can get deleted but the corresponding `KeyDropDownControl` object isn't deleted. The code checks if the drop down is still linked to the parent and accordingly deletes the `KeyDropDownControl` object from the vector.

View file

@ -3,7 +3,7 @@
## Debugging Prerequisite
Setup development environment for PowerToys by following instruction [here.](https://github.com/microsoft/PowerToys/tree/main/doc/devdocs#prerequisites-for-compiling-powertoys)
Setup development environment for PowerToys by following instruction [here.](https://github.com/microsoft/PowerToys/tree/master/doc/devdocs#prerequisites-for-compiling-powertoys)
## Direct debugging
This approach is used to test UI, plugins, and core `PowerToys Run` functionality. This **cannot** be used to test `PowerToys Run` settings. The approach is significantly faster compared to `Debugging with runner`, as it requires compiling projects relevant to `PowerToys Run`. Please follow the steps below for direct debugging.

View file

@ -1,161 +0,0 @@
# Windows Settings Plugin
The Windows settings Plugin allows users to search the Windows settings.
## Special functions (differ from the regular functions)
* Support modern Windows settings (Windows 10+)
* Support legacy Windows settings (Windows 7, 8.1)
* Support extra programs for setting (like ODBC)
* Support search by the area of the setting (like `Privacy`)
* Support search for alternative names of a setting
## How to add a new Windows Setting or change one
All Windows settings are located in `WindowsSettings.json` in root folder of the project.
The `WindowsSettings.json` use a JSON schema file that make it easier to edit it.
| Key | Optional | Value type | String prefix |
| ------------------- | -------- | ----------------- | ------------- |
| `Name` | **No** | String | |
| `Type` | **No** | String | `App` |
| `Command` | **No** | String | |
| `Areas` | Yes | List with strings | `Area` |
| `AltNames` | Yes | List with strings | |
| `Note` | Yes | String | `Note` |
| `IntroducedInBuild` | Yes | Integer | |
| `DeprecatedInBuild` | Yes | Integer | |
| `ShowAsFirstResult` | Yes | Boolean | |
A minimum entry for the `WindowsSettings.json` looks like:
```json
{
"Name": "mySetting",
"Type": "AppSettingsApp",
"Command": "ms-settings:mySetting"
}
```
A full entry for the `WindowsSettings.json` looks like:
```json
{
"Name": "mySetting",
"Type": "AppSettingsApp",
"Command": "ms-settings:mySetting",
"Areas": [ "AreaMySettingArea" ],
"AltNames": [ "NiceSetting" ],
"Note": "NoteMySettingNote",
"IntroducedInBuild" : 1903,
"DeprecatedInBuild" : 2004,
"ShowAsFirstResult" : true
}
```
### Remarks
* The `Command` for modern Windows settings should start with `ms-settings:`
* The `Command` for legacy Windows settings should start with `control`
* The integer value for `IntroducedInBuild` and `DeprecatedInBuild` must be in range of `0` to `4294967295`
* The strings for `Name`, `AltNames`, `Areas`, `Type` and `Note` must not contain whitespace(s) or special characters (#, €, $, etc.)
* The strings for `Name`, `AltNames`, `Areas`, `Type` and `Note` are used as ids for the resource file under `Properties\Resources.resx`
* When you add new strings make sure you have add add all translations for it.
## Scores
There are three different score types with different start values.
| Score type | Start value |
| ------------------ | ------------ |
| First result score | 10500 |
| High score | 10000 |
| Medium score | 5000 |
| Low score | 1000 |
Each score will decreased by one when a condition match.
| Priority | Condition | Score type |
| -------- | ----------------------------------------------------------------- | ------------ |
| 1. | Settings name starts with the search value | High score |
| 2. | Settings name contain the search value | Medium score |
| 3. | Setting has no area | Low score |
| 4. | One area of the settings starts with the search value | Low score |
| 5. | Setting has no alternative name | Low score |
| 6. | One alternative name of the settings starts with the search value | Medium score |
| x. | no condition match | Low score |
### Remarks
* For each score condition we check if the property "ShowAsFirstResult" of the setting is true. If yes we use the firstResultScore instead of condition`s score.
## Important for developers
### General
* The assembly name is cached into `_assemblyName` (to avoid to many calls of `Assembly.GetExecutingAssembly()`)
## Microsoft.PowerToys.Run.Plugin.WindowsSettings project
### Important plugin values (meta-data)
| Name | Value |
| --------------- | ---------------------------------------------------- |
| ActionKeyword | `$` |
| ExecuteFileName | `Microsoft.PowerToys.Run.Plugin.WindowsSettings.dll` |
| ID | `5043CECEE6A748679CBE02D27D83747A` |
### Interfaces used by this plugin
The plugin use only these interfaces (all inside the `Main.cs`):
* `Wox.Plugin.IPlugin`
* `Wox.Plugin.IContextMenu`
* `Wox.Plugin.IPluginI18n`
### Program files
| File | Content |
| ------------------------------------- | ----------------------------------------------------------------------- |
| `Classes\WindowsSetting.cs` | A class that represent one Windows setting |
| `Classes\WindowsSettings.cs` | A wrapper class that only contains a list with Windows settings (see 1) |
| `Helper\ContextMenuHelper.cs` | All functions to build the context menu (for each result entry) |
| `Helper\JsonSettingsListHelper.cs` | All functions to load the windows settings from a JSON file |
| `Helper\ResultHelper.cs` | All functions to convert internal results into WOX results |
| `Helper\TranslationHelper.cs` | All functions to translate the result in the surface language |
| `Helper\UnsupportedSettingsHelper.cs` | All functions to filter not supported Windows settings out |
| `Helper\WindowsSettingsPathHelper.cs` | All functions to build the area paths |
| `Images\WindowsSettings.dark.png` | Symbol for the results for the dark theme |
| `Images\WindowsSettings.light.png` | Symbol for the results for the light theme |
| `Properties\Resources.Designer.resx` | File that contain all translatable keys |
| `Properties\Resources.resx` | File that contain all translatable strings in the neutral language |
| `GlobalSuppressions.cs` | Code suppressions (no real file, linked via *.csproj) |
| `Main.cs` | Main class, the only place that implement the WOX interfaces |
| `plugin.json` | All meta-data for this plugin |
| `StyleCop.json` | Code style (no real file, linked via *.csproj) |
1. We need this extra wrapper class to make it possible that the JSON file can have and use a JSON schema file.
Because the JSON file must have a object as root type, instead of a array.
### Important project values (*.csproj)
| Name | Value |
| --------------- | --------------------------------------------------------------------------------------------------- |
| TargetFramework | `netcoreapp3.1` (means .NET Core 3.1) |
| Platforms | `x64` |
| Output | `..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\` |
| RootNamespace | `Microsoft.PowerToys.Run.Plugin.WindowsSettings` |
| AssemblyName | `Microsoft.PowerToys.Run.Plugin.WindowsSettings` |
### Project dependencies
#### Packages
| Package | Version |
| ------------------------------------------------------------------------------------- | ------- |
| [`StyleCop.Analyzers`](https://github.com/DotNetAnalyzers/StyleCopAnalyzers) | 1.1.118 |
#### Projects
* `Wox.Infrastructure`
* `Wox.Plugin`

View file

@ -21,3 +21,6 @@ TODO
#### [`trace.cpp`](/src/modules/powerrename/lib/trace.cpp)
TODO
#### [`PowerRenameUI.cpp`](/src/modules/powerrename/ui/PowerRenameUI.cpp)
TODO

View file

@ -53,7 +53,7 @@ bool ExamplePowertoy::get_config(wchar_t* buffer, int* buffer_size)
return settings.serialize_to_buffer(buffer, buffer_size);
}
```
The list of all the available settings elements and their description is [further in this doc](#available-settings-elements). New PowerToy icons need to be [added to the `settings-web` project](https://github.com/microsoft/PowerToys/blob/main/doc/devdocs/settings-web.md#updating-the-icons).
The list of all the available settings elements and their description is [further in this doc](#available-settings-elements). New PowerToy icons need to be [added to the `settings-web` project](https://github.com/microsoft/PowerToys/blob/master/doc/devdocs/settings-web.md#updating-the-icons).
## User changes settings
When user closes the settings screen, the runner will call the [`get_config()`](modules/interface.md) method. Use [`PowerToyValues`](/src/common/settings_objects.h) class static `from_json_string` method to parse the settings. After that, the code is similar to loading the settings from disk:

View file

@ -6,7 +6,7 @@
## Formatting
- We use [`.clang-format`](https://github.com/microsoft/PowerToys/blob/main/src/.clang-format) style file to enable automatic code formatting. You can [easily format source files from Visual Studio](https://devblogs.microsoft.com/cppblog/clangformat-support-in-visual-studio-2017-15-7-preview-1/). For example, `CTRL+K CTRL+D` formats the current document.
- If you prefer another text editor or have ClangFormat disabled in Visual Studio, you could invoke [`format_sources`](https://github.com/microsoft/PowerToys/blob/main/src/codeAnalysis/format_sources.ps1) powershell script from command line. It gets a list of all currently modified files from `git` and invokes clang-format on them.
- We use [`.clang-format`](https://github.com/microsoft/PowerToys/blob/master/src/.clang-format) style file to enable automatic code formatting. You can [easily format source files from Visual Studio](https://devblogs.microsoft.com/cppblog/clangformat-support-in-visual-studio-2017-15-7-preview-1/). For example, `CTRL+K CTRL+D` formats the current document.
- If you prefer another text editor or have ClangFormat disabled in Visual Studio, you could invoke [`format_sources`](https://github.com/microsoft/PowerToys/blob/master/src/codeAnalysis/format_sources.ps1) powershell script from command line. It gets a list of all currently modified files from `git` and invokes clang-format on them.
Please note that you should also have `clang-format.exe` in `%PATH%` for it to work. The script can infer the path of `clang-format.exe` version which is shipped with Visual Studio at `%VCINSTALLDIR%\Tools\Llvm\bin\`, if you launch it from the *Native Tools Command Prompt for VS*.
- CI doesn't enforce code formatting yet, since we're gradually applying code formatting to the codebase, but please adhere to our formatting style for any new code.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

View file

Before

Width:  |  Height:  |  Size: 447 KiB

After

Width:  |  Height:  |  Size: 447 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 100 KiB

View file

@ -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. 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.
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.
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 WorkArea per monitor (currently active work area on each connected monitor).
2. Keeping track of ZoneWindow 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 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.
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.
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 its 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.
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 its 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.

View file

@ -1,143 +0,0 @@
# PowerToys SCOOBE Dialog
- **What is it:** Post-upgrade prompted dialog that walks users through the latest additions to PowerToys utilities and functionalities
- **Author:** Deondre Davis
- **Spec Status:** Draft
## 1. Overview
### 1.1. Executive Summary
To expand on our end-user on-boarding efforts, we seek to resolve the critical issue of informing users of new additions and improvements to PowerToys during upgrade scenarios. We currently list release notes on the main repository, in addition to affiliated information on Microsoft Docs. However, neither of these mediums are internal to the application, and thus requires users to proactively seek out information on what&#39;s been updated, or merely notice by chance what&#39;s been changed from their regular usage. As these are not ideal experiences, this document describes the inclusion of a post-upgrade &#39;SCOOBE&#39; prompt that launches the previously developed OOBE dialog loaded with new information related to upgrade improvements and additions.
### 1.2. Key-Definitions/Concepts
Here are definitions for words and acronyms found throughout this document to ensure clarity:
- **OOBE:** Out of box experience The users&#39; initial interactions with the product immediately after installing the product and/or launching the product for the first time.
- **SCOOBE:** Second chance out of box experience - The users&#39; initial interactions with the product immediately after upgrading the product and/or launching the product for the first time after upgrading.
### 1.3. Goals and Non-Goals
Goals:
- Create a guided prompt that exposes the user to a brief overview of the new features and/or improvements included with the latest version of PowerToys.
Non-Goals:
- Present a copy-and-paste replica of the repository release notes. This information needs to be readily consumable, often requiring visual demonstrations of the new behavior and/or functionality that&#39;s either not possible or not necessary to depict on the repository release notes.
## 2. Definition of Success
**2.1. Customers**
The PowerToys SCOOBE is for existing and new power users and developers who are looking to tune and streamline their Windows experience for greater productivity and enhanced user experience. As the PowerToys customer base tends to be particularly biased against SCOOBE prompts in general, we need to present the PowerToys SCOOBE dialog in such a way that it provides immediate value to end-users to improve the likelihood of users discovering all the additions to PowerToys by making their way through the prompt.
**2.2. Expected Impact: Customer, and Technology Outcomes**
- **High Reliability** : Less than 0.1% crash rate.
- **Increased Activation** : 50% or more adoption rate of new feature/utilities among PowerToys users who already utilize associated tools.
- **High User Retention:** 25% or more active PowerToys users after 28 days of upgrade.
## 3. Requirements
The SCOOBE dialog builds off the currently implemented OOBE dialog originally drafted by [Niels&#39;s mock-up.](https://github.com/microsoft/PowerToys/issues/1285)
**3.1. Functional Requirements**
**3.1.1. Functional Requirements** **Overview**
| **No.** | **Requirement** | **Pri** |
| --- | --- | --- |
|1. | The SCOOBE dialog should launch immediately when PowerToys runs after having been updated. | P0 |
|2. | The SCOOBE dialog should be contained inside the existing OOBE Dialog under its own &quot;What&#39;s New&quot; page of the dialog window. See figure 5.1.1. | P0 |
|3. | The content for the SCOOBE dialog should be stored externally from the PowerToys application on the PowerToys Github in distinct wiki pages on for each release. **\*** | P0 |
|4. | When the &quot;What&#39;s New&quot; page is opened, the content displayed should be loaded from the information contained in the relevant wiki pages discussed in 3.1.1.3 above. Assumes the user&#39;s device is connected to the internet. | P0 |
|6. | The SCOOBE dialog should display information on updates that have occurred on the version of PowerToys the user has installed/updated to. | P0 |
|7. | If PowerToys was installed for the first time, the OOBE&#39;s &quot;Welcome to PowerToys&quot; page should display first, not the SCOOBE&#39;s &quot;What&#39;s New&quot; page. See figure 5.1.2. | P0 |
|8. | The structure of the SCOOBE dialog page&#39;s content should follow the guidelines described in section 3.1.2. | P0 |
|9. | After SCOOBE is initially viewed, the user should be able to re-access the SCOOBE dialog at any time by opening the OOBE window again and selecting the &quot;What&#39;s New&quot; page. | P1 |
**\*** - By storing the content for SCOOBE externally from the application, the PowerToys team can update/adjust information without being constrained to PowerToys&#39; release cycles. This is critical in the event of errors or miscommunications that would otherwise be difficult, if not impossible, to correct if stored locally to the app and shipped with the version of PowerToys being released. The content will likely be stored in an archive maintained in the PowerToys Github Wiki.
**3.1.2. Page Content**
| **No.** | **Requirement** | **Pri** |
| --- | --- | --- |
|1. | The SCOOBE dialog should display the version of PowerToys the user has installed, as shown in figures 5.1.1. | P0 |
|2. | The SCOOBE dialog information should be grouped into two sections: &quot;New Features &amp; Improvements&quot; and &quot;Bug fixes Highlights&quot;. | P0 |
|3. | The &quot;New Features &amp; Improvements&quot; section should contain information related to end user functionality that has been added or updated. | P0 |
|4. | The &quot;New Features &amp; Improvements&quot; section should be subdivided by the relevant utilities updated (i.e. Color Picker, FancyZones, etc.). See figure 5.1.1 and section 5.1.3 for examples. | P1 |
|5. | The &quot;Bug fixes Highlights&quot; section should contain information related to noteworthy issues/errors that were corrected. | P0 |
|6. | If there are relevant visuals, they should be included with the information text. See figure 5.1.1. | P1 |
|8. | The SCOOBE dialog should be scrollable if needed to fit all the content. | P0 |
|10. | The bottom of the SCOOBE dialog should include a link to the PowerToys releases page for a complete list of versions and their release notes ([Releases · microsoft/PowerToys (github.com)](https://github.com/microsoft/PowerToys/releases)). | P1 |
## 4. Measure Requirements
| **No.** | **Requirement** | **Implication** | **Pri** |
| --- | --- | --- | --- |
|1. | Date/Time of first-run following upgrade | Helps to categorize usage and retention trends across users who've been exposed to SCOOBE. | P0 |
|2. | SCOOBE section viewed | Used to measure activation of the SCOOBE dialog. Should be 100% for the current version of PowerToys following SCOOBE&#39;s inclusion. | P0 |
|3. | Accesses to linked documentation | Used to gauge interest in user&#39;s desire to learn more about the PowerToys described. | P1 |
|4. | Access to linked settings pages | Used to gauge whether the settings presented to users in the dialog are sufficient for user needs. | P1 |
|5. | PowerToys launched while SCOOBE window is active | Used to track user engagement with the various PowerToys while exploring the content in the SCOOBE. | P1 |
|6. | Screen size | Gives crucial information for considerations related to minimal/maximum window size needed for displaying content. | P2 |
## 5. Appendix
### 5.1. Mock-ups
**5.1.1. SCOOBE Dialog Layout**
![](../images/SCOOBE/SCOOBE.png)
**5.1.2. OOBE Welcome Page**
![](../images/SCOOBE/Welcome_SCOOBE.png)
**5.1.3. Example Textual Descriptions for Updates**
**v0.29 -> v0.31:**
- New Features &amp; Improvements
- FancyZones
- Dark mode for the editor
- Certain settings (e.g. number of zones, spacing settings) can now be set on individual layouts.
- PowerToys Run
- Service management plugin (Start, stop, …)
- Registry key plugin
- System action plugin (Reboot, lock, ...)
- Bug fixes Highlights
- Fixed OneDrive SVG Bug (#9999)
- SVG are scaled appropriately when view box is provided (#9999)
**v0.31 -> v0.33:**
- New Features &amp; Improvements
- General
- Added a &#39;First time load&#39; experience. The hope is a quick, light way to learn about basic functionality
- FancyZones
- New options to change zone activation algorithm
- PowerToys Run
- Plugin Manager now is in settings. You can directly turn on / off, include items in general search, and change the action key
- Improved support for additional window managers by abstracting out shell process calls
- ~ will now act as the user home directory in Folder plugin
- Bug fixes Highlights
- Fix for PT Run registering the hotkey on non-supported OS versions (#9999)
**v0.33 -> v0.35:**
- New Features &amp; Improvements
- Color Picker
- Esc can now be used to exit the editor
- FancyZones
- Added hotkeys and quick swap functionality for custom layouts! Users can now assign a hotkey in the editor and use it to quickly set a desktop&#39;s zones with Ctrl + Win + Alt + NUMBER key binding, or by pressing the hotkey while dragging a window.
- PowerToys Run
- Users can specify where to show the launcher window
- New plugin added to support opening previously used Visual Studio Code workspaces, remote machines (SSH or Codespaces), and containers! When enabled, use { to query for available workspaces. Please note, this plugin is off by default.
- Shell history now saves the raw command instead of the resolved command. A command like %appdata% would now save in the Shell history as is instead of C:\Users\YourUserName\AppData\Roaming.
- Bug fixes Highlights
- PowerToys will start requiring Windows 10 v1903 or greater after 0.35.x release. (#9999)
- Fixed FancyZones placement algorithm for when the Taskbar is vertical (#9999)

View file

@ -9,7 +9,7 @@ namespace fs = std::filesystem;
namespace updating
{
constexpr size_t REQUIRED_MINIMAL_PATCH = 20;
constexpr size_t REQUIRED_MINIMAL_PATCH = 15;
bool dotnet_is_installed()
{
@ -45,7 +45,7 @@ namespace updating
std::optional<fs::path> download_dotnet()
{
const wchar_t DOTNET_DESKTOP_DOWNLOAD_LINK[] = L"https://download.visualstudio.microsoft.com/download/pr/93c69a29-d379-4a5d-bb9e-3116cc14de41/907bbc52446d8bb7baa0c6faebde1d44/windowsdesktop-runtime-3.1.20-win-x64.exe";
const wchar_t DOTNET_DESKTOP_DOWNLOAD_LINK[] = L"https://download.visualstudio.microsoft.com/download/pr/d30352fe-d4f3-4203-91b9-01a3b66a802e/bb416e6573fa278fec92113abefc58b3/windowsdesktop-runtime-3.1.15-win-x64.exe";
const wchar_t DOTNET_DESKTOP_FILENAME[] = L"windowsdesktop-runtime.exe";
auto dotnet_download_path = fs::temp_directory_path() / DOTNET_DESKTOP_FILENAME;

View file

@ -42,9 +42,7 @@ std::optional<fs::path> ExtractEmbeddedInstaller(const fs::path extractPath)
return std::nullopt;
}
std::wstring msiName(L"PowerToysSetup-" STRINGIZE(VERSION_MAJOR) "." STRINGIZE(VERSION_MINOR) "." STRINGIZE(VERSION_REVISION) L"-");
msiName += get_architecture_string(get_current_architecture()) + std::wstring(L".msi");
auto installerPath = extractPath / msiName;
auto installerPath = extractPath / L"PowerToysBootstrappedInstaller-" PRODUCT_VERSION_STRING L".msi";
return executableRes->saveAsFile(installerPath) ? std::make_optional(std::move(installerPath)) : std::nullopt;
}
@ -165,51 +163,6 @@ std::optional<InstalledVersionInfo> get_installed_powertoys_version()
};
}
void ReLaunchElevatedAndExit()
{
std::wstring params;
int nCmdArgs = 0;
LPWSTR* argList = CommandLineToArgvW(GetCommandLineW(), &nCmdArgs);
for (int i = 1; i < nCmdArgs; ++i)
{
if (std::wstring_view{ argList[i] }.find(L' ') != std::wstring_view::npos)
{
params += L'"';
params += argList[i];
params += L'"';
}
else
{
params += argList[i];
}
if (i != nCmdArgs - 1)
{
params += L' ';
}
}
const auto processHandle = run_elevated(argList[0], params.c_str());
if (!processHandle)
{
spdlog::error("Couldn't restart elevated: ({})", GetLastError());
return;
}
if (WaitForSingleObject(processHandle, 3600000) == WAIT_OBJECT_0)
{
DWORD exitCode = 0;
GetExitCodeProcess(processHandle, &exitCode);
std::exit(exitCode);
}
else
{
spdlog::error("Elevated setup process timed out after 60m: ({})", GetLastError());
TerminateProcess(processHandle, 0);
std::exit(1);
}
}
int Bootstrapper(HINSTANCE hInstance)
{
winrt::init_apartment();
@ -344,14 +297,7 @@ int Bootstrapper(HINSTANCE hInstance)
}
}
// Always elevate bootstrapper process since it invokes msiexec multiple times,
// so we can avoid multiple UAC confirmations
if (!is_process_elevated())
{
ReLaunchElevatedAndExit();
}
// Setup MSI UI visibility
// Setup MSI UI visibility and restart as elevated if required
if (!noFullUI)
{
MsiSetInternalUI(INSTALLUILEVEL_FULL, nullptr);
@ -359,7 +305,58 @@ int Bootstrapper(HINSTANCE hInstance)
if (g_Silent)
{
MsiSetInternalUI(INSTALLUILEVEL_NONE, nullptr);
if (is_process_elevated())
{
MsiSetInternalUI(INSTALLUILEVEL_NONE, nullptr);
}
else
{
spdlog::debug("MSI doesn't support silent mode without elevation => restarting elevated");
// MSI fails to run in silent mode due to a suppressed UAC w/o elevation,
// so we restart ourselves elevated with the same args
std::wstring params;
int nCmdArgs = 0;
LPWSTR* argList = CommandLineToArgvW(GetCommandLineW(), &nCmdArgs);
for (int i = 1; i < nCmdArgs; ++i)
{
if (std::wstring_view{ argList[i] }.find(L' ') != std::wstring_view::npos)
{
params += L'"';
params += argList[i];
params += L'"';
}
else
{
params += argList[i];
}
if (i != nCmdArgs - 1)
{
params += L' ';
}
}
const auto processHandle = run_elevated(argList[0], params.c_str());
if (!processHandle)
{
spdlog::error("Couldn't restart elevated to enable silent mode! ({})", GetLastError());
return 1;
}
if (WaitForSingleObject(processHandle, 3600000) == WAIT_OBJECT_0)
{
DWORD exitCode = 0;
GetExitCodeProcess(processHandle, &exitCode);
return exitCode;
}
else
{
spdlog::error("Elevated setup process timed out after 60m => using basic MSI UI ({})", GetLastError());
// Couldn't install using the completely silent mode in an hour, use basic UI.
TerminateProcess(processHandle, 0);
MsiSetInternalUI(INSTALLUILEVEL_BASIC, nullptr);
}
}
}
// Try killing PowerToys and prevent future processes launch by acquiring app mutex

View file

@ -7,10 +7,6 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "PowerToysSetup", "PowerToys
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerToysSetupCustomActions", "PowerToysSetupCustomActions\PowerToysSetupCustomActions.vcxproj", "{32F3882B-F2D6-4586-B5ED-11E39E522BD3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spdlog", "..\src\logging\logging.vcxproj", "{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "logger", "..\src\common\logger\logger.vcxproj", "{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@ -25,14 +21,6 @@ Global
{32F3882B-F2D6-4586-B5ED-11E39E522BD3}.Debug|x64.Build.0 = Debug|x64
{32F3882B-F2D6-4586-B5ED-11E39E522BD3}.Release|x64.ActiveCfg = Release|x64
{32F3882B-F2D6-4586-B5ED-11E39E522BD3}.Release|x64.Build.0 = Release|x64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x64.ActiveCfg = Debug|x64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x64.Build.0 = Debug|x64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|x64.ActiveCfg = Release|x64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|x64.Build.0 = Release|x64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x64.ActiveCfg = Debug|x64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x64.Build.0 = Debug|x64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|x64.ActiveCfg = Release|x64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -10,7 +10,6 @@
<?define ColorPickerProjectName="ColorPicker"?>
<?define VideoConferenceProjectName="VideoConference"?>
<?define AwakeProjectName="Awake"?>
<?define MouseUtilsProjectName="MouseUtils"?>
<?define RepoDir="$(var.ProjectDir)..\..\" ?>
<?define BinX32Dir="$(var.RepoDir)x86\$(var.Configuration)\" ?>
@ -78,19 +77,21 @@
<Property Id="CREATESCHEDULEDTASK" Value="1"/>
<Property Id="WixShellExecTarget" Value="[#PowerToys_ActionRunner.exe]" />
<Property Id ="EXISTINGPOWERRENAMEEXTPATH">
<RegistrySearch Id="ExistingExtPath" Root="HKCR" Key="CLSID\{0440049F-D1DC-4E46-B27B-98393D79486B}\InprocServer32" Type="raw"/>
</Property>
<Property Id ="EXISTINGIMAGERESIZERPATH">
<RegistrySearch Id="ExistingImageResizerPath" Root="HKCR" Key="CLSID\{51B4D7E5-7568-4234-B4BB-47FB3C016A69}\InprocServer32" Type="raw"/>
</Property>
<InstallUISequence>
<Custom Action="DetectPrevInstallPath" After="CostFinalize" />
</InstallUISequence>
<InstallExecuteSequence>
<Custom Action="SetRegisterPowerToysSchTaskParam" Before="RegisterPowerToysSchTask" />
<Custom Action="SetApplyModulesRegistryChangeSetsParam" Before="ApplyModulesRegistryChangeSets" />
<Custom Action="SetUnApplyModulesRegistryChangeSetsParam" Before="UnApplyModulesRegistryChangeSets" />
<Custom Action="RegisterPowerToysSchTask" After="InstallFiles">
NOT Installed and CREATESCHEDULEDTASK = 1
</Custom>
<Custom Action="ApplyModulesRegistryChangeSets" After="InstallFiles">
NOT Installed
</Custom>
<Custom Action="WixCloseApplications" Before="RemoveFiles" />
<Custom Action="RemovePowerToysSchTasks" After="RemoveFiles" />
<!-- TODO: Use to activate embedded MSIX -->
@ -103,10 +104,6 @@
<Custom Action="TelemetryLogUninstallSuccess" After="InstallFinalize">
Installed and (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
</Custom>
<Custom Action="UnApplyModulesRegistryChangeSets" Before="InstallFinalize">
Installed AND (REMOVE="ALL")
</Custom>
<!-- TODO: Use to activate embedded MSIX -->
<!--<Custom Action="UninstallEmbeddedMSIXTask" After="InstallFinalize">
Installed AND (REMOVE="ALL")
@ -126,15 +123,7 @@
Property="RegisterPowerToysSchTask"
Value="[#PowerToys.exe]" />
<CustomAction Id="SetApplyModulesRegistryChangeSetsParam"
Property="ApplyModulesRegistryChangeSets"
Value="[INSTALLFOLDER]" />
<CustomAction Id="SetUnApplyModulesRegistryChangeSetsParam"
Property="UnApplyModulesRegistryChangeSets"
Value="[INSTALLFOLDER]" />
<!-- Needs to Impersonate="no" and Execute="deferred" in order to run elevated. -->
<!-- Needs to Impersonate="no" and Execute="deferred" in order to run elevated. -->
<CustomAction Id="RegisterPowerToysSchTask"
Return="ignore"
Impersonate="no"
@ -228,23 +217,6 @@
DllEntry="DetectPrevInstallPathCA"
/>
<CustomAction Id="ApplyModulesRegistryChangeSets"
Return="check"
Impersonate="no"
Execute="deferred"
BinaryKey="PTCustomActions"
DllEntry="ApplyModulesRegistryChangeSetsCA"
/>
<CustomAction Id="UnApplyModulesRegistryChangeSets"
Return="check"
Impersonate="no"
Execute="deferred"
BinaryKey="PTCustomActions"
DllEntry="UnApplyModulesRegistryChangeSetsCA"
/>
<!-- Close 'PowerToys.exe' before uninstall-->
<Property Id="MSIRESTARTMANAGERCONTROL" Value="DisableShutdown" />
<Property Id="MSIFASTINSTALL" Value="DisableShutdown" />
@ -263,9 +235,7 @@
<Directory Id="ToolsFolder" Name="Tools"/>
<Directory Id="ModulesInstallFolder" Name="modules">
<Directory Id="ImageResizerInstallFolder" Name="$(var.ImageResizerProjectName)" />
<Directory Id="PowerRenameInstallFolder" Name="$(var.PowerRenameProjectName)">
<Directory Id="PowerRenameAssetsFolder" Name="Assets" />
</Directory>
<Directory Id="PowerRenameInstallFolder" Name="$(var.PowerRenameProjectName)"/>
<Directory Id="ShortcutGuideInstallFolder" Name="ShortcutGuide">
<Directory Id="ShortcutGuideExecutableInstallFolder" Name="ShortcutGuide">
<Directory Id="ShortcutGuideSvgsInstallFolder" Name="svgs"/>
@ -300,10 +270,6 @@
<Directory Id="ColorPickerResourcesFolder" Name="Resources"/>
</Directory>
<!-- Mouse Utils -->
<Directory Id="MouseUtilsInstallFolder" Name="$(var.MouseUtilsProjectName)">
</Directory>
<!-- Launcher -->
<Directory Id="LauncherInstallFolder" Name="launcher">
<Directory Id="AssetsFolder" Name="Assets" />
@ -316,27 +282,27 @@
<Directory Id="CalculatorImagesFolder" Name="Images" />
<Directory Id="CalculatorLanguagesFolder" Name="Languages" />
</Directory>
<Directory Id="FolderPluginFolder" Name="Folder">
<Directory Id="FolderPluginFolder" Name="Microsoft.Plugin.Folder">
<Directory Id="FolderPluginImagesFolder" Name="Images" />
<Directory Id="FolderPluginLanguagesFolder" Name="Languages" />
</Directory>
<Directory Id="ProgramPluginFolder" Name="Program">
<Directory Id="ProgramPluginFolder" Name="Microsoft.Plugin.Program">
<Directory Id="ProgramImagesFolder" Name="Images" />
<Directory Id="ProgramLanguagesFolder" Name="Languages" />
</Directory>
<Directory Id="ShellPluginFolder" Name="Shell">
<Directory Id="ShellPluginFolder" Name="Microsoft.Plugin.Shell">
<Directory Id="ShellImagesFolder" Name="Images" />
<Directory Id="ShellLanguagesFolder" Name="Languages" />
</Directory>
<Directory Id="IndexerPluginFolder" Name="Indexer">
<Directory Id="IndexerPluginFolder" Name="Microsoft.Plugin.Indexer">
<Directory Id="IndexerImagesFolder" Name="Images" />
<Directory Id="IndexerLanguagesFolder" Name="Languages" />
</Directory>
<Directory Id="UriPluginFolder" Name="Uri">
<Directory Id="UriPluginFolder" Name="Microsoft.Plugin.Uri">
<Directory Id="UriImagesFolder" Name="Images" />
<Directory Id="UriLanguagesFolder" Name="Languages" />
</Directory>
<Directory Id="UnitConverterPluginFolder" Name="UnitConverter">
<Directory Id="UnitConverterPluginFolder" Name="Community.UnitConverter">
<Directory Id="UnitConverterImagesFolder" Name="Images" />
<Directory Id="UnitConverterLanguagesFolder" Name="Languages" />
</Directory>
@ -344,24 +310,21 @@
<Directory Id="VSCodeWorkspaceImagesFolder" Name="Images" />
<Directory Id="VSCodeWorkspaceLanguagesFolder" Name="Languages" />
</Directory>
<Directory Id="WindowWalkerPluginFolder" Name="WindowWalker">
<Directory Id="WindowWalkerPluginFolder" Name="Microsoft.Plugin.WindowWalker">
<Directory Id="WindowWalkerImagesFolder" Name="Images" />
<Directory Id="WindowWalkerLanguagesFolder" Name="Languages" />
</Directory>
<Directory Id="RegistryPluginFolder" Name="Registry">
<Directory Id="RegistryPluginFolder" Name="Microsoft.PowerToys.Run.Plugin.Registry">
<Directory Id="RegistryImagesFolder" Name="Images" />
<Directory Id="RegistryLanguagesFolder" Name="Languages" />
</Directory>
<Directory Id="ServicePluginFolder" Name="Service">
<Directory Id="ServiceImagesFolder" Name="Images" />
</Directory>
<Directory Id="WindowsTerminalPluginFolder" Name="WindowsTerminal">
<Directory Id="WindowsTerminalImagesFolder" Name="Images" />
</Directory>
<Directory Id="SystemPluginFolder" Name="System">
<Directory Id="SystemImagesFolder" Name="Images" />
</Directory>
<Directory Id="WindowsSettingsPluginFolder" Name="WindowsSettings">
<Directory Id="WindowsSettingsPluginFolder" Name="Microsoft.PowerToys.Run.Plugin.WindowsSettings">
<Directory Id="WindowsSettingsImagesFolder" Name="Images" />
<Directory Id="WindowsSettingsLanguagesFolder" Name="Languages" />
</Directory>
@ -514,7 +477,109 @@
<DirectoryRef Id="ModulesInstallFolder" FileSource="$(var.BinX64Dir)modules\">
<Component Id="Module_PowerPreview_Registry" Guid="CD90ADC0-7CD5-4A62-B0AF-23545C1E6DD3" Win64="yes">
<Component Id="Module_PowerPreview_PerUserRegistry" Guid="CD90ADC0-7CD5-4A62-B0AF-23545C1E6DD3" Win64="yes">
<!-- Added a separate component for Per-User registry changes -->
<!-- Registry Key for Class Registration of Svg Preview Handler -->
<RegistryKey Root="HKCR" Key="CLSID\{ddee2b8a-6807-48a6-bb20-2338174ff779}">
<RegistryValue Type="string" Value="Microsoft.PowerToys.PreviewHandler.Svg.SvgPreviewHandler" />
<RegistryValue Type="string" Name="DisplayName" Value="Svg Preview Handler" />
<RegistryValue Type="string" Name="AppID" Value="{CF142243-F059-45AF-8842-DBBE9783DB14}" />
<RegistryValue Type="string" Key="Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Value=""/>
<RegistryValue Type="string" Key="InprocServer32" Value="[FileExplorerPreviewInstallFolder]SvgPreviewHandler.comhost.dll" />
<RegistryValue Type="string" Key="InprocServer32" Name="Assembly" Value="SvgPreviewHandler, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32" Name="Class" Value="Microsoft.PowerToys.PreviewHandler.Svg.SvgPreviewHandler" />
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Both" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Assembly" Value="SvgPreviewHandler, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Class" Value="Microsoft.PowerToys.PreviewHandler.Svg.SvgPreviewHandler" />
</RegistryKey>
<!-- Registry Key for Class Registration of Svg Thumbnail Provider -->
<RegistryKey Root="HKCR" Key="CLSID\{36B27788-A8BB-4698-A756-DF9F11F64F84}">
<RegistryValue Type="string" Value="Microsoft.PowerToys.ThumbnailHandler.Svg.SvgThumbnailProvider" />
<RegistryValue Type="string" Name="DisplayName" Value="Svg Thumbnail Provider" />
<RegistryValue Type="string" Name="AppID" Value="{CF142243-F059-45AF-8842-DBBE9783DB14}" />
<RegistryValue Type="string" Key="Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Value=""/>
<RegistryValue Type="string" Key="InprocServer32" Value="[FileExplorerPreviewInstallFolder]SvgThumbnailProvider.comhost.dll" />
<RegistryValue Type="string" Key="InprocServer32" Name="Assembly" Value="SvgThumbnailProvider, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32" Name="Class" Value="Microsoft.PowerToys.ThumbnailHandler.Svg.SvgThumbnailProvider" />
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Both" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Assembly" Value="SvgThumbnailProvider, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Class" Value="Microsoft.PowerToys.ThumbnailHandler.Svg.SvgThumbnailProvider" />
</RegistryKey>
<!-- Registry Key for Class Registration of Markdown Preview Handler -->
<RegistryKey Root="HKCR" Key="CLSID\{45769bcc-e8fd-42d0-947e-02beef77a1f5}">
<RegistryValue Type="string" Value="Microsoft.PowerToys.PreviewHandler.Markdown.MarkdownPreviewHandler" />
<RegistryValue Type="string" Name="DisplayName" Value="Markdown Preview Handler" />
<RegistryValue Type="string" Name="AppID" Value="{CF142243-F059-45AF-8842-DBBE9783DB14}" />
<RegistryValue Type="string" Key="Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Value="" />
<RegistryValue Type="string" Key="InprocServer32" Value="[FileExplorerPreviewInstallFolder]MarkdownPreviewHandler.comhost.dll" />
<RegistryValue Type="string" Key="InprocServer32" Name="Assembly" Value="MarkdownPreviewHandler, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32" Name="Class" Value="Microsoft.PowerToys.PreviewHandler.Markdown.MarkdownPreviewHandler" />
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Both" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Assembly" Value="MarkdownPreviewHandler, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Class" Value="Microsoft.PowerToys.PreviewHandler.Markdown.MarkdownPreviewHandler" />
</RegistryKey>
<!-- Registry Key for Class Registration of Pdf Preview Handler -->
<RegistryKey Root="HKCR" Key="CLSID\{07665729-6243-4746-95b7-79579308d1b2}">
<RegistryValue Type="string" Value="Microsoft.PowerToys.PreviewHandler.Pdf.PdfPreviewHandler" />
<RegistryValue Type="string" Name="DisplayName" Value="Pdf Preview Handler" />
<RegistryValue Type="string" Name="AppID" Value="{CF142243-F059-45AF-8842-DBBE9783DB14}" />
<RegistryValue Type="string" Key="Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Value="" />
<RegistryValue Type="string" Key="InprocServer32" Value="[FileExplorerPreviewInstallFolder]PdfPreviewHandler.comhost.dll" />
<RegistryValue Type="string" Key="InprocServer32" Name="Assembly" Value="PdfPreviewHandler, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32" Name="Class" Value="Microsoft.PowerToys.PreviewHandler.Pdf.PdfPreviewHandler" />
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Both" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Assembly" Value="PdfPreviewHandler, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Class" Value="Microsoft.PowerToys.PreviewHandler.Pdf.PdfPreviewHandler" />
</RegistryKey>
<!-- Registry Key for Class Registration of Pdf Thumbnail Provider -->
<RegistryKey Root="HKCR" Key="CLSID\{BCC13D15-9720-4CC4-8371-EA74A274741E}">
<RegistryValue Type="string" Value="Microsoft.PowerToys.ThumbnailHandler.Pdf.PdfThumbnailProvider" />
<RegistryValue Type="string" Name="DisplayName" Value="Pdf Thumbnail Provider" />
<RegistryValue Type="string" Name="AppID" Value="{CF142243-F059-45AF-8842-DBBE9783DB14}" />
<RegistryValue Type="string" Key="Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Value=""/>
<RegistryValue Type="string" Key="InprocServer32" Value="[FileExplorerPreviewInstallFolder]PdfThumbnailProvider.comhost.dll" />
<RegistryValue Type="string" Key="InprocServer32" Name="Assembly" Value="PdfThumbnailProvider, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32" Name="Class" Value="Microsoft.PowerToys.ThumbnailHandler.Pdf.PdfThumbnailProvider" />
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Both" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Assembly" Value="PdfThumbnailProvider, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Class" Value="Microsoft.PowerToys.ThumbnailHandler.Pdf.PdfThumbnailProvider" />
</RegistryKey>
<!-- Registry Key for AppID registration -->
<RegistryKey Root="HKCR" Key="AppID\{CF142243-F059-45AF-8842-DBBE9783DB14}">
<RegistryValue Type="expandable" Name="DllSurrogate" Value="%SystemRoot%\system32\prevhost.exe" />
</RegistryKey>
<!-- Add Svg preview handler to preview handlers list -->
<RegistryKey Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\PreviewHandlers">
<RegistryValue Type="string" Name="{ddee2b8a-6807-48a6-bb20-2338174ff779}" Value="Svg Preview Handler" />
</RegistryKey>
<!-- Add Markdown preview handler to preview handlers list -->
<RegistryKey Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\PreviewHandlers">
<RegistryValue Type="string" Name="{45769bcc-e8fd-42d0-947e-02beef77a1f5}" Value="Markdown Preview Handler" />
</RegistryKey>
<!-- Add Pdf preview handler to preview handlers list -->
<RegistryKey Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\PreviewHandlers">
<RegistryValue Type="string" Name="{07665729-6243-4746-95b7-79579308d1b2}" Value="Pdf Preview Handler" />
</RegistryKey>
<!-- Add file type association for Svg Preview Handler -->
<RegistryKey Root="HKCR" Key=".svg\shellex">
<RegistryValue Type="string" Key="{8895b1c6-b41f-4c1c-a562-0d564250836f}" Value="{ddee2b8a-6807-48a6-bb20-2338174ff779}" />
</RegistryKey>
<!-- Add file type association for Svg Thumbnail Provider -->
<RegistryKey Root="HKCR" Key=".svg\shellex">
<RegistryValue Type="string" Key="{E357FCCD-A995-4576-B01F-234630154E96}" Value="{36B27788-A8BB-4698-A756-DF9F11F64F84}" />
</RegistryKey>
<!-- Add file type association for Markdown Preview Handler -->
<RegistryKey Root="HKCR" Key=".md\shellex">
<RegistryValue Type="string" Key="{8895b1c6-b41f-4c1c-a562-0d564250836f}" Value="{45769bcc-e8fd-42d0-947e-02beef77a1f5}" />
</RegistryKey>
<!-- Add file type association for Pdf Preview Handler -->
<RegistryKey Root="HKCR" Key=".pdf\shellex">
<RegistryValue Type="string" Key="{8895b1c6-b41f-4c1c-a562-0d564250836f}" Value="{07665729-6243-4746-95b7-79579308d1b2}" />
</RegistryKey>
<!-- Add file type association for Pdf Thumbnail Provider -->
<RegistryKey Root="HKCR" Key=".pdf\shellex">
<RegistryValue Type="string" Key="{E357FCCD-A995-4576-B01F-234630154E96}" Value="{BCC13D15-9720-4CC4-8371-EA74A274741E}" />
</RegistryKey>
<!-- Update Key to use IE11 for prevhost.exe -->
<RegistryKey Root="HKLM" Key="Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION">
<RegistryValue Type="integer" Name="prevhost.exe" Value="11000" />
@ -621,19 +686,7 @@
<!-- PowerRename -->
<DirectoryRef Id="PowerRenameInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)">
<Component Id="Module_PowerRename" Guid="E4401D08-27FE-4F96-BA17-0C61FD79E684" Win64="yes">
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\Microsoft.Toolkit.Win32.UI.XamlHost.dll" />
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\Microsoft.UI.Xaml.dll" />
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\msvcp140_app.dll" />
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\PowerRenameUILib.dll" />
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\PowerRename.exe" />
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\resources.pri" />
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\vcruntime140_1_app.dll" />
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\vcruntime140_app.dll" />
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\PowerRenameExt.dll" KeyPath="yes" />
<!-- VCRuntime -->
<?foreach File in vcruntime140.dll;vcruntime140_1.dll;concrt140.dll;msvcp140.dll;msvcp140_1.dll;msvcp140_2.dll;msvcp140_codecvt_ids.dll;vccorlib140.dll?>
<File Id="PowerRename_$(var.File)" Source="$(var.RepoDir)installer\VCRuntime\$(var.File)" />
<?endforeach?>
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\PowerRenameExt.dll" KeyPath="yes" />
<RegistryKey Root="HKCR" Key="CLSID\{0440049F-D1DC-4E46-B27B-98393D79486B}">
<RegistryValue Type="string" Value="PowerRename Shell Extension" />
<RegistryValue Type="string" Name="ContextMenuOptIn" Value="" />
@ -646,22 +699,6 @@
</Component>
</DirectoryRef>
<DirectoryRef Id="PowerRenameAssetsFolder" FileSource="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)">
<Component Id="Module_PowerRename_Assets" Guid="5976BEDF-64F5-4836-8674-EE7577C77508" Win64="yes">
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\Assets\file.png" />
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\Assets\folder.png" />
</Component>
</DirectoryRef>
<!-- MouseUtils -->
<DirectoryRef Id="MouseUtilsInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.MouseUtilsProjectName)">
<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 -->
<DirectoryRef Id="ShortcutGuideModuleInterfaceInstallFolder" FileSource="$(var.ShortcutGuideModuleInterface)">
<Component Id="Module_ShortcutGuideModuleInterface" Guid="CBD0AC09-91D3-428E-B2B3-05745ADF3473" Win64="yes">
@ -863,21 +900,21 @@
</DirectoryRef>
<DirectoryRef Id="SettingsV2AssetsModulesInstallFolder" FileSource="$(var.BinX64Dir)Settings\Assets\Modules">
<Component Id="SettingsV2AssetsModules" Guid="A0B961A9-77D0-4223-88A9-E3B41BD9C329" Win64="yes">
<?foreach File in ColorPicker.png;FancyZones.png;Awake.png;ImageResizer.png;KBM.png;MouseUtils.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ShortcutGuide.png;VideoConference.png?>
<?foreach File in ColorPicker.png;FancyZones.png;Awake.png;ImageResizer.png;KBM.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ShortcutGuide.png;VideoConference.png?>
<File Id="SettingsV2AssetsModules_$(var.File)" Source="$(var.BinX64Dir)Settings\Assets\Modules\$(var.File)" />
<?endforeach?>
</Component>
</DirectoryRef>
<DirectoryRef Id="SettingsV2OOBEAssetsModulesInstallFolder" FileSource="$(var.BinX64Dir)Settings\Assets\Modules\OOBE">
<Component Id="SettingsV2OOBEAssetsModules" Guid="E2360A83-6694-4B33-B5F6-641A906359EE" Win64="yes">
<?foreach File in ColorPicker.gif;Awake.png;FancyZones.gif;FileExplorer.png;ImageResizer.gif;KBM.gif;MouseUtils.gif;PowerRename.gif;Run.gif;OOBEShortcutGuide.png;VideoConferenceMute.png;OOBEPTHero.png?>
<?foreach File in ColorPicker.gif;Awake.png;FancyZones.gif;FileExplorer.png;ImageResizer.gif;KBM.gif;PowerRename.gif;Run.gif;OOBEShortcutGuide.png;VideoConferenceMute.png;OOBEPTHero.png?>
<File Id="SettingsV2OOBEAssetsModules_$(var.File)" Source="$(var.BinX64Dir)Settings\Assets\Modules\OOBE\$(var.File)" />
<?endforeach?>
</Component>
</DirectoryRef>
<DirectoryRef Id="SettingsV2OOBEAssetsFluentIconsInstallFolder" FileSource="$(var.BinX64Dir)Settings\Assets\FluentIcons">
<Component Id="SettingsV2OOBEAssetsFluentIcons" Guid="6A380D5A-DA63-45B5-B68F-06D57CDD1B9C" Win64="yes">
<?foreach File in ColorPicker.png;FancyZones.png;Awake.png;FileExplorerPreview.png;ImageResizer.png;KeyboardManager.png;MouseUtils.png;PowerRename.png;PowerToys.png;PowerToysRun.png;Settings.png;ShortcutGuide.png;VideoConferenceMute.png ?>
<?foreach File in ColorPicker.png;FancyZones.png;Awake.png;FileExplorerPreview.png;ImageResizer.png;KeyboardManager.png;PowerRename.png;PowerToys.png;PowerToysRun.png;Settings.png;ShortcutGuide.png;VideoConferenceMute.png ?>
<File Id="SettingsV2OOBEAssetsFluentIcons_$(var.File)" Source="$(var.BinX64Dir)Settings\Assets\FluentIcons\FluentIcons$(var.File)" />
<?endforeach?>
</Component>
@ -959,11 +996,10 @@
<ComponentRef Id="Module_FancyZones" />
<ComponentRef Id="DesktopShortcut" />
<ComponentRef Id="Module_PowerRename" />
<ComponentRef Id="Module_PowerRename_Assets" />
<ComponentRef Id="Module_ImageResizer" />
<ComponentRef Id="Module_ImageResizer_Registry" />
<ComponentRef Id="Module_PowerPreview" />
<ComponentRef Id="Module_PowerPreview_Registry" />
<ComponentRef Id="Module_PowerPreview_PerUserRegistry" />
<ComponentRef Id="Module_KeyboardManager" />
<ComponentRef Id="Module_KeyboardManager_Editor" />
<ComponentRef Id="Module_KeyboardManager_Engine" />
@ -973,8 +1009,6 @@
<ComponentRef Id="Module_Awake_runtime_netstandard20"/>
<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" />
@ -998,7 +1032,7 @@
<Fragment>
<!-- Resource directories should be added only if the installer is built on the build farm -->
<?ifdef env.IsPipeline?>
<?foreach ParentDirectory in LauncherInstallFolder;FancyZonesInstallFolder;ImageResizerInstallFolder;ColorPickerInstallFolder;FileExplorerPreviewInstallFolder;CalculatorPluginFolder;FolderPluginFolder;ProgramPluginFolder;ShellPluginFolder;IndexerPluginFolder;UnitConverterPluginFolder;UriPluginFolder;WindowWalkerPluginFolder;RegistryPluginFolder;VSCodeWorkspacesPluginFolder;ServicePluginFolder;SystemPluginFolder;WindowsSettingsPluginFolder;WindowsTerminalPluginFolder?>
<?foreach ParentDirectory in LauncherInstallFolder;FancyZonesInstallFolder;ImageResizerInstallFolder;ColorPickerInstallFolder;FileExplorerPreviewInstallFolder;CalculatorPluginFolder;FolderPluginFolder;ProgramPluginFolder;ShellPluginFolder;IndexerPluginFolder;UnitConverterPluginFolder;UriPluginFolder;WindowWalkerPluginFolder;RegistryPluginFolder;VSCodeWorkspacesPluginFolder;ServicePluginFolder;SystemPluginFolder;WindowsSettingsPluginFolder?>
<DirectoryRef Id="$(var.ParentDirectory)">
<!-- Resource file directories -->
<?foreach Language in $(var.LocLanguageList)?>
@ -1063,28 +1097,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\Folder\$(var.Language)\Microsoft.Plugin.Folder.resources.dll" />
<File Id="Launcher_Folder_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.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\Program\$(var.Language)\Microsoft.Plugin.Program.resources.dll" />
<File Id="Launcher_Program_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.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\Shell\$(var.Language)\Microsoft.Plugin.Shell.resources.dll" />
<File Id="Launcher_Shell_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.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\Indexer\$(var.Language)\Microsoft.Plugin.Indexer.resources.dll" />
<File Id="Launcher_Indexer_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.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\Uri\$(var.Language)\Microsoft.Plugin.Uri.resources.dll" />
<File Id="Launcher_Uri_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.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\WindowWalker\$(var.Language)\Microsoft.Plugin.WindowWalker.resources.dll" />
<File Id="Launcher_WindowWalker_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.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\Registry\$(var.Language)\Microsoft.PowerToys.Run.Plugin.Registry.resources.dll" />
<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" />
</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" />
@ -1093,13 +1127,8 @@
<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\WindowsSettings\$(var.Language)\Microsoft.PowerToys.Run.Plugin.WindowsSettings.resources.dll" />
<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" />
</Component>
<!-- Uncomment after Plugin receives the localization files.
<Component Id="Launcher_WindowsTerminal_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)WindowsTerminalFolder">
<File Id="Launcher_WindowsTerminal_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowsTerminal\$(var.Language)\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.resources.dll" />
</Component>
-->
<?undef IdSafeLanguage?>
<?endforeach?>
<?endif?>
@ -1147,71 +1176,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\Folder\$(var.File)" />
<File Id="Folder_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.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\Folder\Images\$(var.File)" />
<File Id="FolderPlugin_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.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\Program\$(var.File)" />
<File Id="Program_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.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\Program\Images\$(var.File)" />
<File Id="Program_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.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\Shell\$(var.File)" />
<File Id="Shell_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.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\Shell\Images\$(var.File)" />
<File Id="Shell_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.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\Indexer\$(var.File)" />
<File Id="Indexer_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.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\Indexer\Images\$(var.File)" />
<File Id="Indexer_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.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\UnitConverter\$(var.File)" />
<File Id="UnitConverter_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Community.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\UnitConverter\Images\unitconverter.light.png" />
<File Id="UnitConverterDark" Source="$(var.BinX64Dir)modules\launcher\Plugins\UnitConverter\Images\unitconverter.dark.png" />
<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" />
</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\Uri\$(var.File)" />
<File Id="Uri_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.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\Uri\Images\Uri.dark.png" />
<File Id="UriLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Uri\Images\Uri.light.png" />
<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" />
</Component>
<!-- VSCodeWorkspaces Plugin -->
@ -1231,23 +1260,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\WindowWalker\$(var.File)" />
<File Id="WindowWalker_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.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\WindowWalker\Images\windowwalker.dark.png" />
<File Id="WindowWalkerLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowWalker\Images\windowwalker.light.png" />
<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" />
</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\Registry\$(var.File)" />
<File Id="Registry_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.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\Registry\Images\reg.dark.png" />
<File Id="RegistryLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Registry\Images\reg.light.png" />
<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" />
</Component>
<!-- Service Plugin -->
@ -1285,25 +1314,14 @@
<!-- 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\WindowsSettings\$(var.File)" />
<File Id="WindowsSettings_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.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\WindowsSettings\Images\WindowsSettings.dark.png" />
<File Id="WindowsSettingsLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowsSettings\Images\WindowsSettings.light.png" />
<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" />
</Component>
<!-- WindowsTerminal Plugin -->
<Component Id="WindowsTerminalComponent" Directory="WindowsTerminalPluginFolder" Guid="5392FD11-9A69-4409-A711-748C225F1A18">
<?foreach File in plugin.json;Microsoft.PowerToys.Run.Plugin.WindowsTerminal.deps.json;Microsoft.PowerToys.Run.Plugin.WindowsTerminal.dll;ManagedTelemetry.dll?>
<File Id="WindowsTerminal_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowsTerminal\$(var.File)" />
<?endforeach?>
</Component>
<Component Id="WindowsTerminalImagesComponent" Directory="WindowsTerminalImagesFolder" Guid="CDD21BEB-E2F3-4138-A1F8-72FD3B52706A">
<File Id="WindowsTerminalDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowsTerminal\Images\WindowsTerminal.dark.png" />
<File Id="WindowsTerminalLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowsTerminal\Images\WindowsTerminal.light.png" />
</Component>
</ComponentGroup>
</Fragment>
</Wix>

View file

@ -2,11 +2,7 @@
#include "resource.h"
#include <ProjectTelemetry.h>
#include <spdlog/sinks/base_sink.h>
#include "../../src/common/logger/logger.h"
#include "../../src/common/utils/MsiUtils.h"
#include "../../src/common/utils/modulesRegistry.h"
#include "../../src/common/updating/installer.h"
#include "../../src/common/version/version.h"
@ -29,94 +25,6 @@ const DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0'
static const wchar_t* POWERTOYS_EXE_COMPONENT = L"{A2C66D91-3485-4D00-B04D-91844E6B345B}";
static const wchar_t* POWERTOYS_UPGRADE_CODE = L"{42B84BF7-5FBF-473B-9C8B-049DC16F7708}";
struct WcaSink : spdlog::sinks::base_sink<std::mutex>
{
virtual void sink_it_(const spdlog::details::log_msg& msg) override
{
WcaLog(LOGMSG_STANDARD, msg.payload.data());
}
virtual void flush_() override
{
// we don't need to flush wca log manually
}
};
void initSystemLogger()
{
static std::once_flag initLoggerFlag;
std::call_once(initLoggerFlag, []() { Logger::init(std::vector<spdlog::sink_ptr>{ std::make_shared<WcaSink>() }); });
}
HRESULT getInstallFolder(MSIHANDLE hInstall, std::wstring& installationDir)
{
DWORD len = 0;
wchar_t _[1];
MsiGetPropertyW(hInstall, L"CustomActionData", _, &len);
len += 1;
installationDir.resize(len);
HRESULT hr = MsiGetPropertyW(hInstall, L"CustomActionData", installationDir.data(), &len);
if (installationDir.length())
{
installationDir.resize(installationDir.length() - 1);
}
ExitOnFailure(hr, "Failed to get INSTALLFOLDER property.");
LExit:
return hr;
}
UINT __stdcall ApplyModulesRegistryChangeSetsCA(MSIHANDLE hInstall)
{
initSystemLogger();
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
std::wstring installationFolder;
bool failedToApply = false;
hr = WcaInitialize(hInstall, "ApplyModulesRegistryChangeSets");
ExitOnFailure(hr, "Failed to initialize");
hr = getInstallFolder(hInstall, installationFolder);
ExitOnFailure(hr, "Failed to get installFolder.");
for (const auto& changeSet : getAllModulesChangeSets(installationFolder, false))
{
if (!changeSet.apply())
{
WcaLog(LOGMSG_STANDARD, "Couldn't apply registry changeSet");
failedToApply = true;
}
}
if (!failedToApply)
{
WcaLog(LOGMSG_STANDARD, "All registry changeSets applied successfully");
}
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall UnApplyModulesRegistryChangeSetsCA(MSIHANDLE hInstall)
{
initSystemLogger();
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
std::wstring installationFolder;
hr = WcaInitialize(hInstall, "UndoModulesRegistryChangeSets"); // original func name is too long
ExitOnFailure(hr, "Failed to initialize");
hr = getInstallFolder(hInstall, installationFolder);
ExitOnFailure(hr, "Failed to get installFolder.");
for (const auto& changeSet : getAllModulesChangeSets(installationFolder, false))
{
changeSet.unApply();
}
ExitOnFailure(hr, "Failed to extract msix");
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall InstallEmbeddedMSIXCA(MSIHANDLE hInstall)
{
HRESULT hr = S_OK;

View file

@ -1,7 +1,6 @@
LIBRARY "PowerToysSetupCustomActions"
EXPORTS
ApplyModulesRegistryChangeSetsCA
CreateScheduledTaskCA
DetectPrevInstallPathCA
RemoveScheduledTasksCA
@ -18,6 +17,5 @@ EXPORTS
CertifyVirtualCameraDriverCA
InstallVirtualCameraDriverCA
InstallEmbeddedMSIXCA
UnApplyModulesRegistryChangeSetsCA
UninstallVirtualCameraDriverCA
UninstallEmbeddedMSIXCA

View file

@ -30,7 +30,6 @@
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="..\..\deps\spdlog.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
@ -123,11 +122,6 @@
<ItemGroup>
<ResourceCompile Include="Resource.rc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\common\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

View file

@ -27,7 +27,6 @@
#include <psapi.h>
#include <vector>
#include <array>
#include <mutex>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>

View file

@ -1,3 +1,3 @@
# PowerToys installer instructions
Please go to https://github.com/microsoft/PowerToys/tree/main/doc/devdocs#compile-the-installer for instructions
Please go to https://github.com/microsoft/PowerToys/tree/master/doc/devdocs#compile-the-installer for instructions

View file

@ -1,80 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.IO;
namespace Microsoft.PowerToys.Common.UI
{
public static class SettingsDeepLink
{
public enum SettingsWindow
{
Overview = 0,
Awake,
ColorPicker,
FancyZones,
Run,
ImageResizer,
KBM,
MouseUtils,
PowerRename,
FileExplorer,
ShortcutGuide,
VideoConference,
}
private static string SettingsWindowNameToString(SettingsWindow value)
{
switch (value)
{
case SettingsWindow.Overview:
return "Overview";
case SettingsWindow.Awake:
return "Awake";
case SettingsWindow.ColorPicker:
return "ColorPicker";
case SettingsWindow.FancyZones:
return "FancyZones";
case SettingsWindow.Run:
return "Run";
case SettingsWindow.ImageResizer:
return "ImageResizer";
case SettingsWindow.KBM:
return "KBM";
case SettingsWindow.MouseUtils:
return "MouseUtils";
case SettingsWindow.PowerRename:
return "PowerRename";
case SettingsWindow.FileExplorer:
return "FileExplorer";
case SettingsWindow.ShortcutGuide:
return "ShortcutGuide";
case SettingsWindow.VideoConference:
return "VideoConference";
default:
{
return string.Empty;
}
}
}
public static void OpenSettings(SettingsWindow window)
{
try
{
var assemblyPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
var fullPath = Directory.GetParent(assemblyPath).FullName;
Process.Start(new ProcessStartInfo(fullPath + "\\..\\PowerToys.exe") { Arguments = "--open-settings=" + SettingsWindowNameToString(window) });
}
#pragma warning disable CA1031 // Do not catch general exception types
catch
#pragma warning restore CA1031 // Do not catch general exception types
{
// TODO(stefan): Log exception once unified logging is implemented
}
}
}
}

View file

@ -313,7 +313,7 @@ namespace PowerToysSettings
return json::has(props, name) && json::has(props.GetNamedObject(name), L"value", type);
}
std::optional<bool> PowerToyValues::get_bool_value(std::wstring_view property_name) const
std::optional<bool> PowerToyValues::get_bool_value(std::wstring_view property_name)
{
if (!has_property(m_json, property_name, json::JsonValueType::Boolean))
{
@ -322,7 +322,7 @@ namespace PowerToysSettings
return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedBoolean(L"value");
}
std::optional<int> PowerToyValues::get_int_value(std::wstring_view property_name) const
std::optional<int> PowerToyValues::get_int_value(std::wstring_view property_name)
{
if (!has_property(m_json, property_name, json::JsonValueType::Number))
{
@ -331,7 +331,7 @@ namespace PowerToysSettings
return static_cast<int>(m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedNumber(L"value"));
}
std::optional<std::wstring> PowerToyValues::get_string_value(std::wstring_view property_name) const
std::optional<std::wstring> PowerToyValues::get_string_value(std::wstring_view property_name)
{
if (!has_property(m_json, property_name, json::JsonValueType::String))
{
@ -340,7 +340,7 @@ namespace PowerToysSettings
return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedString(L"value").c_str();
}
std::optional<json::JsonObject> PowerToyValues::get_json(std::wstring_view property_name) const
std::optional<json::JsonObject> PowerToyValues::get_json(std::wstring_view property_name)
{
if (!has_property(m_json, property_name, json::JsonValueType::Object))
{

View file

@ -79,10 +79,10 @@ namespace PowerToysSettings
m_json.GetNamedObject(L"properties").SetNamedValue(name, prop_value);
}
std::optional<bool> get_bool_value(std::wstring_view property_name) const;
std::optional<int> get_int_value(std::wstring_view property_name) const;
std::optional<std::wstring> get_string_value(std::wstring_view property_name) const;
std::optional<json::JsonObject> get_json(std::wstring_view property_name) const;
std::optional<bool> get_bool_value(std::wstring_view property_name);
std::optional<int> get_int_value(std::wstring_view property_name);
std::optional<std::wstring> get_string_value(std::wstring_view property_name);
std::optional<json::JsonObject> get_json(std::wstring_view property_name);
json::JsonObject get_raw_json();
std::wstring serialize();

View file

@ -10,6 +10,5 @@
#define WIN32_LEAN_AND_MEAN
// add headers that you want to pre-compile here
#include <Windows.h>
#include <Endpointvolume.h>
#endif //PCH_H

View file

@ -3,7 +3,7 @@
#include "pch.h"
#include "framework.h"
#include "logger.h"
#include <unordered_map>
#include <map>
#include <spdlog/sinks/daily_file_sink.h>
#include <spdlog/sinks/msvc_sink.h>
#include <spdlog/sinks/null_sink.h>
@ -16,32 +16,26 @@ using spdlog::sinks::daily_file_sink_mt;
using spdlog::sinks::msvc_sink_mt;
using std::make_shared;
namespace
{
const std::unordered_map<std::wstring, level_enum> logLevelMapping = {
{ L"trace", level_enum::trace },
{ L"debug", level_enum::debug },
{ L"info", level_enum::info },
{ L"warn", level_enum::warn },
{ L"err", level_enum::err },
{ L"critical", level_enum::critical },
{ L"off", level_enum::off },
};
}
std::map<std::wstring, level_enum> logLevelMapping = {
{ L"trace", level_enum::trace },
{ L"debug", level_enum::debug },
{ L"info", level_enum::info },
{ L"warn", level_enum::warn },
{ L"err", level_enum::err },
{ L"critical", level_enum::critical },
{ L"off", level_enum::off },
};
level_enum getLogLevel(std::wstring_view logSettingsPath)
{
auto logLevel = get_log_settings(logSettingsPath).logLevel;
if (auto it = logLevelMapping.find(logLevel); it != logLevelMapping.end())
level_enum result = logLevelMapping[LogSettings::defaultLogLevel];
if (logLevelMapping.find(logLevel) != logLevelMapping.end())
{
return it->second;
result = logLevelMapping[logLevel];
}
if (auto it = logLevelMapping.find(LogSettings::defaultLogLevel); it != logLevelMapping.end())
{
return it->second;
}
return level_enum::trace;
return result;
}
std::shared_ptr<spdlog::logger> Logger::logger = spdlog::null_logger_mt("null");
@ -95,14 +89,3 @@ void Logger::init(std::string loggerName, std::wstring logFilePath, std::wstring
spdlog::flush_every(std::chrono::seconds(3));
logger->info("{} logger is initialized", loggerName);
}
void Logger::init(std::vector<spdlog::sink_ptr> sinks)
{
auto logger = std::make_shared<spdlog::logger>("", begin(sinks), end(sinks));
if (!logger)
{
return;
}
Logger::logger = logger;
}

View file

@ -13,7 +13,6 @@ public:
Logger() = delete;
static void init(std::string loggerName, std::wstring logFilePath, std::wstring_view logSettingsPath);
static void init(std::vector<spdlog::sink_ptr> sinks);
// log message should not be localized
template<typename FormatString, typename... Args>

View file

@ -31,14 +31,12 @@
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="call_tracer.h" />
<ClInclude Include="framework.h" />
<ClInclude Include="logger.h" />
<ClInclude Include="logger_settings.h" />
<ClInclude Include="pch.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="call_tracer.cpp" />
<ClCompile Include="logger.cpp" />
<ClCompile Include="logger_settings.cpp" />
<ClCompile Include="pch.cpp">
@ -52,6 +50,9 @@
<ProjectReference Include="..\..\logging\logging.vcxproj">
<Project>{7e1e3f13-2bd6-3f75-a6a7-873a2b55c60f}</Project>
</ProjectReference>
<ProjectReference Include="..\SettingsAPI\SetttingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View file

@ -27,9 +27,6 @@
<ClInclude Include="logger_settings.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="call_tracer.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="logger.cpp">
@ -41,9 +38,6 @@
<ClCompile Include="logger_settings.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="call_tracer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View file

@ -9,7 +9,7 @@ using namespace winrt::Windows::Data::Json;
LogSettings::LogSettings()
{
logLevel = defaultLogLevel;
this->logLevel = LogSettings::defaultLogLevel;
}
std::optional<JsonObject> from_file(std::wstring_view file_name)

View file

@ -13,8 +13,6 @@ struct LogSettings
inline const static std::wstring actionRunnerLogPath = L"RunnerLogs\\action-runner-log.txt";
inline const static std::string updateLoggerName = "update";
inline const static std::wstring updateLogPath = L"UpdateLogs\\update-log.txt";
inline const static std::string fileExplorerLoggerName = "FileExplorer";
inline const static std::wstring fileExplorerLogPath = L"Logs\\file-explorer-log.txt";
inline const static std::string launcherLoggerName = "launcher";
inline const static std::wstring launcherLogPath = L"LogsModuleInterface\\launcher-log.txt";
inline const static std::wstring awakeLogPath = L"Logs\\awake-log.txt";
@ -25,9 +23,6 @@ struct LogSettings
inline const static std::wstring shortcutGuideLogPath = L"ShortcutGuideLogs\\shortcut-guide-log.txt";
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;
LogSettings();

View file

@ -1,58 +0,0 @@
#pragma once
#include <shellapi.h>
class HDropIterator
{
public:
HDropIterator(IDataObject* pDataObject)
{
_current = 0;
FORMATETC formatetc = {
CF_HDROP,
NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL
};
pDataObject->GetData(&formatetc, &m_medium);
_listCount = DragQueryFile((HDROP)m_medium.hGlobal, 0xFFFFFFFF, NULL, 0);
}
~HDropIterator()
{
ReleaseStgMedium(&m_medium);
}
void First()
{
_current = 0;
}
void Next()
{
_current++;
}
bool IsDone() const
{
return _current >= _listCount;
}
LPTSTR CurrentItem() const
{
UINT cch = DragQueryFile((HDROP)m_medium.hGlobal, _current, NULL, 0) + 1;
LPTSTR pszPath = (LPTSTR)malloc(sizeof(TCHAR) * cch);
DragQueryFile((HDROP)m_medium.hGlobal, _current, pszPath, cch);
return pszPath;
}
private:
UINT _listCount;
STGMEDIUM m_medium;
UINT _current;
};

View file

@ -9,7 +9,10 @@
#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)
{
@ -61,15 +64,15 @@ static inline const char* exceptionDescription(const DWORD& code)
}
/* Returns the index of the last backslash in the file path */
inline int GetFilenameStart(wchar_t* path)
inline int GetFilenameStart(CHAR* path)
{
int pos = 0;
int found = 0;
if (path != NULL)
{
while (path[pos] != L'\0' && pos < MAX_PATH)
while (path[pos] != '\0' && pos < MAX_PATH)
{
if (path[pos] == L'\\')
if (path[pos] == '\\')
{
found = pos + 1;
}
@ -80,73 +83,22 @@ inline int GetFilenameStart(wchar_t* path)
return found;
}
inline std::wstring GetModuleName(HANDLE process, const STACKFRAME64& stack)
{
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(pSymbol, '\0', sizeof(*pSymbol) + MAX_PATH);
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()
{
BOOL result;
HANDLE thread;
HANDLE process;
CONTEXT context;
STACKFRAME64 stack;
ULONG frame;
DWORD64 dw64Displacement;
DWORD dwDisplacement;
memset(&stack, 0, sizeof(STACKFRAME64));
memset(pSymbol, '\0', sizeof(*pSymbol) + MAX_PATH);
memset(&modulePath[0], '\0', sizeof(modulePath));
line.LineNumber = 0;
try
{
RtlCaptureContext(&context);
@ -157,11 +109,9 @@ inline void LogStackTrace()
return;
}
STACKFRAME64 stack;
memset(&stack, 0, sizeof(STACKFRAME64));
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();
process = GetCurrentProcess();
thread = GetCurrentThread();
dw64Displacement = 0;
stack.AddrPC.Offset = context.Rip;
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrStack.Offset = context.Rsp;
@ -169,9 +119,8 @@ inline void LogStackTrace()
stack.AddrFrame.Offset = context.Rbp;
stack.AddrFrame.Mode = AddrModeFlat;
BOOL result = false;
std::wstringstream ss;
for (;;)
std::stringstream ss;
for (frame = 0;; frame++)
{
result = StackWalk64(
IMAGE_FILE_MACHINE_AMD64,
@ -189,10 +138,34 @@ inline void LogStackTrace()
break;
}
ss << GetModuleName(process, stack) << "!" << GetName(process, stack) << GetLine(process, stack) << std::endl;
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;
}
Logger::error(L"STACK TRACE\r\n{}", ss.str());
Logger::error("STACK TRACE\r\n{}", ss.str());
Logger::flush();
}
@ -245,6 +218,7 @@ 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))
{

View file

@ -1,21 +0,0 @@
#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;
}

View file

@ -1,12 +0,0 @@
#pragma once
#include <shellapi.h>
inline bool detect_game_mode()
{
QUERY_USER_NOTIFICATION_STATE notification_state;
if (SHQueryUserNotificationState(&notification_state) != S_OK)
{
return false;
}
return (notification_state == QUNS_RUNNING_D3D_FULL_SCREEN);
}

View file

@ -1,88 +0,0 @@
#pragma once
#include "registry.h"
#include <filesystem>
namespace fs = std::filesystem;
inline registry::ChangeSet getSvgPreviewHandlerChangeSet(const std::wstring installationDir, const bool perUser)
{
using namespace registry::shellex;
return generatePreviewHandler(PreviewHandlerType::preview,
perUser,
L"{ddee2b8a-6807-48a6-bb20-2338174ff779}",
get_std_product_version(),
(fs::path{ installationDir } /
LR"d(modules\FileExplorerPreview\SvgPreviewHandler.comhost.dll)d")
.wstring(),
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
L"Microsoft.PowerToys.PreviewHandler.Svg.SvgPreviewHandler",
L"Svg Preview Handler",
L".svg");
}
inline registry::ChangeSet getMdPreviewHandlerChangeSet(const std::wstring installationDir, const bool perUser)
{
using namespace registry::shellex;
return generatePreviewHandler(PreviewHandlerType::preview,
perUser,
L"{45769bcc-e8fd-42d0-947e-02beef77a1f5}",
get_std_product_version(),
(fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\MarkdownPreviewHandler.comhost.dll)d").wstring(),
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
L"Microsoft.PowerToys.PreviewHandler.Markdown.MarkdownPreviewHandler",
L"Markdown Preview Handler",
L".md");
}
inline registry::ChangeSet getPdfPreviewHandlerChangeSet(const std::wstring installationDir, const bool perUser)
{
using namespace registry::shellex;
return generatePreviewHandler(PreviewHandlerType::preview,
perUser,
L"{07665729-6243-4746-95b7-79579308d1b2}",
get_std_product_version(),
(fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PdfPreviewHandler.comhost.dll)d").wstring(),
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
L"Microsoft.PowerToys.PreviewHandler.Pdf.PdfPreviewHandler",
L"Pdf Preview Handler",
L".pdf");
}
inline registry::ChangeSet getSvgThumbnailHandlerChangeSet(const std::wstring installationDir, const bool perUser)
{
using namespace registry::shellex;
return generatePreviewHandler(PreviewHandlerType::thumbnail,
perUser,
L"{36B27788-A8BB-4698-A756-DF9F11F64F84}",
get_std_product_version(),
(fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\SvgThumbnailProvider.comhost.dll)d").wstring(),
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
L"Microsoft.PowerToys.ThumbnailHandler.Svg.SvgThumbnailProvider",
L"Svg Thumbnail Provider",
L".svg");
}
inline registry::ChangeSet getPdfThumbnailHandlerChangeSet(const std::wstring installationDir, const bool perUser)
{
using namespace registry::shellex;
return generatePreviewHandler(PreviewHandlerType::thumbnail,
perUser,
L"{BCC13D15-9720-4CC4-8371-EA74A274741E}",
get_std_product_version(),
(fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PdfThumbnailProvider.comhost.dll)d").wstring(),
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
L"Microsoft.PowerToys.ThumbnailHandler.Pdf.PdfThumbnailProvider",
L"Pdf Thumbnail Provider",
L".pdf");
}
inline std::vector<registry::ChangeSet> getAllModulesChangeSets(const std::wstring installationDir, const bool perUser)
{
return { getSvgPreviewHandlerChangeSet(installationDir, perUser),
getMdPreviewHandlerChangeSet(installationDir, perUser),
getPdfPreviewHandlerChangeSet(installationDir, perUser),
getSvgThumbnailHandlerChangeSet(installationDir, perUser),
getPdfThumbnailHandlerChangeSet(installationDir, perUser) };
}

View file

@ -1,382 +0,0 @@
#pragma once
#include <Windows.h>
#include <functional>
#include <string>
#include <variant>
#include <vector>
#include <optional>
#include <cassert>
#include <sstream>
#include "../logger/logger.h"
#include "../utils/winapi_error.h"
#include "../version/version.h"
namespace registry
{
namespace detail
{
struct on_exit
{
std::function<void()> f;
on_exit(std::function<void()> f) :
f{ std::move(f) } {}
~on_exit() { f(); }
};
template<class>
inline constexpr bool always_false_v = false;
template<class... Ts>
struct overloaded : Ts...
{
using Ts::operator()...;
};
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
inline const wchar_t* getScopeName(HKEY scope)
{
if (scope == HKEY_LOCAL_MACHINE)
{
return L"HKLM";
}
else if (scope == HKEY_CURRENT_USER)
{
return L"HKCU";
}
else if (scope == HKEY_CLASSES_ROOT)
{
return L"HKCR";
}
else
{
return L"HK??";
}
}
}
struct ValueChange
{
using value_t = std::variant<DWORD, std::wstring>;
static constexpr size_t VALUE_BUFFER_SIZE = 512;
HKEY scope{};
std::wstring path;
std::optional<std::wstring> name; // none == default
value_t value;
ValueChange(const HKEY scope, std::wstring path, std::optional<std::wstring> name, value_t value) :
scope{ scope }, path{ std::move(path) }, name{ std::move(name) }, value{ std::move(value) }
{
}
std::wstring toString() const
{
using namespace detail;
std::wstring value_str;
std::visit(overloaded{ [&](DWORD value) {
std::wostringstream oss;
oss << value;
value_str = oss.str();
},
[&](const std::wstring& value) { value_str = value; } },
value);
return fmt::format(L"{}\\{}\\{}:{}", detail::getScopeName(scope), path, name ? *name : L"Default", value_str);
}
bool isApplied() const
{
HKEY key{};
if (auto res = RegOpenKeyExW(scope, path.c_str(), 0, KEY_READ, &key); res != ERROR_SUCCESS)
{
Logger::info(L"isApplied of {}: RegOpenKeyExW failed: {}", toString(), get_last_error_or_default(res));
return false;
}
detail::on_exit closeKey{ [key] { RegCloseKey(key); } };
const DWORD expectedType = valueTypeToWinapiType(value);
DWORD retrievedType{};
wchar_t buffer[VALUE_BUFFER_SIZE];
DWORD valueSize = sizeof(buffer);
if (auto res = RegQueryValueExW(key,
name.has_value() ? name->c_str() : nullptr,
0,
&retrievedType,
reinterpret_cast<LPBYTE>(&buffer),
&valueSize);
res != ERROR_SUCCESS)
{
Logger::info(L"isApplied of {}: RegQueryValueExW failed: {}", toString(), get_last_error_or_default(res));
return false;
}
if (expectedType != retrievedType)
{
return false;
}
if (const auto retrievedValue = bufferToValue(buffer, valueSize, retrievedType))
{
return value == retrievedValue;
}
else
{
return false;
}
}
bool apply() const
{
HKEY key{};
if (auto res = RegCreateKeyExW(scope, path.c_str(), 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &key, nullptr); res !=
ERROR_SUCCESS)
{
Logger::error(L"apply of {}: RegCreateKeyExW failed: {}", toString(), get_last_error_or_default(res));
return false;
}
detail::on_exit closeKey{ [key] { RegCloseKey(key); } };
wchar_t buffer[VALUE_BUFFER_SIZE];
DWORD valueSize;
DWORD valueType;
valueToBuffer(value, buffer, valueSize, valueType);
if (auto res = RegSetValueExW(key,
name.has_value() ? name->c_str() : nullptr,
0,
valueType,
reinterpret_cast<BYTE*>(buffer),
valueSize);
res != ERROR_SUCCESS)
{
Logger::error(L"apply of {}: RegSetValueExW failed: {}", toString(), get_last_error_or_default(res));
return false;
}
return true;
}
bool unApply() const
{
HKEY key{};
if (auto res = RegOpenKeyExW(scope, path.c_str(), 0, KEY_ALL_ACCESS, &key); res != ERROR_SUCCESS)
{
Logger::error(L"unApply of {}: RegOpenKeyExW failed: {}", toString(), get_last_error_or_default(res));
return false;
}
detail::on_exit closeKey{ [key] { RegCloseKey(key); } };
// delete the value itself
if (auto res = RegDeleteKeyValueW(scope, path.c_str(), name.has_value() ? name->c_str() : nullptr); res != ERROR_SUCCESS)
{
Logger::error(L"unApply of {}: RegDeleteKeyValueW failed: {}", toString(), get_last_error_or_default(res));
return false;
}
// Check if the path doesn't contain anything and delete it if so
DWORD nValues = 0;
DWORD maxValueLen = 0;
const auto ok =
RegQueryInfoKeyW(
key, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, &nValues, nullptr, &maxValueLen, nullptr, nullptr) ==
ERROR_SUCCESS;
if (ok && (!nValues || !maxValueLen))
{
RegDeleteTreeW(scope, path.c_str());
}
return true;
}
bool requiresElevation() const { return scope == HKEY_LOCAL_MACHINE; }
private:
static DWORD valueTypeToWinapiType(const value_t& v)
{
return std::visit(
[](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, DWORD>)
return REG_DWORD;
else if constexpr (std::is_same_v<T, std::wstring>)
return REG_SZ;
else
static_assert(always_false_v<T>, "support for this registry type is not implemented");
},
v);
}
static void valueToBuffer(const value_t& value, wchar_t buffer[VALUE_BUFFER_SIZE], DWORD& valueSize, DWORD& type)
{
using detail::overloaded;
std::visit(overloaded{ [&](DWORD value) {
*reinterpret_cast<DWORD*>(buffer) = value;
type = REG_DWORD;
valueSize = sizeof(value);
},
[&](const std::wstring& value) {
assert(value.size() < VALUE_BUFFER_SIZE);
value.copy(buffer, value.size());
type = REG_SZ;
valueSize = static_cast<DWORD>(sizeof(wchar_t) * value.size());
} },
value);
}
static std::optional<value_t> bufferToValue(const wchar_t buffer[VALUE_BUFFER_SIZE],
const DWORD valueSize,
const DWORD type)
{
switch (type)
{
case REG_DWORD:
return *(DWORD*)buffer;
case REG_SZ:
{
if (!valueSize)
{
return std::wstring{};
}
std::wstring result{ buffer, valueSize / sizeof(wchar_t) };
while (result[result.size() - 1] == L'\0')
{
result.resize(result.size() - 1);
}
return result;
}
default:
return std::nullopt;
}
}
};
struct ChangeSet
{
std::vector<ValueChange> changes;
bool isApplied() const
{
for (const auto& c : changes)
{
if (!c.isApplied())
{
return false;
}
}
return true;
}
bool apply() const
{
bool ok = true;
for (const auto& c : changes)
{
ok = c.apply() && ok;
}
return ok;
}
bool unApply() const
{
bool ok = true;
for (const auto& c : changes)
{
ok = c.unApply() && ok;
}
return ok;
}
};
const inline std::wstring DOTNET_COMPONENT_CATEGORY_CLSID = L"{62C8FE65-4EBB-45E7-B440-6E39B2CDBF29}";
const inline std::wstring ITHUMBNAIL_PROVIDER_CLSID = L"{E357FCCD-A995-4576-B01F-234630154E96}";
const inline std::wstring IPREVIEW_HANDLER_CLSID = L"{8895b1c6-b41f-4c1c-a562-0d564250836f}";
namespace shellex
{
enum PreviewHandlerType
{
preview,
thumbnail
};
inline registry::ChangeSet generatePreviewHandler(const PreviewHandlerType handlerType,
const bool perUser,
std::wstring handlerClsid,
std::wstring powertoysVersion,
std::wstring fullPathToHandler,
std::wstring handlerCategory,
std::wstring className,
std::wstring displayName,
std::wstring fileType)
{
const HKEY scope = perUser ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
std::wstring clsidPath = L"Software\\Classes\\CLSID";
clsidPath += L'\\';
clsidPath += handlerClsid;
std::wstring inprocServerPath = clsidPath;
inprocServerPath += L'\\';
inprocServerPath += L"InprocServer32";
std::wstring implementedCategoriesPath = clsidPath + LR"d(\Implemented Categories\)d";
implementedCategoriesPath += handlerCategory;
std::wstring assemblyKeyValue;
if (const auto lastDotPos = className.rfind(L'.'); lastDotPos != std::wstring::npos)
{
assemblyKeyValue = className.substr(lastDotPos + 1);
}
else
{
assemblyKeyValue = className;
}
assemblyKeyValue += L", Version=";
assemblyKeyValue += powertoysVersion;
assemblyKeyValue += L", Culture=neutral";
std::wstring versionPath = inprocServerPath;
versionPath += L'\\';
versionPath += powertoysVersion;
std::wstring fileAssociationPath = L"Software\\Classes\\";
fileAssociationPath += fileType;
fileAssociationPath += L"\\shellex\\";
fileAssociationPath += handlerType == PreviewHandlerType::preview ? IPREVIEW_HANDLER_CLSID : ITHUMBNAIL_PROVIDER_CLSID;
using vec_t = std::vector<registry::ValueChange>;
// TODO: verify that we actually need all of those
vec_t changes = { { scope, clsidPath, L"DisplayName", displayName },
{ scope, clsidPath, std::nullopt, className },
{ scope, implementedCategoriesPath, std::nullopt, L"" },
{ scope, inprocServerPath, std::nullopt, fullPathToHandler },
{ scope, inprocServerPath, L"Assembly", assemblyKeyValue },
{ scope, inprocServerPath, L"Class", className },
{ scope, inprocServerPath, L"ThreadingModel", L"Both" },
{ scope, versionPath, L"Assembly", assemblyKeyValue },
{ scope, versionPath, L"Class", className },
{ scope, fileAssociationPath, std::nullopt, handlerClsid } };
if (handlerType == PreviewHandlerType::preview)
{
const std::wstring previewHostClsid = L"{6d2b5079-2f0b-48dd-ab7f-97cec514d30b}";
const std::wstring previewHandlerListPath = LR"(Software\Microsoft\Windows\CurrentVersion\PreviewHandlers)";
changes.push_back({ scope, clsidPath, L"AppID", previewHostClsid });
changes.push_back({ scope, previewHandlerListPath, handlerClsid, displayName });
}
return registry::ChangeSet{ .changes = std::move(changes) };
}
}
}

View file

@ -33,14 +33,5 @@ inline std::wstring get_product_version()
L"." + std::to_wstring(VERSION_MINOR) +
L"." + std::to_wstring(VERSION_REVISION);
return version;
}
inline std::wstring get_std_product_version()
{
static std::wstring version = L"v" + std::to_wstring(VERSION_MAJOR) +
L"." + std::to_wstring(VERSION_MINOR) +
L"." + std::to_wstring(VERSION_REVISION) + L".0";
return version;
}

View file

@ -1,5 +0,0 @@
<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 FindMyMouse.base.rc FindMyMouse.rc" />
</Target>
</Project>

View file

@ -1,915 +0,0 @@
// FindMyMouse.cpp : Based on Raymond Chen's SuperSonar.cpp
//
#include "pch.h"
#include "FindMyMouse.h"
#include "trace.h"
#include "common/utils/game_mode.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
#pragma region Super_Sonar_Base_Code
template<typename D>
struct SuperSonar
{
bool Initialize(HINSTANCE hinst);
void Terminate();
protected:
// You are expected to override these, as appropriate.
DWORD GetExtendedStyle()
{
return 0;
}
LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam) noexcept
{
return BaseWndProc(message, wParam, lParam);
}
void BeforeMoveSonar() {}
void AfterMoveSonar() {}
void SetSonarVisibility(bool visible) = delete;
protected:
// Base class members you can access.
D* Shim() { return static_cast<D*>(this); }
LRESULT BaseWndProc(UINT message, WPARAM wParam, LPARAM lParam) noexcept;
HWND m_hwnd;
POINT m_sonarPos = ptNowhere;
// Only consider double left control click if at least 100ms passed between the clicks, to avoid keyboards that might be sending rapid clicks.
// 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;
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:
static bool IsEqual(POINT const& p1, POINT const& p2)
{
return p1.x == p2.x && p1.y == p2.y;
}
static constexpr POINT ptNowhere = { -1, -1 };
static constexpr DWORD TIMER_ID_TRACK = 100;
static constexpr DWORD IdlePeriod = 1000;
// Activate sonar: Hit LeftControl twice.
enum class SonarState
{
Idle,
ControlDown1,
ControlUp1,
ControlDown2,
ControlUp2,
};
HWND m_hwndOwner;
SonarState m_sonarState = SonarState::Idle;
POINT m_lastKeyPos{};
DWORD m_lastKeyTime{};
static constexpr DWORD NoSonar = 0;
static constexpr DWORD SonarWaitingForMouseMove = 1;
DWORD m_sonarStart = NoSonar;
bool m_isSnoopingMouse = false;
private:
static constexpr auto className = L"FindMyMouse";
// Use the runner name for the Window title. Otherwise, since Find My Mouse has an actual visual, its Window name will be the one shown in Task Manager after being shown.
static constexpr auto windowTitle = L"PowerToys Runner";
static LRESULT CALLBACK s_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
BOOL OnSonarCreate();
void OnSonarDestroy();
void OnSonarInput(WPARAM flags, HRAWINPUT hInput);
void OnSonarKeyboardInput(RAWINPUT const& input);
void OnSonarMouseInput(RAWINPUT const& input);
void OnMouseTimer();
void StartSonar();
void StopSonar();
void UpdateMouseSnooping();
};
template<typename D>
bool SuperSonar<D>::Initialize(HINSTANCE hinst)
{
SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
WNDCLASS wc{};
if (!GetClassInfoW(hinst, className, &wc))
{
wc.lpfnWndProc = s_WndProc;
wc.hInstance = hinst;
wc.hIcon = LoadIcon(hinst, IDI_APPLICATION);
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
wc.lpszClassName = className;
if (!RegisterClassW(&wc))
{
return false;
}
}
m_hwndOwner = CreateWindow(L"static", nullptr, WS_POPUP, 0, 0, 0, 0, nullptr, nullptr, hinst, nullptr);
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;
}
template<typename D>
void SuperSonar<D>::Terminate()
{
auto dispatcherQueue = m_dispatcherQueueController.DispatcherQueue();
bool enqueueSucceeded = dispatcherQueue.TryEnqueue([=]() {
m_destroyed = true;
DestroyWindow(m_hwndOwner);
});
if (!enqueueSucceeded)
{
Logger::error("Couldn't enqueue message to destroy the sonar Window.");
}
}
template<typename D>
LRESULT SuperSonar<D>::s_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
SuperSonar* self;
if (message == WM_NCCREATE)
{
auto info = (LPCREATESTRUCT)lParam;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)info->lpCreateParams);
self = (SuperSonar*)info->lpCreateParams;
self->m_hwnd = hwnd;
}
else
{
self = (SuperSonar*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
}
if (self)
{
return self->Shim()->WndProc(message, wParam, lParam);
}
else
{
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
template<typename D>
LRESULT SuperSonar<D>::BaseWndProc(UINT message, WPARAM wParam, LPARAM lParam) noexcept
{
switch (message)
{
case WM_CREATE:
return OnSonarCreate() ? 0 : -1;
case WM_DESTROY:
OnSonarDestroy();
break;
case WM_INPUT:
OnSonarInput(wParam, (HRAWINPUT)lParam);
break;
case WM_TIMER:
switch (wParam)
{
case TIMER_ID_TRACK:
OnMouseTimer();
break;
}
break;
case WM_NCHITTEST:
return HTTRANSPARENT;
}
return DefWindowProc(m_hwnd, message, wParam, lParam);
}
template<typename D>
BOOL SuperSonar<D>::OnSonarCreate()
{
RAWINPUTDEVICE keyboard{};
keyboard.usUsagePage = HID_USAGE_PAGE_GENERIC;
keyboard.usUsage = HID_USAGE_GENERIC_KEYBOARD;
keyboard.dwFlags = RIDEV_INPUTSINK;
keyboard.hwndTarget = m_hwnd;
return RegisterRawInputDevices(&keyboard, 1, sizeof(keyboard));
}
template<typename D>
void SuperSonar<D>::OnSonarDestroy()
{
PostQuitMessage(0);
}
template<typename D>
void SuperSonar<D>::OnSonarInput(WPARAM flags, HRAWINPUT hInput)
{
RAWINPUT input;
UINT size = sizeof(input);
auto result = GetRawInputData(hInput, RID_INPUT, &input, &size, sizeof(RAWINPUTHEADER));
if ((int)result < sizeof(RAWINPUTHEADER))
{
return;
}
switch (input.header.dwType)
{
case RIM_TYPEKEYBOARD:
OnSonarKeyboardInput(input);
break;
case RIM_TYPEMOUSE:
OnSonarMouseInput(input);
break;
}
}
template<typename D>
void SuperSonar<D>::OnSonarKeyboardInput(RAWINPUT const& input)
{
// Don't activate if game mode is on.
if (m_doNotActivateOnGameMode && detect_game_mode())
{
return;
}
if (input.data.keyboard.VKey != VK_CONTROL)
{
StopSonar();
return;
}
bool pressed = (input.data.keyboard.Flags & RI_KEY_BREAK) == 0;
bool rightCtrl = (input.data.keyboard.Flags & RI_KEY_E0) != 0;
// Deal with rightCtrl first.
if (rightCtrl)
{
/*
* SuperSonar originally exited when pressing right control after pressing left control twice.
* We take care of exiting FindMyMouse through module disabling in PowerToys settings instead.
if (m_sonarState == SonarState::ControlUp2)
{
Terminate();
}
*/
StopSonar();
return;
}
switch (m_sonarState)
{
case SonarState::Idle:
if (pressed)
{
m_sonarState = SonarState::ControlDown1;
m_lastKeyTime = GetTickCount();
m_lastKeyPos = {};
GetCursorPos(&m_lastKeyPos);
UpdateMouseSnooping();
}
break;
case SonarState::ControlDown1:
if (!pressed)
{
m_sonarState = SonarState::ControlUp1;
}
break;
case SonarState::ControlUp1:
if (pressed)
{
auto now = GetTickCount();
auto doubleClickInterval = now - m_lastKeyTime;
POINT ptCursor{};
auto doubleClickTimeSetting = GetDoubleClickTime();
if (GetCursorPos(&ptCursor) &&
doubleClickInterval >= min(MIN_DOUBLE_CLICK_TIME, doubleClickTimeSetting / 5) &&
doubleClickInterval <= doubleClickTimeSetting &&
IsEqual(m_lastKeyPos, ptCursor))
{
m_sonarState = SonarState::ControlDown2;
StartSonar();
}
else
{
m_sonarState = SonarState::ControlDown1;
m_lastKeyTime = GetTickCount();
m_lastKeyPos = {};
GetCursorPos(&m_lastKeyPos);
UpdateMouseSnooping();
}
Logger::info("Detecting double left control click with {} ms interval.", doubleClickInterval);
m_lastKeyTime = now;
m_lastKeyPos = ptCursor;
}
break;
case SonarState::ControlUp2:
// Also deactivate sonar with left control.
if (pressed)
{
StopSonar();
}
break;
case SonarState::ControlDown2:
if (!pressed)
{
m_sonarState = SonarState::ControlUp2;
}
break;
}
}
template<typename D>
void SuperSonar<D>::OnSonarMouseInput(RAWINPUT const& input)
{
if (input.data.mouse.usButtonFlags)
{
StopSonar();
}
else if (m_sonarStart != NoSonar)
{
OnMouseTimer();
}
}
template<typename D>
void SuperSonar<D>::StartSonar()
{
Logger::info("Focusing the sonar on the mouse cursor.");
Trace::MousePointerFocused();
// Cover the entire virtual screen.
SetWindowPos(m_hwnd, HWND_TOPMOST, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN), GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN), 0);
m_sonarPos = ptNowhere;
OnMouseTimer();
UpdateMouseSnooping();
Shim()->SetSonarVisibility(true);
}
template<typename D>
void SuperSonar<D>::StopSonar()
{
if (m_sonarStart != NoSonar)
{
m_sonarStart = NoSonar;
Shim()->SetSonarVisibility(false);
KillTimer(m_hwnd, TIMER_ID_TRACK);
}
m_sonarState = SonarState::Idle;
UpdateMouseSnooping();
}
template<typename D>
void SuperSonar<D>::OnMouseTimer()
{
auto now = GetTickCount();
// If mouse has moved, then reset the sonar timer.
POINT ptCursor{};
if (!GetCursorPos(&ptCursor))
{
// We are no longer the active desktop - done.
StopSonar();
return;
}
ScreenToClient(m_hwnd, &ptCursor);
if (IsEqual(m_sonarPos, ptCursor))
{
// Mouse is stationary.
if (m_sonarStart != SonarWaitingForMouseMove && now - m_sonarStart >= IdlePeriod)
{
StopSonar();
return;
}
}
else
{
// Mouse has moved.
if (IsEqual(m_sonarPos, ptNowhere))
{
// Initial call, mark sonar as active but waiting for first mouse-move.
now = SonarWaitingForMouseMove;
}
SetTimer(m_hwnd, TIMER_ID_TRACK, IdlePeriod, nullptr);
Shim()->BeforeMoveSonar();
m_sonarPos = ptCursor;
m_sonarStart = now;
Shim()->AfterMoveSonar();
}
}
template<typename D>
void SuperSonar<D>::UpdateMouseSnooping()
{
bool wantSnoopingMouse = m_sonarStart != NoSonar || m_sonarState != SonarState::Idle;
if (m_isSnoopingMouse != wantSnoopingMouse)
{
m_isSnoopingMouse = wantSnoopingMouse;
RAWINPUTDEVICE mouse{};
mouse.usUsagePage = HID_USAGE_PAGE_GENERIC;
mouse.usUsage = HID_USAGE_GENERIC_MOUSE;
if (wantSnoopingMouse)
{
mouse.dwFlags = RIDEV_INPUTSINK;
mouse.hwndTarget = m_hwnd;
}
else
{
mouse.dwFlags = RIDEV_REMOVE;
mouse.hwndTarget = nullptr;
}
RegisterRawInputDevices(&mouse, 1, sizeof(mouse));
}
}
struct CompositionSpotlight : SuperSonar<CompositionSpotlight>
{
static constexpr UINT WM_OPACITY_ANIMATION_COMPLETED = WM_APP;
float m_sonarRadiusFloat = static_cast<float>(m_sonarRadius);
DWORD GetExtendedStyle()
{
return WS_EX_NOREDIRECTIONBITMAP;
}
void AfterMoveSonar()
{
m_spotlight.Offset({ (float)m_sonarPos.x, (float)m_sonarPos.y, 0.0f });
}
LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam) noexcept
{
switch (message)
{
case WM_CREATE:
return OnCompositionCreate() && BaseWndProc(message, wParam, lParam);
case WM_OPACITY_ANIMATION_COMPLETED:
OnOpacityAnimationCompleted();
break;
}
return BaseWndProc(message, wParam, lParam);
}
void SetSonarVisibility(bool visible)
{
m_batch = m_compositor.GetCommitBatch(winrt::CompositionBatchTypes::Animation);
m_batch.Completed([hwnd = m_hwnd](auto&&, auto&&) {
PostMessage(hwnd, WM_OPACITY_ANIMATION_COMPLETED, 0, 0);
});
m_root.Opacity(visible ? static_cast<float>(m_finalAlphaNumerator) / FinalAlphaDenominator : 0.0f);
if (visible)
{
ShowWindow(m_hwnd, SW_SHOWNOACTIVATE);
}
}
private:
bool OnCompositionCreate()
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;
// Our composition tree:
//
// [root] ContainerVisual
// \ LayerVisual
// \[gray backdrop]
// [spotlight]
m_root = m_compositor.CreateContainerVisual();
m_root.RelativeSizeAdjustment({ 1.0f, 1.0f }); // fill the parent
m_root.Opacity(0.0f);
m_target.Root(m_root);
auto layer = m_compositor.CreateLayerVisual();
layer.RelativeSizeAdjustment({ 1.0f, 1.0f }); // fill the parent
m_root.Children().InsertAtTop(layer);
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
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({ m_sonarRadiusFloat * 2 * m_sonarZoomFactor, m_sonarRadiusFloat * 2 * m_sonarZoomFactor });
m_spotlight.AnchorPoint({ 0.5f, 0.5f });
m_spotlight.Shapes().Append(m_circleShape);
layer.Children().InsertAtTop(m_spotlight);
// Implicitly animate the alpha.
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", m_animation);
m_root.ImplicitAnimations(collection);
// Radius of spotlight shrinks as opacity increases.
// 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)", m_sonarRadius * m_sonarZoomFactor, m_sonarRadius * m_sonarZoomFactor, m_sonarRadius, m_sonarRadius, FinalAlphaDenominator, m_finalAlphaNumerator));
radiusExpression.Expression(expressionText);
m_circleGeometry.StartAnimation(L"Radius", radiusExpression);
return true;
}
catch (...)
{
return false;
}
void OnOpacityAnimationCompleted()
{
if (m_root.Opacity() < 0.01f)
{
ShowWindow(m_hwnd, SW_HIDE);
}
}
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 };
winrt::ContainerVisual m_root{ nullptr };
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>
struct GdiSonar : SuperSonar<D>
{
LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam) noexcept
{
switch (message)
{
case WM_CREATE:
SetLayeredWindowAttributes(this->m_hwnd, 0, 0, LWA_ALPHA);
break;
case WM_TIMER:
switch (wParam)
{
case TIMER_ID_FADE:
OnFadeTimer();
break;
}
break;
case WM_PAINT:
this->Shim()->OnPaint();
break;
}
return this->BaseWndProc(message, wParam, lParam);
}
void BeforeMoveSonar() { this->Shim()->InvalidateSonar(); }
void AfterMoveSonar() { this->Shim()->InvalidateSonar(); }
void SetSonarVisibility(bool visible)
{
m_alphaTarget = visible ? MaxAlpha : 0;
m_fadeStart = GetTickCount() - FadeFramePeriod;
SetTimer(this->m_hwnd, TIMER_ID_FADE, FadeFramePeriod, nullptr);
OnFadeTimer();
}
void OnFadeTimer()
{
auto now = GetTickCount();
auto step = (int)((now - m_fadeStart) * MaxAlpha / this->m_fadeDuration);
this->Shim()->InvalidateSonar();
if (m_alpha < m_alphaTarget)
{
m_alpha += step;
if (m_alpha > m_alphaTarget)
m_alpha = m_alphaTarget;
}
else if (m_alpha > m_alphaTarget)
{
m_alpha -= step;
if (m_alpha < m_alphaTarget)
m_alpha = m_alphaTarget;
}
SetLayeredWindowAttributes(this->m_hwnd, 0, (BYTE)m_alpha, LWA_ALPHA);
this->Shim()->InvalidateSonar();
if (m_alpha == m_alphaTarget)
{
KillTimer(this->m_hwnd, TIMER_ID_FADE);
if (m_alpha == 0)
{
ShowWindow(this->m_hwnd, SW_HIDE);
}
}
else
{
ShowWindow(this->m_hwnd, SW_SHOWNOACTIVATE);
}
}
protected:
int CurrentSonarRadius()
{
int range = MaxAlpha - m_alpha;
int radius = this->m_sonarRadius + this->m_sonarRadius * range * (this->m_sonarZoomFactor - 1) / MaxAlpha;
return radius;
}
private:
static constexpr DWORD FadeFramePeriod = 10;
int MaxAlpha = SuperSonar<D>::m_finalAlphaNumerator * 255 / SuperSonar<D>::FinalAlphaDenominator;
static constexpr DWORD TIMER_ID_FADE = 101;
private:
int m_alpha = 0;
int m_alphaTarget = 0;
DWORD m_fadeStart = 0;
};
struct GdiSpotlight : GdiSonar<GdiSpotlight>
{
void InvalidateSonar()
{
RECT rc;
auto radius = CurrentSonarRadius();
rc.left = this->m_sonarPos.x - radius;
rc.top = this->m_sonarPos.y - radius;
rc.right = this->m_sonarPos.x + radius;
rc.bottom = this->m_sonarPos.y + radius;
InvalidateRect(this->m_hwnd, &rc, FALSE);
}
void OnPaint()
{
PAINTSTRUCT ps;
BeginPaint(this->m_hwnd, &ps);
auto radius = CurrentSonarRadius();
auto spotlight = CreateRoundRectRgn(
this->m_sonarPos.x - radius, this->m_sonarPos.y - radius, this->m_sonarPos.x + radius, this->m_sonarPos.y + radius, radius * 2, radius * 2);
FillRgn(ps.hdc, spotlight, (HBRUSH)GetStockObject(WHITE_BRUSH));
Sleep(1000 / 60);
ExtSelectClipRgn(ps.hdc, spotlight, RGN_DIFF);
FillRect(ps.hdc, &ps.rcPaint, (HBRUSH)GetStockObject(BLACK_BRUSH));
DeleteObject(spotlight);
EndPaint(this->m_hwnd, &ps);
}
};
struct GdiCrosshairs : GdiSonar<GdiCrosshairs>
{
void InvalidateSonar()
{
RECT rc;
auto radius = CurrentSonarRadius();
GetClientRect(m_hwnd, &rc);
rc.left = m_sonarPos.x - radius;
rc.right = m_sonarPos.x + radius;
InvalidateRect(m_hwnd, &rc, FALSE);
GetClientRect(m_hwnd, &rc);
rc.top = m_sonarPos.y - radius;
rc.bottom = m_sonarPos.y + radius;
InvalidateRect(m_hwnd, &rc, FALSE);
}
void OnPaint()
{
PAINTSTRUCT ps;
BeginPaint(this->m_hwnd, &ps);
auto radius = CurrentSonarRadius();
RECT rc;
HBRUSH white = (HBRUSH)GetStockObject(WHITE_BRUSH);
rc.left = m_sonarPos.x - radius;
rc.top = ps.rcPaint.top;
rc.right = m_sonarPos.x + radius;
rc.bottom = ps.rcPaint.bottom;
FillRect(ps.hdc, &rc, white);
rc.left = ps.rcPaint.left;
rc.top = m_sonarPos.y - radius;
rc.right = ps.rcPaint.right;
rc.bottom = m_sonarPos.y + radius;
FillRect(ps.hdc, &rc, white);
HBRUSH black = (HBRUSH)GetStockObject(BLACK_BRUSH);
// Top left
rc.left = ps.rcPaint.left;
rc.top = ps.rcPaint.top;
rc.right = m_sonarPos.x - radius;
rc.bottom = m_sonarPos.y - radius;
FillRect(ps.hdc, &rc, black);
// Top right
rc.left = m_sonarPos.x + radius;
rc.top = ps.rcPaint.top;
rc.right = ps.rcPaint.right;
rc.bottom = m_sonarPos.y - radius;
FillRect(ps.hdc, &rc, black);
// Bottom left
rc.left = ps.rcPaint.left;
rc.top = m_sonarPos.y + radius;
rc.right = m_sonarPos.x - radius;
rc.bottom = ps.rcPaint.bottom;
FillRect(ps.hdc, &rc, black);
// Bottom right
rc.left = m_sonarPos.x + radius;
rc.top = m_sonarPos.y + radius;
rc.right = ps.rcPaint.right;
rc.bottom = ps.rcPaint.bottom;
FillRect(ps.hdc, &rc, black);
EndPaint(this->m_hwnd, &ps);
}
};
#pragma endregion Super_Sonar_Base_Code
#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()
{
if (m_sonar != nullptr)
{
Logger::info("Terminating a sonar instance.");
m_sonar->Terminate();
}
}
bool FindMyMouseIsEnabled()
{
return (m_sonar != nullptr);
}
// Based on SuperSonar's original wWinMain.
int FindMyMouseMain(HINSTANCE hinst, const FindMyMouseSettings& settings)
{
Logger::info("Starting a sonar instance.");
if (m_sonar != nullptr)
{
Logger::error("A sonar instance was still working when trying to start a new one.");
return 0;
}
CompositionSpotlight sonar;
sonar.ApplySettings(settings, false);
if (!sonar.Initialize(hinst))
{
Logger::error("Couldn't initialize a sonar instance.");
return 0;
}
m_sonar = &sonar;
Logger::info("Initialized the sonar instance.");
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Logger::info("Sonar message loop ended.");
m_sonar = nullptr;
return (int)msg.wParam;
}
#pragma endregion Super_Sonar_API

View file

@ -1,26 +0,0 @@
#pragma once
#include "pch.h"
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 FindMyMouseApplySettings(const FindMyMouseSettings& settings);

View file

@ -1,146 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.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>{e94fd11c-0591-456f-899f-efc0ca548336}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>FindMyMouse</RootNamespace>
<OverrideWindowsTargetPlatformVersion>true</OverrideWindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
<ProjectName>FindMyMouse</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="FindMyMouse.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="Generated Files\resource.h" />
<None Include="resource.base.h" />
<ClInclude Include="trace.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="FindMyMouse.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="trace.cpp" />
<None Include="FindMyMouse.base.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>
<ItemGroup>
<ResourceCompile Include="Generated Files\FindMyMouse.rc" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="..\..\..\..\deps\spdlog.props" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.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>

View file

@ -1,273 +0,0 @@
#include "pch.h"
#include <interface/powertoy_module_interface.h>
#include <common/SettingsAPI/settings_objects.h>
#include "trace.h"
#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;
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"FindMyMouse";
// Add a description that will we shown in the module settings page.
const static wchar_t* MODULE_DESC = L"Focus the mouse pointer";
// Implement the PowerToy Module Interface and all the required methods.
class FindMyMouse : public PowertoyModuleIface
{
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();
// Helper function to extract the settings
void parse_settings(PowerToysSettings::PowerToyValues& settings);
public:
// Constructor
FindMyMouse()
{
LoggerHelpers::init_logger(MODULE_NAME, L"ModuleInterface", LogSettings::findMyMouseLoggerName);
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);
// Create a Settings object.
PowerToysSettings::Settings settings(hinstance, get_name());
settings.set_description(MODULE_DESC);
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);
FindMyMouseApplySettings(m_findMyMouseSettings);
}
catch (std::exception&)
{
// Improper JSON.
}
}
// Enable the powertoy
virtual void enable()
{
m_enabled = true;
Trace::EnableFindMyMouse(true);
std::thread([=]() { FindMyMouseMain(m_hModule, m_findMyMouseSettings); }).detach();
}
// Disable the powertoy
virtual void disable()
{
m_enabled = false;
Trace::EnableFindMyMouse(false);
FindMyMouseDisable();
}
// Returns if the powertoys is enabled
virtual bool is_enabled() override
{
return m_enabled;
}
};
// Load the settings file.
void FindMyMouse::init_settings()
{
try
{
// Load and parse the settings file for this PowerToy.
PowerToysSettings::PowerToyValues settings =
PowerToysSettings::PowerToyValues::load_from_settings_file(FindMyMouse::get_key());
parse_settings(settings);
}
catch (std::exception&)
{
// Error while loading from the settings file. Let default values stay as they are.
}
}
void FindMyMouse::parse_settings(PowerToysSettings::PowerToyValues& settings)
{
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);
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;
}
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
{
return new FindMyMouse();
}

View file

@ -1,20 +0,0 @@
#pragma once
#define COMPOSITION
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
#include <strsafe.h>
#include <hIdUsage.h>
#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>
#endif
#include <winrt/Windows.Foundation.Collections.h>
#include <ProjectTelemetry.h>
#include <common/SettingsAPI/settings_helpers.h>
#include <common/logger/logger.h>

View file

@ -1,14 +0,0 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by FindMyMouse.rc
//////////////////////////////
// Non-localizable
#define FILE_DESCRIPTION "PowerToys FindMyMouse"
#define INTERNAL_NAME "FindMyMouse"
#define ORIGINAL_FILENAME "FindMyMouse.dll"
#define IDS_KEYBOARDMANAGER_ICON 1001
// Non-localizable
//////////////////////////////

View file

@ -1,40 +0,0 @@
#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 FindMyMouse enabled or disabled
void Trace::EnableFindMyMouse(const bool enabled) noexcept
{
TraceLoggingWrite(
g_hProvider,
"FindMyMouse_EnableFindMyMouse",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
TraceLoggingBoolean(enabled, "Enabled"));
}
// Log that the user activated the module by focusing the mouse pointer
void Trace::MousePointerFocused() noexcept
{
TraceLoggingWrite(
g_hProvider,
"FindMyMouse_MousePointerFocused",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
}

View file

@ -1,14 +0,0 @@
#pragma once
class Trace
{
public:
static void RegisterProvider() noexcept;
static void UnregisterProvider() noexcept;
// Log if the user has FindMyMouse enabled or disabled
static void EnableFindMyMouse(const bool enabled) noexcept;
// Log that the user activated the module by focusing the mouse pointer
static void MousePointerFocused() noexcept;
};

View file

@ -1,5 +0,0 @@
<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>

View file

@ -1,40 +0,0 @@
#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

View file

@ -1,443 +0,0 @@
// 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

View file

@ -1,24 +0,0 @@
#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);

View file

@ -1,145 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.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>

View file

@ -1,62 +0,0 @@
<?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>

View file

@ -1,304 +0,0 @@
#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();
}

View file

@ -1 +0,0 @@
#include "pch.h"

View file

@ -1,22 +0,0 @@
#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>

View file

@ -1,14 +0,0 @@
//{{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
//////////////////////////////

View file

@ -1,40 +0,0 @@
#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));
}

View file

@ -1,14 +0,0 @@
#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;
};

View file

@ -157,9 +157,6 @@
<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>
<ProjectReference Include="..\..\..\common\Themes\Themes.vcxproj">
<Project>{98537082-0fdb-40de-abd8-0dc5a4269bab}</Project>
</ProjectReference>

View file

@ -463,36 +463,27 @@ void D2DOverlayWindow::init()
{
colors.update();
landscape.load(L"svgs\\overlay.svg", d2d_dc.get())
.find_thumbnail(L"monitorRect")
.find_window_group(L"WindowControlsGroup")
.recolor(0x2582FB, colors.start_color_menu);
.find_thumbnail(L"path-1")
.find_window_group(L"Group-1")
.recolor(0x000000, colors.start_color_menu);
portrait.load(L"svgs\\overlay_portrait.svg", d2d_dc.get())
.find_thumbnail(L"monitorRect")
.find_window_group(L"WindowControlsGroup")
.recolor(0x2582FB, colors.start_color_menu);
.find_thumbnail(L"path-1")
.find_window_group(L"Group-1")
.recolor(0x000000, colors.start_color_menu);
no_active.load(L"svgs\\no_active_window.svg", d2d_dc.get());
arrows.resize(10);
for (unsigned i = 0; i < arrows.size(); ++i)
{
arrows[i].load(L"svgs\\" + std::to_wstring((i + 1) % 10) + L".svg", d2d_dc.get()).recolor(0x2582FB, colors.start_color_menu);
arrows[i].load(L"svgs\\" + std::to_wstring((i + 1) % 10) + L".svg", d2d_dc.get()).recolor(0x000000, colors.start_color_menu);
}
light_mode = (theme_setting == Light) || (theme_setting == System && colors.light_mode);
if (light_mode)
if (!light_mode)
{
landscape.recolor(0x2E17FC, 0x000000);
portrait.recolor(0x2E17FC, 0x000000);
landscape.recolor(0x222222, 0xDDDDDD);
portrait.recolor(0x222222, 0xDDDDDD);
for (auto& arrow : arrows)
{
arrow.recolor(0x222222, 0x000000);
}
}
else
{
landscape.recolor(0x2E17FC, 0xFFFFFF);
portrait.recolor(0x2E17FC, 0xFFFFFF);
for (auto& arrow : arrows)
{
arrow.recolor(0x222222, 0xFFFFFF);
arrow.recolor(0x222222, 0xDDDDDD);
}
}
}
@ -505,13 +496,13 @@ void D2DOverlayWindow::resize()
{ // portrait is broke right now
use_overlay = &landscape;
no_active_scale = 0.3f;
font = 12.0f;
font = 15.0f;
}
else
{
use_overlay = &portrait;
no_active_scale = 0.5f;
font = 13.0f;
font = 16.0f;
}
use_overlay->resize(0, 0, window_width, window_height, 0.8f);
auto thumb_no_active_rect = use_overlay->get_thumbnail_rect_and_scale(0, 0, no_active.width(), no_active.height(), no_active_scale).rect;
@ -727,7 +718,7 @@ void D2DOverlayWindow::render(ID2D1DeviceContext5* d2d_dc)
// render the monitors
if (render_monitors)
{
brushColor = D2D1::ColorF(colors.start_color_menu, miniature_shown ? current_anim_value * 0.9f : current_anim_value * 0.3f);
brushColor = D2D1::ColorF(colors.desktop_fill_color, miniature_shown ? current_anim_value : current_anim_value * 0.3f);
brush = nullptr;
winrt::check_hresult(d2d_dc->CreateSolidColorBrush(brushColor, brush.put()));
for (auto& monitor : monitors)

View file

@ -1,21 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="53px" height="52px" viewBox="0 0 53 52" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Artboard" clip-path="url(#clip-Artboard)">
<g id="_0" data-name="0">
<rect id="Rectangle" width="29" height="36" rx="4" transform="translate(13 8)" fill="#2582fb"/>
<g id="bottom">
<rect id="carat" width="14" height="14" transform="translate(18 39) rotate(-45)" fill="#2582fb"/>
</g>
<g id="left">
<rect id="carat-2" data-name="carat" width="14" height="14" transform="translate(7.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="right">
<rect id="carat-3" data-name="carat" width="14" height="14" transform="translate(26.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="top">
<rect id="carat-4" data-name="carat" width="14" height="14" transform="translate(18 13) rotate(-45)" fill="#2582fb"/>
</g>
<path id="A" d="M13.968,15.171a2.7,2.7,0,0,1-2.427-1.251,6.713,6.713,0,0,1-.813-3.644,7.215,7.215,0,0,1,.868-3.9,2.784,2.784,0,0,1,2.481-1.343,2.684,2.684,0,0,1,2.468,1.251,7.283,7.283,0,0,1,.772,3.76,6.981,6.981,0,0,1-.861,3.8A2.79,2.79,0,0,1,13.968,15.171ZM14.05,6.3a1.365,1.365,0,0,0-1.289.981,7.967,7.967,0,0,0-.414,2.943,7.039,7.039,0,0,0,.414,2.758,1.345,1.345,0,0,0,1.268.919,1.323,1.323,0,0,0,1.268-.94,7.716,7.716,0,0,0,.393-2.827A7.991,7.991,0,0,0,15.3,7.258,1.315,1.315,0,0,0,14.05,6.3Z" transform="translate(13.5 15.689)" fill="#fff"/>
</g>
</g>
<!-- Generator: Sketch 54.1 (76490) - https://sketchapp.com -->
<title>0</title>
<desc>Created with Sketch.</desc>
<g id="Devices" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Artboard" transform="translate(-7.000000, -159.000000)">
<g id="0" transform="translate(7.000000, 159.000000)">
<rect id="Rectangle" fill="#000000" x="7" y="6" width="40" height="40"></rect>
<g id="left" transform="translate(0.000000, 14.000000)" fill="#000000">
<rect id="carat" transform="translate(12.000000, 12.000000) rotate(-314.000000) translate(-12.000000, -12.000000) " x="4" y="4" width="16" height="16"></rect>
</g>
<g id="bottom" transform="translate(15.000000, 28.000000)" fill="#000000">
<rect id="carat" transform="translate(12.000000, 12.000000) rotate(-314.000000) translate(-12.000000, -12.000000) " x="4" y="4" width="16" height="16"></rect>
</g>
<g id="right" transform="translate(29.000000, 14.000000)" fill="#000000">
<rect id="carat" transform="translate(12.000000, 12.000000) rotate(-314.000000) translate(-12.000000, -12.000000) " x="4" y="4" width="16" height="16"></rect>
</g>
<g id="top" transform="translate(16.000000, 0.000000)" fill="#000000">
<rect id="carat" transform="translate(11.311985, 12.000000) rotate(-314.000000) translate(-11.311985, -12.000000) " x="3.31198537" y="4" width="16" height="16"></rect>
</g>
<path d="M26.5,31.1376953 C24.166655,31.1376953 23,29.4993653 23,26.2226562 C23,24.522778 23.3155893,23.2273808 23.9467773,22.3364258 C24.5779654,21.4454708 25.4928325,21 26.6914062,21 C28.9700635,21 30.109375,22.6656734 30.109375,25.9970703 C30.109375,27.6559328 29.798343,28.9274044 29.1762695,29.8115234 C28.5541961,30.6956424 27.6621152,31.1376953 26.5,31.1376953 Z M26.5957031,22.6474609 C25.6614537,22.6474609 25.1943359,23.8209518 25.1943359,26.1679688 C25.1943359,28.3782663 25.6523392,29.4833984 26.5683594,29.4833984 C27.461593,29.4833984 27.9082031,28.3440869 27.9082031,26.0654297 C27.9082031,23.7867725 27.4707075,22.6474609 26.5957031,22.6474609 Z" fill="#FFFFFF" fill-rule="nonzero"></path>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -1,21 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="53px" height="52px" viewBox="0 0 53 52" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Artboard" clip-path="url(#clip-Artboard)">
<g id="_1" data-name="1">
<rect id="Rectangle" width="29" height="36" rx="4" transform="translate(13 8)" fill="#2582fb"/>
<g id="bottom">
<rect id="carat" width="14" height="14" transform="translate(18 39) rotate(-45)" fill="#2582fb"/>
</g>
<g id="left">
<rect id="carat-2" data-name="carat" width="14" height="14" transform="translate(7.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="right">
<rect id="carat-3" data-name="carat" width="14" height="14" transform="translate(26.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="top">
<rect id="carat-4" data-name="carat" width="14" height="14" transform="translate(18 13) rotate(-45)" fill="#2582fb"/>
</g>
<path id="A" d="M15.277,15H13.691V7.022a4.525,4.525,0,0,1-.868.482,8.428,8.428,0,0,1-1.08.4l-.437-1.319a8.886,8.886,0,0,0,1.716-.673,7.345,7.345,0,0,0,1.436-.933h.82Z" transform="translate(13.5 15.689)" fill="#fff"/>
</g>
</g>
</svg>
<!-- Generator: Sketch 54.1 (76490) - https://sketchapp.com -->
<title>1</title>
<desc>Created with Sketch.</desc>
<g id="Devices" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Artboard" transform="translate(-67.000000, -159.000000)">
<g id="1" transform="translate(67.000000, 159.000000)">
<rect id="Rectangle" fill="#000000" x="7" y="6" width="40" height="40"></rect>
<g id="left" transform="translate(0.000000, 14.000000)" fill="#000000">
<rect id="carat" transform="translate(12.000000, 12.000000) rotate(-314.000000) translate(-12.000000, -12.000000) " x="4" y="4" width="16" height="16"></rect>
</g>
<g id="bottom" transform="translate(15.000000, 28.000000)" fill="#000000">
<rect id="carat" transform="translate(12.000000, 12.000000) rotate(-314.000000) translate(-12.000000, -12.000000) " x="4" y="4" width="16" height="16"></rect>
</g>
<g id="right" transform="translate(29.000000, 14.000000)" fill="#000000">
<rect id="carat" transform="translate(12.000000, 12.000000) rotate(-314.000000) translate(-12.000000, -12.000000) " x="4" y="4" width="16" height="16"></rect>
</g>
<g id="top" transform="translate(16.000000, 0.000000)" fill="#000000">
<rect id="carat" transform="translate(11.311985, 12.000000) rotate(-314.000000) translate(-11.311985, -12.000000) " x="3.31198537" y="4" width="16" height="16"></rect>
</g>
<polygon fill="#FFFFFF" fill-rule="nonzero" points="30.2548828 30.9667969 24.0546875 30.9667969 24.0546875 29.2578125 26.0849609 29.2578125 26.0849609 23.1533203 24 23.6044922 24 21.8544922 28.2382812 21 28.2382812 29.2578125 30.2548828 29.2578125"></polygon>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -1,21 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="53px" height="52px" viewBox="0 0 53 52" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Artboard" clip-path="url(#clip-Artboard)">
<g id="_2" data-name="2">
<rect id="Rectangle" width="29" height="36" rx="4" transform="translate(13 8)" fill="#2582fb"/>
<g id="bottom">
<rect id="carat" width="14" height="14" transform="translate(18 39) rotate(-45)" fill="#2582fb"/>
</g>
<g id="left">
<rect id="carat-2" data-name="carat" width="14" height="14" transform="translate(7.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="right">
<rect id="carat-3" data-name="carat" width="14" height="14" transform="translate(26.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="top">
<rect id="carat-4" data-name="carat" width="14" height="14" transform="translate(18 13) rotate(-45)" fill="#2582fb"/>
</g>
<path id="A" d="M10.974,15v-.6a3.649,3.649,0,0,1,.188-1.217A3.508,3.508,0,0,1,11.7,12.2a5.092,5.092,0,0,1,.827-.851q.485-.4,1.073-.831a7.588,7.588,0,0,0,.824-.66,5.023,5.023,0,0,0,.571-.625,1.98,1.98,0,0,0,.328-.625,2.443,2.443,0,0,0,.109-.742,1.561,1.561,0,0,0-.4-1.1,1.448,1.448,0,0,0-1.121-.431,3.157,3.157,0,0,0-1.135.229,3.742,3.742,0,0,0-1.135.708L10.8,6.291A4.651,4.651,0,0,1,14.1,5.033a2.9,2.9,0,0,1,2.167.786,2.564,2.564,0,0,1,.772,1.859,3.645,3.645,0,0,1-.178,1.2,3.375,3.375,0,0,1-.479.913,4.918,4.918,0,0,1-.728.807,10.746,10.746,0,0,1-.94.745q-.526.369-.909.66a5.2,5.2,0,0,0-.629.55,1.988,1.988,0,0,0-.373.526,1.324,1.324,0,0,0-.12.561h4.553V15Z" transform="translate(13.5 15.689)" fill="#fff"/>
</g>
</g>
<!-- Generator: Sketch 54.1 (76490) - https://sketchapp.com -->
<title>2</title>
<desc>Created with Sketch.</desc>
<g id="Devices" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Artboard" transform="translate(-127.000000, -159.000000)">
<g id="2" transform="translate(127.000000, 159.000000)">
<rect id="Rectangle" fill="#000000" x="7" y="6" width="40" height="40"></rect>
<g id="left" transform="translate(0.000000, 14.000000)" fill="#000000">
<rect id="carat" transform="translate(12.000000, 12.000000) rotate(-314.000000) translate(-12.000000, -12.000000) " x="4" y="4" width="16" height="16"></rect>
</g>
<g id="bottom" transform="translate(15.000000, 28.000000)" fill="#000000">
<rect id="carat" transform="translate(12.000000, 12.000000) rotate(-314.000000) translate(-12.000000, -12.000000) " x="4" y="4" width="16" height="16"></rect>
</g>
<g id="right" transform="translate(29.000000, 14.000000)" fill="#000000">
<rect id="carat" transform="translate(12.000000, 12.000000) rotate(-314.000000) translate(-12.000000, -12.000000) " x="4" y="4" width="16" height="16"></rect>
</g>
<g id="top" transform="translate(16.000000, 0.000000)" fill="#000000">
<rect id="carat" transform="translate(11.311985, 12.000000) rotate(-314.000000) translate(-11.311985, -12.000000) " x="3.31198537" y="4" width="16" height="16"></rect>
</g>
<path d="M26.4746094,29.1347656 L26.4746094,29.1757812 L30.453125,29.1757812 L30.453125,30.9667969 L24,30.9667969 L24,29.2851562 L26.8095703,26.5986328 C27.3746773,26.0563124 27.772297,25.6017271 28.0024414,25.2348633 C28.2325858,24.8679995 28.3476562,24.4817729 28.3476562,24.0761719 C28.3476562,23.1738236 27.8623095,22.7226562 26.8916016,22.7226562 C26.0484984,22.7226562 25.2418658,23.0576138 24.4716797,23.7275391 L24.4716797,21.8271484 C25.3238975,21.2757134 26.2854764,21 27.3564453,21 C28.3590545,21 29.1417615,21.2517878 29.7045898,21.7553711 C30.2674182,22.2589543 30.5488281,22.9391233 30.5488281,23.7958984 C30.5488281,24.9397844 29.8629626,26.1223897 28.4912109,27.34375 L26.4746094,29.1347656 Z" fill="#FFFFFF" fill-rule="nonzero"></path>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -1,21 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="53px" height="52px" viewBox="0 0 53 52" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Artboard" clip-path="url(#clip-Artboard)">
<g id="_3" data-name="3">
<rect id="Rectangle" width="29" height="36" rx="4" transform="translate(13 8)" fill="#2582fb"/>
<g id="bottom">
<rect id="carat" width="14" height="14" transform="translate(18 39) rotate(-45)" fill="#2582fb"/>
</g>
<g id="left">
<rect id="carat-2" data-name="carat" width="14" height="14" transform="translate(7.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="right">
<rect id="carat-3" data-name="carat" width="14" height="14" transform="translate(26.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="top">
<rect id="carat-4" data-name="carat" width="14" height="14" transform="translate(18 13) rotate(-45)" fill="#2582fb"/>
</g>
<path id="A" d="M10.857,14.344l.663-1.094a4.564,4.564,0,0,0,1.036.5,3.6,3.6,0,0,0,1.083.154,2,2,0,0,0,1.446-.461,1.516,1.516,0,0,0,.475-1.131,1.453,1.453,0,0,0-.636-1.3,3.3,3.3,0,0,0-1.832-.424h-.807V9.319h.752a2.827,2.827,0,0,0,1.644-.393,1.435,1.435,0,0,0,.55-1.254,1.3,1.3,0,0,0-.4-1.022A1.477,1.477,0,0,0,13.817,6.3a3.274,3.274,0,0,0-1.008.164,4.127,4.127,0,0,0-1.029.513l-.67-1.053A4.8,4.8,0,0,1,14,5.033a3.1,3.1,0,0,1,2.071.663,2.192,2.192,0,0,1,.786,1.764,2.46,2.46,0,0,1-.455,1.5,2.608,2.608,0,0,1-1.371.9v.027a2.585,2.585,0,0,1,1.555.762,2.2,2.2,0,0,1,.6,1.583,2.679,2.679,0,0,1-.926,2.129,3.629,3.629,0,0,1-2.464.8,5.294,5.294,0,0,1-2.933-.827Z" transform="translate(13.5 15.689)" fill="#fff"/>
</g>
</g>
<!-- Generator: Sketch 54.1 (76490) - https://sketchapp.com -->
<title>3</title>
<desc>Created with Sketch.</desc>
<g id="Devices" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Artboard" transform="translate(-187.000000, -159.000000)">
<g id="3" transform="translate(187.000000, 159.000000)">
<rect id="Rectangle" fill="#000000" x="7" y="6" width="40" height="40"></rect>
<g id="left" transform="translate(0.000000, 14.000000)" fill="#000000">
<rect id="carat" transform="translate(12.000000, 12.000000) rotate(-314.000000) translate(-12.000000, -12.000000) " x="4" y="4" width="16" height="16"></rect>
</g>
<g id="bottom" transform="translate(15.000000, 28.000000)" fill="#000000">
<rect id="carat" transform="translate(12.000000, 12.000000) rotate(-314.000000) translate(-12.000000, -12.000000) " x="4" y="4" width="16" height="16"></rect>
</g>
<g id="right" transform="translate(29.000000, 14.000000)" fill="#000000">
<rect id="carat" transform="translate(12.000000, 12.000000) rotate(-314.000000) translate(-12.000000, -12.000000) " x="4" y="4" width="16" height="16"></rect>
</g>
<g id="top" transform="translate(16.000000, 0.000000)" fill="#000000">
<rect id="carat" transform="translate(11.311985, 12.000000) rotate(-314.000000) translate(-11.311985, -12.000000) " x="3.31198537" y="4" width="16" height="16"></rect>
</g>
<path d="M24,30.6455078 L24,28.765625 C24.6562533,29.244143 25.4218706,29.4833984 26.296875,29.4833984 C26.84831,29.4833984 27.2778305,29.36491 27.5854492,29.1279297 C27.8930679,28.8909493 28.046875,28.560549 28.046875,28.1367188 C28.046875,27.6992166 27.85661,27.3619804 27.4760742,27.125 C27.0955385,26.8880196 26.5725945,26.7695312 25.9072266,26.7695312 L25.0253906,26.7695312 L25.0253906,25.1152344 L25.8388672,25.1152344 C27.1149152,25.1152344 27.7529297,24.6914105 27.7529297,23.84375 C27.7529297,23.04622 27.2630257,22.6474609 26.2832031,22.6474609 C25.6269498,22.6474609 24.9889354,22.8593729 24.3691406,23.2832031 L24.3691406,21.5195312 C25.0572951,21.1731754 25.8593704,21 26.7753906,21 C27.7779998,21 28.5584282,21.2255837 29.1166992,21.6767578 C29.6749702,22.1279319 29.9541016,22.7135381 29.9541016,23.4335938 C29.9541016,24.7141991 29.304694,25.5162744 28.0058594,25.8398438 L28.0058594,25.8740234 C28.6985712,25.9606124 29.2454407,26.2124003 29.6464844,26.6293945 C30.047528,27.0463888 30.2480469,27.5579397 30.2480469,28.1640625 C30.2480469,29.0800827 29.9130893,29.8046848 29.2431641,30.3378906 C28.5732388,30.8710964 27.6481179,31.1376953 26.4677734,31.1376953 C25.4560496,31.1376953 24.6334667,30.9736345 24,30.6455078 Z" fill="#FFFFFF" fill-rule="nonzero"></path>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -1,21 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="53px" height="52px" viewBox="0 0 53 52" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Artboard" clip-path="url(#clip-Artboard)">
<g id="_4" data-name="4">
<rect id="Rectangle" width="29" height="36" rx="4" transform="translate(13 8)" fill="#2582fb"/>
<g id="bottom">
<rect id="carat" width="14" height="14" transform="translate(18 39) rotate(-45)" fill="#2582fb"/>
</g>
<g id="left">
<rect id="carat-2" data-name="carat" width="14" height="14" transform="translate(7.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="right">
<rect id="carat-3" data-name="carat" width="14" height="14" transform="translate(26.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="top">
<rect id="carat-4" data-name="carat" width="14" height="14" transform="translate(18 13) rotate(-45)" fill="#2582fb"/>
</g>
<path id="A" d="M16.576,5.149v6.405h1.032V12.86H16.576v2.194H14.983V12.86H10.43V11.555q.629-.69,1.275-1.494t1.241-1.637q.595-.834,1.1-1.671a15.328,15.328,0,0,0,.858-1.6Zm-4.532,6.405h2.939v-4.2q-.41.7-.8,1.3t-.752,1.114q-.376.52-.721.957T12.043,11.555Z" transform="translate(13.5 15.689)" fill="#fff"/>
</g>
</g>
</svg>
<!-- Generator: Sketch 54.1 (76490) - https://sketchapp.com -->
<title>4</title>
<desc>Created with Sketch.</desc>
<g id="Devices" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Artboard" transform="translate(-247.000000, -159.000000)">
<g id="4" transform="translate(247.000000, 159.000000)">
<rect id="Rectangle" fill="#000000" x="7" y="6" width="40" height="40"></rect>
<g id="left" transform="translate(0.000000, 14.000000)" fill="#000000">
<rect id="carat" transform="translate(12.000000, 12.000000) rotate(-314.000000) translate(-12.000000, -12.000000) " x="4" y="4" width="16" height="16"></rect>
</g>
<g id="bottom" transform="translate(15.000000, 28.000000)" fill="#000000">
<rect id="carat" transform="translate(12.000000, 12.000000) rotate(-314.000000) translate(-12.000000, -12.000000) " x="4" y="4" width="16" height="16"></rect>
</g>
<g id="right" transform="translate(29.000000, 14.000000)" fill="#000000">
<rect id="carat" transform="translate(12.000000, 12.000000) rotate(-314.000000) translate(-12.000000, -12.000000) " x="4" y="4" width="16" height="16"></rect>
</g>
<g id="top" transform="translate(16.000000, 0.000000)" fill="#000000">
<rect id="carat" transform="translate(11.311985, 12.000000) rotate(-314.000000) translate(-11.311985, -12.000000) " x="3.31198537" y="4" width="16" height="16"></rect>
</g>
<path d="M30.4169922,28.7177734 L29.2412109,28.7177734 L29.2412109,30.8027344 L27.2724609,30.8027344 L27.2724609,28.7177734 L23,28.7177734 L23,27.34375 L27.1152344,21 L29.2412109,21 L29.2412109,27.1796875 L30.4169922,27.1796875 L30.4169922,28.7177734 Z M27.2998047,23.1601562 L27.2587891,23.1601562 C27.1949867,23.3242196 27.071941,23.5794254 26.8896484,23.9257812 L24.7910156,27.1796875 L27.2724609,27.1796875 L27.2724609,24.0966797 C27.2724609,23.8232408 27.2815754,23.5110695 27.2998047,23.1601562 Z" fill="#FFFFFF" fill-rule="nonzero"></path>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -1,21 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="53px" height="52px" viewBox="0 0 53 52" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Artboard" clip-path="url(#clip-Artboard)">
<g id="_5" data-name="5">
<rect id="Rectangle" width="29" height="36" rx="4" transform="translate(13 8)" fill="#2582fb"/>
<g id="bottom">
<rect id="carat" width="14" height="14" transform="translate(18 39) rotate(-45)" fill="#2582fb"/>
</g>
<g id="left">
<rect id="carat-2" data-name="carat" width="14" height="14" transform="translate(7.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="right">
<rect id="carat-3" data-name="carat" width="14" height="14" transform="translate(26.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="top">
<rect id="carat-4" data-name="carat" width="14" height="14" transform="translate(18 13) rotate(-45)" fill="#2582fb"/>
</g>
<path id="A" d="M10.816,14.18l.772-1.012a3.292,3.292,0,0,0,2.1.731,1.913,1.913,0,0,0,1.395-.513,1.753,1.753,0,0,0,.526-1.312,1.613,1.613,0,0,0-.588-1.35,2.748,2.748,0,0,0-1.723-.461q-.39,0-.841.027t-.861.075L11.944,5.2h4.826V6.551H13.223l-.171,2.461q.239-.014.475-.024t.427-.01a3.435,3.435,0,0,1,2.4.79,2.8,2.8,0,0,1,.868,2.177,3.054,3.054,0,0,1-.954,2.328,3.532,3.532,0,0,1-2.526.9,4.532,4.532,0,0,1-2.926-.991Z" transform="translate(13.5 15.689)" fill="#fff"/>
</g>
</g>
<!-- Generator: Sketch 54.1 (76490) - https://sketchapp.com -->
<title>5</title>
<desc>Created with Sketch.</desc>
<g id="Devices" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Artboard" transform="translate(-307.000000, -159.000000)">
<g id="5" transform="translate(307.000000, 159.000000)">
<rect id="Rectangle" fill="#000000" x="7" y="6" width="40" height="40"></rect>
<g id="left" transform="translate(0.000000, 14.000000)" fill="#000000">
<rect id="carat" transform="translate(12.000000, 12.000000) rotate(-314.000000) translate(-12.000000, -12.000000) " x="4" y="4" width="16" height="16"></rect>
</g>
<g id="bottom" transform="translate(15.000000, 28.000000)" fill="#000000">
<rect id="carat" transform="translate(12.000000, 12.000000) rotate(-314.000000) translate(-12.000000, -12.000000) " x="4" y="4" width="16" height="16"></rect>
</g>
<g id="right" transform="translate(29.000000, 14.000000)" fill="#000000">
<rect id="carat" transform="translate(12.000000, 12.000000) rotate(-314.000000) translate(-12.000000, -12.000000) " x="4" y="4" width="16" height="16"></rect>
</g>
<g id="top" transform="translate(16.000000, 0.000000)" fill="#000000">
<rect id="carat" transform="translate(11.311985, 12.000000) rotate(-314.000000) translate(-11.311985, -12.000000) " x="3.31198537" y="4" width="16" height="16"></rect>
</g>
<path d="M24,30.5498047 L24,28.7041016 C24.6699252,29.1142599 25.3831342,29.3193359 26.1396484,29.3193359 C26.7093127,29.3193359 27.1547835,29.1837579 27.4760742,28.9125977 C27.7973649,28.6414374 27.9580078,28.2734398 27.9580078,27.8085938 C27.9580078,26.8378858 27.2721423,26.3525391 25.9003906,26.3525391 C25.4537738,26.3525391 24.9137401,26.3935543 24.2802734,26.4755859 L24.2802734,21 L29.7080078,21 L29.7080078,22.7636719 L26.1259766,22.7636719 L26.1259766,24.7255859 C26.4130874,24.6982421 26.6842435,24.6845703 26.9394531,24.6845703 C27.9466196,24.6845703 28.7350232,24.9488906 29.3046875,25.4775391 C29.8743518,26.0061875 30.1591797,26.7171179 30.1591797,27.6103516 C30.1591797,28.5992888 29.8196649,29.4070607 29.140625,30.0336914 C28.4615851,30.6603221 27.5410214,30.9736328 26.3789062,30.9736328 C25.4355422,30.9736328 24.6425813,30.8323582 24,30.5498047 Z" fill="#FFFFFF" fill-rule="nonzero"></path>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Some files were not shown because too many files have changed in this diff Show more