mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-25 13:37:22 +01:00
Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d952661734 | ||
|
|
dbde5e3854 | ||
|
|
bed7f2a240 | ||
|
|
73a6f76610 | ||
|
|
9d70f784a2 | ||
|
|
4ded7132a5 | ||
|
|
b469b87d75 | ||
|
|
12f9239889 | ||
|
|
d302c761d7 | ||
|
|
814c8e382c | ||
|
|
b98be49bfa | ||
|
|
91d36b4b47 | ||
|
|
03c36b4f65 | ||
|
|
792a04cf48 | ||
|
|
a1bb281386 | ||
|
|
941ff0a5a6 | ||
|
|
39b98dab3b | ||
|
|
f9434ac812 | ||
|
|
022ed601ec | ||
|
|
e131d0ff4b | ||
|
|
f6f8e4c4eb | ||
|
|
5880f3855b | ||
|
|
1a25dacc73 | ||
|
|
b6a207c4b6 | ||
|
|
cccadec44c | ||
|
|
edc43e39ca | ||
|
|
5eaf60e8a2 | ||
|
|
2182aabe35 | ||
|
|
2ccf492707 | ||
|
|
0506f06a18 | ||
|
|
2e8dfa73d2 | ||
|
|
453bb613af | ||
|
|
7833ace553 | ||
|
|
6a01be2c38 | ||
|
|
ac4f725433 | ||
|
|
a1f319afa7 | ||
|
|
714ca349ff | ||
|
|
dec1aca97f | ||
|
|
409f58e55a | ||
|
|
f721c1f226 | ||
|
|
a1643b0a2e | ||
|
|
f6576e01f3 | ||
|
|
758a21a22f | ||
|
|
167ec5a3a8 | ||
|
|
8c24d7e942 | ||
|
|
5035dc6754 | ||
|
|
ba431c5bfd | ||
|
|
a96187bd04 | ||
|
|
127cf4e412 | ||
|
|
aa876838d4 | ||
|
|
1a9473c896 | ||
|
|
d52037fd5e | ||
|
|
bcba63e4b2 | ||
|
|
f303c29d4c | ||
|
|
cf0c45a319 | ||
|
|
67933a8470 | ||
|
|
a0dca4f401 |
7
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
7
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -12,7 +12,7 @@ body:
|
||||
attributes:
|
||||
label: Microsoft PowerToys version
|
||||
placeholder: |
|
||||
"0.33.1"
|
||||
"0.53.0"
|
||||
description: |
|
||||
Hover over system tray icon or look at Settings
|
||||
validations:
|
||||
@@ -32,8 +32,10 @@ body:
|
||||
multiple: true
|
||||
options:
|
||||
- General
|
||||
- Always on Top
|
||||
- Awake
|
||||
- ColorPicker
|
||||
- Developer file preview
|
||||
- FancyZones
|
||||
- FancyZones Editor
|
||||
- Image Resizer
|
||||
@@ -47,6 +49,7 @@ body:
|
||||
- PowerRename
|
||||
- PowerToys Run
|
||||
- Shortcut Guide
|
||||
- STL Thumbnail
|
||||
- SVG Preview
|
||||
- SVG Thumbnail
|
||||
- Settings
|
||||
@@ -77,7 +80,7 @@ body:
|
||||
label: ❌ Actual Behavior
|
||||
placeholder: What happened instead?
|
||||
validations:
|
||||
required: true
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
|
||||
11
.github/ISSUE_TEMPLATE/translation_issue.yml
vendored
11
.github/ISSUE_TEMPLATE/translation_issue.yml
vendored
@@ -13,7 +13,7 @@ body:
|
||||
- type: input
|
||||
attributes:
|
||||
label: Microsoft PowerToys version
|
||||
placeholder: "0.35.0"
|
||||
placeholder: "0.53.0"
|
||||
description: |
|
||||
Hover over system tray icon or look at Settings
|
||||
validations:
|
||||
@@ -23,20 +23,27 @@ body:
|
||||
label: Utility with translation issue
|
||||
options:
|
||||
- General
|
||||
- PowerToys Awake
|
||||
- Always on Top
|
||||
- Awake
|
||||
- ColorPicker
|
||||
- Developer file preview
|
||||
- FancyZones
|
||||
- FancyZones Editor
|
||||
- Image Resizer
|
||||
- Keyboard Manager
|
||||
- MD Preview
|
||||
- Mouse Utilities
|
||||
- PDF Preview
|
||||
- PDF Thumbnail
|
||||
- G-code Preview
|
||||
- G-code Thumbnail
|
||||
- PowerRename
|
||||
- PowerToys Run
|
||||
- Shortcut Guide
|
||||
- SVG Preview
|
||||
- SVG Thumbnail
|
||||
- Settings
|
||||
- Video Conference Mute
|
||||
- Welcome / PowerToys Tour window
|
||||
- System tray interaction
|
||||
- Installer
|
||||
|
||||
7
.github/actions/spell-check/excludes.txt
vendored
7
.github/actions/spell-check/excludes.txt
vendored
@@ -1,4 +1,8 @@
|
||||
# See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-excludes
|
||||
(?:^|/)monacoSRC/
|
||||
(?:^|/)MonacoPreviewHandler/languages.json
|
||||
(?:^|/)MonacoPreviewHandler/index.html
|
||||
(?:^|/)MonacoPreviewHandler/generateLanguagesJson.html
|
||||
(?:^|/)(?i)COPYRIGHT
|
||||
(?:^|/)(?i)LICEN[CS]E
|
||||
(?:^|/)package(?:-lock)\.json$
|
||||
@@ -26,6 +30,7 @@ ignore$
|
||||
\.pdf$
|
||||
\.PNG$
|
||||
\.png$
|
||||
\.stl$
|
||||
\.woff$
|
||||
\.zip$
|
||||
^doc/devdocs/akaLinks\.md$
|
||||
@@ -37,8 +42,6 @@ ignore$
|
||||
^src/modules/imageresizer/dll/ContextMenuHandler\.rgs$
|
||||
^src/modules/imageresizer/dll/ImageResizerExt\.rgs$
|
||||
^src/modules/powerrename/testapp/PowerRenameTest\.vcxproj\.filters$
|
||||
^src/modules/powerrename/UWPui/pch\.h$
|
||||
^src/modules/powerrename/UWPui/PowerRenameUWPUI\.vcxproj\.filters$
|
||||
^src/modules/previewpane/PreviewPaneUnitTests/HelperFiles/MarkdownWithHTMLImageTag\.txt$
|
||||
^src/modules/previewpane/UnitTests-MarkdownPreviewHandler/HelperFiles/MarkdownWithHTMLImageTag.txt$
|
||||
^tools/CleanUp_tool/CleanUp_tool\.vcxproj\.filters$
|
||||
|
||||
128
.github/actions/spell-check/expect.txt
vendored
128
.github/actions/spell-check/expect.txt
vendored
@@ -1,5 +1,8 @@
|
||||
aaaa
|
||||
abap
|
||||
abcd
|
||||
abcdef
|
||||
abcdefgh
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
abgr
|
||||
abi
|
||||
@@ -9,6 +12,7 @@ Abug
|
||||
accctrl
|
||||
Acceleratorkeys
|
||||
ACCEPTFILES
|
||||
ACCESSDENIED
|
||||
accessibile
|
||||
accessibilityinsights
|
||||
Acl
|
||||
@@ -58,6 +62,7 @@ api
|
||||
APIENTRY
|
||||
APIIs
|
||||
APPBARDATA
|
||||
appcontainer
|
||||
appdata
|
||||
APPICON
|
||||
appid
|
||||
@@ -104,11 +109,14 @@ atlcom
|
||||
atleast
|
||||
atlfile
|
||||
atlstr
|
||||
atop
|
||||
Attribs
|
||||
attrs
|
||||
aumid
|
||||
Aut
|
||||
Authenticode
|
||||
AUTHN
|
||||
autogenerate
|
||||
autogenerated
|
||||
autogenerates
|
||||
AUTOHIDE
|
||||
@@ -116,10 +124,13 @@ AUTOMATIONPROPERTIES
|
||||
Autorun
|
||||
AUTOUPDATE
|
||||
AValid
|
||||
Awaitable
|
||||
awakeness
|
||||
awakeversion
|
||||
AWAYMODE
|
||||
AYUV
|
||||
AZCLI
|
||||
azurecr
|
||||
backend
|
||||
backtracer
|
||||
BAEC
|
||||
@@ -141,6 +152,8 @@ bigbar
|
||||
bigobj
|
||||
binaryformatter
|
||||
binlog
|
||||
binskim
|
||||
bios
|
||||
bitmapimage
|
||||
BITMAPINFO
|
||||
BITMAPINFOHEADER
|
||||
@@ -173,6 +186,7 @@ Browsable
|
||||
bsd
|
||||
bstr
|
||||
bti
|
||||
btm
|
||||
Btn
|
||||
BTNFACE
|
||||
Bto
|
||||
@@ -181,17 +195,21 @@ BUFSIZE
|
||||
bugreport
|
||||
Buid
|
||||
BUILDARCH
|
||||
buildcommand
|
||||
buildtools
|
||||
buildtransitive
|
||||
BValue
|
||||
bytearray
|
||||
CALG
|
||||
callbackptr
|
||||
cameligo
|
||||
Camer
|
||||
Cangjie
|
||||
CANRENAME
|
||||
CAPTURECHANGED
|
||||
cassert
|
||||
CAtl
|
||||
CCB
|
||||
cch
|
||||
CCom
|
||||
CContext
|
||||
@@ -200,12 +218,17 @@ cdecl
|
||||
CDeclaration
|
||||
CDEF
|
||||
cdpx
|
||||
cdpxwin
|
||||
cdxml
|
||||
CEBB
|
||||
CENTERALIGN
|
||||
CFDB
|
||||
CFFDAFADA
|
||||
cguid
|
||||
changecursor
|
||||
Changemove
|
||||
charconv
|
||||
ChaseKnowlden
|
||||
chdir
|
||||
CHILDACTIVATE
|
||||
CHILDWINDOW
|
||||
@@ -219,11 +242,13 @@ cielab
|
||||
ciexyz
|
||||
CImage
|
||||
cinttypes
|
||||
cjs
|
||||
cla
|
||||
clangformat
|
||||
CLASSDC
|
||||
classname
|
||||
CLASSNOTAVAILABLE
|
||||
CleanCodeDeveloper
|
||||
clickable
|
||||
clickonce
|
||||
CLIENTEDGE
|
||||
@@ -231,8 +256,10 @@ CLIENTPULL
|
||||
clientside
|
||||
CLIPCHILDREN
|
||||
CLIPSIBLINGS
|
||||
cljs
|
||||
clrcall
|
||||
Cls
|
||||
cls
|
||||
CLSCTX
|
||||
clsid
|
||||
cmder
|
||||
@@ -244,6 +271,7 @@ CMINVOKECOMMANDINFO
|
||||
CMINVOKECOMMANDINFOEX
|
||||
CMock
|
||||
CMONITORS
|
||||
cmp
|
||||
cmyk
|
||||
cnt
|
||||
coclass
|
||||
@@ -297,10 +325,12 @@ COULDNOT
|
||||
countof
|
||||
cout
|
||||
CPower
|
||||
CPPARM
|
||||
cppblog
|
||||
cppruntime
|
||||
cppstd
|
||||
cppwinrt
|
||||
CPPx
|
||||
CProj
|
||||
CREATESCHEDULEDTASK
|
||||
CREATESTRUCT
|
||||
@@ -323,6 +353,7 @@ cstdint
|
||||
cstdlib
|
||||
cstring
|
||||
CStyle
|
||||
csx
|
||||
CSY
|
||||
CTAB
|
||||
CTest
|
||||
@@ -355,6 +386,7 @@ dacl
|
||||
DARKPURPLE
|
||||
DARKTEAL
|
||||
DARKYELLOW
|
||||
datareader
|
||||
Datavalue
|
||||
DATAW
|
||||
davidegiacometti
|
||||
@@ -378,6 +410,7 @@ Dedup
|
||||
deduplicate
|
||||
DEFAULTBOOTSTRAPPERINSTALLFOLDER
|
||||
DEFAULTCOLOR
|
||||
defaultcommand
|
||||
DEFAULTFLAGS
|
||||
DEFAULTONLY
|
||||
DEFAULTTONEAREST
|
||||
@@ -460,6 +493,8 @@ dshow
|
||||
dst
|
||||
DSVG
|
||||
DText
|
||||
dupenv
|
||||
DUSTIN
|
||||
dutil
|
||||
DVASPECT
|
||||
DVASPECTINFO
|
||||
@@ -524,11 +559,14 @@ ERASEBKGND
|
||||
EREOF
|
||||
EResize
|
||||
errc
|
||||
errorlevel
|
||||
ERRORMESSAGE
|
||||
ERRORTITLE
|
||||
ESettings
|
||||
esize
|
||||
esrp
|
||||
estdir
|
||||
etcore
|
||||
etl
|
||||
etw
|
||||
EUQ
|
||||
@@ -592,6 +630,7 @@ Filterx
|
||||
finalizer
|
||||
findfast
|
||||
findstr
|
||||
Firefox
|
||||
FIXEDFILEINFO
|
||||
FLASHZONES
|
||||
FLASHZONESONQUICKSWITCH
|
||||
@@ -599,6 +638,7 @@ flt
|
||||
flyout
|
||||
fmtlib
|
||||
FOF
|
||||
fof
|
||||
FOFX
|
||||
FOLDERID
|
||||
folderpath
|
||||
@@ -610,7 +650,9 @@ FPower
|
||||
FRAMECHANGED
|
||||
FRAMEDOWNLOAD
|
||||
franky
|
||||
frankychen
|
||||
Froml
|
||||
fsscript
|
||||
fstream
|
||||
FTYPE
|
||||
func
|
||||
@@ -622,6 +664,7 @@ FZE
|
||||
gabime
|
||||
GAC
|
||||
gacutil
|
||||
Gamebar
|
||||
GBarm
|
||||
GBs
|
||||
GCLP
|
||||
@@ -647,6 +690,9 @@ globals
|
||||
GNumber
|
||||
google
|
||||
GPTR
|
||||
graphql
|
||||
Grayscale
|
||||
gsuberland
|
||||
gtm
|
||||
gui
|
||||
guiddef
|
||||
@@ -714,6 +760,7 @@ HOLDESC
|
||||
homepage
|
||||
homljgmgpmcbpjbnjpfijnhipfkiclkd
|
||||
HOOKPROC
|
||||
Hostbackdropbrush
|
||||
hostname
|
||||
hotkeycontrol
|
||||
hotkeys
|
||||
@@ -883,6 +930,7 @@ Intelli
|
||||
interactable
|
||||
Interlop
|
||||
interop
|
||||
Interoperability
|
||||
intptr
|
||||
INTRESOURCE
|
||||
INVALIDARG
|
||||
@@ -967,6 +1015,7 @@ IZoom
|
||||
JArray
|
||||
jarro
|
||||
Jarryd
|
||||
Javascript
|
||||
jfif
|
||||
jgeosdfsdsgmkedfgdfgdfgbkmhcgcflmi
|
||||
jjw
|
||||
@@ -978,6 +1027,7 @@ JSONOf
|
||||
Jsons
|
||||
jsonval
|
||||
jsoref
|
||||
julia
|
||||
junja
|
||||
jxr
|
||||
jyuwono
|
||||
@@ -1003,14 +1053,19 @@ Keystool
|
||||
Keytool
|
||||
keyup
|
||||
KILLFOCUS
|
||||
Knowlden
|
||||
Knownfolders
|
||||
kotlin
|
||||
KSPROPERTY
|
||||
ktm
|
||||
kts
|
||||
Kybd
|
||||
LAlt
|
||||
Lambson
|
||||
lamotile
|
||||
langword
|
||||
Lastdevice
|
||||
LASTEXITCODE
|
||||
Laute
|
||||
laute
|
||||
laviusmotileng
|
||||
@@ -1029,6 +1084,7 @@ ldx
|
||||
LEFTSCROLLBAR
|
||||
lego
|
||||
len
|
||||
LEQ
|
||||
LError
|
||||
Lessthan
|
||||
LEVELID
|
||||
@@ -1038,12 +1094,15 @@ lhwnd
|
||||
LIBID
|
||||
LIGHTORANGE
|
||||
LIGHTTURQUOISE
|
||||
ligo
|
||||
lindex
|
||||
linkedin
|
||||
linkid
|
||||
linq
|
||||
LINQTo
|
||||
Linux
|
||||
listview
|
||||
litcoffee
|
||||
lld
|
||||
llkhf
|
||||
Llvm
|
||||
@@ -1092,6 +1151,7 @@ LPVOID
|
||||
LPW
|
||||
lpwndpl
|
||||
LPWSTR
|
||||
LReader
|
||||
LRESULT
|
||||
lshift
|
||||
lstrcmp
|
||||
@@ -1158,12 +1218,16 @@ millis
|
||||
mimetype
|
||||
mindaro
|
||||
Minimatch
|
||||
Minimizeallwindows
|
||||
MINIMIZEBOX
|
||||
MINIMIZEEND
|
||||
MINIMIZESTART
|
||||
miniz
|
||||
minlevel
|
||||
Miracast
|
||||
mirophone
|
||||
mjpg
|
||||
mkdir
|
||||
mlcfg
|
||||
mmdeviceapi
|
||||
mmi
|
||||
@@ -1171,6 +1235,7 @@ mmsys
|
||||
mmsystem
|
||||
mockapi
|
||||
MODECHANGE
|
||||
moderncop
|
||||
modernwpf
|
||||
modulekey
|
||||
MONITORINFO
|
||||
@@ -1235,6 +1300,7 @@ MYICON
|
||||
NAMECHANGE
|
||||
nameof
|
||||
namespace
|
||||
namings
|
||||
NATIVEFNTCTL
|
||||
NCACTIVATE
|
||||
ncc
|
||||
@@ -1258,6 +1324,7 @@ NCRBUTTONUP
|
||||
NDEBUG
|
||||
ndp
|
||||
NEEDDISPATCH
|
||||
neq
|
||||
NESW
|
||||
netcore
|
||||
netcoreapp
|
||||
@@ -1284,6 +1351,7 @@ NLSTEXT
|
||||
NOACTIVATE
|
||||
NOAGGREGATION
|
||||
NOASYNC
|
||||
nocache
|
||||
NOCLOSEPROCESS
|
||||
NOCOPYBITS
|
||||
nodeca
|
||||
@@ -1326,6 +1394,7 @@ NOTRACK
|
||||
NOUPDATE
|
||||
NOZORDER
|
||||
NPH
|
||||
npm
|
||||
npos
|
||||
NResize
|
||||
ntdll
|
||||
@@ -1386,6 +1455,7 @@ outsettings
|
||||
OVERLAPPEDWINDOW
|
||||
overlaywindow
|
||||
Overridable
|
||||
Oversampling
|
||||
OWNDC
|
||||
PACL
|
||||
PAINTSTRUCT
|
||||
@@ -1410,6 +1480,7 @@ pch
|
||||
PCIDLIST
|
||||
PCWSTR
|
||||
Pdb
|
||||
pdb
|
||||
pdbonly
|
||||
pdfpreviewhandler
|
||||
pdo
|
||||
@@ -1417,6 +1488,7 @@ pdto
|
||||
pdtobj
|
||||
pdw
|
||||
PDWORD
|
||||
pedrolamas
|
||||
PERCEIVEDFLAG
|
||||
pesi
|
||||
PEXCEPTION
|
||||
@@ -1426,6 +1498,8 @@ pgp
|
||||
pguid
|
||||
phbm
|
||||
phbmp
|
||||
php
|
||||
phps
|
||||
phwnd
|
||||
pici
|
||||
pid
|
||||
@@ -1445,7 +1519,10 @@ ploca
|
||||
plocm
|
||||
plugin
|
||||
pluginsmodel
|
||||
plx
|
||||
PMSIHANDLE
|
||||
policheck
|
||||
popd
|
||||
popup
|
||||
POPUPWINDOW
|
||||
posix
|
||||
@@ -1453,6 +1530,7 @@ Postion
|
||||
powercfg
|
||||
powerlauncher
|
||||
powerpreview
|
||||
powerquery
|
||||
powerrename
|
||||
POWERRENAMETEST
|
||||
POWERRENAMEUIHOST
|
||||
@@ -1505,8 +1583,10 @@ propkey
|
||||
propvarutil
|
||||
prvpane
|
||||
psapi
|
||||
psc
|
||||
PSECURITY
|
||||
psfgao
|
||||
psm
|
||||
Psr
|
||||
psrm
|
||||
psrree
|
||||
@@ -1522,6 +1602,7 @@ PToy
|
||||
ptr
|
||||
ptstr
|
||||
Pui
|
||||
pushd
|
||||
PVOID
|
||||
pwa
|
||||
pwcs
|
||||
@@ -1529,6 +1610,11 @@ pwsh
|
||||
PWSTR
|
||||
pwsz
|
||||
pwtd
|
||||
pyc
|
||||
pyd
|
||||
pyi
|
||||
pyo
|
||||
pyz
|
||||
qianlifeng
|
||||
Qin
|
||||
qit
|
||||
@@ -1561,7 +1647,10 @@ RBUTTONUP
|
||||
rclsid
|
||||
RCONTROL
|
||||
RCtrl
|
||||
rda
|
||||
rdata
|
||||
rdeveen
|
||||
rds
|
||||
readme
|
||||
READMODE
|
||||
readonly
|
||||
@@ -1605,6 +1694,7 @@ renamable
|
||||
RENAMEONCOLLISION
|
||||
Renamer
|
||||
Reparse
|
||||
reportbug
|
||||
requery
|
||||
requerying
|
||||
rescap
|
||||
@@ -1639,6 +1729,7 @@ RKey
|
||||
RMENU
|
||||
RNumber
|
||||
roadmap
|
||||
robocopy
|
||||
Roboto
|
||||
roslyn
|
||||
royvou
|
||||
@@ -1674,6 +1765,7 @@ SAVEFAILED
|
||||
scancode
|
||||
scanled
|
||||
schedtasks
|
||||
scm
|
||||
SCOOBE
|
||||
SCOPEID
|
||||
screenshot
|
||||
@@ -1715,6 +1807,7 @@ SETWORKAREA
|
||||
sfgao
|
||||
SFGAOF
|
||||
SFP
|
||||
SHAREIMAGELISTS
|
||||
sharpkeys
|
||||
SHCNE
|
||||
SHCNF
|
||||
@@ -1756,6 +1849,7 @@ SHOWNOACTIVATE
|
||||
SHOWNORMAL
|
||||
SHOWWINDOW
|
||||
shtypes
|
||||
SICHINT
|
||||
sid
|
||||
siex
|
||||
SIGABRT
|
||||
@@ -1780,6 +1874,7 @@ SKIPOWNPROCESS
|
||||
sku
|
||||
SLGP
|
||||
sln
|
||||
smallbasic
|
||||
SMALLICON
|
||||
SMTO
|
||||
snd
|
||||
@@ -1791,9 +1886,11 @@ SOURCECLIENTAREAONLY
|
||||
SOURCEHEADER
|
||||
sourceid
|
||||
sourcesdirectory
|
||||
spamming
|
||||
spdisp
|
||||
spdlog
|
||||
spdo
|
||||
spdth
|
||||
spec'ing
|
||||
specialfolder
|
||||
spesi
|
||||
@@ -1803,6 +1900,7 @@ spsi
|
||||
spsia
|
||||
spsrm
|
||||
spsv
|
||||
sqlite
|
||||
SRCCOPY
|
||||
sre
|
||||
sregex
|
||||
@@ -1845,6 +1943,7 @@ STEPIT
|
||||
stgm
|
||||
STGMEDIUM
|
||||
sticpl
|
||||
stl
|
||||
stoi
|
||||
stol
|
||||
stoll
|
||||
@@ -1863,6 +1962,7 @@ strsafe
|
||||
strutil
|
||||
sttngs
|
||||
Stubless
|
||||
stx
|
||||
STYLECHANGED
|
||||
STYLECHANGING
|
||||
stylecop
|
||||
@@ -1878,6 +1978,7 @@ SVE
|
||||
SVGIn
|
||||
SVGIO
|
||||
svgpreviewhandler
|
||||
svh
|
||||
SWC
|
||||
SWFO
|
||||
SWITCHEND
|
||||
@@ -1886,6 +1987,8 @@ swprintf
|
||||
SWRESTORE
|
||||
swscanf
|
||||
SYMED
|
||||
symlink
|
||||
symlinks
|
||||
SYMOPT
|
||||
SYNCMFT
|
||||
SYNCPAINT
|
||||
@@ -1898,15 +2001,18 @@ SYSICONINDEX
|
||||
SYSKEY
|
||||
syskeydown
|
||||
SYSKEYUP
|
||||
SYSLIB
|
||||
syslog
|
||||
SYSMENU
|
||||
systemd
|
||||
SYSTEMTIME
|
||||
systemverilog
|
||||
Tadele
|
||||
tadele
|
||||
talynone
|
||||
TApp
|
||||
TApplication
|
||||
TApplied
|
||||
targ
|
||||
TARGETAPPHEADER
|
||||
TARGETDIR
|
||||
@@ -1918,7 +2024,9 @@ taskbar
|
||||
taskkill
|
||||
tasklist
|
||||
taskschd
|
||||
tbc
|
||||
tchar
|
||||
tcl
|
||||
tcscpy
|
||||
TCustom
|
||||
tdbuild
|
||||
@@ -1937,6 +2045,7 @@ textblock
|
||||
TEXTINCLUDE
|
||||
THICKFRAME
|
||||
THISCOMPONENT
|
||||
THotkey
|
||||
thre
|
||||
TILEDWINDOW
|
||||
timedate
|
||||
@@ -1956,6 +2065,7 @@ Toolchain
|
||||
toolkitcontrols
|
||||
toolkitconverters
|
||||
Toolset
|
||||
toolset
|
||||
toolstrip
|
||||
toolwindow
|
||||
TOPDOWNDIB
|
||||
@@ -1966,6 +2076,7 @@ Towindow
|
||||
towlower
|
||||
towupper
|
||||
tracelogging
|
||||
trackpad
|
||||
traies
|
||||
transcoded
|
||||
transparrent
|
||||
@@ -1991,6 +2102,7 @@ UAL
|
||||
uap
|
||||
udit
|
||||
Udp
|
||||
uefi
|
||||
UIA
|
||||
Uid
|
||||
uint
|
||||
@@ -2002,6 +2114,7 @@ ULARGE
|
||||
ULLONG
|
||||
ulong
|
||||
ULONGLONG
|
||||
umd
|
||||
unchecks
|
||||
uncomment
|
||||
uncompilable
|
||||
@@ -2058,6 +2171,7 @@ UWPUI
|
||||
uxtheme
|
||||
UYVY
|
||||
validmodulename
|
||||
vbhtml
|
||||
vcamp
|
||||
vccorlib
|
||||
vcdl
|
||||
@@ -2074,6 +2188,7 @@ vec
|
||||
VERBSONLY
|
||||
VERBW
|
||||
VERIFYCONTEXT
|
||||
verilog
|
||||
verrsrc
|
||||
VERSIONINFO
|
||||
Versioning
|
||||
@@ -2098,8 +2213,11 @@ Vpn
|
||||
VREDRAW
|
||||
VSC
|
||||
VSCBD
|
||||
vscdb
|
||||
vscode
|
||||
VSCROLL
|
||||
vse
|
||||
vsix
|
||||
vsonline
|
||||
vstemplate
|
||||
VSTHRD
|
||||
@@ -2120,13 +2238,19 @@ wcscpy
|
||||
wcslen
|
||||
wcsncmp
|
||||
wcsnicmp
|
||||
WDK
|
||||
wdksetup
|
||||
wdkvsix
|
||||
wdp
|
||||
wdupenv
|
||||
We'd
|
||||
weakme
|
||||
webcam
|
||||
webclient
|
||||
webpack
|
||||
webpage
|
||||
website
|
||||
webview
|
||||
wekyb
|
||||
Wevtapi
|
||||
wgpocpl
|
||||
@@ -2173,7 +2297,8 @@ winkey
|
||||
WINL
|
||||
winmd
|
||||
winmm
|
||||
winnt
|
||||
WINMSAPP
|
||||
WINNT
|
||||
winres
|
||||
winrt
|
||||
winsdk
|
||||
@@ -2224,6 +2349,7 @@ wstr
|
||||
wstring
|
||||
wstringstream
|
||||
wsz
|
||||
WTL
|
||||
wtoi
|
||||
WTS
|
||||
wtsapi
|
||||
|
||||
1
.github/workflows/spelling2.yml
vendored
1
.github/workflows/spelling2.yml
vendored
@@ -72,5 +72,6 @@ jobs:
|
||||
- name: comment
|
||||
uses: check-spelling/check-spelling@v0.0.20-alpha3
|
||||
with:
|
||||
config: .github/actions/spell-check
|
||||
custom_task: comment
|
||||
internal_state_directory: /tmp/data
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -344,3 +344,6 @@ src/common/Telemetry/*.etl
|
||||
/src/modules/previewpane/SvgThumbnailProvider/$(SolutionDir)$(Platform)/$(Configuration)/modules/FileExplorerPreview/SvgThumbnailProvider.xml
|
||||
/src/modules/powerrename/ui/RCa24464
|
||||
/src/modules/powerrename/ui/RCb24464
|
||||
|
||||
# Generated installer file for Monaco source files.
|
||||
/installer/PowerToysSetup/MonacoSRC.wxs
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
"*.resources.dll",
|
||||
|
||||
"PowerToysSetupCustomActions.dll",
|
||||
|
||||
|
||||
"PowerToys.ActionRunner.exe",
|
||||
"PowerToys.Update.exe",
|
||||
@@ -16,14 +15,17 @@
|
||||
"os-detection.dll",
|
||||
"PowerToys.exe",
|
||||
"PowerToys.Interop.dll",
|
||||
"BugReportTool\\BugReportTool.exe",
|
||||
"WebcamReportTool\\WebcamReportTool.exe",
|
||||
"BugReportTool\\PowerToys.BugReportTool.exe",
|
||||
"WebcamReportTool\\PowerToys.WebcamReportTool.exe",
|
||||
"Telemetry.dll",
|
||||
"PowerToys.ManagedTelemetry.dll",
|
||||
"PowerToys.ManagedCommon.dll",
|
||||
"PowerToys.Common.UI.dll",
|
||||
"PowerToys.Settings.UI.Lib.dll",
|
||||
|
||||
"modules\\AlwaysOnTop\\PowerToys.AlwaysOnTop.exe",
|
||||
"modules\\AlwaysOnTop\\PowerToys.AlwaysOnTopModuleInterface.dll",
|
||||
|
||||
"modules\\ColorPicker\\ColorPicker.dll",
|
||||
"modules\\ColorPicker\\ColorPickerUI.dll",
|
||||
"modules\\ColorPicker\\ColorPickerUI.exe",
|
||||
@@ -32,9 +34,6 @@
|
||||
"modules\\ColorPicker\\PowerToys.ColorPickerUI.dll",
|
||||
"modules\\ColorPicker\\PowerToys.ColorPickerUI.exe",
|
||||
|
||||
"modules\\AlwaysOnTop\\PowerToys.AlwaysOnTop.exe",
|
||||
"modules\\AlwaysOnTop\\PowerToys.AlwaysOnTopModuleInterface.dll",
|
||||
|
||||
"modules\\Awake\\PowerToys.AwakeModuleInterface.dll",
|
||||
"modules\\Awake\\PowerToys.Awake.exe",
|
||||
"modules\\Awake\\PowerToys.Awake.dll",
|
||||
@@ -52,12 +51,16 @@
|
||||
"modules\\FileExplorerPreview\\PowerToys.ManagedTelemetry.dll",
|
||||
"modules\\FileExplorerPreview\\PowerToys.MarkdownPreviewHandler.dll",
|
||||
"modules\\FileExplorerPreview\\PowerToys.MarkdownPreviewHandler.comhost.dll",
|
||||
"modules\\FileExplorerPreview\\PowerToys.MonacoPreviewHandler.dll",
|
||||
"modules\\FileExplorerPreview\\PowerToys.MonacoPreviewHandler.comhost.dll",
|
||||
"modules\\FileExplorerPreview\\PowerToys.PdfPreviewHandler.dll",
|
||||
"modules\\FileExplorerPreview\\PowerToys.PdfPreviewHandler.comhost.dll",
|
||||
"modules\\FileExplorerPreview\\PowerToys.PdfThumbnailProvider.dll",
|
||||
"modules\\FileExplorerPreview\\PowerToys.PdfThumbnailProvider.comhost.dll",
|
||||
"modules\\FileExplorerPreview\\PowerToys.powerpreview.dll",
|
||||
"modules\\FileExplorerPreview\\PowerToys.PreviewHandlerCommon.dll",
|
||||
"modules\\FileExplorerPreview\\PowerToys.StlThumbnailProvider.dll",
|
||||
"modules\\FileExplorerPreview\\PowerToys.StlThumbnailProvider.comhost.dll",
|
||||
"modules\\FileExplorerPreview\\PowerToys.SvgPreviewHandler.dll",
|
||||
"modules\\FileExplorerPreview\\PowerToys.SvgPreviewHandler.comhost.dll",
|
||||
"modules\\FileExplorerPreview\\PowerToys.SvgThumbnailProvider.dll",
|
||||
@@ -96,6 +99,7 @@
|
||||
|
||||
"modules\\MouseUtils\\PowerToys.FindMyMouse.dll",
|
||||
"modules\\MouseUtils\\PowerToys.MouseHighlighter.dll",
|
||||
"modules\\MouseUtils\\PowerToys.MousePointerCrosshairs.dll",
|
||||
|
||||
"modules\\PowerRename\\PowerToys.PowerRenameExt.dll",
|
||||
"modules\\PowerRename\\PowerToys.PowerRenameUILib.dll",
|
||||
@@ -165,9 +169,10 @@
|
||||
"NLog.dll",
|
||||
"HtmlAgilityPack.dll",
|
||||
"Markdig.Signed.dll",
|
||||
"HelixToolkit.dll",
|
||||
"HelixToolkit.Core.Wpf.dll",
|
||||
"Mages.Core.dll",
|
||||
"JetBrains.Annotations.dll",
|
||||
"ICSharpCode.SharpZipLib.dll",
|
||||
"NLog.Extensions.Logging.dll",
|
||||
"concrt140_app.dll",
|
||||
"msvcp140_1_app.dll",
|
||||
@@ -178,6 +183,14 @@
|
||||
"vcomp140_app.dll",
|
||||
"vcruntime140_1_app.dll",
|
||||
"vcruntime140_app.dll",
|
||||
"modules\\FileExplorerPreview\\Microsoft.Web.WebView2.Core.dll",
|
||||
"modules\\FileExplorerPreview\\Microsoft.Web.WebView2.WinForms.dll",
|
||||
"modules\\FileExplorerPreview\\Microsoft.Web.WebView2.Wpf.dll",
|
||||
"modules\\FileExplorerPreview\\runtimes\\win-x64\\native\\WebView2Loader.dll",
|
||||
"modules\\launcher\\e_sqlite3.dll",
|
||||
"modules\\launcher\\SQLitePCLRaw.batteries_v2.dll",
|
||||
"modules\\launcher\\SQLitePCLRaw.core.dll",
|
||||
"modules\\launcher\\SQLitePCLRaw.provider.e_sqlite3.dll",
|
||||
"ColorCode.Core.dll",
|
||||
"ColorCode.UWP.dll",
|
||||
"UnitsNet.dll"
|
||||
|
||||
@@ -103,6 +103,7 @@ steps:
|
||||
testAssemblyVer2: |
|
||||
**\UnitTests-GcodeThumbnailProvider.dll
|
||||
**\UnitTests-SvgThumbnailProvider.dll
|
||||
**\UnitTests-StlThumbnailProvider.dll
|
||||
**\UnitTests-PdfThumbnailProvider.dll
|
||||
**\Settings.UI.UnitTests.dll
|
||||
**\UnitTests-MarkdownPreviewHandler.dll
|
||||
@@ -124,6 +125,7 @@ steps:
|
||||
**\Microsoft.PowerToys.Run.Plugin.System.UnitTests.dll
|
||||
**\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.UnitTests.dll
|
||||
!**\obj\**
|
||||
!**\ref\**
|
||||
|
||||
# Native dlls
|
||||
- task: VSTest@2
|
||||
|
||||
@@ -217,6 +217,20 @@ jobs:
|
||||
clean: true
|
||||
maximumCpuCount: true
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: 'Extracting MSI to verify contents'
|
||||
inputs:
|
||||
script: |
|
||||
.\installer\packages\WiX.3.11.2\tools\dark.exe -x $(build.sourcesdirectory)\extractedMsi installer\PowerToysSetup\$(BuildPlatform)\$(BuildConfiguration)\PowerToysSetup-${{ parameters.versionNumber }}-$(BuildPlatform).msi
|
||||
dir $(build.sourcesdirectory)\extractedMsi
|
||||
|
||||
# Did we sign all files
|
||||
- task: PowerShell@1
|
||||
displayName: Verifying entire build is signed and version set
|
||||
inputs:
|
||||
scriptName: .pipelines/versionAndSignCheck.ps1
|
||||
arguments: -targetDir '$(build.sourcesdirectory)\extractedMsi\File'
|
||||
|
||||
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
|
||||
displayName: Sign MSI
|
||||
inputs:
|
||||
|
||||
53
.pipelines/versionAndSignCheck.ps1
Normal file
53
.pipelines/versionAndSignCheck.ps1
Normal file
@@ -0,0 +1,53 @@
|
||||
[CmdletBinding()]
|
||||
# todo: send in arch / conf, could send in actual path
|
||||
Param(
|
||||
[Parameter(Mandatory=$True,Position=1)]
|
||||
[AllowEmptyString()]
|
||||
[string]$targetDir = $PSScriptRoot + '/../extractedMsi/File'
|
||||
)
|
||||
|
||||
$DirPath = $targetDir; #this file is in pipeline, we need root.
|
||||
$items = Get-ChildItem -Path $DirPath -File -Include *.exe,*.dll,*.ttf -Recurse -Force -ErrorAction SilentlyContinue
|
||||
$totalFailure = 0;
|
||||
|
||||
Write-Host $DirPath;
|
||||
|
||||
if(-not (Test-Path $DirPath))
|
||||
{
|
||||
Write-Host "Folder does not exist!"
|
||||
}
|
||||
|
||||
Write-Host "Total items: " $items.Count
|
||||
|
||||
if($items.Count -eq 0)
|
||||
{
|
||||
# no items means something bad happened. We should fail ASAP
|
||||
exit 1;
|
||||
}
|
||||
|
||||
$items | ForEach-Object {
|
||||
if($_.VersionInfo.FileVersion -eq "1.0.0.0" )
|
||||
{
|
||||
if(-not $_.Name.EndsWith("Microsoft.Search.Interop.dll"))
|
||||
{
|
||||
Write-Host "Version not set: " + $_.FullName
|
||||
$totalFailure++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$items | ForEach-Object {
|
||||
$auth = Get-AuthenticodeSignature $_.FullName
|
||||
if($auth.SignerCertificate -eq $null)
|
||||
{
|
||||
Write-Host "Not Signed: " + $_.FullName
|
||||
$totalFailure++;
|
||||
}
|
||||
}
|
||||
|
||||
if($totalFailure -gt 0)
|
||||
{
|
||||
exit 1
|
||||
}
|
||||
|
||||
exit 0
|
||||
11
COMMUNITY.md
11
COMMUNITY.md
@@ -6,11 +6,20 @@ Names are in alphabetical order based on first name.
|
||||
|
||||
## High impact community members
|
||||
|
||||
### [@Aaron-Junker](https://github.com/Aaron-Junker) - [Aaron Junker](https://aaron-junker.github.io)
|
||||
Aaron has helped triaging, discussing, and creating a substantial number of issues and contributed features/fixes as well as work on an upcoming utility.
|
||||
|
||||
### [@davidegiacometti](https://github.com/davidegiacometti) - [Davide Giacometti](https://www.linkedin.com/in/davidegiacometti/)
|
||||
Davide has helped fix multiple bugs, added new features, as well as help us with the ARM64 effort by porting applications to .NET Core.
|
||||
|
||||
### [@franky920920](https://github.com/franky920920) - [Franky Chen](https://frankychen.net)
|
||||
Franky has helped triaging, discussing, and creating a substantial number of issues and contributed features/fixes to PowerToys.
|
||||
|
||||
### [@htcfreek](https://github.com/htcfreek) - Heiko
|
||||
Heiko has helped triaging, discussing, and creating a substantial number of issues and contributed features/fixes to PowerToys Run.
|
||||
Heiko has helped triaging, discussing, and creating a substantial number of issues and contributed features/fixes to PowerToys.
|
||||
|
||||
### [@Jay-o-Way](https://github.com/Jay-o-Way) - Jay
|
||||
Jay has helped triaging, discussing, creating a substantial number of issues and PRs.
|
||||
|
||||
### [@jsoref](https://github.com/jsoref) - [Josh Soref](https://check-spelling.dev/)
|
||||
Helping keep our spelling correct :)
|
||||
|
||||
44
NOTICE.md
44
NOTICE.md
@@ -1,7 +1,13 @@
|
||||
# NOTICES AND INFORMATION
|
||||
This software incorporates material from third parties.
|
||||
|
||||
## PowerToy: Color Picker
|
||||
- Color Picker
|
||||
- File Explorer Add-ins
|
||||
- ImageResizer
|
||||
- PowerToys Run
|
||||
- Installer/Runner
|
||||
|
||||
## Utility: Color Picker
|
||||
|
||||
### Martin Chrzan's Color Picker
|
||||
|
||||
@@ -29,7 +35,37 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
## PowerToy: ImageResizer
|
||||
## Utility: File Explorer Add-ins
|
||||
|
||||
### Monaco Editor
|
||||
|
||||
**Source**: https://github.com/Microsoft/monaco-editor
|
||||
|
||||
**Additional third party notifications:** https://github.com/microsoft/monaco-editor/blob/main/ThirdPartyNotices.txt
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 - present Microsoft Corporation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
## Utility: ImageResizer
|
||||
|
||||
### Brice Lams's Image Resizer License
|
||||
|
||||
@@ -57,7 +93,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
## PowerToy: Launcher
|
||||
## Utility: PowerToys Run
|
||||
|
||||
### Wox License
|
||||
|
||||
@@ -99,7 +135,7 @@ The above copyright notice and this permission notice shall be included in all c
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
## PowerToy: PowerRename
|
||||
## Utility: PowerRename
|
||||
|
||||
### Chris Davis's SmartRename License
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "src\runner\runner
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
|
||||
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB} = {6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73} = {031AC72E-FA28-4AB7-B690-6F7B9C28AA73}
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387} = {0485F45C-EA7A-4BB5-804B-3E8D14699387}
|
||||
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D} = {D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481} = {5CCC8468-DEC8-4D36-99D4-5C891BEBD481}
|
||||
{BA58206B-1493-4C75-BFEA-A85768A1E156} = {BA58206B-1493-4C75-BFEA-A85768A1E156}
|
||||
@@ -74,8 +73,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameUnitTests", "src
|
||||
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}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManager", "src\modules\keyboardmanager\dll\KeyboardManager.vcxproj", "{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "imageresizer", "imageresizer", "{6C7F47CC-2151-44A3-A546-41C70025132C}"
|
||||
@@ -391,6 +388,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AlwaysOnTopModuleInterface"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Community.PowerToys.Run.Plugin.WebSearch", "src\modules\launcher\Plugins\Community.PowerToys.Run.Plugin.WebSearch\Community.PowerToys.Run.Plugin.WebSearch.csproj", "{9F94B303-5E21-4364-9362-64426F8DB932}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MousePointerCrosshairs", "src\modules\MouseUtils\MousePointerCrosshairs\MousePointerCrosshairs.vcxproj", "{EAE14C0E-7A6B-45DA-9080-A7D8C077BA6E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StlThumbnailProvider", "src\modules\previewpane\StlThumbnailProvider\StlThumbnailProvider.csproj", "{F7C8C0F1-5431-4347-89D0-8E5354F93CF2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-StlThumbnailProvider", "src\modules\previewpane\UnitTests-StlThumbnailProvider\UnitTests-StlThumbnailProvider.csproj", "{F1F6B6B6-9F18-4A17-8B5C-97DF552C53DC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MonacoPreviewHandler", "src\modules\previewpane\MonacoPreviewHandler\MonacoPreviewHandler.csproj", "{04B193D7-3E21-46B8-A958-89B63A8A69DE}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
@@ -459,12 +464,6 @@ Global
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|x64.ActiveCfg = Release|x64
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|x64.Build.0 = Release|x64
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|x86.ActiveCfg = Release|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Debug|x64.Build.0 = Debug|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Release|x64.ActiveCfg = Release|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Release|x64.Build.0 = Release|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Release|x86.ActiveCfg = Release|x64
|
||||
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Debug|x64.Build.0 = Debug|x64
|
||||
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Debug|x86.ActiveCfg = Debug|x64
|
||||
@@ -1054,6 +1053,30 @@ Global
|
||||
{9F94B303-5E21-4364-9362-64426F8DB932}.Release|x64.ActiveCfg = Release|x64
|
||||
{9F94B303-5E21-4364-9362-64426F8DB932}.Release|x64.Build.0 = Release|x64
|
||||
{9F94B303-5E21-4364-9362-64426F8DB932}.Release|x86.ActiveCfg = Release|x64
|
||||
{EAE14C0E-7A6B-45DA-9080-A7D8C077BA6E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{EAE14C0E-7A6B-45DA-9080-A7D8C077BA6E}.Debug|x64.Build.0 = Debug|x64
|
||||
{EAE14C0E-7A6B-45DA-9080-A7D8C077BA6E}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{EAE14C0E-7A6B-45DA-9080-A7D8C077BA6E}.Release|x64.ActiveCfg = Release|x64
|
||||
{EAE14C0E-7A6B-45DA-9080-A7D8C077BA6E}.Release|x64.Build.0 = Release|x64
|
||||
{EAE14C0E-7A6B-45DA-9080-A7D8C077BA6E}.Release|x86.ActiveCfg = Release|x64
|
||||
{F7C8C0F1-5431-4347-89D0-8E5354F93CF2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F7C8C0F1-5431-4347-89D0-8E5354F93CF2}.Debug|x64.Build.0 = Debug|x64
|
||||
{F7C8C0F1-5431-4347-89D0-8E5354F93CF2}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{F7C8C0F1-5431-4347-89D0-8E5354F93CF2}.Release|x64.ActiveCfg = Release|x64
|
||||
{F7C8C0F1-5431-4347-89D0-8E5354F93CF2}.Release|x64.Build.0 = Release|x64
|
||||
{F7C8C0F1-5431-4347-89D0-8E5354F93CF2}.Release|x86.ActiveCfg = Release|x64
|
||||
{F1F6B6B6-9F18-4A17-8B5C-97DF552C53DC}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F1F6B6B6-9F18-4A17-8B5C-97DF552C53DC}.Debug|x64.Build.0 = Debug|x64
|
||||
{F1F6B6B6-9F18-4A17-8B5C-97DF552C53DC}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{F1F6B6B6-9F18-4A17-8B5C-97DF552C53DC}.Release|x64.ActiveCfg = Release|x64
|
||||
{F1F6B6B6-9F18-4A17-8B5C-97DF552C53DC}.Release|x64.Build.0 = Release|x64
|
||||
{F1F6B6B6-9F18-4A17-8B5C-97DF552C53DC}.Release|x86.ActiveCfg = Release|x64
|
||||
{04B193D7-3E21-46B8-A958-89B63A8A69DE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{04B193D7-3E21-46B8-A958-89B63A8A69DE}.Debug|x64.Build.0 = Debug|x64
|
||||
{04B193D7-3E21-46B8-A958-89B63A8A69DE}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{04B193D7-3E21-46B8-A958-89B63A8A69DE}.Release|x64.ActiveCfg = Release|x64
|
||||
{04B193D7-3E21-46B8-A958-89B63A8A69DE}.Release|x64.Build.0 = Release|x64
|
||||
{04B193D7-3E21-46B8-A958-89B63A8A69DE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -1070,7 +1093,6 @@ Global
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2} = {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}
|
||||
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
|
||||
{6C7F47CC-2151-44A3-A546-41C70025132C} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34} = {6C7F47CC-2151-44A3-A546-41C70025132C}
|
||||
@@ -1182,6 +1204,10 @@ Global
|
||||
{1DC3BE92-CE89-43FB-8110-9C043A2FE7A2} = {60CD2D4F-C3B9-4897-9821-FCA5098B41CE}
|
||||
{48A0A19E-A0BE-4256-ACF8-CC3B80291AF9} = {60CD2D4F-C3B9-4897-9821-FCA5098B41CE}
|
||||
{9F94B303-5E21-4364-9362-64426F8DB932} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{EAE14C0E-7A6B-45DA-9080-A7D8C077BA6E} = {322566EF-20DC-43A6-B9F8-616AF942579A}
|
||||
{F7C8C0F1-5431-4347-89D0-8E5354F93CF2} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{F1F6B6B6-9F18-4A17-8B5C-97DF552C53DC} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{04B193D7-3E21-46B8-A958-89B63A8A69DE} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
||||
166
README.md
166
README.md
@@ -6,10 +6,10 @@
|
||||
|
||||
## Build status
|
||||
|
||||
| Architecture | Solution (Main) | Solution (Stable) | Installer (Main)<br/>Existing pipeline | Installer (Main)<br/>New pipeline |
|
||||
|--------------|-----------------|-------------------|-----------------------|-------------------------------|
|
||||
| x64 | [](https://dev.azure.com/ms/PowerToys/_build/latest?definitionId=219&branchName=main) | [](https://dev.azure.com/ms/PowerToys/_build/latest?definitionId=219&branchName=stable) | [](https://github-private.visualstudio.com/microsoft/_build/latest?definitionId=61&branchName=main) | [](https://dev.azure.com/microsoft/Dart/_build/latest?definitionId=76541&branchName=main) |
|
||||
| ARM64 | Currently investigating | [Issue #490](https://github.com/microsoft/PowerToys/issues/490) | | |
|
||||
| Architecture | Solution (Main) | Solution (Stable) | Installer (Main) |
|
||||
|--------------|-----------------|-------------------|------------------|
|
||||
| x64 | [](https://dev.azure.com/ms/PowerToys/_build/latest?definitionId=219&branchName=main) | [](https://dev.azure.com/ms/PowerToys/_build/latest?definitionId=219&branchName=stable) | [](https://dev.azure.com/microsoft/Dart/_build/latest?definitionId=76541&branchName=main) |
|
||||
| ARM64 | Currently investigating | [Issue #490](https://github.com/microsoft/PowerToys/issues/490) | |
|
||||
|
||||
## About
|
||||
|
||||
@@ -17,21 +17,21 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
|
||||
|
||||
| | 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) | |
|
||||
| [Always on Top](https://aka.ms/PowerToysOverview_AoT) | [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) |
|
||||
|
||||
## 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.
|
||||
- [.NET Core 3.1.22 Desktop Runtime](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-desktop-3.1.22-windows-x64-installer) or a newer 3.1.x runtime. The installer will handle this if not present.
|
||||
|
||||
### Via GitHub with EXE [Recommended]
|
||||
|
||||
[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.51.1-x64.exe` to download the PowerToys installer.
|
||||
[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.53.3-x64.exe` to download the PowerToys installer.
|
||||
|
||||
This is our preferred method.
|
||||
|
||||
@@ -66,104 +66,98 @@ 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.51 - November 2021 Update
|
||||
#### 0.53 - December 2021 Update
|
||||
|
||||
The [v0.51 release cycle][github-current-release-work] introduces some new things regarding our mouse utilities. First is we've added in a presentation mode helper to highlight your mouse when you click. We've also added additional settings toward Find my mouse to enable more customization.
|
||||
We hope everyone has had a wonderful December 2021. The PowerToys community has been busy with a bunch of improvements. We're still working on improving the installer but this should drastically improve things. 3 things you will want to check out are G-code support in file explorer preview pane and thumbnails, the new web search plugin from PowerToys Run via <kbd>??</kbd> action phrase, and the new Always on Top utility via <kbd>Win</kbd>+<kbd>Ctrl</kbd>+<kbd>T</kbd>.
|
||||
|
||||
Next we've been focusing work on "Always on Top" system to help make any window you want to be the top most. A lot of thought is currently going into interaction models to make sure it 'feels' right for toggling as well as visualizing.
|
||||
[@Aaron-Junker](https://github.com/Aaron-Junker) also has done some great progress on [implementing developer file preview pane](https://github.com/microsoft/PowerToys/issues/1527) via the Monaco engine from Visual Studio Code.
|
||||
|
||||
Last, we've been working on our engineering systems this month and into next. This work will improve our localization integration and our 'build farm' match our CI system far more. Behind the scene work but very important work for working faster.
|
||||
#### Things to be aware of
|
||||
- The new installer currently has a visual quirk when upgrade if you have a custom install path. It will show the default install path but it will actually overwrite the current location. We are investigating how to fix this.
|
||||
|
||||
#### Highlights from v0.51
|
||||
#### Always on Top
|
||||
- Welcome to the family! With a quick <kbd>Win</kbd>+<kbd>Ctrl</kbd>+<kbd>T</kbd>, the window in focus is toggled to be on top. Toggle again, and it reverts back to normal.
|
||||
|
||||
**Things to note**
|
||||
- We shifted our localization internal service and are working on adding automated integrations back in.
|
||||
#### ColorPicker
|
||||
- HEX input improvements for adjust color menu including support for hex code without hashtag and short hex code like #CF0. Thanks @htcfreek!
|
||||
- Better bottom right screen detection for overlay
|
||||
|
||||
**PowerToys Awake**
|
||||
- System tray and settings use same language for turning things on.
|
||||
#### FancyZones
|
||||
- Increased negative space margin
|
||||
- Fix for not snapping child windows
|
||||
- Fix for clearing keyboard focus on editor launch
|
||||
- Fix to improve overlays to reduce brightness and hide numbers. Thanks @davidegiacometti
|
||||
|
||||
**Color Picker**
|
||||
- New formats added to copy colors as a float or decimal value.
|
||||
- Adjust color window now accepts lower-case HEX codes.
|
||||
#### File Explorer
|
||||
- Added G-code support for thumbnails and preview pane. Thanks @pedrolamas
|
||||
|
||||
**FancyZones**
|
||||
- New window switching functionality! Now users can assign multiple windows to a zone and cycle between them using the <kbd>Win</kbd> + <kbd>PgDn/PgUp</kbd> commands by default. Thanks [@FLOAT4](https://github.com/FLOAT4)!
|
||||
- Added functionality for zones to adopt system accent color and theme. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Added visual preview of zone appearance in settings menu. Thanks [@niels9001](https://github.com/niels9001)!
|
||||
- Fixed bug where FancyZones crashes on launch.
|
||||
#### Image Resizer
|
||||
- Fixed regression from Metadata tag removal of ColorSpace. Thanks @CleanCodeDeveloper
|
||||
|
||||
**Image Resizer**
|
||||
- Fixed bug where resizing images creates empty folders.
|
||||
- Added option to remove non-essential metadata. Helps significantly reduce the size of files. Thanks [@CleanCodeDeveloper](https://github.com/CleanCodeDeveloper)!
|
||||
- Fixed bug caused by Image Resizer receiving an unexpected property type or value. Thanks [@CleanCodeDeveloper](https://github.com/CleanCodeDeveloper)!
|
||||
#### PowerRename
|
||||
- Row highlighting + preview support now implemented. Thanks @niels9001
|
||||
- Fixed AltGR input issue
|
||||
- Improved folder renaming support
|
||||
- Opens on active monitor
|
||||
|
||||
**Mouse utilities**
|
||||
- Find My Mouse: Improved functionality to activate when user double click time configuration is set above 100ms.
|
||||
- Find My Mouse: Fixed display on all virtual desktops as opposed to only the virtual desktop where it was created.
|
||||
- Find My Mouse: New settings to enable a lot more customization based on your feedback.
|
||||
- Minor UI tweaks for fluent icons, appearance, <kbd>Ctrl</kbd> usage, and utility descriptions. Thanks [@niels9001](https://github.com/niels9001)!
|
||||
- New Mouse Highlighter PowerToy! When enabled, activate mouse highlighting with <kbd>Win</kbd> + <kbd>Shift</kbd> + <kbd>H</kbd> by default to begin displaying visual cues on your display when either the left or right mouse buttons are clicked. There is a much more powerful tool called [SysInternal ZoomIt](https://docs.microsoft.com/en-us/sysinternals/downloads/zoomit) that is very helpful as well.
|
||||
#### PowerToys Run
|
||||
- Web searching has been added! `?? What is the answer to life` will go to your favorite search engine via your browser. You can change the default action key too! Thanks @cyberrex5 for primary implementation and @franky920920 and @htcfreek for supporting
|
||||
- VS Code workspace improvements. Thanks @ricardosantos9521
|
||||
- Binary and Hex number support. Thanks @gsuberland
|
||||
- Ability to use factorials in calculations
|
||||
- PT Run will not show in Window Walker results anymore. Thanks @davidegiacometti
|
||||
- Fix log / ln calculations
|
||||
- Fix to make previous results clear
|
||||
- Fix to detect symlinks and prevent recursive loops
|
||||
- Fix for trackpad scrolling being too fast
|
||||
- Removed unneeded nuget package. Thanks @ChaseKnowlden
|
||||
- Better detection for if a packaged app can be elevated
|
||||
- Improve crash resiliency for Program plugin. Thanks @davidegiacometti
|
||||
- Improved Windows setting results. Thanks @htcfreek
|
||||
- Fixed a bug where some similar activation phrases aren't working as expected. Thanks @htcfreek and @cyberrex5.
|
||||
|
||||

|
||||
#### Video conference mute
|
||||
- Disabled by default as this requires elevation to register the virtual camera.
|
||||
- Changed (default) hotkey for mute camera & microphone from <kbd>Win</kbd>+<kbd>N</kbd> to <kbd>Win</kbd>+<kbd>Shift</kbd>+<kbd>Q</kbd> to not conflict with a Windows 11 keyboard shortcut
|
||||
|
||||
**PowerRename**
|
||||
- Improved rename performance! This is now at parity (or better) with the prior version based on multiple tests.
|
||||
- Added keyboard accelerators with <kbd>Enter</kbd> and <kbd>Ctrl</kbd> + <kbd>Enter</kbd> to execute rename. Thanks [@niels9001](https://github.com/niels9001)!
|
||||
- UI tweaks to now add number of items selected, grid-lines for improved readability, reduced font sizes & margins, and improved window resizing.
|
||||
- Fixed UI focus issues. Thanks [@niels9001](https://github.com/niels9001)!
|
||||
- Added default window width and height. Thanks [@niels9001](https://github.com/niels9001)!
|
||||
- Added PowerRename event logging for BugReportTool
|
||||
#### Settings
|
||||
- Multiple accessibility, layout, image, string and icons fixes. Thanks @niels9001
|
||||
|
||||
**PowerToys Run**
|
||||
- New entries added for settings plugin. Thanks [@htcfreek](https://github.com/htcfreek)!
|
||||
- Added support for application URI handling like `mailto:` and `ms-settings:`. Thanks [@franky920920](https://github.com/franky920920)!
|
||||
- Added DevContainer workspaces to search results of the VSCode Workspaces Plugin. Thanks [@JacobDeuchert](https://github.com/JacobDeuchert)!
|
||||
- Fixes for crashing issues.
|
||||
#### Runner
|
||||
- Improved mutex support to prevent multiple PT Run instances from running
|
||||
|
||||
**Shortcut Guide**
|
||||
- Added rounded corners to keys and tooltips, and system accent colors for desktop backdrop. Thanks [@niels9001](https://github.com/niels9001)!
|
||||
#### Installer
|
||||
- **NOTE:** The new installer currently has a visual quirk when upgrade if you have a custom install path. It will show the default install path but it will actually overwrite the current location. We are investigating how to fix this.
|
||||
- Large progress toward user based installing vs machine wide. Upgrade scenario still needs additional work.
|
||||
- Removed custom bootstrapper and now are using a WiX bundle.
|
||||
- Removed unused image assets that were still being shipped. Thanks @niels9001
|
||||
|
||||
**Settings**
|
||||
- Fixed default settings window size to prevent it from opening offscreen. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
#### ARM64 support
|
||||
- Setting WinUI3 proof-of-concept and validate we do need at least one more feature, elevation support from WinUI 3 unpackaged applications.
|
||||
|
||||
**Video Conference Mute**
|
||||
- Minor UI tweaks for icon, clear button, and overlay image selection [#14248](https://github.com/microsoft/PowerToys/issues/14248). Thanks [@niels9001](https://github.com/niels9001)!
|
||||
#### Dev improvements
|
||||
- New YAML based pipeline for building our signed installer. This will allow us to consolidate our CI to use same file. This was critical for us to unblock ARM64 and .NET 6 migration.
|
||||
- Our submodules will no longer auto fetch to prevent locking issues. If you want a refresher on how to do this, head to [our dev docs](https://github.com/microsoft/PowerToys/tree/main/doc/devdocs#get-submodules-to-compile)
|
||||
- Localization system shifted to Touchdown from CDPx. This should remove many of the loc issues.
|
||||
- Consolidated a lot of the naming of EXEs and DLLs along with projects
|
||||
- Update to spell checker. Thanks @jsoref
|
||||
- /dup response has been added
|
||||
- /reportbug /bugreport will ask for a "report bug" zip
|
||||
|
||||
**Prototype work**
|
||||
- Always on top prototype of being actively worked on. Right now you hit a key-combo and it enables it. We are investigating ways to highlight the window in some form as well.
|
||||
|
||||
**Installer**
|
||||
- Investigated how to fully shift to WIX bootstrapper and remove custom boot strapper
|
||||
- Investigated how to fully shift to HKCU vs HKLM.
|
||||
|
||||
**Random helping out**
|
||||
- Spell check fix - Thanks [@franky920920](https://github.com/franky920920)!
|
||||
- Fix a URL - Thanks [@JeffersonQin](https://github.com/JeffersonQin)!
|
||||
|
||||
**Development relevant**
|
||||
- Focusing on cleaning up backlog of issues and developing a method to aid in prioritizing. [@Dend](https://github.com/dend) and [@crutkas](https://github.com/crutkas) are partnering to see if we can develop one signal to see what we are calling ['centers of gravity'](https://gravity-issues.netlify.app/).
|
||||
- Our primary dev branch is now named `Main`.
|
||||
- Adjusting plugin folder structure for PT Run [#10796](https://github.com/microsoft/PowerToys/issues/10796)
|
||||
- Working on shifting our release pipeline onto same system that Windows Terminal uses.
|
||||
- Improvements to environment variable usage/update process in PT Run. Thanks [@htcfreek](https://github.com/htcfreek)!
|
||||
- Update .NET to 3.1.20.
|
||||
- Centralized process list in the BugReportTool.
|
||||
- Registry handling improvement for MSI and File Explorer add-ons.
|
||||
|
||||
**Community contributions**
|
||||
#### 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.
|
||||
|
||||
[@AnonymousWP](https://github.com/AnonymousWP), [@Aaron-Junker](https://github.com/Aaron-Junker), [@CleanCodeDeveloper](https://github.com/CleanCodeDeveloper), [@davidegiacometti](https://github.com/davidegiacometti), [@FLOAT4](https://github.com/FLOAT4), [@franky920920](https://github.com/franky920920), [@htcfreek](https://github.com/htcfreek), [@JacobDeuchert](https://github.com/JacobDeuchert), [@Jay-o-Way](https://github.com/jay-o-way) [@JeffersonQin](https://github.com/JeffersonQin), [@niels9001](https://github.com/niels9001), and [@rdeveen](https://github.com/rdeveen).
|
||||
[@Aaron-Junker](https://github.com/Aaron-Junker), [@ChaseKnowlden](https://github.com/ChaseKnowlden), [@CleanCodeDeveloper](https://github.com/CleanCodeDeveloper), [@cyberrex5](https://github.com/cyberrex5), [@davidegiacometti](https://github.com/davidegiacometti), [@franky920920](https://github.com/franky920920), [@gsuberland](https://github.com/gsuberland), [@jay-o-way](https://github.com/jay-o-way), [@jsoref](https://github.com/jsoref), [@niels9001](https://github.com/niels9001), and [@ricardosantos9521](https://github.com/ricardosantos9521)
|
||||
|
||||
#### What is being planned for v0.53
|
||||
#### What is being planned for v0.55
|
||||
|
||||
For [v0.53][github-next-release-work], due to holidays, we'll be in a maintenance sprint but here are some of the larger items:
|
||||
For [v0.55][github-next-release-work], we'll work on adding more stability in with VCM and getting dev file preview pane added in so we get 150 file types :)
|
||||
|
||||
- Hope to add Always on Top into PowerToys. We currently have a proof of concept ready.
|
||||
- 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)
|
||||
- Update the PowerToys Build Pipeline to allow .NET 6 integration
|
||||
- Engineering Systems/Stability/Bug fixes
|
||||
- Getting the dev file preview pane work integrated. (Monaco Editor)
|
||||
- .NET 6 upgrade to all available surfaces
|
||||
- Find my mouse feature, accessibility cross-hair
|
||||
|
||||
## PowerToys Community
|
||||
|
||||
@@ -190,5 +184,5 @@ The application logs basic telemetry. Our Telemetry Data page (Coming Soon) has
|
||||
[usingPowerToys-docs-link]: https://aka.ms/powertoys-docs
|
||||
|
||||
<!-- 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%2F27
|
||||
[github-current-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%2F28
|
||||
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F27
|
||||
|
||||
@@ -78,7 +78,7 @@ The plugin use only these interfaces (all inside the `Main.cs`):
|
||||
|
||||
| Name | Value |
|
||||
| --------------- | ------------------------------------------------------------------------------ |
|
||||
| TargetFramework | `netcoreapp3.1` (means .NET Core 3.1) |
|
||||
| TargetFramework | `net5.0-windows` (.NET 5) or `net5.0-windows10.0.18362.0` (OS version specific)|
|
||||
| LangVersion | `8.0` (mean C# 8.0) |
|
||||
| Platforms | `x64` |
|
||||
| Nullable | `true` |
|
||||
|
||||
@@ -141,7 +141,7 @@ Because the JSON file must have a object as root type, instead of a array.
|
||||
|
||||
| Name | Value |
|
||||
| --------------- | --------------------------------------------------------------------------------------------------- |
|
||||
| TargetFramework | `netcoreapp3.1` (means .NET Core 3.1) |
|
||||
| TargetFramework | `net5.0-windows` (.NET 5) or `net5.0-windows10.0.18362.0` (OS version specific) |
|
||||
| Platforms | `x64` |
|
||||
| Output | `..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\` |
|
||||
| RootNamespace | `Microsoft.PowerToys.Run.Plugin.WindowsSettings` |
|
||||
|
||||
@@ -3,16 +3,19 @@ The window walker plugin matches the user entered query with the open windows on
|
||||
|
||||

|
||||
|
||||
### [`OpenWindows.cs`](src/modules/launcher/Plugins/Microsoft.Plugin.WindowWalker/Components/OpenWindows.cs)
|
||||
- The window walker plugin uses the `EnumWindows` function to enumerate all the open windows in the [`OpenWindows.cs`](src/modules/launcher/Plugins/Microsoft.Plugin.WindowWalker/Components/OpenWindows.cs) class.
|
||||
### [`OpenWindows.cs`](/src/modules/launcher/Plugins/Microsoft.Plugin.WindowWalker/Components/OpenWindows.cs)
|
||||
- The window walker plugin uses the `EnumWindows` function to enumerate all the open windows in the [`OpenWindows.cs`](/src/modules/launcher/Plugins/Microsoft.Plugin.WindowWalker/Components/OpenWindows.cs) class.
|
||||
|
||||
### [`SearchController.cs`](/src/modules/launcher/Plugins/Microsoft.Plugin.WindowWalker/Components/SearchController.cs)
|
||||
- The [`SearchController`](/src/modules/launcher/Plugins/Microsoft.Plugin.WindowWalker/Components/SearchController.cs) encapsulates the functions needed to search and find matches.
|
||||
- It is responsible for updating the search text and performing a fuzzy search on all the open windows.
|
||||
|
||||
### [`SearchController.cs`](src/modules/launcher/Plugins/Microsoft.Plugin.WindowWalker/Components/SearchController.cs)
|
||||
- The [`SearchController`](src/modules/launcher/Plugins/Microsoft.Plugin.WindowWalker/Components/SearchController.cs) encapsulates the functions needed to search and find matches.
|
||||
- It is responsible for updating the search text and performing a fuzzy search on all the open windows in an asynchronous manner.
|
||||
### [`Window.cs`](/src/modules/launcher/Plugins/Microsoft.Plugin.WindowWalker/Components/Window.cs)
|
||||
- The [`Window`](/src/modules/launcher/Plugins/Microsoft.Plugin.WindowWalker/Components/Window.cs) class represents a specific window and has functions to get the name of the window, the state of the window (whether it is visible or not), and the `SwitchTowindow` function which switches the desktop focus to the selected window. This action is performed when the user clicks on a window walker plugin result.
|
||||
- The `Window` class holds a static cache with the process information of all windows we know so far and each window instance has a property which holds its process information (name, file, ...). The process data in the cache and the window property are of the type `WindowProcess`.
|
||||
|
||||
### [`Window.cs`](src/modules/launcher/Plugins/Microsoft.Plugin.WindowWalker/Components/Window.cs)
|
||||
- The [`Window`](src/modules/launcher/Plugins/Microsoft.Plugin.WindowWalker/Components/Window.cs) class represents a specific window and has functions to get the name of the process, the state of the window (whether it is visible or not), and the `SwitchTowindow` function which switches the desktop focus to the selected window. This action is performed when the user clicks on a window walker plugin result.
|
||||
### [`WindowProcess.cs`](/src/modules/launcher/Plugins/Microsoft.Plugin.WindowWalker/Components/WindowProcess.cs)
|
||||
- The [`WindowProcess`](/src/modules/launcher/Plugins/Microsoft.Plugin.WindowWalker/Components/WindowProcess.cs) class represents a specific process for a window. It contains static methods to query process information from the system. And it contains instance methods and properties to hold/retrieve the process information we want to know about a window's process.
|
||||
|
||||
### Score
|
||||
The window walker plugin uses [`FuzzyMatching`](src/modules/launcher/Plugins/Microsoft.Plugin.WindowWalker/Components/FuzzyMatching.cs) to get the matching indices and calculates the score by creating a 2 dimensional array of the window and the query text.
|
||||
The window walker plugin uses [`FuzzyMatching`](/src/modules/launcher/Plugins/Microsoft.Plugin.WindowWalker/Components/FuzzyMatching.cs) to get the matching indices and calculates the score by creating a 2 dimensional array of the window and the query text.
|
||||
|
||||
22
doc/devdocs/modules/powerpreview/monaco/readme.md
Normal file
22
doc/devdocs/modules/powerpreview/monaco/readme.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Developer Preview (Monaco)
|
||||
|
||||
Developer preview is based on [Microsofts Monaco Editor](https://microsoft.github.io/monaco-editor/) which is maintained by the Visual Studio Code team.
|
||||
|
||||
## Update monaco editor
|
||||
|
||||
1. Download Monaco editor with npm: `npm i monaco-editor`.
|
||||
2. Delete everything except the `min` folder (the minimised code).
|
||||
3. Copy the `min` folder inside the [`monacoSRC`](/src/modules/previewpane/MonacoPreviewHandler/monacoSRC) folder.
|
||||
4. Generate the JSON file (see section below)
|
||||
|
||||
## languages.json
|
||||
|
||||
[`languages.json`](/src/modules/previewpane/MonacoPreviewHandler/languages.json) contains all extensions and Id's for the supported languages of Monaco. The [`FileHandler`](/src/modules/previewpane/MonacoPreviewHandler/FileHandler.cs) class and the installer are using this file.
|
||||
|
||||
### Generate languages.json file
|
||||
|
||||
After you updated monaco editor or adding a new language you should update the [`languages.json`](/src/modules/previewpane/MonacoPreviewHandler/languages.json) file.
|
||||
|
||||
1. Build monaco in debug mode.
|
||||
2. Open [generateLanguagesJson.html](/src/modules/previewpane/MonacoPreviewHandler/generateLanguagesJson.html) in a browser.
|
||||
3. Replace the old JSON file.
|
||||
BIN
doc/images/icons/Mouse Crosshairs.png
Normal file
BIN
doc/images/icons/Mouse Crosshairs.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -16,7 +16,6 @@
|
||||
<File DestinationPath="modules\Microsoft.Xaml.Behaviors.dll" SourcePath="..\..\x64\Release\modules\Microsoft.Xaml.Behaviors.dll"/>
|
||||
<File DestinationPath="modules\PowerToys.PowerRenameExt.dll" SourcePath="..\..\x64\Release\modules\PowerToys.PowerRenameExt.dll"/>
|
||||
<File DestinationPath="modules\shortcut_guide.dll" SourcePath="..\..\x64\Release\modules\shortcut_guide.dll"/>
|
||||
<File DestinationPath="modules\PowerRenameUWPUI.exe" SourcePath="..\..\x64\Release\modules\PowerRenameUWPUI.exe"/>
|
||||
<File DestinationPath="modules\PowerToys.ImageResizer.exe" SourcePath="..\..\x64\Release\modules\PowerToys.ImageResizer.exe"/>
|
||||
<File DestinationPath="modules\PowerToys.ImageResizerExt.dll" SourcePath="..\..\x64\Release\modules\PowerToys.ImageResizerExt.dll"/>
|
||||
<File DestinationPath="modules\GalaSoft.MvvmLight.dll" SourcePath="..\..\x64\Release\modules\GalaSoft.MvvmLight.dll"/>
|
||||
|
||||
@@ -42,9 +42,6 @@
|
||||
</uap5:Extension>
|
||||
<com:Extension Category="windows.comServer">
|
||||
<com:ComServer>
|
||||
<com:ExeServer Executable="modules\PowerRenameUWPUI.exe" DisplayName="PowerRenameUWPUI">
|
||||
<com:Class Id="0440049F-D1DC-4E46-B27B-98393D79486B"/>
|
||||
</com:ExeServer>
|
||||
<com:SurrogateServer DisplayName="ImageResizerExt">
|
||||
<com:Class Id="51B4D7E5-7568-4234-B4BB-47FB3C016A69" Path="modules\PowerToys.ImageResizerExt.dll" ThreadingModel="STA"/>
|
||||
</com:SurrogateServer>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
taskkill /f /im PowerRenameUWPUI.exe
|
||||
|
||||
.\uninstall_msix.ps1
|
||||
.\build_msix.ps1
|
||||
.\sign_msix.ps1
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
</BootstrapperApplicationRef>
|
||||
|
||||
<util:FileSearch Variable="HasDotnet3122" Path="[ProgramFiles64Folder]dotnet\shared\Microsoft.WindowsDesktop.App\3.1.22\System.Xaml.dll" Result="exists" />
|
||||
<util:FileSearch Variable="HasDotnet5014" Path="[ProgramFiles64Folder]dotnet\shared\Microsoft.WindowsDesktop.App\5.0.14\System.Xaml.dll" Result="exists" />
|
||||
<util:RegistrySearch Variable="HasWebView2PerMachine" Root="HKLM" Key="SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" Result="exists" />
|
||||
<util:RegistrySearch Variable="HasWebView2PerUser" Root="HKCU" Key="Software\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" Result="exists" />
|
||||
|
||||
<Variable Name="InstallFolder" Type="string" Value="[ProgramFiles64Folder]PowerToys" bal:Overridable="yes"/>
|
||||
|
||||
@@ -48,6 +51,7 @@
|
||||
Permanent="yes"
|
||||
PerMachine="yes"
|
||||
UninstallCommand="/uninstall /quiet">
|
||||
<ExitCode Value="1638" Behavior="success"/>
|
||||
<RemotePayload
|
||||
Description="Microsoft Windows Desktop Runtime - 3.1.22 (x64)"
|
||||
ProductName="Microsoft Windows Desktop Runtime - 3.1.22 (x64)"
|
||||
@@ -55,6 +59,37 @@
|
||||
Version="3.1.22.30721"
|
||||
Hash="08EF2F6CFDB33946061884B1CE13FA867EFBD576" />
|
||||
</ExePackage>
|
||||
<ExePackage
|
||||
Name="windowsdesktop-runtime-5.0.14-win-x64.exe"
|
||||
Compressed="no"
|
||||
Id="DotnetRuntime5"
|
||||
DetectCondition="HasDotnet5014"
|
||||
DownloadUrl="https://download.visualstudio.microsoft.com/download/pr/2887cb40-178c-4c1c-8fc1-ad5b8a29075b/33b8f9d6bbcf1b8bef4170ff101e85d0/windowsdesktop-runtime-5.0.14-win-x64.exe"
|
||||
InstallCommand="/install /quiet"
|
||||
RepairCommand="/repair /passive"
|
||||
Permanent="yes"
|
||||
PerMachine="yes"
|
||||
UninstallCommand="/uninstall /quiet">
|
||||
<ExitCode Value="1638" Behavior="success"/>
|
||||
<RemotePayload
|
||||
Description="Microsoft Windows Desktop Runtime - 5.0.14 (x64)"
|
||||
ProductName="Microsoft Windows Desktop Runtime - 5.0.14 (x64)"
|
||||
Size="54932640"
|
||||
Version="5.0.14.30911"
|
||||
Hash="37C5BF69E2792E85E418A168BC319052C787AD3F" />
|
||||
</ExePackage>
|
||||
<ExePackage
|
||||
Name="MicrosoftEdgeWebview2Setup.exe"
|
||||
Compressed="yes"
|
||||
Id="WebView2"
|
||||
DetectCondition="HasWebView2PerMachine OR HasWebView2PerUser"
|
||||
SourceFile="WebView2\MicrosoftEdgeWebview2Setup.exe"
|
||||
InstallCommand="/silent /install"
|
||||
RepairCommand="/repair /passive"
|
||||
Permanent="yes"
|
||||
PerMachine="yes"
|
||||
UninstallCommand="/silent /uninstall">
|
||||
</ExePackage>
|
||||
<MsiPackage
|
||||
SourceFile="x64\Release\PowerToysSetup-$(var.Version)-x64.msi"
|
||||
Compressed="yes"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<Import Project="..\packages\WiX.3.11.2\build\wix.props" Condition="Exists('..\packages\WiX.3.11.2\build\wix.props')" />
|
||||
<Import Project="..\..\src\Version.props" />
|
||||
<PropertyGroup>
|
||||
<DefineConstants>Version=$(Version)</DefineConstants>
|
||||
<DefineConstants>Version=$(Version);MonacoSRCHarvestPath=$(ProjectDir)..\..\x64\$(Configuration)\modules\FileExplorerPreview\monacoSRC</DefineConstants>
|
||||
<Name>PowerToysInstaller</Name>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
@@ -35,6 +35,7 @@
|
||||
<Compile Include="CustomDialogs\PTLicenseDlg.wxs" />
|
||||
<Compile Include="CustomDialogs\WixUI_PTInstallDir.wxs" />
|
||||
<Compile Include="Product.wxs" />
|
||||
<Compile Include="MonacoSRC.wxs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<WixExtension Include="WixUtilExtension">
|
||||
@@ -96,4 +97,16 @@ call "..\..\publish.cmd"
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
<Target Name="BeforeBuild">
|
||||
<HeatDirectory Directory="..\..\src\modules\previewpane\MonacoPreviewHandler\monacoSRC"
|
||||
PreprocessorVariable="var.MonacoSRCHarvestPath"
|
||||
OutputFile="MonacoSRC.wxs"
|
||||
ComponentGroupName="MonacoSRCHeatGenerated"
|
||||
DirectoryRefId="MonacoPreviewHandlerMonacoSRCFolder"
|
||||
AutogenerateGuids="true"
|
||||
ToolPath="$(WixToolPath)"
|
||||
SuppressFragments="true"
|
||||
SuppressRegistry="true"
|
||||
SuppressRootDirectory="true" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -54,6 +54,7 @@
|
||||
<ComponentGroupRef Id="ResourcesComponents" />
|
||||
<ComponentGroupRef Id="LauncherComponents" />
|
||||
<ComponentGroupRef Id="ToolComponents" />
|
||||
<ComponentGroupRef Id="MonacoSRCHeatGenerated" />
|
||||
</Feature>
|
||||
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLFOLDER]" After="CostFinalize" />
|
||||
|
||||
@@ -127,7 +128,7 @@
|
||||
<Custom Action="TelemetryLogUninstallSuccess" After="InstallFinalize">
|
||||
Installed and (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
|
||||
</Custom>
|
||||
<Custom Action="UnApplyModulesRegistryChangeSets" Before="InstallFinalize">
|
||||
<Custom Action="UnApplyModulesRegistryChangeSets" Before="RemoveFiles">
|
||||
Installed AND (REMOVE="ALL")
|
||||
</Custom>
|
||||
|
||||
@@ -147,7 +148,7 @@
|
||||
Impersonate="yes"
|
||||
Return="asyncNoWait"
|
||||
FileKey="PowerToys.exe"
|
||||
ExeCommand="" />
|
||||
ExeCommand="--dont-elevate" />
|
||||
|
||||
<CustomAction
|
||||
Id="TerminateProcesses"
|
||||
@@ -308,9 +309,17 @@
|
||||
<Directory Id="VideoConferenceInstallFolder" Name="$(var.VideoConferenceProjectName)">
|
||||
<Directory Id="VideoConferenceIconsFolder" Name="Icons" />
|
||||
</Directory>
|
||||
<Directory Id="FileExplorerPreviewInstallFolder" Name="FileExplorerPreview" />
|
||||
<Directory Id="FileExplorerPreviewInstallFolder" Name="FileExplorerPreview">
|
||||
<Directory Id="MonacoPreviewHandlerMonacoSRCFolder" Name="monacoSRC" />
|
||||
<Directory Id="MonacoPreviewHandlerRuntimesFolder" Name="runtimes">
|
||||
<Directory Id="MonacoPreviewHandlerRuntimesWinX64Folder" Name="win-x64">
|
||||
<Directory Id="MonacoPreviewHandlerRuntimesWinX64NativeFolder" Name="native" />
|
||||
</Directory>
|
||||
</Directory>
|
||||
</Directory>
|
||||
<Directory Id="FancyZonesInstallFolder" Name="$(var.FancyZonesProjectName)" />
|
||||
<Directory Id="AwakeInstallFolder" Name="$(var.AwakeProjectName)">
|
||||
<Directory Id="AwakeImagesFolder" Name="Images" />
|
||||
<Directory Id="AwakeInstallFolderRuntimes" Name="Runtimes">
|
||||
<Directory Id="AwakeInstallFolderRuntimesWin" Name="Win">
|
||||
<Directory Id="AwakeInstallFolderRuntimesWinLib" Name="Lib">
|
||||
@@ -539,17 +548,17 @@
|
||||
<File Id="FancyZones_Common.UI" Source="$(var.BinX64Dir)modules\$(var.FancyZonesProjectName)\PowerToys.Common.UI.dll" />
|
||||
<File Id="FancyZones_Telemetry.dll" Source="$(var.BinX64Dir)modules\$(var.FancyZonesProjectName)\PowerToys.ManagedTelemetry.dll" />
|
||||
<File Id="FancyZone_System.IO.Abstractions.dll" Source="$(var.BinX64Dir)modules\$(var.FancyZonesProjectName)\System.IO.Abstractions.dll" />
|
||||
<File Id="FancyZones_System.Runtime.CompilerServices.Unsafe.dll" Source="$(var.BinX64Dir)modules\$(var.FancyZonesProjectName)\System.Runtime.CompilerServices.Unsafe.dll" />
|
||||
<File Id="FancyZones_System.Text.Encodings.Web.dll" Source="$(var.BinX64Dir)modules\$(var.FancyZonesProjectName)\System.Text.Encodings.Web.dll" />
|
||||
<File Id="FancyZones_Microsoft.Windows.SDK.NET.dll" Source="$(var.BinX64Dir)modules\$(var.FancyZonesProjectName)\Microsoft.Windows.SDK.NET.dll" />
|
||||
<File Id="FancyZones_WinRT.Runtime.dll" Source="$(var.BinX64Dir)modules\$(var.FancyZonesProjectName)\WinRT.Runtime.dll" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<DirectoryRef Id="ToolsFolder">
|
||||
<Component Id="BugReportTool_exe" Guid="0F8E3E9F-2E86-4660-A3BF-AE4DD431B93C" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)BugReportTool\BugReportTool.exe" Id="BugReportTool.exe" KeyPath="yes" Checksum="yes" />
|
||||
<File Source="$(var.BinX64Dir)BugReportTool\PowerToys.BugReportTool.exe" Id="BugReportTool.exe" KeyPath="yes" Checksum="yes" />
|
||||
</Component>
|
||||
<Component Id="WebcamReportTool_exe" Guid="B6005DAC-8C26-4865-91B3-99F098422C13" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)WebcamReportTool\WebcamReportTool.exe" Id="WebcamReportTool.exe" Checksum="yes" />
|
||||
<File Source="$(var.BinX64Dir)WebcamReportTool\PowerToys.WebcamReportTool.exe" Id="WebcamReportTool.exe" Checksum="yes" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
@@ -584,8 +593,8 @@
|
||||
<File Id="Module_ImageResizer_Microsoft_Xaml_Behaviors" Source="$(var.BinX64Dir)modules\$(var.ImageResizerProjectName)\Microsoft.Xaml.Behaviors.dll" />
|
||||
<File Id="ImageResizer_interop" Source="$(var.BinX64Dir)modules\$(var.ImageResizerProjectName)\PowerToys.Interop.dll" />
|
||||
<File Id="ImageResizer_System.IO.Abstractions.dll" Source="$(var.BinX64Dir)modules\$(var.ImageResizerProjectName)\System.IO.Abstractions.dll" />
|
||||
<File Id="ImageResizer_System.Runtime.CompilerServices.Unsafe.dll" Source="$(var.BinX64Dir)modules\$(var.ImageResizerProjectName)\System.Runtime.CompilerServices.Unsafe.dll" />
|
||||
<File Id="ImageResizer_System.Text.Encodings.Web.dll" Source="$(var.BinX64Dir)modules\$(var.ImageResizerProjectName)\System.Text.Encodings.Web.dll" />
|
||||
<File Id="ImageResizer_WinRT.Runtime.dll" Source="$(var.BinX64Dir)modules\$(var.ImageResizerProjectName)\WinRT.Runtime.dll" />
|
||||
<File Id="ImageResizer_Microsoft.Windows.SDK.NET.dll" Source="$(var.BinX64Dir)modules\$(var.ImageResizerProjectName)\Microsoft.Windows.SDK.NET.dll" />
|
||||
<!-- 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="ImageResizer_$(var.File)" Source="$(var.RepoDir)installer\VCRuntime\$(var.File)" />
|
||||
@@ -706,6 +715,9 @@
|
||||
<Component Id="Module_MouseHighlighter" Guid="3BAEA39F-A73D-48D2-9616-BBED5B8C86D3" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.MouseUtilsProjectName)\PowerToys.MouseHighlighter.dll" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="Module_MousePointerCrosshairs" Guid="157F664C-E993-49AC-B9E1-EBF73080D072" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.MouseUtilsProjectName)\PowerToys.MousePointerCrosshairs.dll" KeyPath="yes" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- Shortcut guide -->
|
||||
@@ -771,7 +783,7 @@
|
||||
<!-- Color Picker -->
|
||||
<DirectoryRef Id="ColorPickerInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.ColorPickerProjectName)">
|
||||
<Component Id="Module_ColorPicker" Guid="8A52A69E-37B2-4BEA-9D73-77763066052F" Win64="yes">
|
||||
<?foreach File in PowerToys.ColorPicker.dll;System.IO.Abstractions.dll;PowerToys.ColorPickerUI.exe;PowerToys.ColorPickerUI.dll;PowerToys.ColorPickerUI.deps.json;PowerToys.ColorPickerUI.runtimeconfig.json;PowerToys.Settings.UI.Lib.dll;PowerToys.Interop.dll;System.Text.Json.dll;PowerToys.ManagedTelemetry.dll;PowerToys.ManagedCommon.dll;ControlzEx.dll;Microsoft.Xaml.Behaviors.dll;ModernWpf.Controls.dll;ModernWpf.dll;System.ComponentModel.Composition.dll;PowerToys.Common.UI.dll;System.Runtime.CompilerServices.Unsafe.dll;System.Text.Encodings.Web.dll?>
|
||||
<?foreach File in PowerToys.ColorPicker.dll;System.IO.Abstractions.dll;PowerToys.ColorPickerUI.exe;PowerToys.ColorPickerUI.dll;PowerToys.ColorPickerUI.deps.json;PowerToys.ColorPickerUI.runtimeconfig.json;PowerToys.Settings.UI.Lib.dll;PowerToys.Interop.dll;System.Text.Json.dll;PowerToys.ManagedTelemetry.dll;PowerToys.ManagedCommon.dll;ControlzEx.dll;Microsoft.Xaml.Behaviors.dll;ModernWpf.Controls.dll;ModernWpf.dll;System.ComponentModel.Composition.dll;PowerToys.Common.UI.dll;WinRT.Runtime.dll;Microsoft.Windows.SDK.NET.dll?>
|
||||
<File Id="ColorPickerFile_$(var.File)" Source="$(var.BinX64Dir)modules\$(var.ColorPickerProjectName)\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
@@ -789,15 +801,21 @@
|
||||
<!-- Awake -->
|
||||
<DirectoryRef Id="AwakeInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.AwakeProjectName)">
|
||||
<Component Id="Module_Awake" Guid="F26F5780-5B38-43B2-BC21-8406ED6E2071" Win64="yes">
|
||||
<?foreach File in PowerToys.AwakeModuleInterface.dll;PowerToys.ManagedCommon.dll;PowerToys.ManagedTelemetry.dll;PowerToys.Settings.UI.Lib.dll;Microsoft.Win32.Registry.dll;Microsoft.Win32.SystemEvents.dll;NLog.config;NLog.dll;PowerToys.Awake.deps.json;PowerToys.Awake.dll;PowerToys.Awake.exe;PowerToys.Awake.runtimeconfig.json;PowerToys.Interop.dll;System.CommandLine.dll;System.Configuration.ConfigurationManager.dll;System.Drawing.Common.dll;System.IO.Abstractions.dll;System.Reactive.dll;System.Runtime.Caching.dll;System.Runtime.CompilerServices.Unsafe.dll;System.Security.AccessControl.dll;System.Security.Cryptography.ProtectedData.dll;System.Security.Permissions.dll;System.Security.Principal.Windows.dll;System.Text.Encodings.Web.dll;System.Text.Json.dll;System.Windows.Extensions.dll?>
|
||||
<?foreach File in PowerToys.AwakeModuleInterface.dll;PowerToys.ManagedCommon.dll;PowerToys.ManagedTelemetry.dll;PowerToys.Settings.UI.Lib.dll;Microsoft.Win32.SystemEvents.dll;NLog.config;NLog.dll;PowerToys.Awake.deps.json;PowerToys.Awake.dll;PowerToys.Awake.exe;PowerToys.Awake.runtimeconfig.json;PowerToys.Interop.dll;System.CommandLine.dll;System.Configuration.ConfigurationManager.dll;System.Drawing.Common.dll;System.IO.Abstractions.dll;System.Reactive.dll;System.Runtime.Caching.dll;System.Security.AccessControl.dll;System.Security.Cryptography.ProtectedData.dll;System.Security.Permissions.dll;System.Security.Principal.Windows.dll;System.Text.Json.dll;System.Windows.Extensions.dll?>
|
||||
<File Id="AwakeFile_$(var.File)" Source="$(var.BinX64Dir)modules\$(var.AwakeProjectName)\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- Awake images -->
|
||||
<DirectoryRef Id="AwakeImagesFolder" FileSource="$(var.BinX64Dir)modules\$(var.AwakeProjectName)\Images">
|
||||
<Component Id="Module_Awake_Images" Guid="7ED8D364-9C23-4FFF-9FEA-FBC0760D99F7">
|
||||
<File Id="Awake_Awake.ico" Source="$(var.BinX64Dir)modules\$(var.AwakeProjectName)\Images\Awake.ico" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<DirectoryRef Id="AwakeInstallFolderNetStandard20" FileSource="$(var.BinX64Dir)modules\$(var.AwakeProjectName)\runtimes\win\lib\netstandard2.0">
|
||||
<Component Id="Module_Awake_runtime_netstandard20" Guid="414A31AB-91A8-4F17-9B4B-DB7B93A2BB23">
|
||||
<File Id="AwakeFile_runtime_Microsoft.Win32.Registry.dll" Source="$(var.BinX64Dir)modules\$(var.AwakeProjectName)\runtimes\win\lib\netstandard2.0\Microsoft.Win32.Registry.dll" />
|
||||
<File Id="AwakeFile_runtime_System.Runtime.Caching.dll" Source="$(var.BinX64Dir)modules\$(var.AwakeProjectName)\runtimes\win\lib\netstandard2.0\System.Runtime.Caching.dll" />
|
||||
<File Id="AwakeFile_runtime_System.Security.AccessControl.dll" Source="$(var.BinX64Dir)modules\$(var.AwakeProjectName)\runtimes\win\lib\netstandard2.0\System.Security.AccessControl.dll" />
|
||||
<File Id="AwakeFile_runtime_System.Security.Cryptography.ProtectedData.dll" Source="$(var.BinX64Dir)modules\$(var.AwakeProjectName)\runtimes\win\lib\netstandard2.0\System.Security.Cryptography.ProtectedData.dll" />
|
||||
@@ -826,6 +844,7 @@
|
||||
<!-- File to include common library used by preview handlers -->
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.PreviewHandlerCommon.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.PreviewHandlerCommon.deps.json" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.ManagedCommon.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.ManagedTelemetry.dll" />
|
||||
<!-- File to include dll for Svg Preview Handler -->
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.SvgPreviewHandler.dll" />
|
||||
@@ -845,11 +864,26 @@
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\Markdig.Signed.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\HtmlAgilityPack.dll" />
|
||||
<File Id="FileExplorerPreview_System.IO.Abstractions.dll" Source="$(var.BinX64Dir)modules\FileExplorerPreview\System.IO.Abstractions.dll" />
|
||||
<!-- Files to include dll's for Monaco Preview Handler and it's dependencies -->
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\languages.json" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.Common.UI.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.MonacoPreviewHandler.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.MonacoPreviewHandler.comhost.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.MonacoPreviewHandler.runtimeconfig.json" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.MonacoPreviewHandler.deps.json" />
|
||||
<File Id="FileExplorerPreview_ControlzEx.dll" Source="$(var.BinX64Dir)modules\FileExplorerPreview\ControlzEx.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\Microsoft.Web.WebView2.Core.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\Microsoft.Web.WebView2.WinForms.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\Microsoft.Web.WebView2.Wpf.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\System.Runtime.WindowsRuntime.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\index.html" />
|
||||
<!-- File to include dll for Pdf Preview Handler -->
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.PdfPreviewHandler.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.PdfPreviewHandler.comhost.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.PdfPreviewHandler.runtimeconfig.json" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.PdfPreviewHandler.deps.json" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\Microsoft.Windows.SDK.NET.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\WinRT.Runtime.dll" />
|
||||
<!-- File to include dll for Pdf Thumbnail Provider -->
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.PdfThumbnailProvider.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.PdfThumbnailProvider.comhost.dll" />
|
||||
@@ -865,6 +899,18 @@
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.GcodeThumbnailProvider.comhost.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.GcodeThumbnailProvider.runtimeconfig.json" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.GcodeThumbnailProvider.deps.json" />
|
||||
<!-- File to include dll for Stl Thumbnail Provider -->
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.StlThumbnailProvider.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.StlThumbnailProvider.comhost.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.StlThumbnailProvider.runtimeconfig.json" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.StlThumbnailProvider.deps.json" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\HelixToolkit.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\HelixToolkit.Core.Wpf.dll" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="MonacoPreviewHandlerRuntimesWinX64NativeFolder" FileSource="$(var.BinX64Dir)modules\FileExplorerPreview\runtimes\win-x64\native">
|
||||
<Component Id="MonacoPreviewHandlerRuntimesWinX64NativeLibs" Guid="A867098B-5F8B-491B-A7DC-51F0907B570F" Win64="yes">
|
||||
<File Id="MonacoPreviewHandler_WebView2Loader" Source="$(var.BinX64Dir)modules\FileExplorerPreview\runtimes\win-x64\native\WebView2Loader.dll" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
@@ -937,7 +983,7 @@
|
||||
</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;AlwaysOnTop.png;Awake.png;FileExplorerPreview.png;FindMyMouse.png;ImageResizer.png;KeyboardManager.png;MouseHighlighter.png;MouseUtils.png;PowerRename.png;PowerToys.png;PowerToysRun.png;Settings.png;ShortcutGuide.png;VideoConferenceMute.png ?>
|
||||
<?foreach File in ColorPicker.png;FancyZones.png;AlwaysOnTop.png;Awake.png;FileExplorerPreview.png;FindMyMouse.png;ImageResizer.png;KeyboardManager.png;MouseHighlighter.png;MouseCrosshairs.png;MouseUtils.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>
|
||||
@@ -1023,6 +1069,7 @@
|
||||
<ComponentRef Id="Module_ImageResizer" />
|
||||
<ComponentRef Id="Module_ImageResizer_Registry" />
|
||||
<ComponentRef Id="Module_PowerPreview" />
|
||||
<ComponentRef Id="MonacoPreviewHandlerRuntimesWinX64NativeLibs" />
|
||||
<ComponentRef Id="Module_PowerPreview_Registry" />
|
||||
<ComponentRef Id="Module_KeyboardManager" />
|
||||
<ComponentRef Id="Module_KeyboardManager_Editor" />
|
||||
@@ -1030,11 +1077,13 @@
|
||||
<ComponentRef Id="Module_ColorPicker" />
|
||||
<ComponentRef Id="Module_ColorPicker_Resources"/>
|
||||
<ComponentRef Id="Module_Awake"/>
|
||||
<ComponentRef Id="Module_Awake_Images"/>
|
||||
<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="Module_MousePointerCrosshairs" />
|
||||
<ComponentRef Id="Module_AlwaysOnTop"/>
|
||||
<ComponentRef Id="SettingsV2" />
|
||||
<ComponentRef Id="SettingsV2Assets" />
|
||||
@@ -1330,7 +1379,7 @@
|
||||
|
||||
<Component Id="launcherInstallComponent" Directory="LauncherInstallFolder" Guid="5E688DB4-C522-4268-BA54-ED1CDFFE9DB6">
|
||||
<File Source="$(var.BinX64Dir)modules\Launcher\PowerToys.Launcher.dll" />
|
||||
<?foreach File in concrt140_app.dll;ICSharpCode.SharpZipLib.dll;JetBrains.Annotations.dll;Mages.Core.dll;Microsoft.Search.Interop.dll;Mono.Cecil.dll;Mono.Cecil.Mdb.dll;Mono.Cecil.Pdb.dll;Mono.Cecil.Rocks.dll;msvcp140_1_app.dll;msvcp140_2_app.dll;msvcp140_app.dll;NLog.dll;NLog.Extensions.Logging.dll;PowerToys.PowerLauncher.deps.json;PowerToys.PowerLauncher.dll;PowerToys.PowerLauncher.exe;Microsoft.Xaml.Behaviors.dll;System.Text.Json.dll;PowerToys.PowerLauncher.runtimeconfig.json;System.Data.OleDb.dll;UnitsNet.dll;vcamp140_app.dll;vccorlib140_app.dll;vcomp140_app.dll;vcruntime140_1_app.dll;vcruntime140_app.dll;Wox.Infrastructure.dll;Wox.Plugin.dll;PowerToys.Interop.dll;PowerToys.ManagedTelemetry.dll;PowerToys.PowerLauncher.Telemetry.dll;Microsoft.Extensions.Configuration.Abstractions.dll;Microsoft.Extensions.Configuration.Binder.dll;Microsoft.Extensions.Configuration.dll;Microsoft.Extensions.DependencyInjection.Abstractions.dll;Microsoft.Extensions.DependencyInjection.dll;Microsoft.Extensions.Logging.Abstractions.dll;Microsoft.Extensions.Logging.dll;Microsoft.Extensions.Options.dll;Microsoft.Extensions.Primitives.dll;ControlzEx.dll;PowerToys.ManagedCommon.dll;System.IO.Abstractions.dll;PowerToys.Common.UI.dll;System.ServiceProcess.ServiceController.dll;Microsoft.Toolkit.Uwp.Notifications.dll;ModernWpf.Controls.dll;ModernWpf.dll;System.Runtime.CompilerServices.Unsafe.dll;System.Text.Encodings.Web.dll?>
|
||||
<?foreach File in concrt140_app.dll;e_sqlite3.dll;JetBrains.Annotations.dll;Mages.Core.dll;Microsoft.Search.Interop.dll;Mono.Cecil.dll;Mono.Cecil.Mdb.dll;Mono.Cecil.Pdb.dll;Mono.Cecil.Rocks.dll;msvcp140_1_app.dll;msvcp140_2_app.dll;msvcp140_app.dll;NLog.dll;NLog.Extensions.Logging.dll;PowerToys.PowerLauncher.deps.json;PowerToys.PowerLauncher.dll;PowerToys.PowerLauncher.exe;Microsoft.Xaml.Behaviors.dll;System.Text.Json.dll;PowerToys.PowerLauncher.runtimeconfig.json;System.Data.OleDb.dll;UnitsNet.dll;vcamp140_app.dll;vccorlib140_app.dll;vcomp140_app.dll;vcruntime140_1_app.dll;vcruntime140_app.dll;Wox.Infrastructure.dll;Wox.Plugin.dll;PowerToys.Interop.dll;PowerToys.ManagedTelemetry.dll;PowerToys.PowerLauncher.Telemetry.dll;Microsoft.Data.Sqlite.dll;SQLitePCLRaw.batteries_v2.dll;SQLitePCLRaw.core.dll;SQLitePCLRaw.provider.e_sqlite3.dll;Microsoft.Extensions.Configuration.Abstractions.dll;Microsoft.Extensions.Configuration.Binder.dll;Microsoft.Extensions.Configuration.dll;Microsoft.Extensions.DependencyInjection.Abstractions.dll;Microsoft.Extensions.DependencyInjection.dll;Microsoft.Extensions.Logging.Abstractions.dll;Microsoft.Extensions.Logging.dll;Microsoft.Extensions.Options.dll;Microsoft.Extensions.Primitives.dll;ControlzEx.dll;PowerToys.ManagedCommon.dll;System.IO.Abstractions.dll;PowerToys.Common.UI.dll;System.ServiceProcess.ServiceController.dll;Microsoft.Toolkit.Uwp.Notifications.dll;ModernWpf.Controls.dll;ModernWpf.dll;WinRT.Runtime.dll;Microsoft.Windows.SDK.NET.dll?>
|
||||
<File Id="File_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\$(var.File)" />
|
||||
<?endforeach?>
|
||||
<File Source="$(var.BinX64Dir)Settings\PowerToys.Settings.UI.Lib.dll" />
|
||||
@@ -1503,6 +1552,8 @@
|
||||
<File Id="SystemShutdownLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\System\Images\shutdown.light.png" />
|
||||
<File Id="SystemSleepDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\System\Images\sleep.dark.png" />
|
||||
<File Id="SystemSleepLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\System\Images\sleep.light.png" />
|
||||
<File Id="SystemFirmwareSettingsDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\System\Images\firmwareSettings.dark.png" />
|
||||
<File Id="SystemFirmwareSettingsLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\System\Images\firmwareSettings.light.png" />
|
||||
</Component>
|
||||
|
||||
<!-- WindowsSettings Plugin -->
|
||||
|
||||
BIN
installer/PowerToysSetup/WebView2/MicrosoftEdgeWebview2Setup.exe
Normal file
BIN
installer/PowerToysSetup/WebView2/MicrosoftEdgeWebview2Setup.exe
Normal file
Binary file not shown.
@@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\Version.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<UseWPF>true</UseWPF>
|
||||
<Platforms>x64</Platforms>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
||||
@@ -107,6 +107,11 @@ namespace Common.UI
|
||||
ChangeTheme(_settingsTheme == Theme.System ? Theme.System : _currentTheme);
|
||||
}
|
||||
|
||||
public static string GetWindowsBaseColor()
|
||||
{
|
||||
return ControlzEx.Theming.WindowsThemeHelper.GetWindowsBaseColor();
|
||||
}
|
||||
|
||||
public void ChangeTheme(Theme theme, bool fromSettings = false)
|
||||
{
|
||||
if (fromSettings)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<Import Project="..\..\..\Version.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
|
||||
<RuntimeIdentifiers>win-x64</RuntimeIdentifiers>
|
||||
|
||||
@@ -27,6 +27,7 @@ struct LogSettings
|
||||
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 mousePointerCrosshairsLoggerName = "mouse-pointer-crosshairs";
|
||||
inline const static std::string powerRenameLoggerName = "powerrename";
|
||||
inline const static std::string alwaysOnTopLoggerName = "always-on-top";
|
||||
inline const static std::wstring alwaysOnTopLogPath = L"always-on-top-log.txt";
|
||||
|
||||
@@ -2,10 +2,21 @@
|
||||
|
||||
#include "registry.h"
|
||||
|
||||
#include <common/utils/json.h>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace NonLocalizable
|
||||
{
|
||||
const static wchar_t* MONACO_LANGUAGES_FILE_NAME = L"modules\\FileExplorerPreview\\languages.json";
|
||||
const static wchar_t* ListID = L"list";
|
||||
const static wchar_t* ExtensionsID = L"extensions";
|
||||
const static wchar_t* MDExtension = L".md";
|
||||
const static wchar_t* SVGExtension = L".svg";
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getSvgPreviewHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
{
|
||||
using namespace registry::shellex;
|
||||
@@ -19,7 +30,7 @@ inline registry::ChangeSet getSvgPreviewHandlerChangeSet(const std::wstring inst
|
||||
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
|
||||
L"Microsoft.PowerToys.PreviewHandler.Svg.SvgPreviewHandler",
|
||||
L"Svg Preview Handler",
|
||||
L".svg");
|
||||
{ L".svg" });
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getMdPreviewHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
@@ -33,7 +44,55 @@ inline registry::ChangeSet getMdPreviewHandlerChangeSet(const std::wstring insta
|
||||
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
|
||||
L"Microsoft.PowerToys.PreviewHandler.Markdown.MarkdownPreviewHandler",
|
||||
L"Markdown Preview Handler",
|
||||
L".md");
|
||||
{ L".md" });
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getMonacoPreviewHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
{
|
||||
using namespace registry::shellex;
|
||||
std::vector<std::wstring> extensions;
|
||||
|
||||
std::wstring languagesFilePath = fs::path{ installationDir } / NonLocalizable::MONACO_LANGUAGES_FILE_NAME;
|
||||
auto json = json::from_file(languagesFilePath);
|
||||
|
||||
if (json)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto list = json->GetNamedArray(NonLocalizable::ListID);
|
||||
for (uint32_t i = 0; i < list.Size(); ++i)
|
||||
{
|
||||
auto entry = list.GetObjectAt(i);
|
||||
auto extensionsList = entry.GetNamedArray(NonLocalizable::ExtensionsID);
|
||||
|
||||
for (uint32_t j = 0; j < extensionsList.Size(); ++j)
|
||||
{
|
||||
auto extension = extensionsList.GetStringAt(j);
|
||||
|
||||
// Ignore extensions we already have dedicated handlers for
|
||||
if (std::wstring{ extension } == std::wstring{ NonLocalizable::MDExtension } ||
|
||||
std::wstring{ extension } == std::wstring{ NonLocalizable::SVGExtension })
|
||||
{
|
||||
continue;
|
||||
}
|
||||
extensions.push_back(std::wstring{ extension });
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return generatePreviewHandler(PreviewHandlerType::preview,
|
||||
perUser,
|
||||
L"{afbd5a44-2520-4ae0-9224-6cfce8fe4400}",
|
||||
get_std_product_version(),
|
||||
(fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.MonacoPreviewHandler.comhost.dll)d").wstring(),
|
||||
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
|
||||
L"Microsoft.PowerToys.PreviewHandler.Monaco.MonacoPreviewHandler",
|
||||
L"Monaco Preview Handler",
|
||||
extensions);
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getPdfPreviewHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
@@ -47,7 +106,7 @@ inline registry::ChangeSet getPdfPreviewHandlerChangeSet(const std::wstring inst
|
||||
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
|
||||
L"Microsoft.PowerToys.PreviewHandler.Pdf.PdfPreviewHandler",
|
||||
L"Pdf Preview Handler",
|
||||
L".pdf");
|
||||
{ L".pdf" });
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getGcodePreviewHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
@@ -61,7 +120,7 @@ inline registry::ChangeSet getGcodePreviewHandlerChangeSet(const std::wstring in
|
||||
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
|
||||
L"Microsoft.PowerToys.PreviewHandler.Gcode.GcodePreviewHandler",
|
||||
L"G-code Preview Handler",
|
||||
L".gcode");
|
||||
{ L".gcode" });
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getSvgThumbnailHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
@@ -75,7 +134,7 @@ inline registry::ChangeSet getSvgThumbnailHandlerChangeSet(const std::wstring in
|
||||
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
|
||||
L"Microsoft.PowerToys.ThumbnailHandler.Svg.SvgThumbnailProvider",
|
||||
L"Svg Thumbnail Provider",
|
||||
L".svg");
|
||||
{ L".svg" });
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getPdfThumbnailHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
@@ -89,7 +148,7 @@ inline registry::ChangeSet getPdfThumbnailHandlerChangeSet(const std::wstring in
|
||||
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
|
||||
L"Microsoft.PowerToys.ThumbnailHandler.Pdf.PdfThumbnailProvider",
|
||||
L"Pdf Thumbnail Provider",
|
||||
L".pdf");
|
||||
{ L".pdf" });
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getGcodeThumbnailHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
@@ -103,7 +162,21 @@ inline registry::ChangeSet getGcodeThumbnailHandlerChangeSet(const std::wstring
|
||||
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
|
||||
L"Microsoft.PowerToys.ThumbnailHandler.Gcode.GcodeThumbnailProvider",
|
||||
L"G-code Thumbnail Provider",
|
||||
L".gcode");
|
||||
{ L".gcode" });
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getStlThumbnailHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
{
|
||||
using namespace registry::shellex;
|
||||
return generatePreviewHandler(PreviewHandlerType::thumbnail,
|
||||
perUser,
|
||||
L"{8BC8AFC2-4E7C-4695-818E-8C1FFDCEA2AF}",
|
||||
get_std_product_version(),
|
||||
(fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.StlThumbnailProvider.comhost.dll)d").wstring(),
|
||||
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
|
||||
L"Microsoft.PowerToys.ThumbnailHandler.Stl.StlThumbnailProvider",
|
||||
L"Stl Thumbnail Provider",
|
||||
{ L".stl" });
|
||||
}
|
||||
|
||||
inline std::vector<registry::ChangeSet> getAllModulesChangeSets(const std::wstring installationDir)
|
||||
@@ -111,9 +184,11 @@ inline std::vector<registry::ChangeSet> getAllModulesChangeSets(const std::wstri
|
||||
constexpr bool PER_USER = true;
|
||||
return { getSvgPreviewHandlerChangeSet(installationDir, PER_USER),
|
||||
getMdPreviewHandlerChangeSet(installationDir, PER_USER),
|
||||
getMonacoPreviewHandlerChangeSet(installationDir, PER_USER),
|
||||
getPdfPreviewHandlerChangeSet(installationDir, PER_USER),
|
||||
getGcodePreviewHandlerChangeSet(installationDir, PER_USER),
|
||||
getSvgThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getPdfThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getGcodeThumbnailHandlerChangeSet(installationDir, PER_USER) };
|
||||
getGcodeThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getStlThumbnailHandlerChangeSet(installationDir, PER_USER) };
|
||||
}
|
||||
@@ -317,7 +317,7 @@ namespace registry
|
||||
std::wstring handlerCategory,
|
||||
std::wstring className,
|
||||
std::wstring displayName,
|
||||
std::wstring fileType)
|
||||
std::vector<std::wstring> fileTypes)
|
||||
{
|
||||
const HKEY scope = perUser ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
|
||||
|
||||
@@ -350,11 +350,6 @@ namespace registry
|
||||
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 },
|
||||
@@ -365,8 +360,17 @@ namespace registry
|
||||
{ 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 } };
|
||||
{ scope, versionPath, L"Class", className } };
|
||||
|
||||
for (const auto& fileType : fileTypes)
|
||||
{
|
||||
std::wstring fileAssociationPath = L"Software\\Classes\\";
|
||||
fileAssociationPath += fileType;
|
||||
fileAssociationPath += L"\\shellex\\";
|
||||
fileAssociationPath += handlerType == PreviewHandlerType::preview ? IPREVIEW_HANDLER_CLSID : ITHUMBNAIL_PROVIDER_CLSID;
|
||||
changes.push_back({ scope, fileAssociationPath, std::nullopt, handlerClsid });
|
||||
}
|
||||
|
||||
if (handlerType == PreviewHandlerType::preview)
|
||||
{
|
||||
const std::wstring previewHostClsid = L"{6d2b5079-2f0b-48dd-ab7f-97cec514d30b}";
|
||||
|
||||
@@ -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>
|
||||
@@ -598,6 +598,12 @@ public:
|
||||
else
|
||||
{
|
||||
// Runtime objects already created. Should update in the owner thread.
|
||||
if (m_dispatcherQueueController == nullptr)
|
||||
{
|
||||
Logger::warn("Tried accessing the dispatch queue controller before it was initialized.");
|
||||
// No dispatcher Queue Controller? Means initialization still hasn't run, so settings will be applied then.
|
||||
return;
|
||||
}
|
||||
auto dispatcherQueue = m_dispatcherQueueController.DispatcherQueue();
|
||||
FindMyMouseSettings localSettings = settings;
|
||||
bool enqueueSucceeded = dispatcherQueue.TryEnqueue([=]() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <windows.h>
|
||||
#include "resource.h"
|
||||
#include "../../../../common/version/version.h"
|
||||
#include "../../../common/version/version.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
#include "winres.h"
|
||||
@@ -106,8 +106,7 @@
|
||||
<ItemGroup>
|
||||
<ClInclude Include="FindMyMouse.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="Generated Files\resource.h" />
|
||||
<None Include="resource.base.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -117,7 +116,6 @@
|
||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp" />
|
||||
<None Include="FindMyMouse.base.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
@@ -128,7 +126,7 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Generated Files\FindMyMouse.rc" />
|
||||
<ResourceCompile Include="FindMyMouse.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
||||
@@ -41,22 +41,16 @@
|
||||
<ClInclude Include="FindMyMouse.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Generated Files\resource.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<None Include="resource.base.h">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="FindMyMouse.base.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Generated Files\FindMyMouse.rc">
|
||||
<Filter>Generated Files</Filter>
|
||||
<ResourceCompile Include="FindMyMouse.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -8,7 +8,6 @@
|
||||
#define FILE_DESCRIPTION "PowerToys FindMyMouse"
|
||||
#define INTERNAL_NAME "PowerToys.FindMyMouse"
|
||||
#define ORIGINAL_FILENAME "PowerToys.FindMyMouse.dll"
|
||||
#define IDS_KEYBOARDMANAGER_ICON 1001
|
||||
|
||||
// Non-localizable
|
||||
//////////////////////////////
|
||||
@@ -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>
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <windows.h>
|
||||
#include "resource.h"
|
||||
#include "../../../../common/version/version.h"
|
||||
#include "../../../common/version/version.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
#include "winres.h"
|
||||
@@ -106,8 +106,7 @@
|
||||
<ClInclude Include="MouseHighlighter.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="Generated Files\resource.h" />
|
||||
<None Include="resource.base.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
@@ -116,13 +115,12 @@
|
||||
<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" />
|
||||
<ResourceCompile Include="MouseHighlighter.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
<ClInclude Include="trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Generated Files\resource.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MouseHighlighter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
@@ -30,12 +30,6 @@
|
||||
</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">
|
||||
@@ -55,8 +49,8 @@
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Generated Files\MouseHighlighter.rc">
|
||||
<Filter>Generated Files</Filter>
|
||||
<ResourceCompile Include="MouseHighlighter.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -8,7 +8,6 @@
|
||||
#define FILE_DESCRIPTION "PowerToys MouseHighlighter"
|
||||
#define INTERNAL_NAME "PowerToys.MouseHighlighter"
|
||||
#define ORIGINAL_FILENAME "PowerToys.MouseHighlighter.dll"
|
||||
#define IDS_KEYBOARDMANAGER_ICON 1001
|
||||
|
||||
// Non-localizable
|
||||
//////////////////////////////
|
||||
@@ -0,0 +1,458 @@
|
||||
// InclusiveCrosshairs.cpp : Defines the entry point for the application.
|
||||
//
|
||||
|
||||
#include "pch.h"
|
||||
#include "InclusiveCrosshairs.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 InclusiveCrosshairs
|
||||
{
|
||||
bool MyRegisterClass(HINSTANCE hInstance);
|
||||
static InclusiveCrosshairs* instance;
|
||||
void Terminate();
|
||||
void SwitchActivationMode();
|
||||
void ApplySettings(InclusiveCrosshairsSettings& settings, bool applyToRuntimeObjects);
|
||||
|
||||
private:
|
||||
enum class MouseButton
|
||||
{
|
||||
Left,
|
||||
Right
|
||||
};
|
||||
|
||||
void DestroyInclusiveCrosshairs();
|
||||
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) noexcept;
|
||||
void StartDrawing();
|
||||
void StopDrawing();
|
||||
bool CreateInclusiveCrosshairs();
|
||||
void UpdateCrosshairsPosition();
|
||||
HHOOK m_mouseHook = NULL;
|
||||
static LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) noexcept;
|
||||
|
||||
static constexpr auto m_className = L"MousePointerCrosshairs";
|
||||
static constexpr auto m_windowTitle = L"PowerToys Mouse Pointer Crosshairs";
|
||||
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_crosshairs_border_layer{ nullptr };
|
||||
winrt::LayerVisual m_crosshairs_layer{ nullptr };
|
||||
winrt::SpriteVisual m_left_crosshairs_border{ nullptr };
|
||||
winrt::SpriteVisual m_left_crosshairs{ nullptr };
|
||||
winrt::SpriteVisual m_right_crosshairs_border{ nullptr };
|
||||
winrt::SpriteVisual m_right_crosshairs{ nullptr };
|
||||
winrt::SpriteVisual m_top_crosshairs_border{ nullptr };
|
||||
winrt::SpriteVisual m_top_crosshairs{ nullptr };
|
||||
winrt::SpriteVisual m_bottom_crosshairs_border{ nullptr };
|
||||
winrt::SpriteVisual m_bottom_crosshairs{ nullptr };
|
||||
|
||||
bool m_visible = false;
|
||||
bool m_destroyed = false;
|
||||
|
||||
// Configurable Settings
|
||||
winrt::Windows::UI::Color m_crosshairs_border_color = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_BORDER_COLOR;
|
||||
winrt::Windows::UI::Color m_crosshairs_color = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_COLOR;
|
||||
float m_crosshairs_radius = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_RADIUS;
|
||||
float m_crosshairs_thickness = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_THICKNESS;
|
||||
float m_crosshairs_border_size = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_BORDER_SIZE;
|
||||
float m_crosshairs_opacity = max(0.f, min(1.f, (float)INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_OPACITY / 100.0f));
|
||||
};
|
||||
|
||||
InclusiveCrosshairs* InclusiveCrosshairs::instance = nullptr;
|
||||
|
||||
bool InclusiveCrosshairs::CreateInclusiveCrosshairs()
|
||||
{
|
||||
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
|
||||
// \ [crosshairs border layer] LayerVisual
|
||||
// \ [crosshairs border sprites]
|
||||
// [crosshairs layer] LayerVisual
|
||||
// \ [crosshairs sprites]
|
||||
|
||||
m_root = m_compositor.CreateContainerVisual();
|
||||
m_root.RelativeSizeAdjustment({ 1.0f, 1.0f });
|
||||
m_target.Root(m_root);
|
||||
|
||||
m_root.Opacity(m_crosshairs_opacity);
|
||||
|
||||
m_crosshairs_border_layer = m_compositor.CreateLayerVisual();
|
||||
m_crosshairs_border_layer.RelativeSizeAdjustment({ 1.0f, 1.0f });
|
||||
m_root.Children().InsertAtTop(m_crosshairs_border_layer);
|
||||
m_crosshairs_border_layer.Opacity(1.0f);
|
||||
|
||||
m_crosshairs_layer = m_compositor.CreateLayerVisual();
|
||||
m_crosshairs_layer.RelativeSizeAdjustment({ 1.0f, 1.0f });
|
||||
|
||||
// Create the crosshairs sprites.
|
||||
m_left_crosshairs_border = m_compositor.CreateSpriteVisual();
|
||||
m_left_crosshairs_border.AnchorPoint({ 1.0f, 0.5f });
|
||||
m_left_crosshairs_border.Brush(m_compositor.CreateColorBrush(m_crosshairs_border_color));
|
||||
m_crosshairs_border_layer.Children().InsertAtTop(m_left_crosshairs_border);
|
||||
m_left_crosshairs = m_compositor.CreateSpriteVisual();
|
||||
m_left_crosshairs.AnchorPoint({ 1.0f, 0.5f });
|
||||
m_left_crosshairs.Brush(m_compositor.CreateColorBrush(m_crosshairs_color));
|
||||
m_crosshairs_layer.Children().InsertAtTop(m_left_crosshairs);
|
||||
|
||||
m_right_crosshairs_border = m_compositor.CreateSpriteVisual();
|
||||
m_right_crosshairs_border.AnchorPoint({ 0.0f, 0.5f });
|
||||
m_right_crosshairs_border.Brush(m_compositor.CreateColorBrush(m_crosshairs_border_color));
|
||||
m_crosshairs_border_layer.Children().InsertAtTop(m_right_crosshairs_border);
|
||||
m_right_crosshairs = m_compositor.CreateSpriteVisual();
|
||||
m_right_crosshairs.AnchorPoint({ 0.0f, 0.5f });
|
||||
m_right_crosshairs.Brush(m_compositor.CreateColorBrush(m_crosshairs_color));
|
||||
m_crosshairs_layer.Children().InsertAtTop(m_right_crosshairs);
|
||||
|
||||
m_top_crosshairs_border = m_compositor.CreateSpriteVisual();
|
||||
m_top_crosshairs_border.AnchorPoint({ 0.5f, 1.0f });
|
||||
m_top_crosshairs_border.Brush(m_compositor.CreateColorBrush(m_crosshairs_border_color));
|
||||
m_crosshairs_border_layer.Children().InsertAtTop(m_top_crosshairs_border);
|
||||
m_top_crosshairs = m_compositor.CreateSpriteVisual();
|
||||
m_top_crosshairs.AnchorPoint({ 0.5f, 1.0f });
|
||||
m_top_crosshairs.Brush(m_compositor.CreateColorBrush(m_crosshairs_color));
|
||||
m_crosshairs_layer.Children().InsertAtTop(m_top_crosshairs);
|
||||
|
||||
m_bottom_crosshairs_border = m_compositor.CreateSpriteVisual();
|
||||
m_bottom_crosshairs_border.AnchorPoint({ 0.5f, 0.0f });
|
||||
m_bottom_crosshairs_border.Brush(m_compositor.CreateColorBrush(m_crosshairs_border_color));
|
||||
m_crosshairs_border_layer.Children().InsertAtTop(m_bottom_crosshairs_border);
|
||||
m_bottom_crosshairs = m_compositor.CreateSpriteVisual();
|
||||
m_bottom_crosshairs.AnchorPoint({ 0.5f, 0.0f });
|
||||
m_bottom_crosshairs.Brush(m_compositor.CreateColorBrush(m_crosshairs_color));
|
||||
m_crosshairs_layer.Children().InsertAtTop(m_bottom_crosshairs);
|
||||
|
||||
m_crosshairs_border_layer.Children().InsertAtTop(m_crosshairs_layer);
|
||||
m_crosshairs_layer.Opacity(1.0f);
|
||||
|
||||
UpdateCrosshairsPosition();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void InclusiveCrosshairs::UpdateCrosshairsPosition()
|
||||
{
|
||||
POINT ptCursor;
|
||||
|
||||
GetCursorPos(&ptCursor);
|
||||
|
||||
HMONITOR cursorMonitor = MonitorFromPoint(ptCursor, MONITOR_DEFAULTTONEAREST);
|
||||
|
||||
if (cursorMonitor == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MONITORINFO monitorInfo;
|
||||
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||
|
||||
if (!GetMonitorInfo(cursorMonitor, &monitorInfo))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
POINT ptMonitorUpperLeft;
|
||||
ptMonitorUpperLeft.x = monitorInfo.rcMonitor.left;
|
||||
ptMonitorUpperLeft.y = monitorInfo.rcMonitor.top;
|
||||
|
||||
POINT ptMonitorBottomRight;
|
||||
ptMonitorBottomRight.x = monitorInfo.rcMonitor.right;
|
||||
ptMonitorBottomRight.y = monitorInfo.rcMonitor.bottom;
|
||||
|
||||
// Convert everything to client coordinates.
|
||||
ScreenToClient(m_hwnd, &ptCursor);
|
||||
ScreenToClient(m_hwnd, &ptMonitorUpperLeft);
|
||||
ScreenToClient(m_hwnd, &ptMonitorBottomRight);
|
||||
|
||||
// Position crosshairs components around the mouse pointer.
|
||||
m_left_crosshairs_border.Offset({ (float)ptCursor.x - m_crosshairs_radius + m_crosshairs_border_size, (float)ptCursor.y, .0f });
|
||||
m_left_crosshairs_border.Size({ (float)ptCursor.x - (float)ptMonitorUpperLeft.x - m_crosshairs_radius + m_crosshairs_border_size, m_crosshairs_thickness + m_crosshairs_border_size * 2 });
|
||||
m_left_crosshairs.Offset({ (float)ptCursor.x - m_crosshairs_radius, (float)ptCursor.y, .0f });
|
||||
m_left_crosshairs.Size({ (float)ptCursor.x - (float)ptMonitorUpperLeft.x - m_crosshairs_radius, m_crosshairs_thickness });
|
||||
|
||||
m_right_crosshairs_border.Offset({ (float)ptCursor.x + m_crosshairs_radius - m_crosshairs_border_size, (float)ptCursor.y, .0f });
|
||||
m_right_crosshairs_border.Size({ (float)ptMonitorBottomRight.x - (float)ptCursor.x - m_crosshairs_radius + m_crosshairs_border_size, m_crosshairs_thickness + m_crosshairs_border_size * 2 });
|
||||
m_right_crosshairs.Offset({ (float)ptCursor.x + m_crosshairs_radius, (float)ptCursor.y, .0f });
|
||||
m_right_crosshairs.Size({ (float)ptMonitorBottomRight.x - (float)ptCursor.x - m_crosshairs_radius, m_crosshairs_thickness });
|
||||
|
||||
m_top_crosshairs_border.Offset({ (float)ptCursor.x, (float)ptCursor.y - m_crosshairs_radius + m_crosshairs_border_size, .0f });
|
||||
m_top_crosshairs_border.Size({ m_crosshairs_thickness + m_crosshairs_border_size * 2, (float)ptCursor.y - (float)ptMonitorUpperLeft.y - m_crosshairs_radius + m_crosshairs_border_size });
|
||||
m_top_crosshairs.Offset({ (float)ptCursor.x, (float)ptCursor.y - m_crosshairs_radius, .0f });
|
||||
m_top_crosshairs.Size({ m_crosshairs_thickness, (float)ptCursor.y - (float)ptMonitorUpperLeft.y - m_crosshairs_radius });
|
||||
|
||||
m_bottom_crosshairs_border.Offset({ (float)ptCursor.x, (float)ptCursor.y + m_crosshairs_radius - m_crosshairs_border_size, .0f });
|
||||
m_bottom_crosshairs_border.Size({ m_crosshairs_thickness + m_crosshairs_border_size * 2, (float)ptMonitorBottomRight.y - (float)ptCursor.y - m_crosshairs_radius + m_crosshairs_border_size });
|
||||
m_bottom_crosshairs.Offset({ (float)ptCursor.x, (float)ptCursor.y + m_crosshairs_radius, .0f });
|
||||
m_bottom_crosshairs.Size({ m_crosshairs_thickness, (float)ptMonitorBottomRight.y - (float)ptCursor.y - m_crosshairs_radius });
|
||||
|
||||
}
|
||||
|
||||
LRESULT CALLBACK InclusiveCrosshairs::MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
if (nCode >= 0)
|
||||
{
|
||||
MSLLHOOKSTRUCT* hookData = (MSLLHOOKSTRUCT*)lParam;
|
||||
if (wParam == WM_MOUSEMOVE) {
|
||||
instance->UpdateCrosshairsPosition();
|
||||
}
|
||||
}
|
||||
return CallNextHookEx(0, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
void InclusiveCrosshairs::StartDrawing()
|
||||
{
|
||||
Logger::info("Start drawing crosshairs.");
|
||||
Trace::StartDrawingCrosshairs();
|
||||
m_visible = true;
|
||||
SetWindowPos(m_hwnd, HWND_TOPMOST, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN), GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN), 0);
|
||||
ShowWindow(m_hwnd, SW_SHOWNOACTIVATE);
|
||||
m_mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, m_hinstance, 0);
|
||||
UpdateCrosshairsPosition();
|
||||
}
|
||||
|
||||
void InclusiveCrosshairs::StopDrawing()
|
||||
{
|
||||
Logger::info("Stop drawing crosshairs.");
|
||||
m_visible = false;
|
||||
ShowWindow(m_hwnd, SW_HIDE);
|
||||
UnhookWindowsHookEx(m_mouseHook);
|
||||
m_mouseHook = NULL;
|
||||
}
|
||||
|
||||
void InclusiveCrosshairs::SwitchActivationMode()
|
||||
{
|
||||
PostMessage(m_hwnd, WM_SWITCH_ACTIVATION_MODE, 0, 0);
|
||||
}
|
||||
|
||||
void InclusiveCrosshairs::ApplySettings(InclusiveCrosshairsSettings& settings, bool applyToRunTimeObjects)
|
||||
{
|
||||
m_crosshairs_radius = (float)settings.crosshairsRadius;
|
||||
m_crosshairs_thickness = (float)settings.crosshairsThickness;
|
||||
m_crosshairs_color = settings.crosshairsColor;
|
||||
m_crosshairs_opacity = max(0.f, min(1.f, (float)settings.crosshairsOpacity / 100.0f));
|
||||
m_crosshairs_border_color = settings.crosshairsBorderColor;
|
||||
m_crosshairs_border_size = (float)settings.crosshairsBorderSize;
|
||||
|
||||
if (applyToRunTimeObjects)
|
||||
{
|
||||
// Runtime objects already created. Should update in the owner thread.
|
||||
if (m_dispatcherQueueController == nullptr)
|
||||
{
|
||||
Logger::warn("Tried accessing the dispatch queue controller before it was initialized.");
|
||||
// No dispatcher Queue Controller? Means initialization still hasn't run, so settings will be applied then.
|
||||
return;
|
||||
}
|
||||
auto dispatcherQueue = m_dispatcherQueueController.DispatcherQueue();
|
||||
InclusiveCrosshairsSettings localSettings = settings;
|
||||
bool enqueueSucceeded = dispatcherQueue.TryEnqueue([=]() {
|
||||
if (!m_destroyed)
|
||||
{
|
||||
// Apply new settings to runtime composition objects.
|
||||
m_left_crosshairs.Brush().as<winrt::CompositionColorBrush>().Color(m_crosshairs_color);
|
||||
m_right_crosshairs.Brush().as<winrt::CompositionColorBrush>().Color(m_crosshairs_color);
|
||||
m_top_crosshairs.Brush().as<winrt::CompositionColorBrush>().Color(m_crosshairs_color);
|
||||
m_bottom_crosshairs.Brush().as<winrt::CompositionColorBrush>().Color(m_crosshairs_color);
|
||||
m_left_crosshairs_border.Brush().as<winrt::CompositionColorBrush>().Color(m_crosshairs_border_color);
|
||||
m_right_crosshairs_border.Brush().as<winrt::CompositionColorBrush>().Color(m_crosshairs_border_color);
|
||||
m_top_crosshairs_border.Brush().as<winrt::CompositionColorBrush>().Color(m_crosshairs_border_color);
|
||||
m_bottom_crosshairs_border.Brush().as<winrt::CompositionColorBrush>().Color(m_crosshairs_border_color);
|
||||
m_root.Opacity(m_crosshairs_opacity);
|
||||
UpdateCrosshairsPosition();
|
||||
}
|
||||
});
|
||||
if (!enqueueSucceeded)
|
||||
{
|
||||
Logger::error("Couldn't enqueue message to update the crosshairs settings.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InclusiveCrosshairs::DestroyInclusiveCrosshairs()
|
||||
{
|
||||
StopDrawing();
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK InclusiveCrosshairs::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->CreateInclusiveCrosshairs() ? 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->DestroyInclusiveCrosshairs();
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool InclusiveCrosshairs::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 InclusiveCrosshairs::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 window.");
|
||||
}
|
||||
}
|
||||
|
||||
#pragma region InclusiveCrosshairs_API
|
||||
|
||||
void InclusiveCrosshairsApplySettings(InclusiveCrosshairsSettings& settings)
|
||||
{
|
||||
if (InclusiveCrosshairs::instance != nullptr)
|
||||
{
|
||||
Logger::info("Applying settings.");
|
||||
InclusiveCrosshairs::instance->ApplySettings(settings, true);
|
||||
}
|
||||
}
|
||||
|
||||
void InclusiveCrosshairsSwitch()
|
||||
{
|
||||
if (InclusiveCrosshairs::instance != nullptr)
|
||||
{
|
||||
Logger::info("Switching activation mode.");
|
||||
InclusiveCrosshairs::instance->SwitchActivationMode();
|
||||
}
|
||||
}
|
||||
|
||||
void InclusiveCrosshairsDisable()
|
||||
{
|
||||
if (InclusiveCrosshairs::instance != nullptr)
|
||||
{
|
||||
Logger::info("Terminating the crosshairs instance.");
|
||||
InclusiveCrosshairs::instance->Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
bool InclusiveCrosshairsIsEnabled()
|
||||
{
|
||||
return (InclusiveCrosshairs::instance != nullptr);
|
||||
}
|
||||
|
||||
int InclusiveCrosshairsMain(HINSTANCE hInstance, InclusiveCrosshairsSettings& settings)
|
||||
{
|
||||
Logger::info("Starting a crosshairs instance.");
|
||||
if (InclusiveCrosshairs::instance != nullptr)
|
||||
{
|
||||
Logger::error("A crosshairs instance was still working when trying to start a new one.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Perform application initialization:
|
||||
InclusiveCrosshairs crosshairs;
|
||||
InclusiveCrosshairs::instance = &crosshairs;
|
||||
crosshairs.ApplySettings(settings, false);
|
||||
if (!crosshairs.MyRegisterClass(hInstance))
|
||||
{
|
||||
Logger::error("Couldn't initialize a crosshairs instance.");
|
||||
InclusiveCrosshairs::instance = nullptr;
|
||||
return FALSE;
|
||||
}
|
||||
Logger::info("Initialized the crosshairs instance.");
|
||||
|
||||
MSG msg;
|
||||
|
||||
// Main message loop:
|
||||
while (GetMessage(&msg, nullptr, 0, 0))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
Logger::info("Crosshairs message loop ended.");
|
||||
InclusiveCrosshairs::instance = nullptr;
|
||||
|
||||
return (int)msg.wParam;
|
||||
}
|
||||
|
||||
#pragma endregion InclusiveCrosshairs_API
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
|
||||
constexpr int INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_OPACITY = 75;
|
||||
const winrt::Windows::UI::Color INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(255, 255, 0, 0);
|
||||
const winrt::Windows::UI::Color INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_BORDER_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(255, 255, 255, 255);
|
||||
constexpr int INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_RADIUS = 20;
|
||||
constexpr int INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_THICKNESS = 5;
|
||||
constexpr int INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_BORDER_SIZE = 1;
|
||||
|
||||
struct InclusiveCrosshairsSettings
|
||||
{
|
||||
winrt::Windows::UI::Color crosshairsColor = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_COLOR;
|
||||
winrt::Windows::UI::Color crosshairsBorderColor = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_BORDER_COLOR;
|
||||
int crosshairsRadius = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_RADIUS;
|
||||
int crosshairsThickness = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_THICKNESS;
|
||||
int crosshairsOpacity = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_OPACITY;
|
||||
int crosshairsBorderSize = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_BORDER_SIZE;
|
||||
};
|
||||
|
||||
int InclusiveCrosshairsMain(HINSTANCE hinst, InclusiveCrosshairsSettings& settings);
|
||||
void InclusiveCrosshairsDisable();
|
||||
bool InclusiveCrosshairsIsEnabled();
|
||||
void InclusiveCrosshairsSwitch();
|
||||
void InclusiveCrosshairsApplySettings(InclusiveCrosshairsSettings& settings);
|
||||
@@ -0,0 +1,40 @@
|
||||
#include <windows.h>
|
||||
#include "resource.h"
|
||||
#include "../../../common/version/version.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
#include "winres.h"
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION FILE_VERSION
|
||||
PRODUCTVERSION PRODUCT_VERSION
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
|
||||
BEGIN
|
||||
VALUE "CompanyName", COMPANY_NAME
|
||||
VALUE "FileDescription", FILE_DESCRIPTION
|
||||
VALUE "FileVersion", FILE_VERSION_STRING
|
||||
VALUE "InternalName", INTERNAL_NAME
|
||||
VALUE "LegalCopyright", COPYRIGHT_NOTE
|
||||
VALUE "OriginalFilename", ORIGINAL_FILENAME
|
||||
VALUE "ProductName", PRODUCT_NAME
|
||||
VALUE "ProductVersion", PRODUCT_VERSION_STRING
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
|
||||
END
|
||||
END
|
||||
@@ -0,0 +1,145 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{eae14c0e-7a6b-45da-9080-a7d8c077ba6e}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>MousePointerCrosshairs</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>MousePointerCrosshairs</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.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>
|
||||
<TargetName>PowerToys.MousePointerCrosshairs</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\MouseUtils\</OutDir>
|
||||
<TargetName>PowerToys.MousePointerCrosshairs</TargetName>
|
||||
</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="InclusiveCrosshairs.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="InclusiveCrosshairs.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="MousePointerCrosshairs.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" />
|
||||
<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>
|
||||
@@ -1,52 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="targetver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="PowerRenameUWPUI.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\dll\PowerRenameExt.cpp">
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="InclusiveCrosshairs.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="..\ui\PowerRename.ico">
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="PowerRenameUWPUI.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ClInclude>
|
||||
<ClInclude Include="InclusiveCrosshairs.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Generated Files">
|
||||
<UniqueIdentifier>{890924c4-f592-4e84-b140-4b07a607a224}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{a9a2fd9b-de66-43dc-99b2-56f0d1ddecda}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{b5d0d62e-0275-439b-a910-e7c5befad045}</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="Source Files">
|
||||
<UniqueIdentifier>{5e350f4d-b07a-4bb2-8e63-b2c527358234}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="MousePointerCrosshairs.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
312
src/modules/MouseUtils/MousePointerCrosshairs/dllmain.cpp
Normal file
312
src/modules/MouseUtils/MousePointerCrosshairs/dllmain.cpp
Normal file
@@ -0,0 +1,312 @@
|
||||
#include "pch.h"
|
||||
#include <interface/powertoy_module_interface.h>
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include "trace.h"
|
||||
#include "InclusiveCrosshairs.h"
|
||||
#include "common/utils/color.h"
|
||||
|
||||
// Non-Localizable strings
|
||||
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_CROSSHAIRS_COLOR[] = L"crosshairs_color";
|
||||
const wchar_t JSON_KEY_CROSSHAIRS_OPACITY[] = L"crosshairs_opacity";
|
||||
const wchar_t JSON_KEY_CROSSHAIRS_RADIUS[] = L"crosshairs_radius";
|
||||
const wchar_t JSON_KEY_CROSSHAIRS_THICKNESS[] = L"crosshairs_thickness";
|
||||
const wchar_t JSON_KEY_CROSSHAIRS_BORDER_COLOR[] = L"crosshairs_border_color";
|
||||
const wchar_t JSON_KEY_CROSSHAIRS_BORDER_SIZE[] = L"crosshairs_border_size";
|
||||
}
|
||||
|
||||
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"MousePointerCrosshairs";
|
||||
// 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 MousePointerCrosshairs : public PowertoyModuleIface
|
||||
{
|
||||
private:
|
||||
// The PowerToy state.
|
||||
bool m_enabled = false;
|
||||
|
||||
// Hotkey to invoke the module
|
||||
HotkeyEx m_hotkey;
|
||||
|
||||
// Mouse Pointer Crosshairs specific settings
|
||||
InclusiveCrosshairsSettings m_inclusiveCrosshairsSettings;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
MousePointerCrosshairs()
|
||||
{
|
||||
LoggerHelpers::init_logger(MODULE_NAME, L"ModuleInterface", LogSettings::mousePointerCrosshairsLoggerName);
|
||||
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);
|
||||
|
||||
InclusiveCrosshairsApplySettings(m_inclusiveCrosshairsSettings);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
Logger::error("Invalid json when trying to parse Mouse Pointer Crosshairs settings json.");
|
||||
}
|
||||
}
|
||||
|
||||
// Enable the powertoy
|
||||
virtual void enable()
|
||||
{
|
||||
m_enabled = true;
|
||||
Trace::EnableMousePointerCrosshairs(true);
|
||||
std::thread([=]() { InclusiveCrosshairsMain(m_hModule, m_inclusiveCrosshairsSettings); }).detach();
|
||||
}
|
||||
|
||||
// Disable the powertoy
|
||||
virtual void disable()
|
||||
{
|
||||
m_enabled = false;
|
||||
Trace::EnableMousePointerCrosshairs(false);
|
||||
InclusiveCrosshairsDisable();
|
||||
}
|
||||
|
||||
// Returns if the powertoys is enabled
|
||||
virtual bool is_enabled() override
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
// Returns whether the PowerToys should be enabled by default
|
||||
virtual bool is_enabled_by_default() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual std::optional<HotkeyEx> GetHotkeyEx() override
|
||||
{
|
||||
return m_hotkey;
|
||||
}
|
||||
|
||||
virtual void OnHotkeyEx() override
|
||||
{
|
||||
InclusiveCrosshairsSwitch();
|
||||
}
|
||||
// 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(MousePointerCrosshairs::get_key());
|
||||
parse_settings(settings);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
Logger::error("Invalid json when trying to load the Mouse Pointer Crosshairs 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();
|
||||
InclusiveCrosshairsSettings inclusiveCrosshairsSettings;
|
||||
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 Pointer Crosshairs activation shortcut");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Opacity
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIRS_OPACITY);
|
||||
inclusiveCrosshairsSettings.crosshairsOpacity = (uint8_t)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Opacity from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse crosshairs color
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIRS_COLOR);
|
||||
auto crosshairsColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE);
|
||||
uint8_t r, g, b;
|
||||
if (!checkValidRGB(crosshairsColor, &r, &g, &b))
|
||||
{
|
||||
Logger::error("Crosshairs color RGB value is invalid. Will use default value");
|
||||
}
|
||||
else
|
||||
{
|
||||
inclusiveCrosshairsSettings.crosshairsColor = winrt::Windows::UI::ColorHelper::FromArgb(255, r, g, b);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize crosshairs color from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Radius
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIRS_RADIUS);
|
||||
inclusiveCrosshairsSettings.crosshairsRadius = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Radius from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Thickness
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIRS_THICKNESS);
|
||||
inclusiveCrosshairsSettings.crosshairsThickness = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Thickness from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse crosshairs border color
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIRS_BORDER_COLOR);
|
||||
auto crosshairsBorderColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE);
|
||||
uint8_t r, g, b;
|
||||
if (!checkValidRGB(crosshairsBorderColor, &r, &g, &b))
|
||||
{
|
||||
Logger::error("Crosshairs border color RGB value is invalid. Will use default value");
|
||||
}
|
||||
else
|
||||
{
|
||||
inclusiveCrosshairsSettings.crosshairsBorderColor = winrt::Windows::UI::ColorHelper::FromArgb(255, r, g, b);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize crosshairs border color from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse border size
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIRS_BORDER_SIZE);
|
||||
inclusiveCrosshairsSettings.crosshairsBorderSize = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize border color from settings. Will use default value");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info("Mouse Pointer Crosshairs settings are empty");
|
||||
}
|
||||
if (!m_hotkey.modifiersMask)
|
||||
{
|
||||
Logger::info("Mouse Pointer Crosshairs is going to use default shortcut");
|
||||
m_hotkey.modifiersMask = MOD_CONTROL | MOD_ALT;
|
||||
m_hotkey.vkCode = 0x50; // P key
|
||||
}
|
||||
m_inclusiveCrosshairsSettings = inclusiveCrosshairsSettings;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
{
|
||||
return new MousePointerCrosshairs();
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="boost" version="1.72.0.0" targetFramework="native" />
|
||||
<package id="boost_regex-vc142" version="1.72.0.0" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" />
|
||||
</packages>
|
||||
16
src/modules/MouseUtils/MousePointerCrosshairs/pch.h
Normal file
16
src/modules/MouseUtils/MousePointerCrosshairs/pch.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#define COMPOSITION
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <windows.ui.composition.interop.h>
|
||||
#include <DispatcherQueue.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/Windows.System.h>
|
||||
#include <winrt/Windows.UI.Composition.Desktop.h>
|
||||
#include <ProjectTelemetry.h>
|
||||
#include <thread>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
13
src/modules/MouseUtils/MousePointerCrosshairs/resource.h
Normal file
13
src/modules/MouseUtils/MousePointerCrosshairs/resource.h
Normal file
@@ -0,0 +1,13 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by MousePointerCrosshairs.rc
|
||||
|
||||
//////////////////////////////
|
||||
// Non-localizable
|
||||
|
||||
#define FILE_DESCRIPTION "PowerToys MousePointerCrosshairs"
|
||||
#define INTERNAL_NAME "MousePointerCrosshairs"
|
||||
#define ORIGINAL_FILENAME "PowerToys.MousePointerCrosshairs.dll"
|
||||
|
||||
// Non-localizable
|
||||
//////////////////////////////
|
||||
40
src/modules/MouseUtils/MousePointerCrosshairs/trace.cpp
Normal file
40
src/modules/MouseUtils/MousePointerCrosshairs/trace.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "pch.h"
|
||||
#include "trace.h"
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
g_hProvider,
|
||||
"Microsoft.PowerToys",
|
||||
// {38e8889b-9731-53f5-e901-e8a7c1753074}
|
||||
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
|
||||
TraceLoggingOptionProjectTelemetry());
|
||||
|
||||
void Trace::RegisterProvider() noexcept
|
||||
{
|
||||
TraceLoggingRegister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::UnregisterProvider() noexcept
|
||||
{
|
||||
TraceLoggingUnregister(g_hProvider);
|
||||
}
|
||||
|
||||
// Log if the user has MousePointerCrosshairs enabled or disabled
|
||||
void Trace::EnableMousePointerCrosshairs(const bool enabled) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"MousePointerCrosshairs_EnableMousePointerCrosshairs",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingBoolean(enabled, "Enabled"));
|
||||
}
|
||||
|
||||
// Log that the user activated the module by having the crosshairs be drawn
|
||||
void Trace::StartDrawingCrosshairs() noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"MousePointerCrosshairs_StartDrawingCrosshairs",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
||||
14
src/modules/MouseUtils/MousePointerCrosshairs/trace.h
Normal file
14
src/modules/MouseUtils/MousePointerCrosshairs/trace.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
class Trace
|
||||
{
|
||||
public:
|
||||
static void RegisterProvider() noexcept;
|
||||
static void UnregisterProvider() noexcept;
|
||||
|
||||
// Log if the user has MousePointerCrosshairs enabled or disabled
|
||||
static void EnableMousePointerCrosshairs(const bool enabled) noexcept;
|
||||
|
||||
// Log that the user activated the module by having the crosshairs be drawn
|
||||
static void StartDrawingCrosshairs() noexcept;
|
||||
};
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace NonLocalizable
|
||||
{
|
||||
const static wchar_t* TOOL_WINDOW_CLASS_NAME = L"AlwaysOnTopWindow";
|
||||
const static wchar_t* WINDOW_IS_PINNED_PROP = L"AlwaysOnTop_Pinned";
|
||||
}
|
||||
|
||||
// TODO: move to common utils
|
||||
@@ -103,7 +104,7 @@ void AlwaysOnTop::SettingsUpdate(SettingId id)
|
||||
{
|
||||
if (!iter.second)
|
||||
{
|
||||
AssignBorderTracker(iter.first);
|
||||
AssignBorder(iter.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,7 +120,7 @@ void AlwaysOnTop::SettingsUpdate(SettingId id)
|
||||
case SettingId::ExcludeApps:
|
||||
{
|
||||
std::vector<HWND> toErase{};
|
||||
for (const auto& [window, tracker] : m_topmostWindows)
|
||||
for (const auto& [window, border] : m_topmostWindows)
|
||||
{
|
||||
if (isExcluded(window))
|
||||
{
|
||||
@@ -187,14 +188,7 @@ void AlwaysOnTop::ProcessCommand(HWND window)
|
||||
if (PinTopmostWindow(window))
|
||||
{
|
||||
soundType = Sound::Type::On;
|
||||
if (AlwaysOnTopSettings::settings().enableFrame)
|
||||
{
|
||||
AssignBorderTracker(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_topmostWindows[window] = nullptr;
|
||||
}
|
||||
AssignBorder(window);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,36 +228,28 @@ void AlwaysOnTop::StartTrackingTopmostWindows()
|
||||
|
||||
for (HWND window : result)
|
||||
{
|
||||
if (IsTopmost(window))
|
||||
if (IsPinned(window))
|
||||
{
|
||||
if (AlwaysOnTopSettings::settings().enableFrame)
|
||||
{
|
||||
AssignBorderTracker(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_topmostWindows[window] = nullptr;
|
||||
}
|
||||
AssignBorder(window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AlwaysOnTop::AssignBorderTracker(HWND window)
|
||||
bool AlwaysOnTop::AssignBorder(HWND window)
|
||||
{
|
||||
auto tracker = std::make_unique<WindowBorder>(window);
|
||||
if (!tracker->Init(m_hinstance))
|
||||
if (m_virtualDesktopUtils.IsWindowOnCurrentDesktop(window) && AlwaysOnTopSettings::settings().enableFrame)
|
||||
{
|
||||
// Failed to init tracker, reset topmost
|
||||
UnpinTopmostWindow(window);
|
||||
return false;
|
||||
auto border = WindowBorder::Create(window, m_hinstance);
|
||||
if (border)
|
||||
{
|
||||
m_topmostWindows[window] = std::move(border);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_virtualDesktopUtils.IsWindowOnCurrentDesktop(window))
|
||||
else
|
||||
{
|
||||
tracker->Show();
|
||||
m_topmostWindows[window] = nullptr;
|
||||
}
|
||||
|
||||
m_topmostWindows[window] = std::move(tracker);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -276,10 +262,11 @@ void AlwaysOnTop::RegisterHotkey() const
|
||||
void AlwaysOnTop::SubscribeToEvents()
|
||||
{
|
||||
// subscribe to windows events
|
||||
std::array<DWORD, 5> events_to_subscribe = {
|
||||
std::array<DWORD, 6> events_to_subscribe = {
|
||||
EVENT_OBJECT_LOCATIONCHANGE,
|
||||
EVENT_SYSTEM_MINIMIZESTART,
|
||||
EVENT_SYSTEM_MINIMIZEEND,
|
||||
EVENT_SYSTEM_MOVESIZEEND,
|
||||
EVENT_SYSTEM_SWITCHEND,
|
||||
EVENT_OBJECT_DESTROY,
|
||||
EVENT_OBJECT_NAMECHANGE
|
||||
};
|
||||
@@ -300,7 +287,7 @@ void AlwaysOnTop::SubscribeToEvents()
|
||||
|
||||
void AlwaysOnTop::UnpinAll()
|
||||
{
|
||||
for (const auto& [topWindow, tracker] : m_topmostWindows)
|
||||
for (const auto& [topWindow, border] : m_topmostWindows)
|
||||
{
|
||||
if (!UnpinTopmostWindow(topWindow))
|
||||
{
|
||||
@@ -329,13 +316,24 @@ bool AlwaysOnTop::IsTopmost(HWND window) const noexcept
|
||||
return (exStyle & WS_EX_TOPMOST) == WS_EX_TOPMOST;
|
||||
}
|
||||
|
||||
bool AlwaysOnTop::IsPinned(HWND window) const noexcept
|
||||
{
|
||||
auto handle = GetProp(window, NonLocalizable::WINDOW_IS_PINNED_PROP);
|
||||
return (handle != NULL);
|
||||
}
|
||||
|
||||
bool AlwaysOnTop::PinTopmostWindow(HWND window) const noexcept
|
||||
{
|
||||
if (!SetProp(window, NonLocalizable::WINDOW_IS_PINNED_PROP, (HANDLE)1))
|
||||
{
|
||||
Logger::error(L"SetProp failed");
|
||||
}
|
||||
return SetWindowPos(window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
||||
}
|
||||
|
||||
bool AlwaysOnTop::UnpinTopmostWindow(HWND window) const noexcept
|
||||
{
|
||||
RemoveProp(window, NonLocalizable::WINDOW_IS_PINNED_PROP);
|
||||
return SetWindowPos(window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
||||
}
|
||||
|
||||
@@ -355,13 +353,46 @@ void AlwaysOnTop::HandleWinHookEvent(WinHookEvent* data) noexcept
|
||||
switch (data->event)
|
||||
{
|
||||
case EVENT_OBJECT_LOCATIONCHANGE:
|
||||
{
|
||||
auto iter = m_topmostWindows.find(data->hwnd);
|
||||
if (iter != m_topmostWindows.end())
|
||||
{
|
||||
const auto& border = iter->second;
|
||||
if (border)
|
||||
{
|
||||
border->UpdateBorderPosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EVENT_SYSTEM_MINIMIZESTART:
|
||||
{
|
||||
auto iter = m_topmostWindows.find(data->hwnd);
|
||||
if (iter != m_topmostWindows.end())
|
||||
{
|
||||
m_topmostWindows[data->hwnd] = nullptr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EVENT_SYSTEM_MINIMIZEEND:
|
||||
{
|
||||
auto iter = m_topmostWindows.find(data->hwnd);
|
||||
if (iter != m_topmostWindows.end())
|
||||
{
|
||||
AssignBorder(data->hwnd);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EVENT_SYSTEM_MOVESIZEEND:
|
||||
{
|
||||
auto iter = m_topmostWindows.find(data->hwnd);
|
||||
if (iter != m_topmostWindows.end())
|
||||
{
|
||||
const auto& tracker = iter->second;
|
||||
tracker->UpdateBorderPosition();
|
||||
const auto& border = iter->second;
|
||||
if (border)
|
||||
{
|
||||
border->UpdateBorderPosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -374,16 +405,6 @@ void AlwaysOnTop::HandleWinHookEvent(WinHookEvent* data) noexcept
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EVENT_SYSTEM_SWITCHEND:
|
||||
{
|
||||
auto iter = m_topmostWindows.find(data->hwnd);
|
||||
if (iter != m_topmostWindows.end())
|
||||
{
|
||||
const auto& tracker = iter->second;
|
||||
tracker->Hide();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EVENT_OBJECT_NAMECHANGE:
|
||||
{
|
||||
// The accessibility name of the desktop window changes whenever the user
|
||||
@@ -401,15 +422,15 @@ void AlwaysOnTop::HandleWinHookEvent(WinHookEvent* data) noexcept
|
||||
|
||||
void AlwaysOnTop::VirtualDesktopSwitchedHandle()
|
||||
{
|
||||
for (const auto& [window, tracker] : m_topmostWindows)
|
||||
for (const auto& [window, border] : m_topmostWindows)
|
||||
{
|
||||
if (m_virtualDesktopUtils.IsWindowOnCurrentDesktop(window))
|
||||
{
|
||||
tracker->Show();
|
||||
AssignBorder(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
tracker->Hide();
|
||||
m_topmostWindows[window] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,10 +64,11 @@ private:
|
||||
|
||||
bool IsTracked(HWND window) const noexcept;
|
||||
bool IsTopmost(HWND window) const noexcept;
|
||||
bool IsPinned(HWND window) const noexcept;
|
||||
|
||||
bool PinTopmostWindow(HWND window) const noexcept;
|
||||
bool UnpinTopmostWindow(HWND window) const noexcept;
|
||||
bool AssignBorderTracker(HWND window);
|
||||
bool AssignBorder(HWND window);
|
||||
|
||||
virtual void SettingsUpdate(SettingId type) override;
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace NonLocalizable
|
||||
const static wchar_t* FrameColorID = L"frame-color";
|
||||
const static wchar_t* BlockInGameModeID = L"do-not-activate-on-game-mode";
|
||||
const static wchar_t* ExcludedAppsID = L"excluded-apps";
|
||||
const static wchar_t* FrameAccentColor = L"frame-accent-color";
|
||||
}
|
||||
|
||||
// TODO: move to common utils
|
||||
@@ -42,6 +43,14 @@ inline COLORREF HexToRGB(std::wstring_view hex, const COLORREF fallbackColor = R
|
||||
|
||||
AlwaysOnTopSettings::AlwaysOnTopSettings()
|
||||
{
|
||||
m_uiSettings.ColorValuesChanged([&](winrt::Windows::UI::ViewManagement::UISettings const& settings,
|
||||
winrt::Windows::Foundation::IInspectable const& args)
|
||||
{
|
||||
if (m_settings.frameAccentColor)
|
||||
{
|
||||
NotifyObservers(SettingId::FrameAccentColor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
AlwaysOnTopSettings& AlwaysOnTopSettings::instance()
|
||||
@@ -167,6 +176,16 @@ void AlwaysOnTopSettings::LoadSettings()
|
||||
NotifyObservers(SettingId::ExcludeApps);
|
||||
}
|
||||
}
|
||||
|
||||
if (const auto jsonVal = values.get_bool_value(NonLocalizable::FrameAccentColor))
|
||||
{
|
||||
auto val = *jsonVal;
|
||||
if (m_settings.frameAccentColor != val)
|
||||
{
|
||||
m_settings.frameAccentColor = val;
|
||||
NotifyObservers(SettingId::FrameAccentColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
#include <SettingsConstants.h>
|
||||
|
||||
#include <winrt/Windows.UI.ViewManagement.h>
|
||||
|
||||
class SettingsObserver;
|
||||
|
||||
// Needs to be kept in sync with src\settings-ui\Settings.UI.Library\AlwaysOnTopProperties.cs
|
||||
@@ -16,6 +18,7 @@ struct Settings
|
||||
bool enableFrame = true;
|
||||
bool enableSound = true;
|
||||
bool blockInGameMode = true;
|
||||
bool frameAccentColor = true;
|
||||
float frameThickness = 15.0f;
|
||||
COLORREF frameColor = RGB(0, 173, 239);
|
||||
std::vector<std::wstring> excludedApps{};
|
||||
@@ -42,6 +45,7 @@ private:
|
||||
AlwaysOnTopSettings();
|
||||
~AlwaysOnTopSettings() = default;
|
||||
|
||||
winrt::Windows::UI::ViewManagement::UISettings m_uiSettings;
|
||||
Settings m_settings;
|
||||
std::unique_ptr<FileWatcher> m_settingsFileWatcher;
|
||||
std::unordered_set<SettingsObserver*> m_observers;
|
||||
|
||||
@@ -8,5 +8,6 @@ enum class SettingId
|
||||
FrameThickness,
|
||||
FrameColor,
|
||||
BlockInGameMode,
|
||||
ExcludeApps
|
||||
ExcludeApps,
|
||||
FrameAccentColor
|
||||
};
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <FrameDrawer.h>
|
||||
#include <Settings.h>
|
||||
#include "winrt/Windows.Foundation.h"
|
||||
|
||||
// Non-Localizable strings
|
||||
namespace NonLocalizable
|
||||
@@ -30,7 +31,7 @@ std::optional<RECT> GetFrameRect(HWND window)
|
||||
}
|
||||
|
||||
WindowBorder::WindowBorder(HWND window) :
|
||||
SettingsObserver({SettingId::FrameColor, SettingId::FrameThickness}),
|
||||
SettingsObserver({SettingId::FrameColor, SettingId::FrameThickness, SettingId::FrameAccentColor }),
|
||||
m_window(nullptr),
|
||||
m_trackingWindow(window),
|
||||
m_frameDrawer(nullptr)
|
||||
@@ -38,7 +39,7 @@ WindowBorder::WindowBorder(HWND window) :
|
||||
}
|
||||
|
||||
WindowBorder::WindowBorder(WindowBorder&& other) :
|
||||
SettingsObserver({ SettingId::FrameColor, SettingId::FrameThickness }),
|
||||
SettingsObserver({ SettingId::FrameColor, SettingId::FrameThickness, SettingId::FrameAccentColor }),
|
||||
m_window(other.m_window),
|
||||
m_trackingWindow(other.m_trackingWindow),
|
||||
m_frameDrawer(std::move(other.m_frameDrawer))
|
||||
@@ -60,6 +61,17 @@ WindowBorder::~WindowBorder()
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<WindowBorder> WindowBorder::Create(HWND window, HINSTANCE hinstance)
|
||||
{
|
||||
auto self = std::unique_ptr<WindowBorder>(new WindowBorder(window));
|
||||
if (self->Init(hinstance))
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool WindowBorder::Init(HINSTANCE hinstance)
|
||||
{
|
||||
if (!m_trackingWindow)
|
||||
@@ -117,7 +129,14 @@ bool WindowBorder::Init(HINSTANCE hinstance)
|
||||
, SWP_NOMOVE | SWP_NOSIZE);
|
||||
|
||||
m_frameDrawer = FrameDrawer::Create(m_window);
|
||||
return m_frameDrawer != nullptr;
|
||||
if (!m_frameDrawer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
UpdateBorderProperties();
|
||||
m_frameDrawer->Show();
|
||||
return true;
|
||||
}
|
||||
|
||||
void WindowBorder::UpdateBorderPosition() const
|
||||
@@ -130,6 +149,7 @@ void WindowBorder::UpdateBorderPosition() const
|
||||
auto rectOpt = GetFrameRect(m_trackingWindow);
|
||||
if (!rectOpt.has_value())
|
||||
{
|
||||
m_frameDrawer->Hide();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -152,18 +172,20 @@ void WindowBorder::UpdateBorderProperties() const
|
||||
|
||||
RECT windowRect = windowRectOpt.value();
|
||||
RECT frameRect{ 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top };
|
||||
m_frameDrawer->SetBorderRect(frameRect, AlwaysOnTopSettings::settings().frameColor, AlwaysOnTopSettings::settings().frameThickness);
|
||||
}
|
||||
|
||||
void WindowBorder::Show() const
|
||||
{
|
||||
UpdateBorderProperties();
|
||||
m_frameDrawer->Show();
|
||||
}
|
||||
COLORREF color;
|
||||
if (AlwaysOnTopSettings::settings().frameAccentColor)
|
||||
{
|
||||
winrt::Windows::UI::ViewManagement::UISettings settings;
|
||||
auto accentValue = settings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::Accent);
|
||||
color = RGB(accentValue.R, accentValue.G, accentValue.B);
|
||||
}
|
||||
else
|
||||
{
|
||||
color = AlwaysOnTopSettings::settings().frameColor;
|
||||
}
|
||||
|
||||
void WindowBorder::Hide() const
|
||||
{
|
||||
m_frameDrawer->Hide();
|
||||
m_frameDrawer->SetBorderRect(frameRect, color, AlwaysOnTopSettings::settings().frameThickness);
|
||||
}
|
||||
|
||||
LRESULT WindowBorder::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
||||
@@ -216,6 +238,11 @@ void WindowBorder::SettingsUpdate(SettingId id)
|
||||
}
|
||||
break;
|
||||
|
||||
case SettingId::FrameAccentColor:
|
||||
{
|
||||
UpdateBorderProperties();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -6,16 +6,13 @@ class FrameDrawer;
|
||||
|
||||
class WindowBorder : public SettingsObserver
|
||||
{
|
||||
public:
|
||||
WindowBorder(HWND window);
|
||||
WindowBorder(WindowBorder&& other);
|
||||
|
||||
public:
|
||||
static std::unique_ptr<WindowBorder> Create(HWND window, HINSTANCE hinstance);
|
||||
~WindowBorder();
|
||||
|
||||
bool Init(HINSTANCE hinstance);
|
||||
|
||||
void Show() const;
|
||||
void Hide() const;
|
||||
|
||||
void UpdateBorderPosition() const;
|
||||
void UpdateBorderProperties() const;
|
||||
|
||||
@@ -41,5 +38,6 @@ private:
|
||||
|
||||
LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept;
|
||||
|
||||
bool Init(HINSTANCE hinstance);
|
||||
virtual void SettingsUpdate(SettingId id) override;
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\Version.props" />
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\modules\Awake</OutputPath>
|
||||
<Nullable>enable</Nullable>
|
||||
<Platforms>x64</Platforms>
|
||||
@@ -79,6 +79,8 @@
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Images\Awake.ico" />
|
||||
<None Update="Images\Awake.ico">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -51,32 +51,6 @@ namespace Awake.Core
|
||||
private static Task? _runnerThread;
|
||||
private static System.Timers.Timer _timedLoopTimer;
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern bool SetConsoleCtrlHandler(ConsoleEventHandler handler, bool add);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool AllocConsole();
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern uint GetCurrentThreadId();
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern IntPtr CreateFile(
|
||||
[MarshalAs(UnmanagedType.LPTStr)] string filename,
|
||||
[MarshalAs(UnmanagedType.U4)] uint access,
|
||||
[MarshalAs(UnmanagedType.U4)] FileShare share,
|
||||
IntPtr securityAttributes,
|
||||
[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
|
||||
[MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes,
|
||||
IntPtr templateFile);
|
||||
|
||||
static APIHelper()
|
||||
{
|
||||
_timedLoopTimer = new System.Timers.Timer();
|
||||
@@ -86,19 +60,19 @@ namespace Awake.Core
|
||||
|
||||
public static void SetConsoleControlHandler(ConsoleEventHandler handler, bool addHandler)
|
||||
{
|
||||
SetConsoleCtrlHandler(handler, addHandler);
|
||||
NativeMethods.SetConsoleCtrlHandler(handler, addHandler);
|
||||
}
|
||||
|
||||
public static void AllocateConsole()
|
||||
{
|
||||
_log.Debug("Bootstrapping the console allocation routine.");
|
||||
AllocConsole();
|
||||
NativeMethods.AllocConsole();
|
||||
_log.Debug($"Console allocation result: {Marshal.GetLastWin32Error()}");
|
||||
|
||||
var outputFilePointer = CreateFile("CONOUT$", GenericRead | GenericWrite, FileShare.Write, IntPtr.Zero, FileMode.OpenOrCreate, 0, IntPtr.Zero);
|
||||
var outputFilePointer = NativeMethods.CreateFile("CONOUT$", GenericRead | GenericWrite, FileShare.Write, IntPtr.Zero, FileMode.OpenOrCreate, 0, IntPtr.Zero);
|
||||
_log.Debug($"CONOUT creation result: {Marshal.GetLastWin32Error()}");
|
||||
|
||||
SetStdHandle(StdOutputHandle, outputFilePointer);
|
||||
NativeMethods.SetStdHandle(StdOutputHandle, outputFilePointer);
|
||||
_log.Debug($"SetStdHandle result: {Marshal.GetLastWin32Error()}");
|
||||
|
||||
Console.SetOut(new StreamWriter(Console.OpenStandardOutput(), Console.OutputEncoding) { AutoFlush = true });
|
||||
@@ -115,7 +89,7 @@ namespace Awake.Core
|
||||
{
|
||||
try
|
||||
{
|
||||
var stateResult = SetThreadExecutionState(state);
|
||||
var stateResult = NativeMethods.SetThreadExecutionState(state);
|
||||
return stateResult != 0;
|
||||
}
|
||||
catch
|
||||
@@ -205,7 +179,7 @@ namespace Awake.Core
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
_log.Info($"Initiated indefinite keep awake in background thread: {GetCurrentThreadId()}. Screen on: {keepDisplayOn}");
|
||||
_log.Info($"Initiated indefinite keep awake in background thread: {NativeMethods.GetCurrentThreadId()}. Screen on: {keepDisplayOn}");
|
||||
|
||||
WaitHandle.WaitAny(new[] { _threadToken.WaitHandle });
|
||||
|
||||
@@ -220,7 +194,7 @@ namespace Awake.Core
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
// Task was clearly cancelled.
|
||||
_log.Info($"Background thread termination: {GetCurrentThreadId()}. Message: {ex.Message}");
|
||||
_log.Info($"Background thread termination: {NativeMethods.GetCurrentThreadId()}. Message: {ex.Message}");
|
||||
return success;
|
||||
}
|
||||
}
|
||||
@@ -244,7 +218,7 @@ namespace Awake.Core
|
||||
|
||||
if (success)
|
||||
{
|
||||
_log.Info($"Initiated temporary keep awake in background thread: {GetCurrentThreadId()}. Screen on: {keepDisplayOn}");
|
||||
_log.Info($"Initiated temporary keep awake in background thread: {NativeMethods.GetCurrentThreadId()}. Screen on: {keepDisplayOn}");
|
||||
|
||||
_timedLoopTimer = new System.Timers.Timer(seconds * 1000);
|
||||
_timedLoopTimer.Elapsed += (s, e) =>
|
||||
@@ -276,7 +250,7 @@ namespace Awake.Core
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
// Task was clearly cancelled.
|
||||
_log.Info($"Background thread termination: {GetCurrentThreadId()}. Message: {ex.Message}");
|
||||
_log.Info($"Background thread termination: {NativeMethods.GetCurrentThreadId()}. Message: {ex.Message}");
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
39
src/modules/awake/Awake/NativeMethods.cs
Normal file
39
src/modules/awake/Awake/NativeMethods.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Awake.Core
|
||||
{
|
||||
internal static class NativeMethods
|
||||
{
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
internal static extern bool SetConsoleCtrlHandler(ConsoleEventHandler handler, bool add);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
internal static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool AllocConsole();
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
internal static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
internal static extern uint GetCurrentThreadId();
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
internal static extern IntPtr CreateFile(
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string filename,
|
||||
[MarshalAs(UnmanagedType.U4)] uint access,
|
||||
[MarshalAs(UnmanagedType.U4)] FileShare share,
|
||||
IntPtr securityAttributes,
|
||||
[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
|
||||
[MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes,
|
||||
IntPtr templateFile);
|
||||
}
|
||||
}
|
||||
@@ -190,14 +190,16 @@ namespace Awake
|
||||
}
|
||||
}).Start();
|
||||
|
||||
TrayHelper.InitializeTray(InternalConstants.FullAppName, new Icon(Application.GetResourceStream(new Uri("/Images/Awake.ico", UriKind.Relative)).Stream));
|
||||
TrayHelper.InitializeTray(InternalConstants.FullAppName, new Icon("modules/Awake/Images/Awake.ico"));
|
||||
|
||||
string? settingsPath = _settingsUtils.GetSettingsFilePath(InternalConstants.AppName);
|
||||
_log.Info($"Reading configuration file: {settingsPath}");
|
||||
|
||||
_watcher = new FileSystemWatcher
|
||||
{
|
||||
#pragma warning disable CS8601 // Possible null reference assignment.
|
||||
Path = Path.GetDirectoryName(settingsPath),
|
||||
#pragma warning restore CS8601 // Possible null reference assignment.
|
||||
EnableRaisingEvents = true,
|
||||
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.CreationTime,
|
||||
Filter = Path.GetFileName(settingsPath),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\Version.props" />
|
||||
<PropertyGroup>
|
||||
<AssemblyTitle>PowerToys.ColorPickerUI</AssemblyTitle>
|
||||
@@ -21,7 +21,7 @@
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>ColorPicker</RootNamespace>
|
||||
<AssemblyName>PowerToys.ColorPickerUI</AssemblyName>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0-windows10.0.18362.0</TargetFramework>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using ColorPicker.Helpers;
|
||||
using ColorPicker.Mouse;
|
||||
|
||||
@@ -19,7 +18,7 @@ namespace ColorPicker
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
_args = args;
|
||||
Logger.LogInfo($"Color Picker started with pid={Process.GetCurrentProcess().Id}");
|
||||
Logger.LogInfo($"Color Picker started with pid={Environment.ProcessId}");
|
||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||
try
|
||||
{
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\Version.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0-windows10.0.18362.0</TargetFramework>
|
||||
<ProjectGuid>{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}</ProjectGuid>
|
||||
<RootNamespace>Microsoft.ColorPicker.UnitTests</RootNamespace>
|
||||
<IsPackable>false</IsPackable>
|
||||
@@ -11,6 +12,7 @@
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<Platforms>x64</Platforms>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>$(Version).0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@@ -33,8 +35,8 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.5" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.5" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.3" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.3" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
@@ -18,8 +18,7 @@ FancyZonesApp::FancyZonesApp(const std::wstring& appName, const std::wstring& ap
|
||||
DPIAware::EnableDPIAwarenessForThisProcess();
|
||||
|
||||
m_settings = MakeFancyZonesSettings(reinterpret_cast<HINSTANCE>(&__ImageBase), appName.c_str(), appKey.c_str());
|
||||
FancyZonesDataInstance().LoadFancyZonesData();
|
||||
|
||||
|
||||
InitializeWinhookEventIds();
|
||||
m_app = MakeFancyZones(reinterpret_cast<HINSTANCE>(&__ImageBase), m_settings, std::bind(&FancyZonesApp::DisableModule, this));
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
#include <common/utils/resources.h>
|
||||
|
||||
#include <FancyZonesLib/FancyZones.h>
|
||||
#include <FancyZonesLib/FancyZonesData.h>
|
||||
#include <FancyZonesLib/FancyZonesWinHookEventIDs.h>
|
||||
#include <FancyZonesLib/ModuleConstants.h>
|
||||
|
||||
#include <FancyZonesApp.h>
|
||||
|
||||
@@ -61,7 +61,7 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
|
||||
|
||||
Trace::RegisterProvider();
|
||||
|
||||
FancyZonesApp app(GET_RESOURCE_STRING(IDS_FANCYZONES), NonLocalizable::FancyZonesStr);
|
||||
FancyZonesApp app(GET_RESOURCE_STRING(IDS_FANCYZONES), NonLocalizable::ModuleKey);
|
||||
app.Run();
|
||||
|
||||
run_message_loop();
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
#include <common/SettingsAPI/FileWatcher.h>
|
||||
|
||||
#include <FancyZonesLib/FancyZonesData.h>
|
||||
#include <FancyZonesLib/FancyZonesData/AppliedLayouts.h>
|
||||
#include <FancyZonesLib/FancyZonesData/AppZoneHistory.h>
|
||||
#include <FancyZonesLib/FancyZonesData/CustomLayouts.h>
|
||||
#include <FancyZonesLib/FancyZonesData/LayoutHotkeys.h>
|
||||
#include <FancyZonesLib/FancyZonesData/LayoutTemplates.h>
|
||||
#include <FancyZonesLib/FancyZonesWindowProperties.h>
|
||||
#include <FancyZonesLib/FancyZonesWinHookEventIDs.h>
|
||||
#include <FancyZonesLib/MonitorUtils.h>
|
||||
@@ -54,9 +59,6 @@ public:
|
||||
m_windowMoveHandler(settings, [this]() {
|
||||
PostMessageW(m_window, WM_PRIV_LOCATIONCHANGE, NULL, NULL);
|
||||
}),
|
||||
m_zonesSettingsFileWatcher(FancyZonesDataInstance().GetZonesSettingsFileName(), [this]() {
|
||||
PostMessageW(m_window, WM_PRIV_FILE_UPDATE, NULL, NULL);
|
||||
}),
|
||||
m_settingsFileWatcher(FancyZonesDataInstance().GetSettingsFileName(), [this]() {
|
||||
PostMessageW(m_window, WM_PRIV_SETTINGS_CHANGED, NULL, NULL);
|
||||
}),
|
||||
@@ -68,6 +70,13 @@ public:
|
||||
})
|
||||
{
|
||||
this->disableModuleCallback = std::move(disableModuleCallback);
|
||||
|
||||
FancyZonesDataInstance().ReplaceZoneSettingsFileFromOlderVersions();
|
||||
LayoutTemplates::instance().LoadData();
|
||||
CustomLayouts::instance().LoadData();
|
||||
LayoutHotkeys::instance().LoadData();
|
||||
AppliedLayouts::instance().LoadData();
|
||||
AppZoneHistory::instance().LoadData();
|
||||
}
|
||||
|
||||
// IFancyZones
|
||||
@@ -191,7 +200,6 @@ private:
|
||||
MonitorWorkAreaHandler m_workAreaHandler;
|
||||
VirtualDesktop m_virtualDesktop;
|
||||
|
||||
FileWatcher m_zonesSettingsFileWatcher;
|
||||
FileWatcher m_settingsFileWatcher;
|
||||
|
||||
winrt::com_ptr<IFancyZonesSettings> m_settings{};
|
||||
@@ -268,7 +276,8 @@ FancyZones::Run() noexcept
|
||||
}
|
||||
});
|
||||
|
||||
FancyZonesDataInstance().SetVirtualDesktopCheckCallback(std::bind(&VirtualDesktop::IsVirtualDesktopIdSavedInRegistry, &m_virtualDesktop, std::placeholders::_1));
|
||||
AppliedLayouts::instance().SetVirtualDesktopCheckCallback(std::bind(&VirtualDesktop::IsVirtualDesktopIdSavedInRegistry, &m_virtualDesktop, std::placeholders::_1));
|
||||
AppZoneHistory::instance().SetVirtualDesktopCheckCallback(std::bind(&VirtualDesktop::IsVirtualDesktopIdSavedInRegistry, &m_virtualDesktop, std::placeholders::_1));
|
||||
}
|
||||
|
||||
// IFancyZones
|
||||
@@ -327,15 +336,15 @@ std::pair<winrt::com_ptr<IWorkArea>, ZoneIndexSet> FancyZones::GetAppZoneHistory
|
||||
void FancyZones::MoveWindowIntoZone(HWND window, winrt::com_ptr<IWorkArea> workArea, const ZoneIndexSet& zoneIndexSet) noexcept
|
||||
{
|
||||
_TRACER_;
|
||||
auto& fancyZonesData = FancyZonesDataInstance();
|
||||
if (!fancyZonesData.IsAnotherWindowOfApplicationInstanceZoned(window, workArea->UniqueId()))
|
||||
|
||||
if (!AppZoneHistory::instance().IsAnotherWindowOfApplicationInstanceZoned(window, workArea->UniqueId()))
|
||||
{
|
||||
if (workArea)
|
||||
{
|
||||
Trace::FancyZones::SnapNewWindowIntoZone(workArea->ZoneSet());
|
||||
}
|
||||
m_windowMoveHandler.MoveWindowIntoZoneByIndexSet(window, zoneIndexSet, workArea);
|
||||
fancyZonesData.UpdateProcessIdToHandleMap(window, workArea->UniqueId());
|
||||
AppZoneHistory::instance().UpdateProcessIdToHandleMap(window, workArea->UniqueId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,8 +495,8 @@ FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept
|
||||
|
||||
if (changeLayoutWhileNotDragging || changeLayoutWhileDragging)
|
||||
{
|
||||
auto quickKeysMap = FancyZonesDataInstance().GetLayoutQuickKeys();
|
||||
if (std::any_of(quickKeysMap.begin(), quickKeysMap.end(), [=](auto item) { return item.second == digitPressed; }))
|
||||
auto layoutId = LayoutHotkeys::instance().GetLayoutId(digitPressed);
|
||||
if (layoutId.has_value())
|
||||
{
|
||||
PostMessageW(m_window, WM_PRIV_QUICK_LAYOUT_KEY, 0, static_cast<LPARAM>(digitPressed));
|
||||
Trace::FancyZones::QuickLayoutSwitched(changeLayoutWhileNotDragging);
|
||||
@@ -762,9 +771,21 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
|
||||
auto hwnd = reinterpret_cast<HWND>(wparam);
|
||||
WindowCreated(hwnd);
|
||||
}
|
||||
else if (message == WM_PRIV_FILE_UPDATE)
|
||||
else if (message == WM_PRIV_LAYOUT_HOTKEYS_FILE_UPDATE)
|
||||
{
|
||||
FancyZonesDataInstance().LoadFancyZonesData();
|
||||
LayoutHotkeys::instance().LoadData();
|
||||
}
|
||||
else if (message == WM_PRIV_LAYOUT_TEMPLATES_FILE_UPDATE)
|
||||
{
|
||||
LayoutTemplates::instance().LoadData();
|
||||
}
|
||||
else if (message == WM_PRIV_CUSTOM_LAYOUTS_FILE_UPDATE)
|
||||
{
|
||||
CustomLayouts::instance().LoadData();
|
||||
}
|
||||
else if (message == WM_PRIV_APPLIED_LAYOUTS_FILE_UPDATE)
|
||||
{
|
||||
AppliedLayouts::instance().LoadData();
|
||||
UpdateZoneSets();
|
||||
}
|
||||
else if (message == WM_PRIV_QUICK_LAYOUT_KEY)
|
||||
@@ -878,7 +899,7 @@ void FancyZones::AddWorkArea(HMONITOR monitor, const std::wstring& deviceId) noe
|
||||
if (workArea)
|
||||
{
|
||||
m_workAreaHandler.AddWorkArea(m_currentDesktopId, monitor, workArea);
|
||||
FancyZonesDataInstance().SaveZoneSettings();
|
||||
AppliedLayouts::instance().SaveData();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1200,10 +1221,12 @@ void FancyZones::RegisterVirtualDesktopUpdates() noexcept
|
||||
if (guids.has_value())
|
||||
{
|
||||
m_workAreaHandler.RegisterUpdates(*guids);
|
||||
FancyZonesDataInstance().RemoveDeletedDesktops(*guids);
|
||||
AppZoneHistory::instance().RemoveDeletedVirtualDesktops(*guids);
|
||||
AppliedLayouts::instance().RemoveDeletedVirtualDesktops(*guids);
|
||||
}
|
||||
|
||||
FancyZonesDataInstance().SyncVirtualDesktops(m_currentDesktopId);
|
||||
AppZoneHistory::instance().SyncVirtualDesktops(m_currentDesktopId);
|
||||
AppliedLayouts::instance().SyncVirtualDesktops(m_currentDesktopId);
|
||||
}
|
||||
|
||||
void FancyZones::UpdateHotkey(int hotkeyId, const PowerToysSettings::HotkeyObject& hotkeyObject, bool enable) noexcept
|
||||
@@ -1252,8 +1275,8 @@ void FancyZones::OnSettingsChanged() noexcept
|
||||
void FancyZones::OnEditorExitEvent() noexcept
|
||||
{
|
||||
// Collect information about changes in zone layout after editor exited.
|
||||
FancyZonesDataInstance().LoadFancyZonesData();
|
||||
FancyZonesDataInstance().SyncVirtualDesktops(m_currentDesktopId);
|
||||
AppZoneHistory::instance().SyncVirtualDesktops(m_currentDesktopId);
|
||||
AppliedLayouts::instance().SyncVirtualDesktops(m_currentDesktopId);
|
||||
UpdateZoneSets();
|
||||
}
|
||||
|
||||
@@ -1293,28 +1316,30 @@ bool FancyZones::ShouldProcessSnapHotkey(DWORD vkCode) noexcept
|
||||
|
||||
void FancyZones::ApplyQuickLayout(int key) noexcept
|
||||
{
|
||||
std::wstring uuid;
|
||||
for (auto [layoutUuid, hotkey] : FancyZonesDataInstance().GetLayoutQuickKeys())
|
||||
{
|
||||
if (hotkey == key)
|
||||
{
|
||||
uuid = layoutUuid;
|
||||
}
|
||||
}
|
||||
|
||||
auto workArea = m_workAreaHandler.GetWorkAreaFromCursor(m_currentDesktopId);
|
||||
|
||||
// Find a custom zone set with this uuid and apply it
|
||||
auto customZoneSets = FancyZonesDataInstance().GetCustomZoneSetsMap();
|
||||
|
||||
if (!customZoneSets.contains(uuid))
|
||||
auto layoutId = LayoutHotkeys::instance().GetLayoutId(key);
|
||||
if (!layoutId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FancyZonesDataTypes::ZoneSetData data{ .uuid = uuid, .type = FancyZonesDataTypes::ZoneSetLayoutType::Custom };
|
||||
FancyZonesDataInstance().SetActiveZoneSet(workArea->UniqueId(), data);
|
||||
FancyZonesDataInstance().SaveZoneSettings();
|
||||
// Find a custom zone set with this uuid and apply it
|
||||
auto layout = CustomLayouts::instance().GetLayout(layoutId.value());
|
||||
if (!layout)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto uuidStr = FancyZonesUtils::GuidToString(layoutId.value());
|
||||
if (!uuidStr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FancyZonesDataTypes::ZoneSetData data{ .uuid = uuidStr.value(), .type = FancyZonesDataTypes::ZoneSetLayoutType::Custom };
|
||||
|
||||
auto workArea = m_workAreaHandler.GetWorkAreaFromCursor(m_currentDesktopId);
|
||||
AppliedLayouts::instance().ApplyLayout(workArea->UniqueId(), data);
|
||||
AppliedLayouts::instance().SaveData();
|
||||
UpdateZoneSets();
|
||||
FlashZones();
|
||||
}
|
||||
|
||||
@@ -1,144 +1,23 @@
|
||||
#include "pch.h"
|
||||
#include "FancyZonesData.h"
|
||||
#include "FancyZonesDataTypes.h"
|
||||
#include "JsonHelpers.h"
|
||||
#include "ZoneSet.h"
|
||||
#include "Settings.h"
|
||||
#include "GuidUtils.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include <common/Display/dpi_aware.h>
|
||||
#include <common/logger/call_tracer.h>
|
||||
#include <common/utils/json.h>
|
||||
#include <FancyZonesLib/util.h>
|
||||
#include <FancyZonesLib/FancyZonesWindowProperties.h>
|
||||
|
||||
#include <shlwapi.h>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <optional>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
#include <common/utils/process_path.h>
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
|
||||
#include <FancyZonesLib/JsonHelpers.h>
|
||||
#include <FancyZonesLib/ModuleConstants.h>
|
||||
#include <FancyZonesLib/util.h>
|
||||
|
||||
// Non-localizable strings
|
||||
namespace NonLocalizable
|
||||
{
|
||||
const wchar_t NullStr[] = L"null";
|
||||
|
||||
const wchar_t FancyZonesSettingsFile[] = L"settings.json";
|
||||
const wchar_t FancyZonesDataFile[] = L"zones-settings.json";
|
||||
const wchar_t FancyZonesAppZoneHistoryFile[] = L"app-zone-history.json";
|
||||
const wchar_t FancyZonesEditorParametersFile[] = L"editor-parameters.json";
|
||||
const wchar_t RegistryPath[] = L"Software\\SuperFancyZones";
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
std::wstring ExtractVirtualDesktopId(const std::wstring& deviceId)
|
||||
{
|
||||
// Format: <device-id>_<resolution>_<virtual-desktop-id>
|
||||
return deviceId.substr(deviceId.rfind('_') + 1);
|
||||
}
|
||||
|
||||
const std::wstring& GetTempDirPath()
|
||||
{
|
||||
static std::wstring tmpDirPath;
|
||||
static std::once_flag flag;
|
||||
|
||||
std::call_once(flag, []() {
|
||||
wchar_t buffer[MAX_PATH];
|
||||
|
||||
auto charsWritten = GetTempPath(MAX_PATH, buffer);
|
||||
if (charsWritten > MAX_PATH || (charsWritten == 0))
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
tmpDirPath = std::wstring{ buffer };
|
||||
});
|
||||
|
||||
return tmpDirPath;
|
||||
}
|
||||
|
||||
bool DeleteRegistryKey(HKEY hKeyRoot, LPTSTR lpSubKey)
|
||||
{
|
||||
// First, see if we can delete the key without having to recurse.
|
||||
if (ERROR_SUCCESS == RegDeleteKey(hKeyRoot, lpSubKey))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
HKEY hKey;
|
||||
if (ERROR_SUCCESS != RegOpenKeyEx(hKeyRoot, lpSubKey, 0, KEY_READ, &hKey))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for an ending slash and add one if it is missing.
|
||||
LPTSTR lpEnd = lpSubKey + lstrlen(lpSubKey);
|
||||
|
||||
if (*(lpEnd - 1) != TEXT('\\'))
|
||||
{
|
||||
*lpEnd = TEXT('\\');
|
||||
lpEnd++;
|
||||
*lpEnd = TEXT('\0');
|
||||
}
|
||||
|
||||
// Enumerate the keys
|
||||
|
||||
DWORD dwSize = MAX_PATH;
|
||||
TCHAR szName[MAX_PATH];
|
||||
FILETIME ftWrite;
|
||||
auto result = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite);
|
||||
|
||||
if (result == ERROR_SUCCESS)
|
||||
{
|
||||
do
|
||||
{
|
||||
*lpEnd = TEXT('\0');
|
||||
StringCchCat(lpSubKey, MAX_PATH * 2, szName);
|
||||
|
||||
if (!DeleteRegistryKey(hKeyRoot, lpSubKey))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
dwSize = MAX_PATH;
|
||||
result = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite);
|
||||
} while (result == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
lpEnd--;
|
||||
*lpEnd = TEXT('\0');
|
||||
|
||||
RegCloseKey(hKey);
|
||||
|
||||
// Try again to delete the root key.
|
||||
if (ERROR_SUCCESS == RegDeleteKey(hKeyRoot, lpSubKey))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeleteFancyZonesRegistryData()
|
||||
{
|
||||
wchar_t key[256];
|
||||
StringCchPrintf(key, ARRAYSIZE(key), L"%s", NonLocalizable::RegistryPath);
|
||||
|
||||
HKEY hKey;
|
||||
if (ERROR_FILE_NOT_FOUND == RegOpenKeyEx(HKEY_CURRENT_USER, key, 0, KEY_READ, &hKey))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return DeleteRegistryKey(HKEY_CURRENT_USER, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FancyZonesData& FancyZonesDataInstance()
|
||||
@@ -149,551 +28,50 @@ FancyZonesData& FancyZonesDataInstance()
|
||||
|
||||
FancyZonesData::FancyZonesData()
|
||||
{
|
||||
std::wstring saveFolderPath = PTSettingsHelper::get_module_save_folder_location(NonLocalizable::FancyZonesStr);
|
||||
std::wstring saveFolderPath = PTSettingsHelper::get_module_save_folder_location(NonLocalizable::ModuleKey);
|
||||
|
||||
settingsFileName = saveFolderPath + L"\\" + std::wstring(NonLocalizable::FancyZonesSettingsFile);
|
||||
zonesSettingsFileName = saveFolderPath + L"\\" + std::wstring(NonLocalizable::FancyZonesDataFile);
|
||||
appZoneHistoryFileName = saveFolderPath + L"\\" + std::wstring(NonLocalizable::FancyZonesAppZoneHistoryFile);
|
||||
zonesSettingsFileName = saveFolderPath + L"\\" + std::wstring(NonLocalizable::FancyZonesDataFile);
|
||||
editorParametersFileName = saveFolderPath + L"\\" + std::wstring(NonLocalizable::FancyZonesEditorParametersFile);
|
||||
}
|
||||
|
||||
void FancyZonesData::SetVirtualDesktopCheckCallback(std::function<bool(GUID)> callback)
|
||||
void FancyZonesData::ReplaceZoneSettingsFileFromOlderVersions()
|
||||
{
|
||||
m_virtualDesktopCheckCallback = callback;
|
||||
}
|
||||
|
||||
const JSONHelpers::TDeviceInfoMap& FancyZonesData::GetDeviceInfoMap() const
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
return deviceInfoMap;
|
||||
}
|
||||
|
||||
const JSONHelpers::TCustomZoneSetsMap& FancyZonesData::GetCustomZoneSetsMap() const
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
return customZoneSetsMap;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::wstring, std::vector<FancyZonesDataTypes::AppZoneHistoryData>>& FancyZonesData::GetAppZoneHistoryMap() const
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
return appZoneHistoryMap;
|
||||
}
|
||||
|
||||
std::optional<FancyZonesDataTypes::DeviceInfoData> FancyZonesData::FindDeviceInfo(const FancyZonesDataTypes::DeviceIdData& id) const
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
for (const auto& [deviceId, deviceInfo] : deviceInfoMap)
|
||||
if (std::filesystem::exists(zonesSettingsFileName))
|
||||
{
|
||||
if (id.isEqualWithNullVirtualDesktopId(deviceId))
|
||||
Logger::info("Replace zones-settings file");
|
||||
|
||||
json::JsonObject fancyZonesDataJSON = JSONHelpers::GetPersistFancyZonesJSON(zonesSettingsFileName, appZoneHistoryFileName);
|
||||
|
||||
auto deviceInfoMap = JSONHelpers::ParseDeviceInfos(fancyZonesDataJSON);
|
||||
if (deviceInfoMap)
|
||||
{
|
||||
return deviceInfo;
|
||||
JSONHelpers::SaveAppliedLayouts(deviceInfoMap.value());
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<FancyZonesDataTypes::CustomZoneSetData> FancyZonesData::FindCustomZoneSet(const std::wstring& guid) const
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
auto it = customZoneSetsMap.find(guid);
|
||||
return it != end(customZoneSetsMap) ? std::optional{ it->second } : std::nullopt;
|
||||
}
|
||||
|
||||
bool FancyZonesData::AddDevice(const FancyZonesDataTypes::DeviceIdData& deviceId)
|
||||
{
|
||||
_TRACER_;
|
||||
using namespace FancyZonesDataTypes;
|
||||
|
||||
auto deviceInfo = FindDeviceInfo(deviceId);
|
||||
|
||||
std::scoped_lock lock{ dataLock };
|
||||
|
||||
if (!deviceInfo.has_value())
|
||||
{
|
||||
wil::unique_cotaskmem_string virtualDesktopId;
|
||||
if (SUCCEEDED(StringFromCLSID(deviceId.virtualDesktopId, &virtualDesktopId)))
|
||||
auto customLayouts = JSONHelpers::ParseCustomZoneSets(fancyZonesDataJSON);
|
||||
if (customLayouts)
|
||||
{
|
||||
Logger::info(L"Create new device on virtual desktop {}", virtualDesktopId.get());
|
||||
JSONHelpers::SaveCustomLayouts(customLayouts.value());
|
||||
}
|
||||
|
||||
auto templates = JSONHelpers::ParseLayoutTemplates(fancyZonesDataJSON);
|
||||
if (templates)
|
||||
{
|
||||
JSONHelpers::SaveLayoutTemplates(templates.value());
|
||||
}
|
||||
|
||||
// Creates default entry in map when WorkArea is created
|
||||
GUID guid;
|
||||
auto result{ CoCreateGuid(&guid) };
|
||||
wil::unique_cotaskmem_string guidString;
|
||||
if (result == S_OK && SUCCEEDED(StringFromCLSID(guid, &guidString)))
|
||||
auto quickKeysMap = JSONHelpers::ParseQuickKeys(fancyZonesDataJSON);
|
||||
if (quickKeysMap)
|
||||
{
|
||||
const ZoneSetData zoneSetData{ guidString.get(), ZoneSetLayoutType::PriorityGrid };
|
||||
DeviceInfoData defaultDeviceInfoData{ zoneSetData, DefaultValues::ShowSpacing, DefaultValues::Spacing, DefaultValues::ZoneCount, DefaultValues::SensitivityRadius };
|
||||
deviceInfoMap[deviceId] = std::move(defaultDeviceInfoData);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error("Failed to create an ID for the new layout");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FancyZonesData::CloneDeviceInfo(const FancyZonesDataTypes::DeviceIdData& source, const FancyZonesDataTypes::DeviceIdData& destination)
|
||||
{
|
||||
if (source == destination)
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::scoped_lock lock{ dataLock };
|
||||
|
||||
// The source virtual desktop is deleted, simply ignore it.
|
||||
if (!FindDeviceInfo(source).has_value())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
deviceInfoMap[destination] = deviceInfoMap[source];
|
||||
}
|
||||
|
||||
void FancyZonesData::SyncVirtualDesktops(GUID currentVirtualDesktopId)
|
||||
{
|
||||
_TRACER_;
|
||||
// Explorer persists current virtual desktop identifier to registry on a per session basis,
|
||||
// but only after first virtual desktop switch happens. If the user hasn't switched virtual
|
||||
// desktops in this session value in registry will be empty and we will use default GUID in
|
||||
// that case (00000000-0000-0000-0000-000000000000).
|
||||
// This method will go through all our persisted data with default GUID and update it with
|
||||
// valid one.
|
||||
|
||||
std::scoped_lock lock{ dataLock };
|
||||
bool dirtyFlag = false;
|
||||
|
||||
for (auto& [path, perDesktopData] : appZoneHistoryMap)
|
||||
{
|
||||
for (auto& data : perDesktopData)
|
||||
{
|
||||
if (data.deviceId.virtualDesktopId == GUID_NULL)
|
||||
{
|
||||
data.deviceId.virtualDesktopId = currentVirtualDesktopId;
|
||||
dirtyFlag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_virtualDesktopCheckCallback && !m_virtualDesktopCheckCallback(data.deviceId.virtualDesktopId))
|
||||
{
|
||||
data.deviceId.virtualDesktopId = GUID_NULL;
|
||||
dirtyFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<FancyZonesDataTypes::DeviceIdData> replaceWithCurrentId{};
|
||||
std::vector<FancyZonesDataTypes::DeviceIdData> replaceWithNullId{};
|
||||
|
||||
for (const auto& [desktopId, data] : deviceInfoMap)
|
||||
{
|
||||
if (desktopId.virtualDesktopId == GUID_NULL)
|
||||
{
|
||||
replaceWithCurrentId.push_back(desktopId);
|
||||
dirtyFlag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_virtualDesktopCheckCallback && !m_virtualDesktopCheckCallback(desktopId.virtualDesktopId))
|
||||
{
|
||||
replaceWithNullId.push_back(desktopId);
|
||||
dirtyFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& id : replaceWithCurrentId)
|
||||
{
|
||||
auto mapEntry = deviceInfoMap.extract(id);
|
||||
mapEntry.key().virtualDesktopId = currentVirtualDesktopId;
|
||||
deviceInfoMap.insert(std::move(mapEntry));
|
||||
}
|
||||
|
||||
for (const auto& id : replaceWithNullId)
|
||||
{
|
||||
auto mapEntry = deviceInfoMap.extract(id);
|
||||
mapEntry.key().virtualDesktopId = GUID_NULL;
|
||||
deviceInfoMap.insert(std::move(mapEntry));
|
||||
}
|
||||
|
||||
if (dirtyFlag)
|
||||
{
|
||||
wil::unique_cotaskmem_string virtualDesktopIdStr;
|
||||
if (SUCCEEDED(StringFromCLSID(currentVirtualDesktopId, &virtualDesktopIdStr)))
|
||||
{
|
||||
Logger::info(L"Update Virtual Desktop id to {}", virtualDesktopIdStr.get());
|
||||
JSONHelpers::SaveLayoutHotkeys(quickKeysMap.value());
|
||||
}
|
||||
|
||||
SaveAppZoneHistoryAndZoneSettings();
|
||||
std::filesystem::remove(zonesSettingsFileName);
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZonesData::RemoveDeletedDesktops(const std::vector<GUID>& activeDesktops)
|
||||
{
|
||||
std::unordered_set<GUID> active(std::begin(activeDesktops), std::end(activeDesktops));
|
||||
std::scoped_lock lock{ dataLock };
|
||||
bool dirtyFlag = false;
|
||||
|
||||
for (auto it = std::begin(deviceInfoMap); it != std::end(deviceInfoMap);)
|
||||
{
|
||||
GUID desktopId = it->first.virtualDesktopId;
|
||||
|
||||
if (desktopId != GUID_NULL)
|
||||
{
|
||||
auto foundId = active.find(desktopId);
|
||||
if (foundId == std::end(active))
|
||||
{
|
||||
wil::unique_cotaskmem_string virtualDesktopIdStr;
|
||||
if (SUCCEEDED(StringFromCLSID(desktopId, &virtualDesktopIdStr)))
|
||||
{
|
||||
Logger::info(L"Remove Virtual Desktop id {}", virtualDesktopIdStr.get());
|
||||
}
|
||||
|
||||
RemoveDesktopAppZoneHistory(desktopId);
|
||||
it = deviceInfoMap.erase(it);
|
||||
dirtyFlag = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
if (dirtyFlag)
|
||||
{
|
||||
SaveAppZoneHistoryAndZoneSettings();
|
||||
}
|
||||
}
|
||||
|
||||
bool FancyZonesData::IsAnotherWindowOfApplicationInstanceZoned(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId) const
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
auto processPath = get_process_path(window);
|
||||
if (!processPath.empty())
|
||||
{
|
||||
auto history = appZoneHistoryMap.find(processPath);
|
||||
if (history != std::end(appZoneHistoryMap))
|
||||
{
|
||||
auto& perDesktopData = history->second;
|
||||
for (auto& data : perDesktopData)
|
||||
{
|
||||
if (data.deviceId.isEqualWithNullVirtualDesktopId(deviceId))
|
||||
{
|
||||
DWORD processId = 0;
|
||||
GetWindowThreadProcessId(window, &processId);
|
||||
|
||||
auto processIdIt = data.processIdToHandleMap.find(processId);
|
||||
|
||||
if (processIdIt == std::end(data.processIdToHandleMap))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (processIdIt->second != window && IsWindow(processIdIt->second))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FancyZonesData::UpdateProcessIdToHandleMap(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId)
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
auto processPath = get_process_path(window);
|
||||
if (!processPath.empty())
|
||||
{
|
||||
auto history = appZoneHistoryMap.find(processPath);
|
||||
if (history != std::end(appZoneHistoryMap))
|
||||
{
|
||||
auto& perDesktopData = history->second;
|
||||
for (auto& data : perDesktopData)
|
||||
{
|
||||
if (data.deviceId.isEqualWithNullVirtualDesktopId(deviceId))
|
||||
{
|
||||
DWORD processId = 0;
|
||||
GetWindowThreadProcessId(window, &processId);
|
||||
data.processIdToHandleMap[processId] = window;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ZoneIndexSet FancyZonesData::GetAppLastZoneIndexSet(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId) const
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
auto processPath = get_process_path(window);
|
||||
if (!processPath.empty())
|
||||
{
|
||||
auto history = appZoneHistoryMap.find(processPath);
|
||||
if (history != std::end(appZoneHistoryMap))
|
||||
{
|
||||
const auto& perDesktopData = history->second;
|
||||
for (const auto& data : perDesktopData)
|
||||
{
|
||||
if (data.zoneSetUuid == zoneSetId && data.deviceId.isEqualWithNullVirtualDesktopId(deviceId))
|
||||
{
|
||||
return data.zoneIndexSet;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool FancyZonesData::RemoveAppLastZone(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId)
|
||||
{
|
||||
_TRACER_;
|
||||
std::scoped_lock lock{ dataLock };
|
||||
auto processPath = get_process_path(window);
|
||||
if (!processPath.empty())
|
||||
{
|
||||
auto history = appZoneHistoryMap.find(processPath);
|
||||
if (history != std::end(appZoneHistoryMap))
|
||||
{
|
||||
auto& perDesktopData = history->second;
|
||||
for (auto data = std::begin(perDesktopData); data != std::end(perDesktopData);)
|
||||
{
|
||||
if (data->deviceId.isEqualWithNullVirtualDesktopId(deviceId) && data->zoneSetUuid == zoneSetId)
|
||||
{
|
||||
if (!IsAnotherWindowOfApplicationInstanceZoned(window, deviceId))
|
||||
{
|
||||
DWORD processId = 0;
|
||||
GetWindowThreadProcessId(window, &processId);
|
||||
|
||||
data->processIdToHandleMap.erase(processId);
|
||||
}
|
||||
|
||||
// if there is another instance of same application placed in the same zone don't erase history
|
||||
ZoneIndex windowZoneStamp = reinterpret_cast<ZoneIndex>(::GetProp(window, ZonedWindowProperties::PropertyMultipleZoneID));
|
||||
for (auto placedWindow : data->processIdToHandleMap)
|
||||
{
|
||||
ZoneIndex placedWindowZoneStamp = reinterpret_cast<ZoneIndex>(::GetProp(placedWindow.second, ZonedWindowProperties::PropertyMultipleZoneID));
|
||||
if (IsWindow(placedWindow.second) && (windowZoneStamp == placedWindowZoneStamp))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
data = perDesktopData.erase(data);
|
||||
if (perDesktopData.empty())
|
||||
{
|
||||
appZoneHistoryMap.erase(processPath);
|
||||
}
|
||||
SaveAppZoneHistory();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
++data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FancyZonesData::SetAppLastZones(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring& zoneSetId, const ZoneIndexSet& zoneIndexSet)
|
||||
{
|
||||
_TRACER_;
|
||||
std::scoped_lock lock{ dataLock };
|
||||
|
||||
if (IsAnotherWindowOfApplicationInstanceZoned(window, deviceId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto processPath = get_process_path(window);
|
||||
if (processPath.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD processId = 0;
|
||||
GetWindowThreadProcessId(window, &processId);
|
||||
|
||||
auto history = appZoneHistoryMap.find(processPath);
|
||||
if (history != std::end(appZoneHistoryMap))
|
||||
{
|
||||
auto& perDesktopData = history->second;
|
||||
for (auto& data : perDesktopData)
|
||||
{
|
||||
if (data.deviceId.isEqualWithNullVirtualDesktopId(deviceId))
|
||||
{
|
||||
// application already has history on this work area, update it with new window position
|
||||
data.processIdToHandleMap[processId] = window;
|
||||
data.zoneSetUuid = zoneSetId;
|
||||
data.zoneIndexSet = zoneIndexSet;
|
||||
SaveAppZoneHistory();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_map<DWORD, HWND> processIdToHandleMap{};
|
||||
processIdToHandleMap[processId] = window;
|
||||
FancyZonesDataTypes::AppZoneHistoryData data{ .processIdToHandleMap = processIdToHandleMap,
|
||||
.zoneSetUuid = zoneSetId,
|
||||
.deviceId = deviceId,
|
||||
.zoneIndexSet = zoneIndexSet };
|
||||
|
||||
if (appZoneHistoryMap.contains(processPath))
|
||||
{
|
||||
// application already has history but on other desktop, add with new desktop info
|
||||
appZoneHistoryMap[processPath].push_back(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// new application, create entry in app zone history map
|
||||
appZoneHistoryMap[processPath] = std::vector<FancyZonesDataTypes::AppZoneHistoryData>{ data };
|
||||
}
|
||||
|
||||
SaveAppZoneHistory();
|
||||
return true;
|
||||
}
|
||||
|
||||
void FancyZonesData::SetActiveZoneSet(const FancyZonesDataTypes::DeviceIdData& deviceId, const FancyZonesDataTypes::ZoneSetData& data)
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
|
||||
for (auto& [deviceIdData, deviceInfo] : deviceInfoMap)
|
||||
{
|
||||
if (deviceId.isEqualWithNullVirtualDesktopId(deviceIdData))
|
||||
{
|
||||
deviceInfo.activeZoneSet = data;
|
||||
|
||||
// If the zone set is custom, we need to copy its properties to the device
|
||||
auto zonesetIt = customZoneSetsMap.find(data.uuid);
|
||||
if (zonesetIt != customZoneSetsMap.end())
|
||||
{
|
||||
if (zonesetIt->second.type == FancyZonesDataTypes::CustomLayoutType::Grid)
|
||||
{
|
||||
auto layoutInfo = std::get<FancyZonesDataTypes::GridLayoutInfo>(zonesetIt->second.info);
|
||||
deviceInfo.sensitivityRadius = layoutInfo.sensitivityRadius();
|
||||
deviceInfo.showSpacing = layoutInfo.showSpacing();
|
||||
deviceInfo.spacing = layoutInfo.spacing();
|
||||
deviceInfo.zoneCount = layoutInfo.zoneCount();
|
||||
}
|
||||
else if (zonesetIt->second.type == FancyZonesDataTypes::CustomLayoutType::Canvas)
|
||||
{
|
||||
auto layoutInfo = std::get<FancyZonesDataTypes::CanvasLayoutInfo>(zonesetIt->second.info);
|
||||
deviceInfo.sensitivityRadius = layoutInfo.sensitivityRadius;
|
||||
deviceInfo.zoneCount = (int)layoutInfo.zones.size();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
json::JsonObject FancyZonesData::GetPersistFancyZonesJSON()
|
||||
{
|
||||
return JSONHelpers::GetPersistFancyZonesJSON(zonesSettingsFileName, appZoneHistoryFileName);
|
||||
}
|
||||
|
||||
void FancyZonesData::LoadFancyZonesData()
|
||||
{
|
||||
if (!std::filesystem::exists(zonesSettingsFileName))
|
||||
{
|
||||
SaveAppZoneHistoryAndZoneSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
json::JsonObject fancyZonesDataJSON = GetPersistFancyZonesJSON();
|
||||
|
||||
appZoneHistoryMap = JSONHelpers::ParseAppZoneHistory(fancyZonesDataJSON);
|
||||
deviceInfoMap = JSONHelpers::ParseDeviceInfos(fancyZonesDataJSON);
|
||||
customZoneSetsMap = JSONHelpers::ParseCustomZoneSets(fancyZonesDataJSON);
|
||||
quickKeysMap = JSONHelpers::ParseQuickKeys(fancyZonesDataJSON);
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZonesData::SaveAppZoneHistoryAndZoneSettings() const
|
||||
{
|
||||
SaveZoneSettings();
|
||||
SaveAppZoneHistory();
|
||||
}
|
||||
|
||||
void FancyZonesData::SaveZoneSettings() const
|
||||
{
|
||||
_TRACER_;
|
||||
std::scoped_lock lock{ dataLock };
|
||||
|
||||
bool dirtyFlag = false;
|
||||
JSONHelpers::TDeviceInfoMap updatedDeviceInfoMap;
|
||||
if (m_virtualDesktopCheckCallback)
|
||||
{
|
||||
for (const auto& [id, data] : deviceInfoMap)
|
||||
{
|
||||
auto updatedId = id;
|
||||
if (!m_virtualDesktopCheckCallback(id.virtualDesktopId))
|
||||
{
|
||||
updatedId.virtualDesktopId = GUID_NULL;
|
||||
dirtyFlag = true;
|
||||
}
|
||||
|
||||
updatedDeviceInfoMap.insert({ updatedId, data });
|
||||
}
|
||||
}
|
||||
|
||||
if (dirtyFlag)
|
||||
{
|
||||
JSONHelpers::SaveZoneSettings(zonesSettingsFileName, updatedDeviceInfoMap, customZoneSetsMap, quickKeysMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
JSONHelpers::SaveZoneSettings(zonesSettingsFileName, deviceInfoMap, customZoneSetsMap, quickKeysMap);
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZonesData::SaveAppZoneHistory() const
|
||||
{
|
||||
_TRACER_;
|
||||
std::scoped_lock lock{ dataLock };
|
||||
|
||||
bool dirtyFlag = false;
|
||||
std::unordered_map<std::wstring, std::vector<FancyZonesDataTypes::AppZoneHistoryData>> updatedHistory;
|
||||
if (m_virtualDesktopCheckCallback)
|
||||
{
|
||||
for (const auto& [path, dataVector] : appZoneHistoryMap)
|
||||
{
|
||||
auto updatedVector = dataVector;
|
||||
for (auto& data : updatedVector)
|
||||
{
|
||||
if (!m_virtualDesktopCheckCallback(data.deviceId.virtualDesktopId))
|
||||
{
|
||||
data.deviceId.virtualDesktopId = GUID_NULL;
|
||||
dirtyFlag = true;
|
||||
}
|
||||
}
|
||||
|
||||
updatedHistory.insert(std::make_pair(path, updatedVector));
|
||||
}
|
||||
}
|
||||
|
||||
if (dirtyFlag)
|
||||
{
|
||||
JSONHelpers::SaveAppZoneHistory(appZoneHistoryFileName, updatedHistory);
|
||||
}
|
||||
else
|
||||
{
|
||||
JSONHelpers::SaveAppZoneHistory(appZoneHistoryFileName, appZoneHistoryMap);
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZonesData::SaveFancyZonesEditorParameters(bool spanZonesAcrossMonitors, const std::wstring& virtualDesktopId, const HMONITOR& targetMonitor, const std::vector<std::pair<HMONITOR, MONITORINFOEX>>& allMonitors) const
|
||||
{
|
||||
JSONHelpers::EditorArgs argsJson; /* json arguments */
|
||||
@@ -757,31 +135,3 @@ void FancyZonesData::SaveFancyZonesEditorParameters(bool spanZonesAcrossMonitors
|
||||
|
||||
json::to_file(editorParametersFileName, JSONHelpers::EditorArgs::ToJson(argsJson));
|
||||
}
|
||||
|
||||
void FancyZonesData::RemoveDesktopAppZoneHistory(GUID desktopId)
|
||||
{
|
||||
for (auto it = std::begin(appZoneHistoryMap); it != std::end(appZoneHistoryMap);)
|
||||
{
|
||||
auto& perDesktopData = it->second;
|
||||
for (auto desktopIt = std::begin(perDesktopData); desktopIt != std::end(perDesktopData);)
|
||||
{
|
||||
if (desktopIt->deviceId.virtualDesktopId == desktopId)
|
||||
{
|
||||
desktopIt = perDesktopData.erase(desktopIt);
|
||||
}
|
||||
else
|
||||
{
|
||||
++desktopIt;
|
||||
}
|
||||
}
|
||||
|
||||
if (perDesktopData.empty())
|
||||
{
|
||||
it = appZoneHistoryMap.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "JsonHelpers.h"
|
||||
|
||||
#if defined(UNIT_TESTS)
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/utils/json.h>
|
||||
#include <mutex>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <winnt.h>
|
||||
#include <FancyZonesLib/JsonHelpers.h>
|
||||
|
||||
// Non-localizable strings
|
||||
namespace NonLocalizable
|
||||
{
|
||||
const wchar_t FancyZonesStr[] = L"FancyZones";
|
||||
}
|
||||
|
||||
namespace FancyZonesDataTypes
|
||||
{
|
||||
struct ZoneSetData;
|
||||
struct DeviceIdData;
|
||||
struct DeviceInfoData;
|
||||
struct CustomZoneSetData;
|
||||
struct AppZoneHistoryData;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(UNIT_TESTS)
|
||||
namespace FancyZonesUnitTests
|
||||
{
|
||||
class FancyZonesDataUnitTests;
|
||||
class FancyZonesIFancyZonesCallbackUnitTests;
|
||||
class ZoneSetCalculateZonesUnitTests;
|
||||
class WorkAreaUnitTests;
|
||||
class WorkAreaCreationUnitTests;
|
||||
class LayoutHotkeysUnitTests;
|
||||
class LayoutTemplatesUnitTests;
|
||||
class CustomLayoutsUnitTests;
|
||||
class AppliedLayoutsUnitTests;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -44,83 +19,21 @@ class FancyZonesData
|
||||
public:
|
||||
FancyZonesData();
|
||||
|
||||
void SetVirtualDesktopCheckCallback(std::function<bool(GUID)> callback);
|
||||
|
||||
std::optional<FancyZonesDataTypes::DeviceInfoData> FindDeviceInfo(const FancyZonesDataTypes::DeviceIdData& id) const;
|
||||
std::optional<FancyZonesDataTypes::CustomZoneSetData> FindCustomZoneSet(const std::wstring& guid) const;
|
||||
|
||||
const JSONHelpers::TDeviceInfoMap& GetDeviceInfoMap() const;
|
||||
const JSONHelpers::TCustomZoneSetsMap& GetCustomZoneSetsMap() const;
|
||||
const std::unordered_map<std::wstring, std::vector<FancyZonesDataTypes::AppZoneHistoryData>>& GetAppZoneHistoryMap() const;
|
||||
|
||||
inline const JSONHelpers::TLayoutQuickKeysMap& GetLayoutQuickKeys() const
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
return quickKeysMap;
|
||||
}
|
||||
|
||||
inline const std::wstring& GetZonesSettingsFileName() const
|
||||
{
|
||||
return zonesSettingsFileName;
|
||||
}
|
||||
void ReplaceZoneSettingsFileFromOlderVersions();
|
||||
|
||||
inline const std::wstring& GetSettingsFileName() const
|
||||
{
|
||||
return settingsFileName;
|
||||
}
|
||||
|
||||
bool AddDevice(const FancyZonesDataTypes::DeviceIdData& deviceId);
|
||||
void CloneDeviceInfo(const FancyZonesDataTypes::DeviceIdData& source, const FancyZonesDataTypes::DeviceIdData& destination);
|
||||
void SyncVirtualDesktops(GUID desktopId);
|
||||
void RemoveDeletedDesktops(const std::vector<GUID>& activeDesktops);
|
||||
|
||||
bool IsAnotherWindowOfApplicationInstanceZoned(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId) const;
|
||||
void UpdateProcessIdToHandleMap(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId);
|
||||
ZoneIndexSet GetAppLastZoneIndexSet(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId) const;
|
||||
bool RemoveAppLastZone(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId);
|
||||
bool SetAppLastZones(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring& zoneSetId, const ZoneIndexSet& zoneIndexSet);
|
||||
|
||||
void SetActiveZoneSet(const FancyZonesDataTypes::DeviceIdData& deviceId, const FancyZonesDataTypes::ZoneSetData& zoneSet);
|
||||
|
||||
json::JsonObject GetPersistFancyZonesJSON();
|
||||
|
||||
void LoadFancyZonesData();
|
||||
void SaveAppZoneHistoryAndZoneSettings() const;
|
||||
void SaveZoneSettings() const;
|
||||
void SaveAppZoneHistory() const;
|
||||
|
||||
void SaveFancyZonesEditorParameters(bool spanZonesAcrossMonitors, const std::wstring& virtualDesktopId, const HMONITOR& targetMonitor, const std::vector<std::pair<HMONITOR, MONITORINFOEX>>& allMonitors) const;
|
||||
|
||||
private:
|
||||
#if defined(UNIT_TESTS)
|
||||
friend class FancyZonesUnitTests::FancyZonesDataUnitTests;
|
||||
friend class FancyZonesUnitTests::FancyZonesIFancyZonesCallbackUnitTests;
|
||||
friend class FancyZonesUnitTests::WorkAreaUnitTests;
|
||||
friend class FancyZonesUnitTests::WorkAreaCreationUnitTests;
|
||||
friend class FancyZonesUnitTests::ZoneSetCalculateZonesUnitTests;
|
||||
|
||||
inline void SetDeviceInfo(const FancyZonesDataTypes::DeviceIdData& deviceId, FancyZonesDataTypes::DeviceInfoData data)
|
||||
{
|
||||
deviceInfoMap[deviceId] = data;
|
||||
}
|
||||
|
||||
inline void SetCustomZonesets(const std::wstring& uuid, FancyZonesDataTypes::CustomZoneSetData data)
|
||||
{
|
||||
customZoneSetsMap[uuid] = data;
|
||||
}
|
||||
|
||||
inline bool ParseDeviceInfos(const json::JsonObject& fancyZonesDataJSON)
|
||||
{
|
||||
deviceInfoMap = JSONHelpers::ParseDeviceInfos(fancyZonesDataJSON);
|
||||
return !deviceInfoMap.empty();
|
||||
}
|
||||
|
||||
inline void clear_data()
|
||||
{
|
||||
appZoneHistoryMap.clear();
|
||||
deviceInfoMap.clear();
|
||||
customZoneSetsMap.clear();
|
||||
}
|
||||
friend class FancyZonesUnitTests::LayoutHotkeysUnitTests;
|
||||
friend class FancyZonesUnitTests::LayoutTemplatesUnitTests;
|
||||
friend class FancyZonesUnitTests::CustomLayoutsUnitTests;
|
||||
friend class FancyZonesUnitTests::AppliedLayoutsUnitTests;
|
||||
|
||||
inline void SetSettingsModulePath(std::wstring_view moduleName)
|
||||
{
|
||||
@@ -128,34 +41,17 @@ private:
|
||||
zonesSettingsFileName = result + L"\\" + std::wstring(L"zones-settings.json");
|
||||
appZoneHistoryFileName = result + L"\\" + std::wstring(L"app-zone-history.json");
|
||||
}
|
||||
|
||||
inline std::wstring GetZoneSettingsPath(std::wstring_view moduleName)
|
||||
{
|
||||
std::wstring result = PTSettingsHelper::get_module_save_folder_location(moduleName);
|
||||
return result + L"\\" + std::wstring(L"zones-settings.json");
|
||||
}
|
||||
#endif
|
||||
void RemoveDesktopAppZoneHistory(GUID desktopId);
|
||||
|
||||
// Maps app path to app's zone history data
|
||||
std::unordered_map<std::wstring, std::vector<FancyZonesDataTypes::AppZoneHistoryData>> appZoneHistoryMap{};
|
||||
// Maps device unique ID to device data
|
||||
JSONHelpers::TDeviceInfoMap deviceInfoMap{};
|
||||
// Maps custom zoneset UUID to it's data
|
||||
JSONHelpers::TCustomZoneSetsMap customZoneSetsMap{};
|
||||
// Maps zoneset UUID with quick access keys
|
||||
JSONHelpers::TLayoutQuickKeysMap quickKeysMap{};
|
||||
|
||||
std::wstring settingsFileName;
|
||||
std::wstring zonesSettingsFileName;
|
||||
std::wstring appZoneHistoryFileName;
|
||||
std::wstring editorParametersFileName;
|
||||
|
||||
std::function<bool(GUID)> m_virtualDesktopCheckCallback;
|
||||
|
||||
mutable std::recursive_mutex dataLock;
|
||||
};
|
||||
|
||||
FancyZonesData& FancyZonesDataInstance();
|
||||
|
||||
namespace DefaultValues
|
||||
{
|
||||
const int ZoneCount = 3;
|
||||
const bool ShowSpacing = true;
|
||||
const int Spacing = 16;
|
||||
const int SensitivityRadius = 20;
|
||||
}
|
||||
FancyZonesData& FancyZonesDataInstance();
|
||||
@@ -0,0 +1,386 @@
|
||||
#include "../pch.h"
|
||||
#include "AppZoneHistory.h"
|
||||
|
||||
#include <common/logger/call_tracer.h>
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/utils/process_path.h>
|
||||
|
||||
#include <FancyZonesLib/GuidUtils.h>
|
||||
#include <FancyZonesLib/FancyZonesWindowProperties.h>
|
||||
#include <FancyZonesLib/JsonHelpers.h>
|
||||
#include <FancyZonesLib/util.h>
|
||||
|
||||
AppZoneHistory::AppZoneHistory()
|
||||
{
|
||||
}
|
||||
|
||||
AppZoneHistory& AppZoneHistory::instance()
|
||||
{
|
||||
static AppZoneHistory self;
|
||||
return self;
|
||||
}
|
||||
|
||||
void AppZoneHistory::SetVirtualDesktopCheckCallback(std::function<bool(GUID)> callback)
|
||||
{
|
||||
m_virtualDesktopCheckCallback = callback;
|
||||
}
|
||||
|
||||
void AppZoneHistory::LoadData()
|
||||
{
|
||||
auto file = AppZoneHistoryFileName();
|
||||
auto data = json::from_file(file);
|
||||
|
||||
try
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
m_history = JSONHelpers::ParseAppZoneHistory(data.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_history.clear();
|
||||
Logger::error(L"app-zone-history.json file is missing or malformed");
|
||||
}
|
||||
}
|
||||
catch (const winrt::hresult_error& e)
|
||||
{
|
||||
Logger::error(L"Parsing app-zone-history error: {}", e.message());
|
||||
}
|
||||
}
|
||||
|
||||
void AppZoneHistory::SaveData()
|
||||
{
|
||||
_TRACER_;
|
||||
|
||||
bool dirtyFlag = false;
|
||||
std::unordered_map<std::wstring, std::vector<FancyZonesDataTypes::AppZoneHistoryData>> updatedHistory;
|
||||
if (m_virtualDesktopCheckCallback)
|
||||
{
|
||||
for (const auto& [path, dataVector] : m_history)
|
||||
{
|
||||
auto updatedVector = dataVector;
|
||||
for (auto& data : updatedVector)
|
||||
{
|
||||
if (!m_virtualDesktopCheckCallback(data.deviceId.virtualDesktopId))
|
||||
{
|
||||
data.deviceId.virtualDesktopId = GUID_NULL;
|
||||
dirtyFlag = true;
|
||||
}
|
||||
}
|
||||
|
||||
updatedHistory.insert(std::make_pair(path, updatedVector));
|
||||
}
|
||||
}
|
||||
|
||||
if (dirtyFlag)
|
||||
{
|
||||
JSONHelpers::SaveAppZoneHistory(AppZoneHistoryFileName(), updatedHistory);
|
||||
}
|
||||
else
|
||||
{
|
||||
JSONHelpers::SaveAppZoneHistory(AppZoneHistoryFileName(), m_history);
|
||||
}
|
||||
}
|
||||
|
||||
bool AppZoneHistory::SetAppLastZones(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring& zoneSetId, const ZoneIndexSet& zoneIndexSet)
|
||||
{
|
||||
_TRACER_;
|
||||
|
||||
if (IsAnotherWindowOfApplicationInstanceZoned(window, deviceId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto processPath = get_process_path(window);
|
||||
if (processPath.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD processId = 0;
|
||||
GetWindowThreadProcessId(window, &processId);
|
||||
|
||||
auto history = m_history.find(processPath);
|
||||
if (history != std::end(m_history))
|
||||
{
|
||||
auto& perDesktopData = history->second;
|
||||
for (auto& data : perDesktopData)
|
||||
{
|
||||
if (data.deviceId == deviceId)
|
||||
{
|
||||
// application already has history on this work area, update it with new window position
|
||||
data.processIdToHandleMap[processId] = window;
|
||||
data.zoneSetUuid = zoneSetId;
|
||||
data.zoneIndexSet = zoneIndexSet;
|
||||
SaveData();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_map<DWORD, HWND> processIdToHandleMap{};
|
||||
processIdToHandleMap[processId] = window;
|
||||
FancyZonesDataTypes::AppZoneHistoryData data{ .processIdToHandleMap = processIdToHandleMap,
|
||||
.zoneSetUuid = zoneSetId,
|
||||
.deviceId = deviceId,
|
||||
.zoneIndexSet = zoneIndexSet };
|
||||
|
||||
if (m_history.contains(processPath))
|
||||
{
|
||||
// application already has history but on other desktop, add with new desktop info
|
||||
m_history[processPath].push_back(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// new application, create entry in app zone history map
|
||||
m_history[processPath] = std::vector<FancyZonesDataTypes::AppZoneHistoryData>{ data };
|
||||
}
|
||||
|
||||
SaveData();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AppZoneHistory::RemoveAppLastZone(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId)
|
||||
{
|
||||
_TRACER_;
|
||||
|
||||
auto processPath = get_process_path(window);
|
||||
if (!processPath.empty())
|
||||
{
|
||||
auto history = m_history.find(processPath);
|
||||
if (history != std::end(m_history))
|
||||
{
|
||||
auto& perDesktopData = history->second;
|
||||
for (auto data = std::begin(perDesktopData); data != std::end(perDesktopData);)
|
||||
{
|
||||
if (data->deviceId == deviceId && data->zoneSetUuid == zoneSetId)
|
||||
{
|
||||
if (!IsAnotherWindowOfApplicationInstanceZoned(window, deviceId))
|
||||
{
|
||||
DWORD processId = 0;
|
||||
GetWindowThreadProcessId(window, &processId);
|
||||
|
||||
data->processIdToHandleMap.erase(processId);
|
||||
}
|
||||
|
||||
// if there is another instance of same application placed in the same zone don't erase history
|
||||
ZoneIndex windowZoneStamp = reinterpret_cast<ZoneIndex>(::GetProp(window, ZonedWindowProperties::PropertyMultipleZoneID));
|
||||
for (auto placedWindow : data->processIdToHandleMap)
|
||||
{
|
||||
ZoneIndex placedWindowZoneStamp = reinterpret_cast<ZoneIndex>(::GetProp(placedWindow.second, ZonedWindowProperties::PropertyMultipleZoneID));
|
||||
if (IsWindow(placedWindow.second) && (windowZoneStamp == placedWindowZoneStamp))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
data = perDesktopData.erase(data);
|
||||
if (perDesktopData.empty())
|
||||
{
|
||||
m_history.erase(processPath);
|
||||
}
|
||||
SaveData();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
++data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AppZoneHistory::RemoveApp(const std::wstring& appPath)
|
||||
{
|
||||
m_history.erase(appPath);
|
||||
}
|
||||
|
||||
const AppZoneHistory::TAppZoneHistoryMap& AppZoneHistory::GetFullAppZoneHistory() const noexcept
|
||||
{
|
||||
return m_history;
|
||||
}
|
||||
|
||||
std::optional<FancyZonesDataTypes::AppZoneHistoryData> AppZoneHistory::GetZoneHistory(const std::wstring& appPath, const FancyZonesDataTypes::DeviceIdData& deviceId) const noexcept
|
||||
{
|
||||
auto iter = m_history.find(appPath);
|
||||
if (iter != m_history.end())
|
||||
{
|
||||
auto historyVector = iter->second;
|
||||
for (const auto& history : historyVector)
|
||||
{
|
||||
if (history.deviceId == deviceId)
|
||||
{
|
||||
return history;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool AppZoneHistory::IsAnotherWindowOfApplicationInstanceZoned(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId) const noexcept
|
||||
{
|
||||
auto processPath = get_process_path(window);
|
||||
if (!processPath.empty())
|
||||
{
|
||||
auto history = m_history.find(processPath);
|
||||
if (history != std::end(m_history))
|
||||
{
|
||||
auto& perDesktopData = history->second;
|
||||
for (auto& data : perDesktopData)
|
||||
{
|
||||
if (data.deviceId == deviceId)
|
||||
{
|
||||
DWORD processId = 0;
|
||||
GetWindowThreadProcessId(window, &processId);
|
||||
|
||||
auto processIdIt = data.processIdToHandleMap.find(processId);
|
||||
|
||||
if (processIdIt == std::end(data.processIdToHandleMap))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (processIdIt->second != window && IsWindow(processIdIt->second))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AppZoneHistory::UpdateProcessIdToHandleMap(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId)
|
||||
{
|
||||
auto processPath = get_process_path(window);
|
||||
if (!processPath.empty())
|
||||
{
|
||||
auto history = m_history.find(processPath);
|
||||
if (history != std::end(m_history))
|
||||
{
|
||||
auto& perDesktopData = history->second;
|
||||
for (auto& data : perDesktopData)
|
||||
{
|
||||
if (data.deviceId == deviceId)
|
||||
{
|
||||
DWORD processId = 0;
|
||||
GetWindowThreadProcessId(window, &processId);
|
||||
data.processIdToHandleMap[processId] = window;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ZoneIndexSet AppZoneHistory::GetAppLastZoneIndexSet(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId) const
|
||||
{
|
||||
auto processPath = get_process_path(window);
|
||||
if (!processPath.empty())
|
||||
{
|
||||
auto history = m_history.find(processPath);
|
||||
if (history != std::end(m_history))
|
||||
{
|
||||
const auto& perDesktopData = history->second;
|
||||
for (const auto& data : perDesktopData)
|
||||
{
|
||||
if (data.zoneSetUuid == zoneSetId && data.deviceId == deviceId)
|
||||
{
|
||||
return data.zoneIndexSet;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void AppZoneHistory::SyncVirtualDesktops(GUID currentVirtualDesktopId)
|
||||
{
|
||||
_TRACER_;
|
||||
// Explorer persists current virtual desktop identifier to registry on a per session basis,
|
||||
// but only after first virtual desktop switch happens. If the user hasn't switched virtual
|
||||
// desktops in this session value in registry will be empty and we will use default GUID in
|
||||
// that case (00000000-0000-0000-0000-000000000000).
|
||||
|
||||
bool dirtyFlag = false;
|
||||
|
||||
for (auto& [path, perDesktopData] : m_history)
|
||||
{
|
||||
for (auto& data : perDesktopData)
|
||||
{
|
||||
if (data.deviceId.virtualDesktopId == GUID_NULL)
|
||||
{
|
||||
data.deviceId.virtualDesktopId = currentVirtualDesktopId;
|
||||
dirtyFlag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_virtualDesktopCheckCallback && !m_virtualDesktopCheckCallback(data.deviceId.virtualDesktopId))
|
||||
{
|
||||
data.deviceId.virtualDesktopId = GUID_NULL;
|
||||
dirtyFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dirtyFlag)
|
||||
{
|
||||
wil::unique_cotaskmem_string virtualDesktopIdStr;
|
||||
if (SUCCEEDED(StringFromCLSID(currentVirtualDesktopId, &virtualDesktopIdStr)))
|
||||
{
|
||||
Logger::info(L"Update Virtual Desktop id to {}", virtualDesktopIdStr.get());
|
||||
}
|
||||
|
||||
SaveData();
|
||||
}
|
||||
}
|
||||
|
||||
void AppZoneHistory::RemoveDeletedVirtualDesktops(const std::vector<GUID>& activeDesktops)
|
||||
{
|
||||
std::unordered_set<GUID> active(std::begin(activeDesktops), std::end(activeDesktops));
|
||||
bool dirtyFlag = false;
|
||||
|
||||
for (auto it = std::begin(m_history); it != std::end(m_history);)
|
||||
{
|
||||
auto& perDesktopData = it->second;
|
||||
for (auto desktopIt = std::begin(perDesktopData); desktopIt != std::end(perDesktopData);)
|
||||
{
|
||||
if (desktopIt->deviceId.virtualDesktopId != GUID_NULL && !active.contains(desktopIt->deviceId.virtualDesktopId))
|
||||
{
|
||||
auto virtualDesktopIdStr = FancyZonesUtils::GuidToString(desktopIt->deviceId.virtualDesktopId);
|
||||
if (virtualDesktopIdStr)
|
||||
{
|
||||
Logger::info(L"Remove Virtual Desktop id {} from app-zone-history", virtualDesktopIdStr.value());
|
||||
}
|
||||
|
||||
desktopIt = perDesktopData.erase(desktopIt);
|
||||
dirtyFlag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
++desktopIt;
|
||||
}
|
||||
}
|
||||
|
||||
if (perDesktopData.empty())
|
||||
{
|
||||
it = m_history.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
if (dirtyFlag)
|
||||
{
|
||||
SaveData();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <FancyZonesLib/FancyZonesDataTypes.h>
|
||||
#include <FancyZonesLib/ModuleConstants.h>
|
||||
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
|
||||
class AppZoneHistory
|
||||
{
|
||||
public:
|
||||
using TAppZoneHistoryMap = std::unordered_map<std::wstring, std::vector<FancyZonesDataTypes::AppZoneHistoryData>>;
|
||||
|
||||
static AppZoneHistory& instance();
|
||||
|
||||
inline static std::wstring AppZoneHistoryFileName()
|
||||
{
|
||||
std::wstring saveFolderPath = PTSettingsHelper::get_module_save_folder_location(NonLocalizable::ModuleKey);
|
||||
#if defined(UNIT_TESTS)
|
||||
return saveFolderPath + L"\\test-app-zone-history.json";
|
||||
#endif
|
||||
return saveFolderPath + L"\\app-zone-history.json";
|
||||
}
|
||||
|
||||
void LoadData();
|
||||
void SaveData();
|
||||
|
||||
bool SetAppLastZones(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring& zoneSetId, const ZoneIndexSet& zoneIndexSet);
|
||||
bool RemoveAppLastZone(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId);
|
||||
|
||||
void RemoveApp(const std::wstring& appPath);
|
||||
|
||||
const TAppZoneHistoryMap& GetFullAppZoneHistory() const noexcept;
|
||||
std::optional<FancyZonesDataTypes::AppZoneHistoryData> GetZoneHistory(const std::wstring& appPath, const FancyZonesDataTypes::DeviceIdData& deviceId) const noexcept;
|
||||
|
||||
bool IsAnotherWindowOfApplicationInstanceZoned(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId) const noexcept;
|
||||
void UpdateProcessIdToHandleMap(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId);
|
||||
ZoneIndexSet GetAppLastZoneIndexSet(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId) const;
|
||||
|
||||
void SetVirtualDesktopCheckCallback(std::function<bool(GUID)> callback);
|
||||
void SyncVirtualDesktops(GUID currentVirtualDesktopId);
|
||||
void RemoveDeletedVirtualDesktops(const std::vector<GUID>& activeDesktops);
|
||||
|
||||
private:
|
||||
AppZoneHistory();
|
||||
~AppZoneHistory() = default;
|
||||
|
||||
TAppZoneHistoryMap m_history;
|
||||
std::function<bool(GUID)> m_virtualDesktopCheckCallback;
|
||||
};
|
||||
@@ -0,0 +1,420 @@
|
||||
#include "../pch.h"
|
||||
#include "AppliedLayouts.h"
|
||||
|
||||
#include <common/logger/call_tracer.h>
|
||||
#include <common/logger/logger.h>
|
||||
|
||||
#include <FancyZonesLib/GuidUtils.h>
|
||||
#include <FancyZonesLib/FancyZonesData/CustomLayouts.h>
|
||||
#include <FancyZonesLib/FancyZonesData/LayoutDefaults.h>
|
||||
#include <FancyZonesLib/FancyZonesData/LayoutTemplates.h>
|
||||
#include <FancyZonesLib/FancyZonesWinHookEventIDs.h>
|
||||
#include <FancyZonesLib/JsonHelpers.h>
|
||||
#include <FancyZonesLib/util.h>
|
||||
|
||||
namespace JsonUtils
|
||||
{
|
||||
struct LayoutJSON
|
||||
{
|
||||
static std::optional<Layout> FromJson(const json::JsonObject& json)
|
||||
{
|
||||
try
|
||||
{
|
||||
Layout data;
|
||||
auto idStr = json.GetNamedString(NonLocalizable::AppliedLayoutsIds::UuidID);
|
||||
auto id = FancyZonesUtils::GuidFromString(idStr.c_str());
|
||||
if (!id.has_value())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
data.uuid = id.value();
|
||||
data.type = FancyZonesDataTypes::TypeFromString(std::wstring{ json.GetNamedString(NonLocalizable::AppliedLayoutsIds::TypeID) });
|
||||
data.showSpacing = json.GetNamedBoolean(NonLocalizable::AppliedLayoutsIds::ShowSpacingID);
|
||||
data.spacing = static_cast<int>(json.GetNamedNumber(NonLocalizable::AppliedLayoutsIds::SpacingID));
|
||||
data.zoneCount = static_cast<int>(json.GetNamedNumber(NonLocalizable::AppliedLayoutsIds::ZoneCountID));
|
||||
data.sensitivityRadius = static_cast<int>(json.GetNamedNumber(NonLocalizable::AppliedLayoutsIds::SensitivityRadiusID, DefaultValues::SensitivityRadius));
|
||||
|
||||
return data;
|
||||
}
|
||||
catch (const winrt::hresult_error&)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
static json::JsonObject ToJson(const Layout& data)
|
||||
{
|
||||
json::JsonObject result{};
|
||||
result.SetNamedValue(NonLocalizable::AppliedLayoutsIds::UuidID, json::value(FancyZonesUtils::GuidToString(data.uuid).value()));
|
||||
result.SetNamedValue(NonLocalizable::AppliedLayoutsIds::TypeID, json::value(FancyZonesDataTypes::TypeToString(data.type)));
|
||||
result.SetNamedValue(NonLocalizable::AppliedLayoutsIds::ShowSpacingID, json::value(data.showSpacing));
|
||||
result.SetNamedValue(NonLocalizable::AppliedLayoutsIds::SpacingID, json::value(data.spacing));
|
||||
result.SetNamedValue(NonLocalizable::AppliedLayoutsIds::ZoneCountID, json::value(data.zoneCount));
|
||||
result.SetNamedValue(NonLocalizable::AppliedLayoutsIds::SensitivityRadiusID, json::value(data.sensitivityRadius));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct AppliedLayoutsJSON
|
||||
{
|
||||
FancyZonesDataTypes::DeviceIdData deviceId;
|
||||
Layout data;
|
||||
|
||||
static std::optional<AppliedLayoutsJSON> FromJson(const json::JsonObject& json)
|
||||
{
|
||||
try
|
||||
{
|
||||
AppliedLayoutsJSON result;
|
||||
|
||||
std::wstring deviceIdStr = json.GetNamedString(NonLocalizable::AppliedLayoutsIds::DeviceIdID).c_str();
|
||||
auto deviceId = FancyZonesDataTypes::DeviceIdData::ParseDeviceId(deviceIdStr);
|
||||
if (!deviceId.has_value())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto layout = JsonUtils::LayoutJSON::FromJson(json.GetNamedObject(NonLocalizable::AppliedLayoutsIds::AppliedLayoutID));
|
||||
if (!layout.has_value())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
result.deviceId = std::move(deviceId.value());
|
||||
result.data = std::move(layout.value());
|
||||
return result;
|
||||
}
|
||||
catch (const winrt::hresult_error&)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
static json::JsonObject ToJson(const AppliedLayoutsJSON& value)
|
||||
{
|
||||
json::JsonObject result{};
|
||||
|
||||
result.SetNamedValue(NonLocalizable::AppliedLayoutsIds::DeviceIdID, json::value(value.deviceId.toString()));
|
||||
result.SetNamedValue(NonLocalizable::AppliedLayoutsIds::AppliedLayoutID, JsonUtils::LayoutJSON::ToJson(value.data));
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
AppliedLayouts::TAppliedLayoutsMap ParseJson(const json::JsonObject& json)
|
||||
{
|
||||
AppliedLayouts::TAppliedLayoutsMap map{};
|
||||
auto layouts = json.GetNamedArray(NonLocalizable::AppliedLayoutsIds::AppliedLayoutsArrayID);
|
||||
|
||||
for (uint32_t i = 0; i < layouts.Size(); ++i)
|
||||
{
|
||||
if (auto obj = AppliedLayoutsJSON::FromJson(layouts.GetObjectAt(i)); obj.has_value())
|
||||
{
|
||||
map[obj->deviceId] = std::move(obj->data);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
json::JsonObject SerializeJson(const AppliedLayouts::TAppliedLayoutsMap& map)
|
||||
{
|
||||
json::JsonObject json{};
|
||||
json::JsonArray layoutArray{};
|
||||
|
||||
for (const auto& [id, data] : map)
|
||||
{
|
||||
AppliedLayoutsJSON obj{};
|
||||
obj.deviceId = id;
|
||||
obj.data = data;
|
||||
layoutArray.Append(AppliedLayoutsJSON::ToJson(obj));
|
||||
}
|
||||
|
||||
json.SetNamedValue(NonLocalizable::AppliedLayoutsIds::AppliedLayoutsArrayID, layoutArray);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AppliedLayouts::AppliedLayouts()
|
||||
{
|
||||
const std::wstring& fileName = AppliedLayoutsFileName();
|
||||
m_fileWatcher = std::make_unique<FileWatcher>(fileName, [&]() {
|
||||
PostMessageW(HWND_BROADCAST, WM_PRIV_APPLIED_LAYOUTS_FILE_UPDATE, NULL, NULL);
|
||||
});
|
||||
}
|
||||
|
||||
AppliedLayouts& AppliedLayouts::instance()
|
||||
{
|
||||
static AppliedLayouts self;
|
||||
return self;
|
||||
}
|
||||
|
||||
void AppliedLayouts::LoadData()
|
||||
{
|
||||
auto data = json::from_file(AppliedLayoutsFileName());
|
||||
|
||||
try
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
m_layouts = JsonUtils::ParseJson(data.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_layouts.clear();
|
||||
Logger::info(L"applied-layouts.json file is missing or malformed");
|
||||
}
|
||||
}
|
||||
catch (const winrt::hresult_error& e)
|
||||
{
|
||||
Logger::error(L"Parsing applied-layouts error: {}", e.message());
|
||||
}
|
||||
}
|
||||
|
||||
void AppliedLayouts::SaveData()
|
||||
{
|
||||
_TRACER_;
|
||||
|
||||
bool dirtyFlag = false;
|
||||
TAppliedLayoutsMap updatedMap;
|
||||
if (m_virtualDesktopCheckCallback)
|
||||
{
|
||||
for (const auto& [id, data] : m_layouts)
|
||||
{
|
||||
auto updatedId = id;
|
||||
if (!m_virtualDesktopCheckCallback(id.virtualDesktopId))
|
||||
{
|
||||
updatedId.virtualDesktopId = GUID_NULL;
|
||||
dirtyFlag = true;
|
||||
}
|
||||
|
||||
updatedMap.insert({ updatedId, data });
|
||||
}
|
||||
}
|
||||
|
||||
if (dirtyFlag)
|
||||
{
|
||||
json::to_file(AppliedLayoutsFileName(), JsonUtils::SerializeJson(updatedMap));
|
||||
}
|
||||
else
|
||||
{
|
||||
json::to_file(AppliedLayoutsFileName(), JsonUtils::SerializeJson(m_layouts));
|
||||
}
|
||||
}
|
||||
|
||||
void AppliedLayouts::SetVirtualDesktopCheckCallback(std::function<bool(GUID)> callback)
|
||||
{
|
||||
m_virtualDesktopCheckCallback = callback;
|
||||
}
|
||||
|
||||
void AppliedLayouts::SyncVirtualDesktops(GUID currentVirtualDesktopId)
|
||||
{
|
||||
_TRACER_;
|
||||
// Explorer persists current virtual desktop identifier to registry on a per session basis,
|
||||
// but only after first virtual desktop switch happens. If the user hasn't switched virtual
|
||||
// desktops in this session value in registry will be empty and we will use default GUID in
|
||||
// that case (00000000-0000-0000-0000-000000000000).
|
||||
|
||||
bool dirtyFlag = false;
|
||||
|
||||
std::vector<FancyZonesDataTypes::DeviceIdData> replaceWithCurrentId{};
|
||||
std::vector<FancyZonesDataTypes::DeviceIdData> replaceWithNullId{};
|
||||
|
||||
for (const auto& [id, data] : m_layouts)
|
||||
{
|
||||
if (id.virtualDesktopId == GUID_NULL)
|
||||
{
|
||||
replaceWithCurrentId.push_back(id);
|
||||
dirtyFlag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_virtualDesktopCheckCallback && !m_virtualDesktopCheckCallback(id.virtualDesktopId))
|
||||
{
|
||||
replaceWithNullId.push_back(id);
|
||||
dirtyFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& id : replaceWithCurrentId)
|
||||
{
|
||||
auto mapEntry = m_layouts.extract(id);
|
||||
mapEntry.key().virtualDesktopId = currentVirtualDesktopId;
|
||||
m_layouts.insert(std::move(mapEntry));
|
||||
}
|
||||
|
||||
for (const auto& id : replaceWithNullId)
|
||||
{
|
||||
auto mapEntry = m_layouts.extract(id);
|
||||
mapEntry.key().virtualDesktopId = GUID_NULL;
|
||||
m_layouts.insert(std::move(mapEntry));
|
||||
}
|
||||
|
||||
if (dirtyFlag)
|
||||
{
|
||||
wil::unique_cotaskmem_string virtualDesktopIdStr;
|
||||
if (SUCCEEDED(StringFromCLSID(currentVirtualDesktopId, &virtualDesktopIdStr)))
|
||||
{
|
||||
Logger::info(L"Update Virtual Desktop id to {}", virtualDesktopIdStr.get());
|
||||
}
|
||||
|
||||
SaveData();
|
||||
}
|
||||
}
|
||||
|
||||
void AppliedLayouts::RemoveDeletedVirtualDesktops(const std::vector<GUID>& activeDesktops)
|
||||
{
|
||||
std::unordered_set<GUID> active(std::begin(activeDesktops), std::end(activeDesktops));
|
||||
bool dirtyFlag = false;
|
||||
|
||||
for (auto it = std::begin(m_layouts); it != std::end(m_layouts);)
|
||||
{
|
||||
GUID desktopId = it->first.virtualDesktopId;
|
||||
|
||||
if (desktopId != GUID_NULL)
|
||||
{
|
||||
auto foundId = active.find(desktopId);
|
||||
if (foundId == std::end(active))
|
||||
{
|
||||
wil::unique_cotaskmem_string virtualDesktopIdStr;
|
||||
if (SUCCEEDED(StringFromCLSID(desktopId, &virtualDesktopIdStr)))
|
||||
{
|
||||
Logger::info(L"Remove Virtual Desktop id {}", virtualDesktopIdStr.get());
|
||||
}
|
||||
|
||||
it = m_layouts.erase(it);
|
||||
dirtyFlag = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
if (dirtyFlag)
|
||||
{
|
||||
SaveData();
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Layout> AppliedLayouts::GetDeviceLayout(const FancyZonesDataTypes::DeviceIdData& id) const noexcept
|
||||
{
|
||||
auto iter = m_layouts.find(id);
|
||||
if (iter != m_layouts.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const AppliedLayouts::TAppliedLayoutsMap& AppliedLayouts::GetAppliedLayoutMap() const noexcept
|
||||
{
|
||||
return m_layouts;
|
||||
}
|
||||
|
||||
bool AppliedLayouts::IsLayoutApplied(const FancyZonesDataTypes::DeviceIdData& id) const noexcept
|
||||
{
|
||||
auto iter = m_layouts.find(id);
|
||||
return iter != m_layouts.end();
|
||||
}
|
||||
|
||||
bool AppliedLayouts::ApplyLayout(const FancyZonesDataTypes::DeviceIdData& deviceId, const FancyZonesDataTypes::ZoneSetData& layout)
|
||||
{
|
||||
auto uuid = FancyZonesUtils::GuidFromString(layout.uuid);
|
||||
if (!uuid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Layout layoutToApply {
|
||||
.uuid = uuid.value(),
|
||||
.type = layout.type,
|
||||
.showSpacing = DefaultValues::ShowSpacing,
|
||||
.spacing = DefaultValues::Spacing,
|
||||
.zoneCount = DefaultValues::ZoneCount,
|
||||
.sensitivityRadius = DefaultValues::SensitivityRadius,
|
||||
};
|
||||
|
||||
// copy layouts properties to the applied-layout
|
||||
auto customLayout = CustomLayouts::instance().GetLayout(layoutToApply.uuid);
|
||||
if (customLayout)
|
||||
{
|
||||
if (customLayout.value().type == FancyZonesDataTypes::CustomLayoutType::Grid)
|
||||
{
|
||||
auto layoutInfo = std::get<FancyZonesDataTypes::GridLayoutInfo>(customLayout.value().info);
|
||||
layoutToApply.sensitivityRadius = layoutInfo.sensitivityRadius();
|
||||
layoutToApply.showSpacing = layoutInfo.showSpacing();
|
||||
layoutToApply.spacing = layoutInfo.spacing();
|
||||
layoutToApply.zoneCount = layoutInfo.zoneCount();
|
||||
}
|
||||
else if (customLayout.value().type == FancyZonesDataTypes::CustomLayoutType::Canvas)
|
||||
{
|
||||
auto layoutInfo = std::get<FancyZonesDataTypes::CanvasLayoutInfo>(customLayout.value().info);
|
||||
layoutToApply.sensitivityRadius = layoutInfo.sensitivityRadius;
|
||||
layoutToApply.zoneCount = (int)layoutInfo.zones.size();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// check templates only if it wasn't a custom layout, since templates don't have ids yet
|
||||
auto templateLayout = LayoutTemplates::instance().GetLayout(layout.type);
|
||||
if (templateLayout)
|
||||
{
|
||||
auto layoutInfo = templateLayout.value();
|
||||
layoutToApply.sensitivityRadius = layoutInfo.sensitivityRadius;
|
||||
layoutToApply.showSpacing = layoutInfo.showSpacing;
|
||||
layoutToApply.spacing = layoutInfo.spacing;
|
||||
layoutToApply.zoneCount = layoutInfo.zoneCount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_layouts[deviceId] = std::move(layoutToApply);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AppliedLayouts::ApplyDefaultLayout(const FancyZonesDataTypes::DeviceIdData& deviceId)
|
||||
{
|
||||
Logger::info(L"Set default layout on {}", deviceId.toString());
|
||||
|
||||
GUID guid;
|
||||
auto result{ CoCreateGuid(&guid) };
|
||||
if (!SUCCEEDED(result))
|
||||
{
|
||||
Logger::error("Failed to create an ID for the new layout");
|
||||
return false;
|
||||
}
|
||||
|
||||
Layout layout{
|
||||
.uuid = guid,
|
||||
.type = FancyZonesDataTypes::ZoneSetLayoutType::PriorityGrid,
|
||||
.showSpacing = DefaultValues::ShowSpacing,
|
||||
.spacing = DefaultValues::Spacing,
|
||||
.zoneCount = DefaultValues::ZoneCount,
|
||||
.sensitivityRadius = DefaultValues::SensitivityRadius
|
||||
};
|
||||
|
||||
m_layouts[deviceId] = std::move(layout);
|
||||
|
||||
SaveData();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AppliedLayouts::CloneLayout(const FancyZonesDataTypes::DeviceIdData& srcId, const FancyZonesDataTypes::DeviceIdData& dstId)
|
||||
{
|
||||
if (srcId == dstId || m_layouts.find(srcId) == m_layouts.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Logger::info(L"Clone layout from {} to {}", dstId.toString(), srcId.toString());
|
||||
m_layouts[dstId] = m_layouts[srcId];
|
||||
|
||||
SaveData();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <FancyZonesLib/FancyZonesData/Layout.h>
|
||||
#include <FancyZonesLib/ModuleConstants.h>
|
||||
|
||||
#include <common/SettingsAPI/FileWatcher.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
|
||||
namespace NonLocalizable
|
||||
{
|
||||
namespace AppliedLayoutsIds
|
||||
{
|
||||
const static wchar_t* AppliedLayoutsArrayID = L"applied-layouts";
|
||||
const static wchar_t* DeviceIdID = L"device-id";
|
||||
const static wchar_t* AppliedLayoutID = L"applied-layout";
|
||||
const static wchar_t* UuidID = L"uuid";
|
||||
const static wchar_t* TypeID = L"type";
|
||||
const static wchar_t* ShowSpacingID = L"show-spacing";
|
||||
const static wchar_t* SpacingID = L"spacing";
|
||||
const static wchar_t* ZoneCountID = L"zone-count";
|
||||
const static wchar_t* SensitivityRadiusID = L"sensitivity-radius";
|
||||
}
|
||||
}
|
||||
|
||||
class AppliedLayouts
|
||||
{
|
||||
public:
|
||||
using TAppliedLayoutsMap = std::unordered_map<FancyZonesDataTypes::DeviceIdData, Layout>;
|
||||
|
||||
static AppliedLayouts& instance();
|
||||
|
||||
inline static std::wstring AppliedLayoutsFileName()
|
||||
{
|
||||
std::wstring saveFolderPath = PTSettingsHelper::get_module_save_folder_location(NonLocalizable::ModuleKey);
|
||||
#if defined(UNIT_TESTS)
|
||||
return saveFolderPath + L"\\test-applied-layouts.json";
|
||||
#endif
|
||||
return saveFolderPath + L"\\applied-layouts.json";
|
||||
}
|
||||
|
||||
void LoadData();
|
||||
void SaveData();
|
||||
|
||||
void SetVirtualDesktopCheckCallback(std::function<bool(GUID)> callback);
|
||||
void SyncVirtualDesktops(GUID currentVirtualDesktopId);
|
||||
void RemoveDeletedVirtualDesktops(const std::vector<GUID>& activeDesktops);
|
||||
|
||||
std::optional<Layout> GetDeviceLayout(const FancyZonesDataTypes::DeviceIdData& id) const noexcept;
|
||||
const TAppliedLayoutsMap& GetAppliedLayoutMap() const noexcept;
|
||||
|
||||
bool IsLayoutApplied(const FancyZonesDataTypes::DeviceIdData& id) const noexcept;
|
||||
|
||||
bool ApplyLayout(const FancyZonesDataTypes::DeviceIdData& deviceId, const FancyZonesDataTypes::ZoneSetData& layout);
|
||||
bool ApplyDefaultLayout(const FancyZonesDataTypes::DeviceIdData& deviceId);
|
||||
bool CloneLayout(const FancyZonesDataTypes::DeviceIdData& srcId, const FancyZonesDataTypes::DeviceIdData& dstId);
|
||||
|
||||
private:
|
||||
AppliedLayouts();
|
||||
~AppliedLayouts() = default;
|
||||
|
||||
std::unique_ptr<FileWatcher> m_fileWatcher;
|
||||
TAppliedLayoutsMap m_layouts;
|
||||
std::function<bool(GUID)> m_virtualDesktopCheckCallback;
|
||||
};
|
||||
@@ -0,0 +1,233 @@
|
||||
#include "../pch.h"
|
||||
#include "CustomLayouts.h"
|
||||
|
||||
#include <common/logger/logger.h>
|
||||
|
||||
#include <FancyZonesLib/FancyZonesData/LayoutDefaults.h>
|
||||
#include <FancyZonesLib/FancyZonesWinHookEventIDs.h>
|
||||
#include <FancyZonesLib/JsonHelpers.h>
|
||||
#include <FancyZonesLib/util.h>
|
||||
|
||||
namespace JsonUtils
|
||||
{
|
||||
std::vector<int> JsonArrayToNumVec(const json::JsonArray& arr)
|
||||
{
|
||||
std::vector<int> vec;
|
||||
for (const auto& val : arr)
|
||||
{
|
||||
vec.emplace_back(static_cast<int>(val.GetNumber()));
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
namespace CanvasLayoutInfoJSON
|
||||
{
|
||||
std::optional<FancyZonesDataTypes::CanvasLayoutInfo> FromJson(const json::JsonObject& infoJson)
|
||||
{
|
||||
try
|
||||
{
|
||||
FancyZonesDataTypes::CanvasLayoutInfo info;
|
||||
info.lastWorkAreaWidth = static_cast<int>(infoJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::RefWidthID));
|
||||
info.lastWorkAreaHeight = static_cast<int>(infoJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::RefHeightID));
|
||||
|
||||
json::JsonArray zonesJson = infoJson.GetNamedArray(NonLocalizable::CustomLayoutsIds::ZonesID);
|
||||
uint32_t size = zonesJson.Size();
|
||||
info.zones.reserve(size);
|
||||
for (uint32_t i = 0; i < size; ++i)
|
||||
{
|
||||
json::JsonObject zoneJson = zonesJson.GetObjectAt(i);
|
||||
const int x = static_cast<int>(zoneJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::XID));
|
||||
const int y = static_cast<int>(zoneJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::YID));
|
||||
const int width = static_cast<int>(zoneJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::WidthID));
|
||||
const int height = static_cast<int>(zoneJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::HeightID));
|
||||
FancyZonesDataTypes::CanvasLayoutInfo::Rect zone{ x, y, width, height };
|
||||
info.zones.push_back(zone);
|
||||
}
|
||||
|
||||
info.sensitivityRadius = static_cast<int>(infoJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::SensitivityRadiusID, DefaultValues::SensitivityRadius));
|
||||
return info;
|
||||
}
|
||||
catch (const winrt::hresult_error&)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace GridLayoutInfoJSON
|
||||
{
|
||||
std::optional<FancyZonesDataTypes::GridLayoutInfo> FromJson(const json::JsonObject& infoJson)
|
||||
{
|
||||
try
|
||||
{
|
||||
FancyZonesDataTypes::GridLayoutInfo info(FancyZonesDataTypes::GridLayoutInfo::Minimal{});
|
||||
|
||||
info.m_rows = static_cast<int>(infoJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::RowsID));
|
||||
info.m_columns = static_cast<int>(infoJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::ColumnsID));
|
||||
|
||||
json::JsonArray rowsPercentage = infoJson.GetNamedArray(NonLocalizable::CustomLayoutsIds::RowsPercentageID);
|
||||
json::JsonArray columnsPercentage = infoJson.GetNamedArray(NonLocalizable::CustomLayoutsIds::ColumnsPercentageID);
|
||||
json::JsonArray cellChildMap = infoJson.GetNamedArray(NonLocalizable::CustomLayoutsIds::CellChildMapID);
|
||||
|
||||
if (rowsPercentage.Size() != info.m_rows || columnsPercentage.Size() != info.m_columns || cellChildMap.Size() != info.m_rows)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
info.m_rowsPercents = JsonArrayToNumVec(rowsPercentage);
|
||||
info.m_columnsPercents = JsonArrayToNumVec(columnsPercentage);
|
||||
for (const auto& cellsRow : cellChildMap)
|
||||
{
|
||||
const auto cellsArray = cellsRow.GetArray();
|
||||
if (cellsArray.Size() != info.m_columns)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
info.cellChildMap().push_back(JsonArrayToNumVec(cellsArray));
|
||||
}
|
||||
|
||||
info.m_showSpacing = infoJson.GetNamedBoolean(NonLocalizable::CustomLayoutsIds::ShowSpacingID, DefaultValues::ShowSpacing);
|
||||
info.m_spacing = static_cast<int>(infoJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::SpacingID, DefaultValues::Spacing));
|
||||
info.m_sensitivityRadius = static_cast<int>(infoJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::SensitivityRadiusID, DefaultValues::SensitivityRadius));
|
||||
|
||||
return info;
|
||||
}
|
||||
catch (const winrt::hresult_error&)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomLayoutJSON
|
||||
{
|
||||
GUID layoutId;
|
||||
FancyZonesDataTypes::CustomLayoutData data;
|
||||
|
||||
static std::optional<CustomLayoutJSON> FromJson(const json::JsonObject& json)
|
||||
{
|
||||
try
|
||||
{
|
||||
CustomLayoutJSON result;
|
||||
|
||||
auto idStr = json.GetNamedString(NonLocalizable::CustomLayoutsIds::UuidID);
|
||||
auto id = FancyZonesUtils::GuidFromString(idStr.c_str());
|
||||
if (!id)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
result.layoutId = id.value();
|
||||
result.data.name = json.GetNamedString(NonLocalizable::CustomLayoutsIds::NameID);
|
||||
|
||||
json::JsonObject infoJson = json.GetNamedObject(NonLocalizable::CustomLayoutsIds::InfoID);
|
||||
std::wstring zoneSetType = std::wstring{ json.GetNamedString(NonLocalizable::CustomLayoutsIds::TypeID) };
|
||||
if (zoneSetType.compare(NonLocalizable::CustomLayoutsIds::CanvasID) == 0)
|
||||
{
|
||||
if (auto info = CanvasLayoutInfoJSON::FromJson(infoJson); info.has_value())
|
||||
{
|
||||
result.data.type = FancyZonesDataTypes::CustomLayoutType::Canvas;
|
||||
result.data.info = std::move(info.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
else if (zoneSetType.compare(NonLocalizable::CustomLayoutsIds::GridID) == 0)
|
||||
{
|
||||
if (auto info = GridLayoutInfoJSON::FromJson(infoJson); info.has_value())
|
||||
{
|
||||
result.data.type = FancyZonesDataTypes::CustomLayoutType::Grid;
|
||||
result.data.info = std::move(info.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (const winrt::hresult_error&)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CustomLayouts::TCustomLayoutMap ParseJson(const json::JsonObject& json)
|
||||
{
|
||||
CustomLayouts::TCustomLayoutMap map{};
|
||||
auto layouts = json.GetNamedArray(NonLocalizable::CustomLayoutsIds::CustomLayoutsArrayID);
|
||||
|
||||
for (uint32_t i = 0; i < layouts.Size(); ++i)
|
||||
{
|
||||
if (auto obj = CustomLayoutJSON::FromJson(layouts.GetObjectAt(i)); obj.has_value())
|
||||
{
|
||||
map[obj->layoutId] = std::move(obj->data);
|
||||
}
|
||||
}
|
||||
|
||||
return std::move(map);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CustomLayouts::CustomLayouts()
|
||||
{
|
||||
const std::wstring& dataFileName = CustomLayoutsFileName();
|
||||
m_fileWatcher = std::make_unique<FileWatcher>(dataFileName, [&]() {
|
||||
PostMessageW(HWND_BROADCAST, WM_PRIV_CUSTOM_LAYOUTS_FILE_UPDATE, NULL, NULL);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
CustomLayouts& CustomLayouts::instance()
|
||||
{
|
||||
static CustomLayouts self;
|
||||
return self;
|
||||
}
|
||||
|
||||
void CustomLayouts::LoadData()
|
||||
{
|
||||
auto data = json::from_file(CustomLayoutsFileName());
|
||||
|
||||
try
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
m_layouts = JsonUtils::ParseJson(data.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_layouts.clear();
|
||||
Logger::info(L"custom-layouts.json file is missing or malformed");
|
||||
}
|
||||
}
|
||||
catch (const winrt::hresult_error& e)
|
||||
{
|
||||
Logger::error(L"Parsing custom-layouts error: {}", e.message());
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<FancyZonesDataTypes::CustomLayoutData> CustomLayouts::GetLayout(const GUID& id) const noexcept
|
||||
{
|
||||
auto iter = m_layouts.find(id);
|
||||
if (iter != m_layouts.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const CustomLayouts::TCustomLayoutMap& CustomLayouts::GetAllLayouts() const noexcept
|
||||
{
|
||||
return m_layouts;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include <guiddef.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <FancyZonesLib/FancyZonesDataTypes.h>
|
||||
#include <FancyZonesLib/GuidUtils.h>
|
||||
#include <FancyZonesLib/ModuleConstants.h>
|
||||
|
||||
#include <common/SettingsAPI/FileWatcher.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
|
||||
namespace NonLocalizable
|
||||
{
|
||||
namespace CustomLayoutsIds
|
||||
{
|
||||
const static wchar_t* CustomLayoutsArrayID = L"custom-layouts";
|
||||
const static wchar_t* UuidID = L"uuid";
|
||||
const static wchar_t* NameID = L"name";
|
||||
const static wchar_t* InfoID = L"info";
|
||||
const static wchar_t* TypeID = L"type";
|
||||
const static wchar_t* CanvasID = L"canvas";
|
||||
const static wchar_t* GridID = L"grid";
|
||||
const static wchar_t* SensitivityRadiusID = L"sensitivity-radius";
|
||||
|
||||
// canvas
|
||||
const static wchar_t* RefHeightID = L"ref-height";
|
||||
const static wchar_t* RefWidthID = L"ref-width";
|
||||
const static wchar_t* ZonesID = L"zones";
|
||||
const static wchar_t* XID = L"X";
|
||||
const static wchar_t* YID = L"Y";
|
||||
const static wchar_t* WidthID = L"width";
|
||||
const static wchar_t* HeightID = L"height";
|
||||
|
||||
// grid
|
||||
const static wchar_t* RowsID = L"rows";
|
||||
const static wchar_t* ColumnsID = L"columns";
|
||||
const static wchar_t* RowsPercentageID = L"rows-percentage";
|
||||
const static wchar_t* ColumnsPercentageID = L"columns-percentage";
|
||||
const static wchar_t* CellChildMapID = L"cell-child-map";
|
||||
const static wchar_t* ShowSpacingID = L"show-spacing";
|
||||
const static wchar_t* SpacingID = L"spacing";
|
||||
}
|
||||
}
|
||||
|
||||
class CustomLayouts
|
||||
{
|
||||
public:
|
||||
using TCustomLayoutMap = std::unordered_map<GUID, FancyZonesDataTypes::CustomLayoutData>;
|
||||
|
||||
static CustomLayouts& instance();
|
||||
|
||||
inline static std::wstring CustomLayoutsFileName()
|
||||
{
|
||||
std::wstring saveFolderPath = PTSettingsHelper::get_module_save_folder_location(NonLocalizable::ModuleKey);
|
||||
#if defined(UNIT_TESTS)
|
||||
return saveFolderPath + L"\\test-custom-layouts.json";
|
||||
#endif
|
||||
return saveFolderPath + L"\\custom-layouts.json";
|
||||
}
|
||||
|
||||
void LoadData();
|
||||
|
||||
std::optional<FancyZonesDataTypes::CustomLayoutData> GetLayout(const GUID& id) const noexcept;
|
||||
const TCustomLayoutMap& GetAllLayouts() const noexcept;
|
||||
|
||||
private:
|
||||
CustomLayouts();
|
||||
~CustomLayouts() = default;
|
||||
|
||||
TCustomLayoutMap m_layouts;
|
||||
std::unique_ptr<FileWatcher> m_fileWatcher;
|
||||
};
|
||||
15
src/modules/fancyzones/FancyZonesLib/FancyZonesData/Layout.h
Normal file
15
src/modules/fancyzones/FancyZonesLib/FancyZonesData/Layout.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <guiddef.h>
|
||||
|
||||
#include <FancyZonesLib/FancyZonesDataTypes.h>
|
||||
|
||||
struct Layout
|
||||
{
|
||||
GUID uuid;
|
||||
FancyZonesDataTypes::ZoneSetLayoutType type;
|
||||
bool showSpacing;
|
||||
int spacing;
|
||||
int zoneCount;
|
||||
int sensitivityRadius;
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
namespace DefaultValues
|
||||
{
|
||||
const int ZoneCount = 3;
|
||||
const bool ShowSpacing = true;
|
||||
const int Spacing = 16;
|
||||
const int SensitivityRadius = 20;
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
#include "../pch.h"
|
||||
#include "LayoutHotkeys.h"
|
||||
|
||||
#include <common/logger/logger.h>
|
||||
|
||||
#include <FancyZonesLib/FancyZonesWinHookEventIDs.h>
|
||||
#include <FancyZonesLib/JsonHelpers.h>
|
||||
#include <FancyZonesLib/util.h>
|
||||
|
||||
namespace JsonUtils
|
||||
{
|
||||
struct LayoutHotkeysJSON
|
||||
{
|
||||
GUID uuid;
|
||||
int key;
|
||||
|
||||
static std::optional<LayoutHotkeysJSON> FromJson(const json::JsonObject& json)
|
||||
{
|
||||
try
|
||||
{
|
||||
LayoutHotkeysJSON result;
|
||||
|
||||
std::wstring uuidStr = json.GetNamedString(NonLocalizable::LayoutHotkeysIds::LayoutUuidID).c_str();
|
||||
auto uuidOpt = FancyZonesUtils::GuidFromString(uuidStr);
|
||||
if (!uuidOpt)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
result.uuid = uuidOpt.value();
|
||||
result.key = static_cast<int>(json.GetNamedNumber(NonLocalizable::LayoutHotkeysIds::KeyID));
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (const winrt::hresult_error&)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
LayoutHotkeys::THotkeyMap ParseJson(const json::JsonObject& json)
|
||||
{
|
||||
LayoutHotkeys::THotkeyMap map{};
|
||||
auto layoutHotkeys = json.GetNamedArray(NonLocalizable::LayoutHotkeysIds::LayoutHotkeysArrayID);
|
||||
|
||||
for (uint32_t i = 0; i < layoutHotkeys.Size(); ++i)
|
||||
{
|
||||
if (auto obj = LayoutHotkeysJSON::FromJson(layoutHotkeys.GetObjectAt(i)); obj.has_value())
|
||||
{
|
||||
map[obj->key] = obj->uuid;
|
||||
}
|
||||
}
|
||||
|
||||
return std::move(map);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LayoutHotkeys::LayoutHotkeys()
|
||||
{
|
||||
const std::wstring& settingsFileName = LayoutHotkeysFileName();
|
||||
m_fileWatcher = std::make_unique<FileWatcher>(settingsFileName, [&]() {
|
||||
PostMessageW(HWND_BROADCAST, WM_PRIV_LAYOUT_HOTKEYS_FILE_UPDATE, NULL, NULL);
|
||||
});
|
||||
}
|
||||
|
||||
LayoutHotkeys& LayoutHotkeys::instance()
|
||||
{
|
||||
static LayoutHotkeys self;
|
||||
return self;
|
||||
}
|
||||
|
||||
void LayoutHotkeys::LoadData()
|
||||
{
|
||||
auto data = json::from_file(LayoutHotkeysFileName());
|
||||
|
||||
try
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
m_hotkeyMap = JsonUtils::ParseJson(data.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hotkeyMap.clear();
|
||||
Logger::info(L"layout-hotkeys.json file is missing or malformed");
|
||||
}
|
||||
}
|
||||
catch (const winrt::hresult_error& e)
|
||||
{
|
||||
Logger::error(L"Parsing layout-hotkeys error: {}", e.message());
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<GUID> LayoutHotkeys::GetLayoutId(int key) const noexcept
|
||||
{
|
||||
auto iter = m_hotkeyMap.find(key);
|
||||
if (iter != m_hotkeyMap.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
size_t LayoutHotkeys::GetHotkeysCount() const noexcept
|
||||
{
|
||||
return m_hotkeyMap.size();
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include <guiddef.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <FancyZonesLib/ModuleConstants.h>
|
||||
|
||||
#include <common/SettingsAPI/FileWatcher.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
|
||||
namespace NonLocalizable
|
||||
{
|
||||
namespace LayoutHotkeysIds
|
||||
{
|
||||
const static wchar_t* LayoutHotkeysArrayID = L"layout-hotkeys";
|
||||
const static wchar_t* LayoutUuidID = L"layout-id";
|
||||
const static wchar_t* KeyID = L"key";
|
||||
}
|
||||
}
|
||||
|
||||
class LayoutHotkeys
|
||||
{
|
||||
public:
|
||||
using THotkeyMap = std::map<int, GUID>;
|
||||
|
||||
static LayoutHotkeys& instance();
|
||||
|
||||
inline static std::wstring LayoutHotkeysFileName()
|
||||
{
|
||||
std::wstring saveFolderPath = PTSettingsHelper::get_module_save_folder_location(NonLocalizable::ModuleKey);
|
||||
#if defined(UNIT_TESTS)
|
||||
return saveFolderPath + L"\\test-layout-hotkeys.json";
|
||||
#endif
|
||||
return saveFolderPath + L"\\layout-hotkeys.json";
|
||||
}
|
||||
|
||||
void LoadData();
|
||||
|
||||
std::optional<GUID> GetLayoutId(int key) const noexcept;
|
||||
size_t GetHotkeysCount() const noexcept;
|
||||
|
||||
private:
|
||||
LayoutHotkeys();
|
||||
~LayoutHotkeys() = default;
|
||||
|
||||
THotkeyMap m_hotkeyMap;
|
||||
std::unique_ptr<FileWatcher> m_fileWatcher;
|
||||
};
|
||||
@@ -0,0 +1,100 @@
|
||||
#include "../pch.h"
|
||||
#include "LayoutTemplates.h"
|
||||
|
||||
#include <common/logger/logger.h>
|
||||
|
||||
#include <FancyZonesLib/FancyZonesData/LayoutDefaults.h>
|
||||
#include <FancyZonesLib/FancyZonesWinHookEventIDs.h>
|
||||
|
||||
namespace JsonUtils
|
||||
{
|
||||
struct TemplateLayoutJSON
|
||||
{
|
||||
static std::optional<Layout> FromJson(const json::JsonObject& json)
|
||||
{
|
||||
try
|
||||
{
|
||||
Layout data;
|
||||
|
||||
data.uuid = GUID_NULL;
|
||||
data.type = FancyZonesDataTypes::TypeFromString(std::wstring{ json.GetNamedString(NonLocalizable::LayoutTemplatesIds::TypeID) });
|
||||
data.showSpacing = json.GetNamedBoolean(NonLocalizable::LayoutTemplatesIds::ShowSpacingID, DefaultValues::ShowSpacing);
|
||||
data.spacing = static_cast<int>(json.GetNamedNumber(NonLocalizable::LayoutTemplatesIds::SpacingID, DefaultValues::Spacing));
|
||||
data.zoneCount = static_cast<int>(json.GetNamedNumber(NonLocalizable::LayoutTemplatesIds::ZoneCountID, DefaultValues::ZoneCount));
|
||||
data.sensitivityRadius = static_cast<int>(json.GetNamedNumber(NonLocalizable::LayoutTemplatesIds::SensitivityRadiusID, DefaultValues::SensitivityRadius));
|
||||
|
||||
return data;
|
||||
}
|
||||
catch (const winrt::hresult_error&)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<Layout> ParseJson(const json::JsonObject& json)
|
||||
{
|
||||
std::vector<Layout> vec{};
|
||||
auto layouts = json.GetNamedArray(NonLocalizable::LayoutTemplatesIds::LayoutTemplatesArrayID);
|
||||
|
||||
for (uint32_t i = 0; i < layouts.Size(); ++i)
|
||||
{
|
||||
if (auto obj = TemplateLayoutJSON::FromJson(layouts.GetObjectAt(i)); obj.has_value())
|
||||
{
|
||||
vec.emplace_back(std::move(obj.value()));
|
||||
}
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
}
|
||||
|
||||
LayoutTemplates::LayoutTemplates()
|
||||
{
|
||||
const std::wstring& fileName = LayoutTemplatesFileName();
|
||||
m_fileWatcher = std::make_unique<FileWatcher>(fileName, [&]() {
|
||||
PostMessageW(HWND_BROADCAST, WM_PRIV_LAYOUT_TEMPLATES_FILE_UPDATE, NULL, NULL);
|
||||
});
|
||||
}
|
||||
|
||||
LayoutTemplates& LayoutTemplates::instance()
|
||||
{
|
||||
static LayoutTemplates self;
|
||||
return self;
|
||||
}
|
||||
|
||||
void LayoutTemplates::LoadData()
|
||||
{
|
||||
auto data = json::from_file(LayoutTemplatesFileName());
|
||||
|
||||
try
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
m_layouts = JsonUtils::ParseJson(data.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_layouts.clear();
|
||||
Logger::info(L"layout-templates.json file is missing or malformed");
|
||||
}
|
||||
}
|
||||
catch (const winrt::hresult_error& e)
|
||||
{
|
||||
Logger::error(L"Parsing layout-templates error: {}", e.message());
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Layout> LayoutTemplates::GetLayout(FancyZonesDataTypes::ZoneSetLayoutType type) const noexcept
|
||||
{
|
||||
for (const auto& layout : m_layouts)
|
||||
{
|
||||
if (layout.type == type)
|
||||
{
|
||||
return layout;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <FancyZonesLib/FancyZonesData/Layout.h>
|
||||
#include <FancyZonesLib/ModuleConstants.h>
|
||||
|
||||
#include <common/SettingsAPI/FileWatcher.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
|
||||
namespace NonLocalizable
|
||||
{
|
||||
namespace LayoutTemplatesIds
|
||||
{
|
||||
const static wchar_t* LayoutTemplatesArrayID = L"layout-templates";
|
||||
const static wchar_t* TypeID = L"type";
|
||||
const static wchar_t* ShowSpacingID = L"show-spacing";
|
||||
const static wchar_t* SpacingID = L"spacing";
|
||||
const static wchar_t* ZoneCountID = L"zone-count";
|
||||
const static wchar_t* SensitivityRadiusID = L"sensitivity-radius";
|
||||
}
|
||||
}
|
||||
|
||||
class LayoutTemplates
|
||||
{
|
||||
public:
|
||||
static LayoutTemplates& instance();
|
||||
|
||||
inline static std::wstring LayoutTemplatesFileName()
|
||||
{
|
||||
std::wstring saveFolderPath = PTSettingsHelper::get_module_save_folder_location(NonLocalizable::ModuleKey);
|
||||
#if defined(UNIT_TESTS)
|
||||
return saveFolderPath + L"\\test-layout-templates.json";
|
||||
#endif
|
||||
return saveFolderPath + L"\\layout-templates.json";
|
||||
}
|
||||
|
||||
void LoadData();
|
||||
|
||||
std::optional<Layout> GetLayout(FancyZonesDataTypes::ZoneSetLayoutType type) const noexcept;
|
||||
|
||||
private:
|
||||
LayoutTemplates();
|
||||
~LayoutTemplates() = default;
|
||||
|
||||
std::unique_ptr<FileWatcher> m_fileWatcher;
|
||||
std::vector<Layout> m_layouts;
|
||||
};
|
||||
@@ -305,9 +305,4 @@ namespace FancyZonesDataTypes
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DeviceIdData::isEqualWithNullVirtualDesktopId(const DeviceIdData& other) const
|
||||
{
|
||||
return deviceName.compare(other.deviceName) == 0 && width == other.width && height == other.height && (virtualDesktopId == other.virtualDesktopId || virtualDesktopId == GUID_NULL || other.virtualDesktopId == GUID_NULL) && monitorId.compare(other.monitorId) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace FancyZonesDataTypes
|
||||
int m_sensitivityRadius;
|
||||
};
|
||||
|
||||
struct CustomZoneSetData
|
||||
struct CustomLayoutData
|
||||
{
|
||||
std::wstring name;
|
||||
CustomLayoutType type;
|
||||
@@ -125,7 +125,6 @@ namespace FancyZonesDataTypes
|
||||
static bool IsValidDeviceId(const std::wstring& str);
|
||||
|
||||
std::wstring toString() const;
|
||||
bool isEqualWithNullVirtualDesktopId(const DeviceIdData& other) const;
|
||||
};
|
||||
|
||||
struct AppZoneHistoryData
|
||||
@@ -153,7 +152,7 @@ namespace FancyZonesDataTypes
|
||||
|
||||
inline bool operator==(const DeviceIdData& lhs, const DeviceIdData& rhs)
|
||||
{
|
||||
return lhs.deviceName.compare(rhs.deviceName) == 0 && lhs.width == rhs.width && lhs.height == rhs.height && lhs.virtualDesktopId == rhs.virtualDesktopId && lhs.monitorId.compare(rhs.monitorId) == 0;
|
||||
return lhs.deviceName.compare(rhs.deviceName) == 0 && lhs.width == rhs.width && lhs.height == rhs.height && (lhs.virtualDesktopId == rhs.virtualDesktopId || lhs.virtualDesktopId == GUID_NULL || rhs.virtualDesktopId == GUID_NULL) && lhs.monitorId.compare(rhs.monitorId) == 0;
|
||||
}
|
||||
|
||||
inline bool operator!=(const DeviceIdData& lhs, const DeviceIdData& rhs)
|
||||
|
||||
@@ -37,14 +37,22 @@
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="FancyZonesData\CustomLayouts.h" />
|
||||
<ClInclude Include="FancyZonesData\AppliedLayouts.h" />
|
||||
<ClInclude Include="FancyZonesData\AppZoneHistory.h" />
|
||||
<ClInclude Include="FancyZones.h" />
|
||||
<ClInclude Include="FancyZonesDataTypes.h" />
|
||||
<ClInclude Include="FancyZonesData\Layout.h" />
|
||||
<ClInclude Include="FancyZonesData\LayoutDefaults.h" />
|
||||
<ClInclude Include="FancyZonesData\LayoutTemplates.h" />
|
||||
<ClInclude Include="FancyZonesWinHookEventIDs.h" />
|
||||
<ClInclude Include="GenericKeyHook.h" />
|
||||
<ClInclude Include="FancyZonesData.h" />
|
||||
<ClInclude Include="GuidUtils.h" />
|
||||
<ClInclude Include="JsonHelpers.h" />
|
||||
<ClInclude Include="KeyState.h" />
|
||||
<ClInclude Include="FancyZonesData\LayoutHotkeys.h" />
|
||||
<ClInclude Include="ModuleConstants.h" />
|
||||
<ClInclude Include="MonitorUtils.h" />
|
||||
<ClInclude Include="MonitorWorkAreaHandler.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
@@ -64,11 +72,31 @@
|
||||
<ClInclude Include="ZonesOverlay.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="FancyZonesData\AppZoneHistory.cpp">
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FancyZonesData\CustomLayouts.cpp">
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FancyZones.cpp" />
|
||||
<ClCompile Include="FancyZonesDataTypes.cpp" />
|
||||
<ClCompile Include="FancyZonesData\AppliedLayouts.cpp">
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FancyZonesData\LayoutTemplates.cpp">
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FancyZonesWinHookEventIDs.cpp" />
|
||||
<ClCompile Include="FancyZonesData.cpp" />
|
||||
<ClCompile Include="JsonHelpers.cpp" />
|
||||
<ClCompile Include="FancyZonesData\LayoutHotkeys.cpp">
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MonitorUtils.cpp" />
|
||||
<ClCompile Include="MonitorWorkAreaHandler.cpp" />
|
||||
<ClCompile Include="OnThreadExecutor.cpp" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
@@ -90,6 +90,30 @@
|
||||
<ClInclude Include="GuidUtils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FancyZonesData\AppZoneHistory.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FancyZonesData\AppliedLayouts.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FancyZonesData\CustomLayouts.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FancyZonesData\LayoutHotkeys.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ModuleConstants.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FancyZonesData\LayoutTemplates.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FancyZonesData\LayoutDefaults.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FancyZonesData\Layout.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
@@ -149,6 +173,21 @@
|
||||
<ClCompile Include="MonitorUtils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FancyZonesData\CustomLayouts.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FancyZonesData\LayoutHotkeys.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FancyZonesData\AppZoneHistory.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FancyZonesData\AppliedLayouts.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FancyZonesData\LayoutTemplates.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
||||
@@ -11,7 +11,10 @@ UINT WM_PRIV_VD_INIT;
|
||||
UINT WM_PRIV_VD_SWITCH;
|
||||
UINT WM_PRIV_VD_UPDATE;
|
||||
UINT WM_PRIV_EDITOR;
|
||||
UINT WM_PRIV_FILE_UPDATE;
|
||||
UINT WM_PRIV_LAYOUT_HOTKEYS_FILE_UPDATE;
|
||||
UINT WM_PRIV_LAYOUT_TEMPLATES_FILE_UPDATE;
|
||||
UINT WM_PRIV_CUSTOM_LAYOUTS_FILE_UPDATE;
|
||||
UINT WM_PRIV_APPLIED_LAYOUTS_FILE_UPDATE;
|
||||
UINT WM_PRIV_SNAP_HOTKEY;
|
||||
UINT WM_PRIV_QUICK_LAYOUT_KEY;
|
||||
UINT WM_PRIV_SETTINGS_CHANGED;
|
||||
@@ -30,7 +33,10 @@ void InitializeWinhookEventIds()
|
||||
WM_PRIV_VD_SWITCH = RegisterWindowMessage(L"{128c2cb0-6bdf-493e-abbe-f8705e04aa95}");
|
||||
WM_PRIV_VD_UPDATE = RegisterWindowMessage(L"{b8b72b46-f42f-4c26-9e20-29336cf2f22e}");
|
||||
WM_PRIV_EDITOR = RegisterWindowMessage(L"{87543824-7080-4e91-9d9c-0404642fc7b6}");
|
||||
WM_PRIV_FILE_UPDATE = RegisterWindowMessage(L"{632f17a9-55a7-45f1-a4db-162e39271d92}");
|
||||
WM_PRIV_LAYOUT_HOTKEYS_FILE_UPDATE = RegisterWindowMessage(L"{07229b7e-4f22-4357-b136-33c289be2295}");
|
||||
WM_PRIV_LAYOUT_TEMPLATES_FILE_UPDATE = RegisterWindowMessage(L"{4686f019-5d3d-4c5c-9051-b7cbbccca77d}");
|
||||
WM_PRIV_CUSTOM_LAYOUTS_FILE_UPDATE = RegisterWindowMessage(L"{0972787e-cdab-4e16-b228-91acdc38f40f}");
|
||||
WM_PRIV_APPLIED_LAYOUTS_FILE_UPDATE = RegisterWindowMessage(L"{2ef2c8a7-e0d5-4f31-9ede-52aade2d284d}");
|
||||
WM_PRIV_SNAP_HOTKEY = RegisterWindowMessage(L"{72f4fd8e-23f1-43ab-bbbc-029363df9a84}");
|
||||
WM_PRIV_QUICK_LAYOUT_KEY = RegisterWindowMessage(L"{15baab3d-c67b-4a15-aFF0-13610e05e947}");
|
||||
WM_PRIV_SETTINGS_CHANGED = RegisterWindowMessage(L"{89ca3Daa-bf2d-4e73-9f3f-c60716364e27}");
|
||||
|
||||
@@ -9,7 +9,10 @@ extern UINT WM_PRIV_VD_INIT; // Scheduled when FancyZones is initialized
|
||||
extern UINT WM_PRIV_VD_SWITCH; // Scheduled when virtual desktop switch occurs
|
||||
extern UINT WM_PRIV_VD_UPDATE; // Scheduled on virtual desktops update (creation/deletion)
|
||||
extern UINT WM_PRIV_EDITOR; // Scheduled when the editor exits
|
||||
extern UINT WM_PRIV_FILE_UPDATE; // Scheduled when the a watched zone-settings file is updated
|
||||
extern UINT WM_PRIV_LAYOUT_HOTKEYS_FILE_UPDATE; // Scheduled when the watched layout-hotkeys.json file is updated
|
||||
extern UINT WM_PRIV_LAYOUT_TEMPLATES_FILE_UPDATE; // Scheduled when the watched layout-templates.json file is updated
|
||||
extern UINT WM_PRIV_CUSTOM_LAYOUTS_FILE_UPDATE; // Scheduled when the watched custom-layouts.json file is updated
|
||||
extern UINT WM_PRIV_APPLIED_LAYOUTS_FILE_UPDATE; // Scheduled when the watched applied-layouts.json file is updated
|
||||
extern UINT WM_PRIV_SNAP_HOTKEY; // Scheduled when we receive a snap hotkey key down press
|
||||
extern UINT WM_PRIV_QUICK_LAYOUT_KEY; // Scheduled when we receive a key down press to quickly apply a layout
|
||||
extern UINT WM_PRIV_SETTINGS_CHANGED; // Scheduled when the a watched settings file is updated
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "JsonHelpers.h"
|
||||
#include "FancyZonesData.h"
|
||||
#include "FancyZonesDataTypes.h"
|
||||
#include "trace.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <FancyZonesLib/FancyZonesData/AppliedLayouts.h>
|
||||
#include <FancyZonesLib/FancyZonesData/CustomLayouts.h>
|
||||
#include <FancyZonesLib/FancyZonesData/LayoutDefaults.h>
|
||||
#include <FancyZonesLib/FancyZonesData/LayoutHotkeys.h>
|
||||
#include <FancyZonesLib/FancyZonesData/LayoutTemplates.h>
|
||||
|
||||
#include <common/logger/logger.h>
|
||||
|
||||
#include <filesystem>
|
||||
@@ -576,37 +581,6 @@ namespace JSONHelpers
|
||||
}
|
||||
}
|
||||
|
||||
void SaveZoneSettings(const std::wstring& zonesSettingsFileName, const TDeviceInfoMap& deviceInfoMap, const TCustomZoneSetsMap& customZoneSetsMap, const TLayoutQuickKeysMap& quickKeysMap)
|
||||
{
|
||||
auto before = json::from_file(zonesSettingsFileName);
|
||||
|
||||
json::JsonObject root{};
|
||||
json::JsonArray templates{};
|
||||
|
||||
try
|
||||
{
|
||||
if (before.has_value() && before->HasKey(NonLocalizable::Templates))
|
||||
{
|
||||
templates = before->GetNamedArray(NonLocalizable::Templates);
|
||||
}
|
||||
}
|
||||
catch (const winrt::hresult_error&)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
root.SetNamedValue(NonLocalizable::DevicesStr, JSONHelpers::SerializeDeviceInfos(deviceInfoMap));
|
||||
root.SetNamedValue(NonLocalizable::CustomZoneSetsStr, JSONHelpers::SerializeCustomZoneSets(customZoneSetsMap));
|
||||
root.SetNamedValue(NonLocalizable::Templates, templates);
|
||||
root.SetNamedValue(NonLocalizable::QuickLayoutKeys, JSONHelpers::SerializeQuickKeys(quickKeysMap));
|
||||
|
||||
if (!before.has_value() || before.value().Stringify() != root.Stringify())
|
||||
{
|
||||
Trace::FancyZones::DataChanged();
|
||||
json::to_file(zonesSettingsFileName, root);
|
||||
}
|
||||
}
|
||||
|
||||
void SaveAppZoneHistory(const std::wstring& appZoneHistoryFileName, const TAppZoneHistoryMap& appZoneHistoryMap)
|
||||
{
|
||||
json::JsonObject root{};
|
||||
@@ -656,7 +630,7 @@ namespace JSONHelpers
|
||||
return appHistoryArray;
|
||||
}
|
||||
|
||||
TDeviceInfoMap ParseDeviceInfos(const json::JsonObject& fancyZonesDataJSON)
|
||||
std::optional<TDeviceInfoMap> ParseDeviceInfos(const json::JsonObject& fancyZonesDataJSON)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -673,45 +647,37 @@ namespace JSONHelpers
|
||||
|
||||
return std::move(deviceInfoMap);
|
||||
}
|
||||
catch (const winrt::hresult_error&)
|
||||
catch (const winrt::hresult_error& e)
|
||||
{
|
||||
return {};
|
||||
Logger::error(L"Parsing device info error: {}", e.message());
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
json::JsonArray SerializeDeviceInfos(const TDeviceInfoMap& deviceInfoMap)
|
||||
void SaveAppliedLayouts(const TDeviceInfoMap& deviceInfoMap)
|
||||
{
|
||||
json::JsonArray DeviceInfosJSON{};
|
||||
json::JsonObject root{};
|
||||
json::JsonArray layoutsArray{};
|
||||
|
||||
for (const auto& [deviceID, deviceData] : deviceInfoMap)
|
||||
for (const auto& [deviceID, data] : deviceInfoMap)
|
||||
{
|
||||
DeviceInfosJSON.Append(DeviceInfoJSON::DeviceInfoJSON::ToJson(DeviceInfoJSON{ deviceID, deviceData }));
|
||||
json::JsonObject layout{};
|
||||
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::UuidID, json::value(data.activeZoneSet.uuid));
|
||||
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::TypeID, json::value(FancyZonesDataTypes::TypeToString(data.activeZoneSet.type)));
|
||||
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::ShowSpacingID, json::value(data.showSpacing));
|
||||
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::SpacingID, json::value(data.spacing));
|
||||
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::ZoneCountID, json::value(data.zoneCount));
|
||||
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::SensitivityRadiusID, json::value(data.sensitivityRadius));
|
||||
|
||||
json::JsonObject obj{};
|
||||
obj.SetNamedValue(NonLocalizable::AppliedLayoutsIds::DeviceIdID, json::value(deviceID.toString()));
|
||||
obj.SetNamedValue(NonLocalizable::AppliedLayoutsIds::AppliedLayoutID, layout);
|
||||
|
||||
layoutsArray.Append(obj);
|
||||
}
|
||||
|
||||
return DeviceInfosJSON;
|
||||
}
|
||||
|
||||
TCustomZoneSetsMap ParseCustomZoneSets(const json::JsonObject& fancyZonesDataJSON)
|
||||
{
|
||||
try
|
||||
{
|
||||
TCustomZoneSetsMap customZoneSetsMap{};
|
||||
auto customZoneSets = fancyZonesDataJSON.GetNamedArray(NonLocalizable::CustomZoneSetsStr);
|
||||
|
||||
for (uint32_t i = 0; i < customZoneSets.Size(); ++i)
|
||||
{
|
||||
if (auto zoneSet = CustomZoneSetJSON::FromJson(customZoneSets.GetObjectAt(i)); zoneSet.has_value())
|
||||
{
|
||||
customZoneSetsMap[zoneSet->uuid] = std::move(zoneSet->data);
|
||||
}
|
||||
}
|
||||
|
||||
return std::move(customZoneSetsMap);
|
||||
}
|
||||
catch (const winrt::hresult_error&)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
root.SetNamedValue(NonLocalizable::AppliedLayoutsIds::AppliedLayoutsArrayID, layoutsArray);
|
||||
json::to_file(AppliedLayouts::AppliedLayoutsFileName(), root);
|
||||
}
|
||||
|
||||
json::JsonArray SerializeCustomZoneSets(const TCustomZoneSetsMap& customZoneSetsMap)
|
||||
@@ -726,7 +692,7 @@ namespace JSONHelpers
|
||||
return customZoneSetsJSON;
|
||||
}
|
||||
|
||||
TLayoutQuickKeysMap ParseQuickKeys(const json::JsonObject& fancyZonesDataJSON)
|
||||
std::optional<TLayoutQuickKeysMap> ParseQuickKeys(const json::JsonObject& fancyZonesDataJSON)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -746,19 +712,86 @@ namespace JSONHelpers
|
||||
catch (const winrt::hresult_error& e)
|
||||
{
|
||||
Logger::error(L"Parsing quick keys error: {}", e.message());
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
json::JsonArray SerializeQuickKeys(const TLayoutQuickKeysMap& quickKeysMap)
|
||||
void SaveLayoutHotkeys(const TLayoutQuickKeysMap& quickKeysMap)
|
||||
{
|
||||
json::JsonArray quickKeysJSON{};
|
||||
json::JsonObject root{};
|
||||
json::JsonArray keysArray{};
|
||||
|
||||
for (const auto& [uuid, key] : quickKeysMap)
|
||||
{
|
||||
quickKeysJSON.Append(LayoutQuickKeyJSON::ToJson(LayoutQuickKeyJSON{ uuid, key }));
|
||||
json::JsonObject keyJson{};
|
||||
|
||||
keyJson.SetNamedValue(NonLocalizable::LayoutHotkeysIds::LayoutUuidID, json::value(uuid));
|
||||
keyJson.SetNamedValue(NonLocalizable::LayoutHotkeysIds::KeyID, json::value(key));
|
||||
|
||||
keysArray.Append(keyJson);
|
||||
}
|
||||
|
||||
return quickKeysJSON;
|
||||
root.SetNamedValue(NonLocalizable::LayoutHotkeysIds::LayoutHotkeysArrayID, keysArray);
|
||||
json::to_file(LayoutHotkeys::LayoutHotkeysFileName(), root);
|
||||
}
|
||||
|
||||
std::optional<json::JsonArray> ParseLayoutTemplates(const json::JsonObject& fancyZonesDataJSON)
|
||||
{
|
||||
try
|
||||
{
|
||||
return fancyZonesDataJSON.GetNamedArray(NonLocalizable::Templates);
|
||||
}
|
||||
catch (const winrt::hresult_error& e)
|
||||
{
|
||||
Logger::error(L"Parsing layout templates error: {}", e.message());
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void SaveLayoutTemplates(const json::JsonArray& templates)
|
||||
{
|
||||
json::JsonObject root{};
|
||||
root.SetNamedValue(NonLocalizable::LayoutTemplatesIds::LayoutTemplatesArrayID, templates);
|
||||
json::to_file(LayoutTemplates::LayoutTemplatesFileName(), root);
|
||||
}
|
||||
|
||||
std::optional<TCustomZoneSetsMap> ParseCustomZoneSets(const json::JsonObject& fancyZonesDataJSON)
|
||||
{
|
||||
try
|
||||
{
|
||||
TCustomZoneSetsMap customZoneSetsMap{};
|
||||
auto customZoneSets = fancyZonesDataJSON.GetNamedArray(NonLocalizable::CustomZoneSetsStr);
|
||||
|
||||
for (uint32_t i = 0; i < customZoneSets.Size(); ++i)
|
||||
{
|
||||
if (auto zoneSet = CustomZoneSetJSON::FromJson(customZoneSets.GetObjectAt(i)); zoneSet.has_value())
|
||||
{
|
||||
customZoneSetsMap[zoneSet->uuid] = std::move(zoneSet->data);
|
||||
}
|
||||
}
|
||||
|
||||
return std::move(customZoneSetsMap);
|
||||
}
|
||||
catch (const winrt::hresult_error& e)
|
||||
{
|
||||
Logger::error(L"Parsing custom layouts error: {}", e.message());
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
void SaveCustomLayouts(const TCustomZoneSetsMap& map)
|
||||
{
|
||||
json::JsonObject root{};
|
||||
json::JsonArray layoutsArray{};
|
||||
|
||||
for (const auto& [uuid, data] : map)
|
||||
{
|
||||
json::JsonObject layoutJson{};
|
||||
layoutsArray.Append(CustomZoneSetJSON::ToJson(CustomZoneSetJSON{ uuid, data }));
|
||||
}
|
||||
|
||||
root.SetNamedValue(NonLocalizable::CustomLayoutsIds::CustomLayoutsArrayID, layoutsArray);
|
||||
json::to_file(CustomLayouts::CustomLayoutsFileName(), root);
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ namespace JSONHelpers
|
||||
struct CustomZoneSetJSON
|
||||
{
|
||||
std::wstring uuid;
|
||||
FancyZonesDataTypes::CustomZoneSetData data;
|
||||
FancyZonesDataTypes::CustomLayoutData data;
|
||||
|
||||
static json::JsonObject ToJson(const CustomZoneSetJSON& device);
|
||||
static std::optional<CustomZoneSetJSON> FromJson(const json::JsonObject& customZoneSet);
|
||||
@@ -66,7 +66,7 @@ namespace JSONHelpers
|
||||
|
||||
using TAppZoneHistoryMap = std::unordered_map<std::wstring, std::vector<FancyZonesDataTypes::AppZoneHistoryData>>;
|
||||
using TDeviceInfoMap = std::unordered_map<FancyZonesDataTypes::DeviceIdData, FancyZonesDataTypes::DeviceInfoData>;
|
||||
using TCustomZoneSetsMap = std::unordered_map<std::wstring, FancyZonesDataTypes::CustomZoneSetData>;
|
||||
using TCustomZoneSetsMap = std::unordered_map<std::wstring, FancyZonesDataTypes::CustomLayoutData>;
|
||||
using TLayoutQuickKeysMap = std::unordered_map<std::wstring, int>;
|
||||
|
||||
struct MonitorInfo
|
||||
@@ -93,18 +93,23 @@ namespace JSONHelpers
|
||||
|
||||
json::JsonObject GetPersistFancyZonesJSON(const std::wstring& zonesSettingsFileName, const std::wstring& appZoneHistoryFileName);
|
||||
|
||||
void SaveZoneSettings(const std::wstring& zonesSettingsFileName, const TDeviceInfoMap& deviceInfoMap, const TCustomZoneSetsMap& customZoneSetsMap, const TLayoutQuickKeysMap& quickKeysMap);
|
||||
void SaveAppZoneHistory(const std::wstring& appZoneHistoryFileName, const TAppZoneHistoryMap& appZoneHistoryMap);
|
||||
|
||||
TAppZoneHistoryMap ParseAppZoneHistory(const json::JsonObject& fancyZonesDataJSON);
|
||||
json::JsonArray SerializeAppZoneHistory(const TAppZoneHistoryMap& appZoneHistoryMap);
|
||||
void SaveAppZoneHistory(const std::wstring& appZoneHistoryFileName, const TAppZoneHistoryMap& appZoneHistoryMap);
|
||||
|
||||
TDeviceInfoMap ParseDeviceInfos(const json::JsonObject& fancyZonesDataJSON);
|
||||
json::JsonArray SerializeDeviceInfos(const TDeviceInfoMap& deviceInfoMap);
|
||||
// replace zones-settings: applied layouts
|
||||
std::optional<TDeviceInfoMap> ParseDeviceInfos(const json::JsonObject& fancyZonesDataJSON);
|
||||
void SaveAppliedLayouts(const TDeviceInfoMap& deviceInfoMap);
|
||||
|
||||
TCustomZoneSetsMap ParseCustomZoneSets(const json::JsonObject& fancyZonesDataJSON);
|
||||
json::JsonArray SerializeCustomZoneSets(const TCustomZoneSetsMap& customZoneSetsMap);
|
||||
// replace zones-settings: layout hotkeys
|
||||
std::optional<TLayoutQuickKeysMap> ParseQuickKeys(const json::JsonObject& fancyZonesDataJSON);
|
||||
void SaveLayoutHotkeys(const TLayoutQuickKeysMap& quickKeysMap);
|
||||
|
||||
TLayoutQuickKeysMap ParseQuickKeys(const json::JsonObject& fancyZonesDataJSON);
|
||||
json::JsonArray SerializeQuickKeys(const TLayoutQuickKeysMap& quickKeysMap);
|
||||
// replace zones-settings: layout templates
|
||||
std::optional<json::JsonArray> ParseLayoutTemplates(const json::JsonObject& fancyZonesDataJSON);
|
||||
void SaveLayoutTemplates(const json::JsonArray& templates);
|
||||
|
||||
// replace zones-settings: custom layouts
|
||||
std::optional<TCustomZoneSetsMap> ParseCustomZoneSets(const json::JsonObject& fancyZonesDataJSON);
|
||||
void SaveCustomLayouts(const TCustomZoneSetsMap& map);
|
||||
}
|
||||
|
||||
6
src/modules/fancyzones/FancyZonesLib/ModuleConstants.h
Normal file
6
src/modules/fancyzones/FancyZonesLib/ModuleConstants.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace NonLocalizable
|
||||
{
|
||||
const inline wchar_t ModuleKey[] = L"FancyZones";
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <common/utils/elevation.h>
|
||||
#include <common/utils/resources.h>
|
||||
|
||||
#include "FancyZonesData.h"
|
||||
#include "FancyZonesData/AppZoneHistory.h"
|
||||
#include "Settings.h"
|
||||
#include "WorkArea.h"
|
||||
#include "util.h"
|
||||
@@ -261,7 +261,7 @@ void WindowMoveHandler::MoveSizeEnd(HWND window, POINT const& ptScreen, const st
|
||||
wil::unique_cotaskmem_string guidString;
|
||||
if (SUCCEEDED_LOG(StringFromCLSID(zoneSet->Id(), &guidString)))
|
||||
{
|
||||
FancyZonesDataInstance().RemoveAppLastZone(window, workAreaPtr->UniqueId(), guidString.get());
|
||||
AppZoneHistory::instance().RemoveAppLastZone(window, workAreaPtr->UniqueId(), guidString.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
#include <common/logger/call_tracer.h>
|
||||
#include <common/logger/logger.h>
|
||||
|
||||
#include "FancyZonesData.h"
|
||||
#include "FancyZonesData/AppliedLayouts.h"
|
||||
#include "FancyZonesData/AppZoneHistory.h"
|
||||
#include "FancyZonesDataTypes.h"
|
||||
#include "ZonesOverlay.h"
|
||||
#include "trace.h"
|
||||
@@ -379,7 +380,7 @@ WorkArea::SaveWindowProcessToZoneIndex(HWND window) noexcept
|
||||
OLECHAR* guidString;
|
||||
if (StringFromCLSID(m_zoneSet->Id(), &guidString) == S_OK)
|
||||
{
|
||||
FancyZonesDataInstance().SetAppLastZones(window, m_uniqueId, guidString, zoneIndexSet);
|
||||
AppZoneHistory::instance().SetAppLastZones(window, m_uniqueId, guidString, zoneIndexSet);
|
||||
}
|
||||
|
||||
CoTaskMemFree(guidString);
|
||||
@@ -395,7 +396,7 @@ WorkArea::GetWindowZoneIndexes(HWND window) const noexcept
|
||||
wil::unique_cotaskmem_string zoneSetId;
|
||||
if (SUCCEEDED(StringFromCLSID(m_zoneSet->Id(), &zoneSetId)))
|
||||
{
|
||||
return FancyZonesDataInstance().GetAppLastZoneIndexSet(window, m_uniqueId, zoneSetId.get());
|
||||
return AppZoneHistory::instance().GetAppLastZoneIndexSet(window, m_uniqueId, zoneSetId.get());
|
||||
}
|
||||
}
|
||||
return {};
|
||||
@@ -485,73 +486,65 @@ void WorkArea::InitializeZoneSets(const FancyZonesDataTypes::DeviceIdData& paren
|
||||
wil::unique_cotaskmem_string virtualDesktopId;
|
||||
if (SUCCEEDED(StringFromCLSID(m_uniqueId.virtualDesktopId, &virtualDesktopId)))
|
||||
{
|
||||
Logger::debug(L"Initialize zone sets on the virtual desktop {}", virtualDesktopId.get());
|
||||
Logger::debug(L"Initialize layout on the virtual desktop {}", virtualDesktopId.get());
|
||||
}
|
||||
|
||||
bool deviceAdded = FancyZonesDataInstance().AddDevice(m_uniqueId);
|
||||
// If the device has been added, check if it should inherit the parent's layout
|
||||
if (deviceAdded && parentUniqueId.virtualDesktopId != GUID_NULL)
|
||||
bool isLayoutAlreadyApplied = AppliedLayouts::instance().IsLayoutApplied(m_uniqueId);
|
||||
if (!isLayoutAlreadyApplied)
|
||||
{
|
||||
FancyZonesDataInstance().CloneDeviceInfo(parentUniqueId, m_uniqueId);
|
||||
if (parentUniqueId.virtualDesktopId != GUID_NULL)
|
||||
{
|
||||
AppliedLayouts::instance().CloneLayout(parentUniqueId, m_uniqueId);
|
||||
}
|
||||
else
|
||||
{
|
||||
AppliedLayouts::instance().ApplyDefaultLayout(m_uniqueId);
|
||||
}
|
||||
}
|
||||
|
||||
CalculateZoneSet(m_overlappingAlgorithm);
|
||||
}
|
||||
|
||||
void WorkArea::CalculateZoneSet(OverlappingZonesAlgorithm overlappingAlgorithm) noexcept
|
||||
{
|
||||
const auto& fancyZonesData = FancyZonesDataInstance();
|
||||
const auto deviceInfoData = fancyZonesData.FindDeviceInfo(m_uniqueId);
|
||||
|
||||
if (!deviceInfoData.has_value())
|
||||
const auto appliedLayout = AppliedLayouts::instance().GetDeviceLayout(m_uniqueId);
|
||||
if (!appliedLayout.has_value())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& activeZoneSet = deviceInfoData->activeZoneSet;
|
||||
auto zoneSet = MakeZoneSet(ZoneSetConfig(
|
||||
appliedLayout->uuid,
|
||||
appliedLayout->type,
|
||||
m_monitor,
|
||||
appliedLayout->sensitivityRadius,
|
||||
overlappingAlgorithm));
|
||||
|
||||
if (activeZoneSet.uuid.empty())
|
||||
RECT workArea;
|
||||
if (m_monitor)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GUID zoneSetId;
|
||||
if (SUCCEEDED_LOG(CLSIDFromString(activeZoneSet.uuid.c_str(), &zoneSetId)))
|
||||
{
|
||||
int sensitivityRadius = deviceInfoData->sensitivityRadius;
|
||||
|
||||
auto zoneSet = MakeZoneSet(ZoneSetConfig(
|
||||
zoneSetId,
|
||||
activeZoneSet.type,
|
||||
m_monitor,
|
||||
sensitivityRadius,
|
||||
overlappingAlgorithm));
|
||||
|
||||
RECT workArea;
|
||||
if (m_monitor)
|
||||
MONITORINFO monitorInfo{};
|
||||
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||
if (GetMonitorInfoW(m_monitor, &monitorInfo))
|
||||
{
|
||||
MONITORINFO monitorInfo{};
|
||||
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||
if (GetMonitorInfoW(m_monitor, &monitorInfo))
|
||||
{
|
||||
workArea = monitorInfo.rcWork;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
workArea = monitorInfo.rcWork;
|
||||
}
|
||||
else
|
||||
{
|
||||
workArea = GetAllMonitorsCombinedRect<&MONITORINFO::rcWork>();
|
||||
return;
|
||||
}
|
||||
|
||||
bool showSpacing = deviceInfoData->showSpacing;
|
||||
int spacing = showSpacing ? deviceInfoData->spacing : 0;
|
||||
int zoneCount = deviceInfoData->zoneCount;
|
||||
|
||||
zoneSet->CalculateZones(workArea, zoneCount, spacing);
|
||||
UpdateActiveZoneSet(zoneSet.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
workArea = GetAllMonitorsCombinedRect<&MONITORINFO::rcWork>();
|
||||
}
|
||||
|
||||
bool showSpacing = appliedLayout->showSpacing;
|
||||
int spacing = showSpacing ? appliedLayout->spacing : 0;
|
||||
int zoneCount = appliedLayout->zoneCount;
|
||||
|
||||
zoneSet->CalculateZones(workArea, zoneCount, spacing);
|
||||
UpdateActiveZoneSet(zoneSet.get());
|
||||
}
|
||||
|
||||
void WorkArea::UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept
|
||||
@@ -567,7 +560,8 @@ void WorkArea::UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept
|
||||
.uuid = zoneSetId.get(),
|
||||
.type = m_zoneSet->LayoutType()
|
||||
};
|
||||
FancyZonesDataInstance().SetActiveZoneSet(m_uniqueId, data);
|
||||
|
||||
AppliedLayouts::instance().ApplyLayout(m_uniqueId, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "ZoneSet.h"
|
||||
|
||||
#include "FancyZonesData.h"
|
||||
#include <FancyZonesLib/FancyZonesData/CustomLayouts.h>
|
||||
#include "FancyZonesDataTypes.h"
|
||||
#include "FancyZonesWindowProperties.h"
|
||||
#include "Settings.h"
|
||||
@@ -880,52 +880,45 @@ bool ZoneSet::CalculateUniquePriorityGridLayout(Rect workArea, int zoneCount, in
|
||||
|
||||
bool ZoneSet::CalculateCustomLayout(Rect workArea, int spacing) noexcept
|
||||
{
|
||||
wil::unique_cotaskmem_string guidStr;
|
||||
if (SUCCEEDED(StringFromCLSID(m_config.Id, &guidStr)))
|
||||
const auto zoneSetSearchResult = CustomLayouts::instance().GetLayout(m_config.Id);
|
||||
if (!zoneSetSearchResult.has_value())
|
||||
{
|
||||
const std::wstring guid = guidStr.get();
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto zoneSetSearchResult = FancyZonesDataInstance().FindCustomZoneSet(guid);
|
||||
|
||||
if (!zoneSetSearchResult.has_value())
|
||||
const auto& zoneSet = *zoneSetSearchResult;
|
||||
if (zoneSet.type == FancyZonesDataTypes::CustomLayoutType::Canvas && std::holds_alternative<FancyZonesDataTypes::CanvasLayoutInfo>(zoneSet.info))
|
||||
{
|
||||
const auto& zoneSetInfo = std::get<FancyZonesDataTypes::CanvasLayoutInfo>(zoneSet.info);
|
||||
for (const auto& zone : zoneSetInfo.zones)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int x = zone.x;
|
||||
int y = zone.y;
|
||||
int width = zone.width;
|
||||
int height = zone.height;
|
||||
|
||||
const auto& zoneSet = *zoneSetSearchResult;
|
||||
if (zoneSet.type == FancyZonesDataTypes::CustomLayoutType::Canvas && std::holds_alternative<FancyZonesDataTypes::CanvasLayoutInfo>(zoneSet.info))
|
||||
{
|
||||
const auto& zoneSetInfo = std::get<FancyZonesDataTypes::CanvasLayoutInfo>(zoneSet.info);
|
||||
for (const auto& zone : zoneSetInfo.zones)
|
||||
DPIAware::Convert(m_config.Monitor, x, y);
|
||||
DPIAware::Convert(m_config.Monitor, width, height);
|
||||
|
||||
auto zone = MakeZone(RECT{ x, y, x + width, y + height }, m_zones.size());
|
||||
if (zone)
|
||||
{
|
||||
int x = zone.x;
|
||||
int y = zone.y;
|
||||
int width = zone.width;
|
||||
int height = zone.height;
|
||||
|
||||
DPIAware::Convert(m_config.Monitor, x, y);
|
||||
DPIAware::Convert(m_config.Monitor, width, height);
|
||||
|
||||
auto zone = MakeZone(RECT{ x, y, x + width, y + height }, m_zones.size());
|
||||
if (zone)
|
||||
{
|
||||
AddZone(zone);
|
||||
}
|
||||
else
|
||||
{
|
||||
// All zones within zone set should be valid in order to use its functionality.
|
||||
m_zones.clear();
|
||||
return false;
|
||||
}
|
||||
AddZone(zone);
|
||||
}
|
||||
else
|
||||
{
|
||||
// All zones within zone set should be valid in order to use its functionality.
|
||||
m_zones.clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (zoneSet.type == FancyZonesDataTypes::CustomLayoutType::Grid && std::holds_alternative<FancyZonesDataTypes::GridLayoutInfo>(zoneSet.info))
|
||||
{
|
||||
const auto& info = std::get<FancyZonesDataTypes::GridLayoutInfo>(zoneSet.info);
|
||||
return CalculateGridZones(workArea, info, spacing);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (zoneSet.type == FancyZonesDataTypes::CustomLayoutType::Grid && std::holds_alternative<FancyZonesDataTypes::GridLayoutInfo>(zoneSet.info))
|
||||
{
|
||||
const auto& info = std::get<FancyZonesDataTypes::GridLayoutInfo>(zoneSet.info);
|
||||
return CalculateGridZones(workArea, info, spacing);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
#include "trace.h"
|
||||
#include "FancyZonesLib/ZoneSet.h"
|
||||
#include "FancyZonesLib/Settings.h"
|
||||
#include "FancyZonesLib/FancyZonesData.h"
|
||||
#include "FancyZonesData/AppZoneHistory.h"
|
||||
#include "FancyZonesLib/FancyZonesData/AppliedLayouts.h"
|
||||
#include "FancyZonesLib/FancyZonesData/CustomLayouts.h"
|
||||
#include "FancyZonesLib/FancyZonesData/LayoutHotkeys.h"
|
||||
#include "FancyZonesLib/FancyZonesDataTypes.h"
|
||||
#include "FancyZonesLib/util.h"
|
||||
|
||||
// Telemetry strings should not be localized.
|
||||
#define LoggingProviderKey "Microsoft.PowerToys"
|
||||
@@ -141,11 +145,10 @@ void Trace::FancyZones::OnKeyDown(DWORD vkCode, bool win, bool control, bool inM
|
||||
|
||||
void Trace::FancyZones::DataChanged() noexcept
|
||||
{
|
||||
const FancyZonesData& data = FancyZonesDataInstance();
|
||||
int appsHistorySize = static_cast<int>(data.GetAppZoneHistoryMap().size());
|
||||
const auto& customZones = data.GetCustomZoneSetsMap();
|
||||
const auto& devices = data.GetDeviceInfoMap();
|
||||
const auto& quickKeys = data.GetLayoutQuickKeys();
|
||||
int appsHistorySize = static_cast<int>(AppZoneHistory::instance().GetFullAppZoneHistory().size());
|
||||
const auto& customZones = CustomLayouts::instance().GetAllLayouts();
|
||||
const auto& layouts = AppliedLayouts::instance().GetAppliedLayoutMap();
|
||||
auto quickKeysCount = LayoutHotkeys::instance().GetHotkeysCount();
|
||||
|
||||
std::unique_ptr<INT32[]> customZonesArray(new (std::nothrow) INT32[customZones.size()]);
|
||||
if (!customZonesArray)
|
||||
@@ -153,7 +156,7 @@ void Trace::FancyZones::DataChanged() noexcept
|
||||
return;
|
||||
}
|
||||
|
||||
auto getCustomZoneCount = [&data](const std::variant<FancyZonesDataTypes::CanvasLayoutInfo, FancyZonesDataTypes::GridLayoutInfo>& layoutInfo) -> int {
|
||||
auto getCustomZoneCount = [](const std::variant<FancyZonesDataTypes::CanvasLayoutInfo, FancyZonesDataTypes::GridLayoutInfo>& layoutInfo) -> int {
|
||||
if (std::holds_alternative<FancyZonesDataTypes::GridLayoutInfo>(layoutInfo))
|
||||
{
|
||||
const auto& info = std::get<FancyZonesDataTypes::GridLayoutInfo>(layoutInfo);
|
||||
@@ -177,9 +180,9 @@ void Trace::FancyZones::DataChanged() noexcept
|
||||
|
||||
// ActiveZoneSetsList
|
||||
std::wstring activeZoneSetInfo;
|
||||
for (const auto& [id, device] : devices)
|
||||
for (const auto& [id, layout] : layouts)
|
||||
{
|
||||
const FancyZonesDataTypes::ZoneSetLayoutType type = device.activeZoneSet.type;
|
||||
const FancyZonesDataTypes::ZoneSetLayoutType type = layout.type;
|
||||
if (!activeZoneSetInfo.empty())
|
||||
{
|
||||
activeZoneSetInfo += L"; ";
|
||||
@@ -189,15 +192,16 @@ void Trace::FancyZones::DataChanged() noexcept
|
||||
int zoneCount = -1;
|
||||
if (type == FancyZonesDataTypes::ZoneSetLayoutType::Custom)
|
||||
{
|
||||
const auto& activeCustomZone = customZones.find(device.activeZoneSet.uuid);
|
||||
auto guid = layout.uuid;
|
||||
const auto& activeCustomZone = customZones.find(guid);
|
||||
if (activeCustomZone != customZones.end())
|
||||
{
|
||||
zoneCount = getCustomZoneCount(activeCustomZone->second.info);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
zoneCount = device.zoneCount;
|
||||
zoneCount = layout.zoneCount;
|
||||
}
|
||||
|
||||
if (zoneCount != -1)
|
||||
@@ -218,9 +222,9 @@ void Trace::FancyZones::DataChanged() noexcept
|
||||
TraceLoggingInt32(appsHistorySize, AppsInHistoryCountKey),
|
||||
TraceLoggingInt32(static_cast<int>(customZones.size()), CustomZoneSetCountKey),
|
||||
TraceLoggingInt32Array(customZonesArray.get(), static_cast<int>(customZones.size()), NumberOfZonesForEachCustomZoneSetKey),
|
||||
TraceLoggingInt32(static_cast<int>(devices.size()), ActiveZoneSetsCountKey),
|
||||
TraceLoggingInt32(static_cast<int>(layouts.size()), ActiveZoneSetsCountKey),
|
||||
TraceLoggingWideString(activeZoneSetInfo.c_str(), ActiveZoneSetsListKey),
|
||||
TraceLoggingInt32(static_cast<int>(quickKeys.size()), LayoutUsingQuickKeyCountKey));
|
||||
TraceLoggingInt32(static_cast<int>(quickKeysCount), LayoutUsingQuickKeyCountKey));
|
||||
}
|
||||
|
||||
void Trace::FancyZones::EditorLaunched(int value) noexcept
|
||||
|
||||
@@ -550,6 +550,17 @@ namespace FancyZonesUtils
|
||||
return SUCCEEDED(CLSIDFromString(str.c_str(), &id));
|
||||
}
|
||||
|
||||
std::optional<GUID> GuidFromString(const std::wstring& str) noexcept
|
||||
{
|
||||
GUID id;
|
||||
if (SUCCEEDED(CLSIDFromString(str.c_str(), &id)))
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::wstring> GuidToString(const GUID& guid) noexcept
|
||||
{
|
||||
wil::unique_cotaskmem_string guidString;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user